@rslsp1/fa-app-tools 3.0.0 → 4.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-566GHYAT.mjs} +1398 -567
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1435 -650
- package/dist/index.mjs +3 -3
- package/dist/szenen.d.mts +355 -17
- package/dist/szenen.d.ts +355 -17
- package/dist/szenen.js +1654 -720
- package/dist/szenen.mjs +138 -25
- 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 = "4.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 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';
|
|
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,7 @@ var MediaArea = ({ port }) => {
|
|
|
15138
15513
|
};
|
|
15139
15514
|
|
|
15140
15515
|
// src/features/szenen/areas/DeriveArea.tsx
|
|
15141
|
-
var
|
|
15516
|
+
var import_react47 = require("react");
|
|
15142
15517
|
|
|
15143
15518
|
// src/lib/szenen/derivationExamples.ts
|
|
15144
15519
|
var PROPOSAL_EXAMPLE = {
|
|
@@ -15546,7 +15921,7 @@ function validateDerivationInput(input) {
|
|
|
15546
15921
|
if (input.policy.produces.length === 0) return "Die Regel erzeugt keinen einzigen Vorschlag.";
|
|
15547
15922
|
return null;
|
|
15548
15923
|
}
|
|
15549
|
-
var
|
|
15924
|
+
var isObject10 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
15550
15925
|
var MAX_PROPOSAL_TITLE_LENGTH = 120;
|
|
15551
15926
|
function fallbackProposalTitle(type) {
|
|
15552
15927
|
return `Rekonstruktion ${type}`;
|
|
@@ -15572,7 +15947,7 @@ function resolveJsonPointer(wurzel, pointer) {
|
|
|
15572
15947
|
aktuell = aktuell[index];
|
|
15573
15948
|
continue;
|
|
15574
15949
|
}
|
|
15575
|
-
if (!
|
|
15950
|
+
if (!isObject10(aktuell) || !(schluessel in aktuell)) {
|
|
15576
15951
|
return { found: false, value: void 0 };
|
|
15577
15952
|
}
|
|
15578
15953
|
aktuell = aktuell[schluessel];
|
|
@@ -15586,7 +15961,7 @@ function collectVersionRefs2(value) {
|
|
|
15586
15961
|
knoten.forEach(besuchen);
|
|
15587
15962
|
return;
|
|
15588
15963
|
}
|
|
15589
|
-
if (!
|
|
15964
|
+
if (!isObject10(knoten)) return;
|
|
15590
15965
|
if (typeof knoten.element_id === "string" && typeof knoten.version_id === "string") {
|
|
15591
15966
|
gefunden.push({ element_id: knoten.element_id, version_id: knoten.version_id });
|
|
15592
15967
|
}
|
|
@@ -15652,7 +16027,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15652
16027
|
envelope: null,
|
|
15653
16028
|
contract_ok: false
|
|
15654
16029
|
});
|
|
15655
|
-
if (!
|
|
16030
|
+
if (!isObject10(value)) {
|
|
15656
16031
|
befund({
|
|
15657
16032
|
code: "response.not_object",
|
|
15658
16033
|
severity: "error",
|
|
@@ -15670,7 +16045,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15670
16045
|
});
|
|
15671
16046
|
}
|
|
15672
16047
|
const rohProposals = value.proposals;
|
|
15673
|
-
const proposalsLesbar =
|
|
16048
|
+
const proposalsLesbar = isObject10(rohProposals);
|
|
15674
16049
|
if (!proposalsLesbar) {
|
|
15675
16050
|
befund({
|
|
15676
16051
|
code: "envelope.proposals_missing",
|
|
@@ -15680,7 +16055,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15680
16055
|
});
|
|
15681
16056
|
}
|
|
15682
16057
|
const roh = proposalsLesbar ? rohProposals : {};
|
|
15683
|
-
const rohGaps =
|
|
16058
|
+
const rohGaps = isObject10(value.gaps) ? value.gaps : {};
|
|
15684
16059
|
const gapsUngefragt = Object.keys(rohGaps).filter(
|
|
15685
16060
|
(t) => !input.policy.produces.includes(t)
|
|
15686
16061
|
);
|
|
@@ -15692,7 +16067,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15692
16067
|
pointer: "/gaps"
|
|
15693
16068
|
});
|
|
15694
16069
|
}
|
|
15695
|
-
const fehlend = input.policy.produces.filter((t) => !
|
|
16070
|
+
const fehlend = input.policy.produces.filter((t) => !isObject10(roh[t]));
|
|
15696
16071
|
if (fehlend.length > 0 && proposalsLesbar) {
|
|
15697
16072
|
const d = befund({
|
|
15698
16073
|
code: "envelope.proposals_missing_types",
|
|
@@ -15713,10 +16088,10 @@ function assessDerivationResponse(value, input) {
|
|
|
15713
16088
|
pointer: "/proposals"
|
|
15714
16089
|
});
|
|
15715
16090
|
}
|
|
15716
|
-
const rohTitles =
|
|
16091
|
+
const rohTitles = isObject10(value.titles) ? value.titles : {};
|
|
15717
16092
|
const umgebucht = [];
|
|
15718
16093
|
for (const type of input.policy.produces) {
|
|
15719
|
-
if (!
|
|
16094
|
+
if (!isObject10(roh[type])) continue;
|
|
15720
16095
|
const payload = roh[type];
|
|
15721
16096
|
const eigene = [];
|
|
15722
16097
|
const bezug = REFERENCE_FIELD[type];
|
|
@@ -15752,7 +16127,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15752
16127
|
const bezugPointer = bezug ? `/${bezug.field}` : null;
|
|
15753
16128
|
let gapFehler = false;
|
|
15754
16129
|
for (const eintrag of benannt) {
|
|
15755
|
-
if (!
|
|
16130
|
+
if (!isObject10(eintrag) || typeof eintrag.pointer !== "string" || typeof eintrag.reason !== "string" || !eintrag.reason.trim()) {
|
|
15756
16131
|
eigene.push(befund({
|
|
15757
16132
|
code: "proposal.gap_entry_invalid",
|
|
15758
16133
|
severity: "error",
|
|
@@ -15828,7 +16203,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15828
16203
|
});
|
|
15829
16204
|
} else {
|
|
15830
16205
|
for (const eintrag of value.not_derivable) {
|
|
15831
|
-
if (!
|
|
16206
|
+
if (!isObject10(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.reason !== "string") {
|
|
15832
16207
|
befund({
|
|
15833
16208
|
code: "envelope.not_derivable_entry_invalid",
|
|
15834
16209
|
severity: "error",
|
|
@@ -15853,7 +16228,7 @@ function assessDerivationResponse(value, input) {
|
|
|
15853
16228
|
});
|
|
15854
16229
|
} else {
|
|
15855
16230
|
for (const eintrag of value.conflicts) {
|
|
15856
|
-
if (!
|
|
16231
|
+
if (!isObject10(eintrag) || typeof eintrag.field !== "string" || typeof eintrag.from_image !== "string" || typeof eintrag.from_prompt !== "string") {
|
|
15857
16232
|
befund({
|
|
15858
16233
|
code: "envelope.conflicts_entry_invalid",
|
|
15859
16234
|
severity: "error",
|
|
@@ -15977,7 +16352,7 @@ async function runSceneDerivation(input, port, userPrompt) {
|
|
|
15977
16352
|
}
|
|
15978
16353
|
|
|
15979
16354
|
// src/features/szenen/areas/RecoveryPanel.tsx
|
|
15980
|
-
var
|
|
16355
|
+
var import_react45 = require("react");
|
|
15981
16356
|
var import_jsx_runtime43 = require("react/jsx-runtime");
|
|
15982
16357
|
var Diagnosen = ({ befunde, testId }) => {
|
|
15983
16358
|
if (befunde.length === 0) return null;
|
|
@@ -16028,11 +16403,11 @@ var Ausbeute = ({ bewertung }) => /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)
|
|
|
16028
16403
|
] })
|
|
16029
16404
|
] });
|
|
16030
16405
|
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,
|
|
16406
|
+
const [arbeitskopie, setArbeitskopie] = (0, import_react45.useState)(null);
|
|
16407
|
+
const [bewertung, setBewertung] = (0, import_react45.useState)(null);
|
|
16408
|
+
const [gesichert, setGesichert] = (0, import_react45.useState)(null);
|
|
16409
|
+
const [meldung, setMeldung] = (0, import_react45.useState)(null);
|
|
16410
|
+
const [laeuft, setLaeuft] = (0, import_react45.useState)(false);
|
|
16036
16411
|
if (!port.derivation) return null;
|
|
16037
16412
|
if (typeof lauf.raw_output !== "string" || lauf.raw_output.length === 0) return null;
|
|
16038
16413
|
const derivation = port.derivation;
|
|
@@ -16155,12 +16530,12 @@ var RecoveryPanel = ({ port, lauf }) => {
|
|
|
16155
16530
|
};
|
|
16156
16531
|
|
|
16157
16532
|
// src/features/szenen/areas/ChainActions.tsx
|
|
16158
|
-
var
|
|
16533
|
+
var import_react46 = require("react");
|
|
16159
16534
|
var import_jsx_runtime44 = require("react/jsx-runtime");
|
|
16160
16535
|
var ChainActions = ({ port, runId, recoveryId }) => {
|
|
16161
|
-
const [graph, setGraph] = (0,
|
|
16162
|
-
const [meldung, setMeldung] = (0,
|
|
16163
|
-
const [laeuft, setLaeuft] = (0,
|
|
16536
|
+
const [graph, setGraph] = (0, import_react46.useState)(null);
|
|
16537
|
+
const [meldung, setMeldung] = (0, import_react46.useState)(null);
|
|
16538
|
+
const [laeuft, setLaeuft] = (0, import_react46.useState)(false);
|
|
16164
16539
|
if (!port.derivation) return null;
|
|
16165
16540
|
const derivation = port.derivation;
|
|
16166
16541
|
const runs = port.runs;
|
|
@@ -16226,7 +16601,13 @@ var ChainActions = ({ port, runId, recoveryId }) => {
|
|
|
16226
16601
|
] }),
|
|
16227
16602
|
shotKnoten && /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_jsx_runtime44.Fragment, { children: [
|
|
16228
16603
|
/* @__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)(
|
|
16604
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(
|
|
16605
|
+
PromptStartAction,
|
|
16606
|
+
{
|
|
16607
|
+
port,
|
|
16608
|
+
source: { kind: "draft_chain", shotElementId: shotKnoten.elementId }
|
|
16609
|
+
}
|
|
16610
|
+
)
|
|
16230
16611
|
] }),
|
|
16231
16612
|
meldung && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)("p", { className: "szenen-error", role: "alert", "data-testid": "kette-meldung", children: meldung })
|
|
16232
16613
|
] });
|
|
@@ -16240,8 +16621,8 @@ var MODUS_TEXT = {
|
|
|
16240
16621
|
image_prompt: "Bild und Prompt"
|
|
16241
16622
|
};
|
|
16242
16623
|
var BelegFeld = ({ titel, text, testId, offen }) => {
|
|
16243
|
-
const [kopiert, setKopiert] = (0,
|
|
16244
|
-
const feld = (0,
|
|
16624
|
+
const [kopiert, setKopiert] = (0, import_react47.useState)(false);
|
|
16625
|
+
const feld = (0, import_react47.useRef)(null);
|
|
16245
16626
|
async function kopieren() {
|
|
16246
16627
|
try {
|
|
16247
16628
|
await navigator.clipboard.writeText(text);
|
|
@@ -16337,7 +16718,7 @@ function readAsBase642(datei) {
|
|
|
16337
16718
|
});
|
|
16338
16719
|
}
|
|
16339
16720
|
var BildWaehler = ({ port, gewaehlt, onWaehlen, onEntfernen }) => {
|
|
16340
|
-
const [suche, setSuche] = (0,
|
|
16721
|
+
const [suche, setSuche] = (0, import_react47.useState)("");
|
|
16341
16722
|
const [bilder] = usePortQuery(
|
|
16342
16723
|
() => port.imageLibrary.listImages({ search: suche.trim() || void 0, limit: 60 }),
|
|
16343
16724
|
[port, suche]
|
|
@@ -16395,19 +16776,19 @@ async function digestOf(datei) {
|
|
|
16395
16776
|
return [...new Uint8Array(hash)].map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
16396
16777
|
}
|
|
16397
16778
|
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,
|
|
16779
|
+
const [policyVersionId, setPolicyVersionId] = (0, import_react47.useState)("");
|
|
16780
|
+
const [modus, setModus] = (0, import_react47.useState)("prompt");
|
|
16781
|
+
const [promptText, setPromptText] = (0, import_react47.useState)("");
|
|
16782
|
+
const [dateien, setDateien] = (0, import_react47.useState)([]);
|
|
16783
|
+
const [bestandsbilder, setBestandsbilder] = (0, import_react47.useState)([]);
|
|
16784
|
+
const [laeuft, setLaeuft] = (0, import_react47.useState)(false);
|
|
16785
|
+
const [lauf, setLauf] = (0, import_react47.useState)(null);
|
|
16786
|
+
const [meldung, setMeldung] = (0, import_react47.useState)(null);
|
|
16787
|
+
const [uebernommen, setUebernommen] = (0, import_react47.useState)({});
|
|
16788
|
+
const [titel, setTitel] = (0, import_react47.useState)({});
|
|
16789
|
+
const [referenzen, setReferenzen] = (0, import_react47.useState)({});
|
|
16790
|
+
const [beanstandung, setBeanstandung] = (0, import_react47.useState)(null);
|
|
16791
|
+
const [zusatz, setZusatz] = (0, import_react47.useState)("");
|
|
16411
16792
|
const [regeln] = usePortQuery(
|
|
16412
16793
|
() => port.derivation.listPolicies(contextId),
|
|
16413
16794
|
[port, contextId]
|
|
@@ -16791,9 +17172,9 @@ var SzenenView = ({
|
|
|
16791
17172
|
initialArea,
|
|
16792
17173
|
onAreaChange
|
|
16793
17174
|
}) => {
|
|
16794
|
-
const bereiche = (0,
|
|
16795
|
-
const faehig = (0,
|
|
16796
|
-
const [aktiv, setAktiv] = (0,
|
|
17175
|
+
const bereiche = (0, import_react48.useMemo)(() => areasFor(port), [port]);
|
|
17176
|
+
const faehig = (0, import_react48.useMemo)(() => capabilitiesOf(port), [port]);
|
|
17177
|
+
const [aktiv, setAktiv] = (0, import_react48.useState)(() => resolveArea(port, initialArea));
|
|
16797
17178
|
const wechsle = (id) => {
|
|
16798
17179
|
setAktiv(id);
|
|
16799
17180
|
onAreaChange?.(id);
|
|
@@ -16824,7 +17205,16 @@ var SzenenView = ({
|
|
|
16824
17205
|
)) }),
|
|
16825
17206
|
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)("section", { className: "szenen-view__area", "aria-label": aktuellerBereich.title, children: [
|
|
16826
17207
|
aktiv === "derive" && port.derivation && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(DeriveArea, { port, contextId }),
|
|
16827
|
-
aktiv === "elements" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
17208
|
+
aktiv === "elements" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
17209
|
+
ElementsArea,
|
|
17210
|
+
{
|
|
17211
|
+
port,
|
|
17212
|
+
contextId,
|
|
17213
|
+
restrictToTypes: BAUSTEIN_TYPES,
|
|
17214
|
+
allTypesLabel: "alle Bausteine",
|
|
17215
|
+
listTitle: "Bausteine"
|
|
17216
|
+
}
|
|
17217
|
+
),
|
|
16828
17218
|
aktiv === "scene" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SceneArea, { port, contextId }),
|
|
16829
17219
|
aktiv === "setup" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(SetupArea, { port, contextId }),
|
|
16830
17220
|
aktiv === "shot" && /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(ShotArea, { port, contextId }),
|
|
@@ -17602,7 +17992,7 @@ var CHAIN_EDGES = {
|
|
|
17602
17992
|
scene_ref: { from: "scene_setup", to: "scene" },
|
|
17603
17993
|
scene_setup_ref: { from: "shot", to: "scene_setup" }
|
|
17604
17994
|
};
|
|
17605
|
-
function
|
|
17995
|
+
function istText3(wert) {
|
|
17606
17996
|
return typeof wert === "string" && wert.trim().length > 0;
|
|
17607
17997
|
}
|
|
17608
17998
|
function checkDraftChainMeta(meta, type) {
|
|
@@ -17613,14 +18003,14 @@ function checkDraftChainMeta(meta, type) {
|
|
|
17613
18003
|
};
|
|
17614
18004
|
}
|
|
17615
18005
|
const m = meta;
|
|
17616
|
-
if (!
|
|
17617
|
-
if (!
|
|
18006
|
+
if (!istText3(m.chain_id)) return { ok: false, message: '"chain_id" fehlt oder ist leer.' };
|
|
18007
|
+
if (!istText3(m.source_run_id)) {
|
|
17618
18008
|
return {
|
|
17619
18009
|
ok: false,
|
|
17620
18010
|
message: '"source_run_id" fehlt oder ist leer \u2014 ohne sie ist die Herkunft eines Kettenknotens nicht rekonstruierbar (D-96/B3).'
|
|
17621
18011
|
};
|
|
17622
18012
|
}
|
|
17623
|
-
if (m.source_recovery_id !== void 0 && !
|
|
18013
|
+
if (m.source_recovery_id !== void 0 && !istText3(m.source_recovery_id)) {
|
|
17624
18014
|
return { ok: false, message: '"source_recovery_id" ist gesetzt, aber leer.' };
|
|
17625
18015
|
}
|
|
17626
18016
|
if (!Array.isArray(m.links)) {
|
|
@@ -17645,7 +18035,7 @@ function checkDraftChainMeta(meta, type) {
|
|
|
17645
18035
|
message: `"${l.field}" gehoert an einen ${kante.from}, nicht an einen ${type}.`
|
|
17646
18036
|
};
|
|
17647
18037
|
}
|
|
17648
|
-
if (!
|
|
18038
|
+
if (!istText3(l.target_element_id) || !istText3(l.target_draft_id)) {
|
|
17649
18039
|
return {
|
|
17650
18040
|
ok: false,
|
|
17651
18041
|
message: `"links[${index}]" braucht target_element_id und target_draft_id.`
|
|
@@ -18292,12 +18682,12 @@ function createHfEventChannel(options) {
|
|
|
18292
18682
|
// src/lib/szenen/resolve.ts
|
|
18293
18683
|
var ResolveTechnicalError = class extends Error {
|
|
18294
18684
|
};
|
|
18295
|
-
var
|
|
18296
|
-
var
|
|
18685
|
+
var isObject11 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
18686
|
+
var asArray3 = (v) => Array.isArray(v) ? v : [];
|
|
18297
18687
|
var str = (v) => typeof v === "string" ? v : null;
|
|
18298
18688
|
var num = (v) => typeof v === "number" ? v : null;
|
|
18299
18689
|
async function refOf(resolver, ref, expected, path) {
|
|
18300
|
-
const versionId =
|
|
18690
|
+
const versionId = isObject11(ref) ? str(ref.version_id) : null;
|
|
18301
18691
|
if (!versionId) {
|
|
18302
18692
|
return {
|
|
18303
18693
|
ok: false,
|
|
@@ -18349,8 +18739,11 @@ async function refOf(resolver, ref, expected, path) {
|
|
|
18349
18739
|
}
|
|
18350
18740
|
return { ok: true, version: version2 };
|
|
18351
18741
|
}
|
|
18742
|
+
function ausgelassen(diagnostics, code, path, message) {
|
|
18743
|
+
diagnostics.push({ code, origin: "resolution", path, message });
|
|
18744
|
+
}
|
|
18352
18745
|
function entraeumlichtePlatzierung(placement, assumptions) {
|
|
18353
|
-
if (!
|
|
18746
|
+
if (!isObject11(placement)) return null;
|
|
18354
18747
|
if (placement.mode !== "pattern") {
|
|
18355
18748
|
assumptions.push(
|
|
18356
18749
|
`Die Kameraplatzierung (mode "${str(placement.mode) ?? "unbekannt"}") ist metrisch und entfaellt ohne can_place. Der Renderer darf daraus keine Position ableiten.`
|
|
@@ -18365,7 +18758,7 @@ function entraeumlichtePlatzierung(placement, assumptions) {
|
|
|
18365
18758
|
const entfallen = [];
|
|
18366
18759
|
if (placement.offsets !== void 0) entfallen.push("offsets");
|
|
18367
18760
|
const height = placement.height;
|
|
18368
|
-
if (
|
|
18761
|
+
if (isObject11(height)) {
|
|
18369
18762
|
if (height.mode === "anchor") {
|
|
18370
18763
|
const behalteneHoehe = {
|
|
18371
18764
|
mode: "anchor",
|
|
@@ -18444,142 +18837,328 @@ async function resolveShotPayload(input) {
|
|
|
18444
18837
|
chain
|
|
18445
18838
|
} = input;
|
|
18446
18839
|
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) {
|
|
18840
|
+
const diagnostics = [];
|
|
18841
|
+
if (!isObject11(shotPayload)) {
|
|
18457
18842
|
return {
|
|
18458
18843
|
kind: "rejected",
|
|
18459
18844
|
failure: {
|
|
18460
18845
|
class: "schema",
|
|
18461
18846
|
where: "shot",
|
|
18462
|
-
message: `Die Shot-Payload
|
|
18463
|
-
errors:
|
|
18847
|
+
message: `Die Shot-Payload ist kein Objekt, sondern ${Array.isArray(shotPayload) ? "ein Array" : typeof shotPayload}. Daraus laesst sich kein Auftrag herstellen.`,
|
|
18848
|
+
errors: []
|
|
18849
|
+
}
|
|
18850
|
+
};
|
|
18851
|
+
}
|
|
18852
|
+
const shot = shotPayload;
|
|
18853
|
+
for (const fehler4 of ohneKettenReferenz(
|
|
18854
|
+
validatePayload("shot", shotPayload).errors,
|
|
18855
|
+
chain ? "scene_setup_ref" : null
|
|
18856
|
+
)) {
|
|
18857
|
+
diagnostics.push(diagnosticOfSchemaError(fehler4, `Shot ${shotElementId}`));
|
|
18858
|
+
}
|
|
18859
|
+
let setup = null;
|
|
18860
|
+
let report = null;
|
|
18861
|
+
let canPlace = false;
|
|
18862
|
+
let capabilities;
|
|
18863
|
+
let scene;
|
|
18864
|
+
const nenntSetup = chain !== void 0 || shot.scene_setup_ref !== void 0;
|
|
18865
|
+
if (!nenntSetup) {
|
|
18866
|
+
return {
|
|
18867
|
+
kind: "rejected",
|
|
18868
|
+
failure: {
|
|
18869
|
+
class: "no_content",
|
|
18870
|
+
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
18871
|
}
|
|
18465
18872
|
};
|
|
18466
18873
|
}
|
|
18467
|
-
const shot = shotVersion.payload;
|
|
18468
18874
|
const setupRef = chain ? { ok: true, version: chain.setup } : await refOf(resolver, shot.scene_setup_ref, "scene_setup", "/scene_setup_ref");
|
|
18469
18875
|
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) {
|
|
18876
|
+
if (!isObject11(setupRef.version.payload)) {
|
|
18475
18877
|
return {
|
|
18476
18878
|
kind: "rejected",
|
|
18477
18879
|
failure: {
|
|
18478
18880
|
class: "schema",
|
|
18479
18881
|
where: "scene_setup",
|
|
18480
|
-
message: `Die Scene-Setup-Payload
|
|
18481
|
-
errors:
|
|
18882
|
+
message: `Die Scene-Setup-Payload ist kein Objekt, sondern ${Array.isArray(setupRef.version.payload) ? "ein Array" : typeof setupRef.version.payload}.`,
|
|
18883
|
+
errors: []
|
|
18482
18884
|
}
|
|
18483
18885
|
};
|
|
18484
18886
|
}
|
|
18485
|
-
|
|
18486
|
-
|
|
18887
|
+
setup = {
|
|
18888
|
+
element_id: setupRef.version.element_id,
|
|
18889
|
+
version_id: setupRef.version.version_id,
|
|
18890
|
+
payload: setupRef.version.payload
|
|
18891
|
+
};
|
|
18892
|
+
report = await capabilityReport({
|
|
18487
18893
|
type: "scene_setup",
|
|
18488
|
-
setupPayload: setup,
|
|
18489
|
-
elementId:
|
|
18894
|
+
setupPayload: setup.payload,
|
|
18895
|
+
elementId: setup.element_id,
|
|
18490
18896
|
resolver,
|
|
18491
18897
|
// Bei einer Draft-Kette kommt die Szene von hier, nicht aus `scene_ref`
|
|
18492
18898
|
// (C1). Dasselbe Regelwerk, ein anderer Weg zur selben Szene.
|
|
18493
18899
|
...chain ? { chainScene: chain.scene.payload } : {}
|
|
18494
18900
|
});
|
|
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";
|
|
18901
|
+
diagnostics.push(...report.promptDiagnostics);
|
|
18902
|
+
canPlace = report.can_place.state === "yes";
|
|
18502
18903
|
if (!canPlace) {
|
|
18503
18904
|
assumptions.push(
|
|
18504
|
-
|
|
18905
|
+
`can_place ist "${report.can_place.state}" \u2014 alle Platzierungen bleiben null. Der Renderer darf daraus keine Koordinaten ableiten (D-47).`
|
|
18505
18906
|
);
|
|
18506
18907
|
}
|
|
18507
|
-
|
|
18908
|
+
capabilities = {
|
|
18909
|
+
can_describe_scene: report.can_describe_scene.state,
|
|
18910
|
+
can_render_prompt: report.can_render_prompt.state,
|
|
18911
|
+
can_place: report.can_place.state
|
|
18912
|
+
};
|
|
18913
|
+
const sceneRef = chain ? { ok: true, version: chain.scene } : await refOf(resolver, setup.payload.scene_ref, "scene", "/scene_ref");
|
|
18508
18914
|
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) {
|
|
18915
|
+
if (!isObject11(sceneRef.version.payload)) {
|
|
18517
18916
|
return {
|
|
18518
18917
|
kind: "rejected",
|
|
18519
18918
|
failure: {
|
|
18520
|
-
class: "
|
|
18521
|
-
|
|
18522
|
-
|
|
18523
|
-
|
|
18524
|
-
reason: "unknown"
|
|
18919
|
+
class: "schema",
|
|
18920
|
+
where: "scene",
|
|
18921
|
+
message: `Die Szenen-Payload ist kein Objekt, sondern ${Array.isArray(sceneRef.version.payload) ? "ein Array" : typeof sceneRef.version.payload}.`,
|
|
18922
|
+
errors: []
|
|
18525
18923
|
}
|
|
18526
18924
|
};
|
|
18527
18925
|
}
|
|
18528
|
-
|
|
18529
|
-
|
|
18926
|
+
scene = {
|
|
18927
|
+
element_id: sceneRef.version.element_id,
|
|
18928
|
+
version_id: sceneRef.version.version_id,
|
|
18929
|
+
payload: sceneRef.version.payload
|
|
18930
|
+
};
|
|
18931
|
+
return komponiere({
|
|
18932
|
+
shot: { element_id: shotElementId, version_id: shotVersionId, payload: shot },
|
|
18933
|
+
setup,
|
|
18934
|
+
scene,
|
|
18935
|
+
report,
|
|
18936
|
+
capabilities,
|
|
18937
|
+
canPlace,
|
|
18530
18938
|
resolver,
|
|
18531
|
-
|
|
18532
|
-
|
|
18533
|
-
|
|
18534
|
-
|
|
18535
|
-
|
|
18536
|
-
|
|
18537
|
-
|
|
18538
|
-
|
|
18539
|
-
|
|
18540
|
-
|
|
18541
|
-
|
|
18542
|
-
|
|
18543
|
-
|
|
18939
|
+
contextChain,
|
|
18940
|
+
userInstruction,
|
|
18941
|
+
assumptions,
|
|
18942
|
+
diagnostics
|
|
18943
|
+
});
|
|
18944
|
+
}
|
|
18945
|
+
async function resolveScenePayload(input) {
|
|
18946
|
+
const {
|
|
18947
|
+
scenePayload,
|
|
18948
|
+
sceneElementId,
|
|
18949
|
+
sceneVersionId = "",
|
|
18950
|
+
resolver,
|
|
18951
|
+
contextChain,
|
|
18952
|
+
userInstruction
|
|
18953
|
+
} = input;
|
|
18954
|
+
if (!isObject11(scenePayload)) {
|
|
18955
|
+
return {
|
|
18956
|
+
kind: "rejected",
|
|
18957
|
+
failure: {
|
|
18958
|
+
class: "schema",
|
|
18959
|
+
where: "scene",
|
|
18960
|
+
message: `Die Szenen-Payload ist kein Objekt, sondern ${Array.isArray(scenePayload) ? "ein Array" : typeof scenePayload}.`,
|
|
18961
|
+
errors: []
|
|
18962
|
+
}
|
|
18963
|
+
};
|
|
18964
|
+
}
|
|
18965
|
+
const assumptions = [
|
|
18966
|
+
"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)."
|
|
18967
|
+
];
|
|
18968
|
+
const diagnostics = [];
|
|
18969
|
+
for (const fehler4 of validatePayload("scene", scenePayload).errors) {
|
|
18970
|
+
diagnostics.push(diagnosticOfSchemaError(fehler4, `Szene ${sceneElementId}`));
|
|
18971
|
+
}
|
|
18972
|
+
const faehig = sceneOnlyCapabilities(scenePayload);
|
|
18973
|
+
return komponiere({
|
|
18974
|
+
shot: null,
|
|
18975
|
+
setup: null,
|
|
18976
|
+
scene: { element_id: sceneElementId, version_id: sceneVersionId, payload: scenePayload },
|
|
18977
|
+
report: null,
|
|
18978
|
+
capabilities: {
|
|
18979
|
+
can_describe_scene: faehig.can_describe_scene.state,
|
|
18980
|
+
can_render_prompt: faehig.can_render_prompt.state,
|
|
18981
|
+
can_place: faehig.can_place.state
|
|
18982
|
+
},
|
|
18983
|
+
canPlace: false,
|
|
18984
|
+
resolver,
|
|
18985
|
+
contextChain,
|
|
18986
|
+
userInstruction,
|
|
18987
|
+
assumptions,
|
|
18988
|
+
diagnostics
|
|
18989
|
+
});
|
|
18990
|
+
}
|
|
18991
|
+
async function komponiere(z) {
|
|
18992
|
+
const {
|
|
18993
|
+
shot,
|
|
18994
|
+
setup,
|
|
18995
|
+
scene,
|
|
18996
|
+
report,
|
|
18997
|
+
capabilities,
|
|
18998
|
+
canPlace,
|
|
18999
|
+
resolver,
|
|
19000
|
+
contextChain,
|
|
19001
|
+
userInstruction,
|
|
19002
|
+
assumptions,
|
|
19003
|
+
diagnostics
|
|
19004
|
+
} = z;
|
|
19005
|
+
const inhalt = describableContent(scene.payload);
|
|
19006
|
+
if (!inhalt.ok) {
|
|
19007
|
+
return {
|
|
19008
|
+
kind: "rejected",
|
|
19009
|
+
failure: {
|
|
19010
|
+
class: "no_content",
|
|
19011
|
+
message: `Szene ${scene.element_id}: ${inhalt.message}`
|
|
19012
|
+
}
|
|
19013
|
+
};
|
|
19014
|
+
}
|
|
19015
|
+
const eingefroreneFaehigkeiten = {
|
|
19016
|
+
...capabilities,
|
|
19017
|
+
can_render_prompt: "yes"
|
|
19018
|
+
};
|
|
19019
|
+
const shotOverrides = shot && isObject11(shot.payload.overrides) ? shot.payload.overrides : {};
|
|
19020
|
+
const settings = shot && isObject11(shot.payload.prompt_render_settings) ? shot.payload.prompt_render_settings : {};
|
|
19021
|
+
let camera = null;
|
|
19022
|
+
if (shot && setup) {
|
|
19023
|
+
const cameraId = str(shot.payload.camera_id);
|
|
19024
|
+
const rig = isObject11(setup.payload.camera_rig) ? setup.payload.camera_rig : {};
|
|
19025
|
+
const cameras = asArray3(rig.cameras);
|
|
19026
|
+
const cameraIndex = cameraId === null ? -1 : cameras.findIndex((c) => isObject11(c) && c.camera_id === cameraId);
|
|
19027
|
+
if (cameraId === null) {
|
|
19028
|
+
ausgelassen(
|
|
19029
|
+
diagnostics,
|
|
19030
|
+
"P-01",
|
|
19031
|
+
"/camera_id",
|
|
19032
|
+
`Der Shot ${shot.element_id} nennt keine camera_id. Der Prompt entsteht ohne Kameravorgabe; eine Kamera wird nicht erfunden (D-75).`
|
|
19033
|
+
);
|
|
19034
|
+
} else if (cameraIndex < 0) {
|
|
19035
|
+
ausgelassen(
|
|
19036
|
+
diagnostics,
|
|
19037
|
+
"P-01",
|
|
19038
|
+
"/camera_id",
|
|
19039
|
+
`Die aktive camera_id "${cameraId}" kommt im Rig der Scene-Setup-Version ${setup.version_id} nicht vor. Der Prompt entsteht ohne Kameravorgabe.`
|
|
19040
|
+
);
|
|
19041
|
+
} else {
|
|
19042
|
+
const rohKamera = cameras[cameraIndex];
|
|
19043
|
+
let preset = null;
|
|
19044
|
+
const presetRef = await refOf(
|
|
19045
|
+
resolver,
|
|
19046
|
+
rohKamera.preset_ref,
|
|
19047
|
+
"camera_preset",
|
|
19048
|
+
`/camera_rig/cameras/${cameraIndex}/preset_ref`
|
|
19049
|
+
);
|
|
19050
|
+
if (presetRef.ok) preset = presetRef.version.payload;
|
|
19051
|
+
else {
|
|
19052
|
+
ausgelassen(
|
|
19053
|
+
diagnostics,
|
|
19054
|
+
"P-04",
|
|
19055
|
+
`/camera_rig/cameras/${cameraIndex}/preset_ref`,
|
|
19056
|
+
`${presetRef.failure.message} Die Kamera geht ohne Preset in den Prompt.`
|
|
19057
|
+
);
|
|
19058
|
+
}
|
|
19059
|
+
let pattern = null;
|
|
19060
|
+
const placementSpec = isObject11(rohKamera.placement) ? rohKamera.placement : null;
|
|
19061
|
+
if (placementSpec && isObject11(placementSpec.pattern_ref)) {
|
|
19062
|
+
const patternRef = await refOf(
|
|
19063
|
+
resolver,
|
|
19064
|
+
placementSpec.pattern_ref,
|
|
19065
|
+
"camera_pattern",
|
|
19066
|
+
`/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`
|
|
19067
|
+
);
|
|
19068
|
+
if (patternRef.ok) pattern = patternRef.version.payload;
|
|
19069
|
+
else {
|
|
19070
|
+
ausgelassen(
|
|
19071
|
+
diagnostics,
|
|
19072
|
+
"P-04",
|
|
19073
|
+
`/camera_rig/cameras/${cameraIndex}/placement/pattern_ref`,
|
|
19074
|
+
`${patternRef.failure.message} Das Kameramuster entfaellt im Prompt.`
|
|
19075
|
+
);
|
|
19076
|
+
}
|
|
19077
|
+
}
|
|
19078
|
+
const cameraPlacement = canPlace ? rohKamera.placement ?? null : entraeumlichtePlatzierung(rohKamera.placement, assumptions);
|
|
19079
|
+
camera = {
|
|
19080
|
+
camera_id: cameraId,
|
|
19081
|
+
name: str(rohKamera.name),
|
|
19082
|
+
preset,
|
|
19083
|
+
placement: cameraPlacement,
|
|
19084
|
+
orientation: rohKamera.orientation ?? null,
|
|
19085
|
+
// Der Shot darf Bildgroesse und Fokus ueberschreiben (D-40) — das ist
|
|
19086
|
+
// die oberste Stufe der Vorrangkette.
|
|
19087
|
+
framing: shotOverrides.framing ?? rohKamera.framing ?? null,
|
|
19088
|
+
focus: shotOverrides.focus !== void 0 ? shotOverrides.focus : rohKamera.focus ?? null,
|
|
19089
|
+
pattern
|
|
19090
|
+
};
|
|
19091
|
+
}
|
|
19092
|
+
} else if (shot && !setup) {
|
|
19093
|
+
ausgelassen(
|
|
19094
|
+
diagnostics,
|
|
19095
|
+
"P-01",
|
|
19096
|
+
"/camera_id",
|
|
19097
|
+
"Ohne Scene Setup gibt es kein Camera Rig. Der Prompt entsteht ohne Kameravorgabe."
|
|
18544
19098
|
);
|
|
18545
|
-
if (!patternRef.ok) return { kind: "rejected", failure: patternRef.failure };
|
|
18546
|
-
pattern = patternRef.version.payload;
|
|
18547
19099
|
}
|
|
18548
19100
|
let shotConcept = null;
|
|
18549
|
-
if (
|
|
19101
|
+
if (shot && isObject11(shot.payload.shot_concept_ref)) {
|
|
18550
19102
|
const conceptRef = await refOf(
|
|
18551
19103
|
resolver,
|
|
18552
|
-
shot.shot_concept_ref,
|
|
19104
|
+
shot.payload.shot_concept_ref,
|
|
18553
19105
|
"shot_concept",
|
|
18554
19106
|
"/shot_concept_ref"
|
|
18555
19107
|
);
|
|
18556
|
-
if (
|
|
18557
|
-
|
|
19108
|
+
if (conceptRef.ok) shotConcept = conceptRef.version.payload;
|
|
19109
|
+
else {
|
|
19110
|
+
ausgelassen(
|
|
19111
|
+
diagnostics,
|
|
19112
|
+
"P-04",
|
|
19113
|
+
"/shot_concept_ref",
|
|
19114
|
+
`${conceptRef.failure.message} Das Shot Concept entfaellt im Prompt.`
|
|
19115
|
+
);
|
|
19116
|
+
}
|
|
18558
19117
|
}
|
|
18559
19118
|
const styles = [];
|
|
18560
19119
|
for (const [ebene, refs] of [
|
|
18561
|
-
["scene_setup",
|
|
18562
|
-
["shot",
|
|
19120
|
+
["scene_setup", setup ? asArray3(setup.payload.style_refs) : []],
|
|
19121
|
+
["shot", shot ? asArray3(shot.payload.style_refs) : []]
|
|
18563
19122
|
]) {
|
|
18564
19123
|
for (const [i, ref] of refs.entries()) {
|
|
18565
19124
|
const resolved = await refOf(resolver, ref, "style", `/${ebene}/style_refs/${i}`);
|
|
18566
|
-
if (!resolved.ok)
|
|
19125
|
+
if (!resolved.ok) {
|
|
19126
|
+
ausgelassen(
|
|
19127
|
+
diagnostics,
|
|
19128
|
+
"P-04",
|
|
19129
|
+
`/${ebene}/style_refs/${i}`,
|
|
19130
|
+
`${resolved.failure.message} Dieser Stil entfaellt im Prompt.`
|
|
19131
|
+
);
|
|
19132
|
+
continue;
|
|
19133
|
+
}
|
|
18567
19134
|
const payload = resolved.version.payload;
|
|
18568
19135
|
styles.push({
|
|
18569
|
-
role: str(
|
|
18570
|
-
rank: num(
|
|
18571
|
-
weight: num(
|
|
19136
|
+
role: str(isObject11(ref) ? ref.role : null) ?? str(payload.role) ?? "unspecified",
|
|
19137
|
+
rank: num(isObject11(ref) ? ref.rank : null) ?? 0,
|
|
19138
|
+
weight: num(isObject11(ref) ? ref.weight : null),
|
|
18572
19139
|
text: str(payload.text) ?? "",
|
|
18573
19140
|
locale: str(payload.locale)
|
|
18574
19141
|
});
|
|
18575
19142
|
}
|
|
18576
19143
|
}
|
|
18577
19144
|
styles.sort((a, b) => a.rank - b.rank);
|
|
18578
|
-
const settings = isObject10(shot.prompt_render_settings) ? shot.prompt_render_settings : {};
|
|
18579
19145
|
const policies = [];
|
|
18580
|
-
for (const [i, ref] of
|
|
18581
|
-
const resolved = await refOf(
|
|
18582
|
-
|
|
19146
|
+
for (const [i, ref] of asArray3(settings.policy_refs).entries()) {
|
|
19147
|
+
const resolved = await refOf(
|
|
19148
|
+
resolver,
|
|
19149
|
+
ref,
|
|
19150
|
+
"prompt_policy",
|
|
19151
|
+
`/prompt_render_settings/policy_refs/${i}`
|
|
19152
|
+
);
|
|
19153
|
+
if (!resolved.ok) {
|
|
19154
|
+
ausgelassen(
|
|
19155
|
+
diagnostics,
|
|
19156
|
+
"P-04",
|
|
19157
|
+
`/prompt_render_settings/policy_refs/${i}`,
|
|
19158
|
+
`${resolved.failure.message} Diese Policy entfaellt im Prompt.`
|
|
19159
|
+
);
|
|
19160
|
+
continue;
|
|
19161
|
+
}
|
|
18583
19162
|
const payload = resolved.version.payload;
|
|
18584
19163
|
policies.push({
|
|
18585
19164
|
subtype: str(payload.subtype) ?? "general",
|
|
@@ -18590,14 +19169,22 @@ async function resolveShotPayload(input) {
|
|
|
18590
19169
|
}
|
|
18591
19170
|
policies.sort((a, b) => a.rank - b.rank);
|
|
18592
19171
|
const fragments = [];
|
|
18593
|
-
for (const [i, ref] of
|
|
19172
|
+
for (const [i, ref] of asArray3(settings.fragment_refs).entries()) {
|
|
18594
19173
|
const resolved = await refOf(
|
|
18595
19174
|
resolver,
|
|
18596
19175
|
ref,
|
|
18597
19176
|
"prompt_fragment",
|
|
18598
19177
|
`/prompt_render_settings/fragment_refs/${i}`
|
|
18599
19178
|
);
|
|
18600
|
-
if (!resolved.ok)
|
|
19179
|
+
if (!resolved.ok) {
|
|
19180
|
+
ausgelassen(
|
|
19181
|
+
diagnostics,
|
|
19182
|
+
"P-04",
|
|
19183
|
+
`/prompt_render_settings/fragment_refs/${i}`,
|
|
19184
|
+
`${resolved.failure.message} Dieses Fragment entfaellt im Prompt.`
|
|
19185
|
+
);
|
|
19186
|
+
continue;
|
|
19187
|
+
}
|
|
18601
19188
|
const payload = resolved.version.payload;
|
|
18602
19189
|
fragments.push({
|
|
18603
19190
|
channel: str(payload.channel) ?? "positive",
|
|
@@ -18607,83 +19194,102 @@ async function resolveShotPayload(input) {
|
|
|
18607
19194
|
});
|
|
18608
19195
|
}
|
|
18609
19196
|
fragments.sort((a, b) => a.rank - b.rank);
|
|
18610
|
-
|
|
18611
|
-
|
|
18612
|
-
|
|
18613
|
-
|
|
18614
|
-
|
|
18615
|
-
|
|
18616
|
-
|
|
18617
|
-
|
|
18618
|
-
}
|
|
18619
|
-
|
|
18620
|
-
}
|
|
18621
|
-
if (!resolver.resolveTargetModel) {
|
|
19197
|
+
let targetModelPayload = null;
|
|
19198
|
+
let targetModelResolution = null;
|
|
19199
|
+
const key = shot ? str(settings.target_model_id) : null;
|
|
19200
|
+
if (key === null) {
|
|
19201
|
+
ausgelassen(
|
|
19202
|
+
diagnostics,
|
|
19203
|
+
"P-17",
|
|
19204
|
+
"/prompt_render_settings/target_model_id",
|
|
19205
|
+
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."
|
|
19206
|
+
);
|
|
19207
|
+
} else if (!resolver.resolveTargetModel) {
|
|
18622
19208
|
throw new ResolveTechnicalError(
|
|
18623
19209
|
`Der Resolver bietet keine Zielmodellsuche an (kein ContextChainPort). Ein Lauf ohne Kontextkette wuerde ein Zielmodell melden, das nicht das gesuchte ist.`
|
|
18624
19210
|
);
|
|
18625
|
-
}
|
|
18626
|
-
|
|
18627
|
-
|
|
18628
|
-
|
|
18629
|
-
|
|
18630
|
-
|
|
18631
|
-
|
|
18632
|
-
|
|
18633
|
-
|
|
19211
|
+
} else {
|
|
19212
|
+
const targetModel = await resolver.resolveTargetModel(key, shot.element_id);
|
|
19213
|
+
if (targetModel.kind !== "resolved") {
|
|
19214
|
+
ausgelassen(
|
|
19215
|
+
diagnostics,
|
|
19216
|
+
"P-17",
|
|
19217
|
+
"/prompt_render_settings/target_model_id",
|
|
19218
|
+
`${describeTargetModelFailure(targetModel)} Der Prompt wird generisch abgeleitet, ohne Modelloptimierung.`
|
|
19219
|
+
);
|
|
19220
|
+
} else {
|
|
19221
|
+
targetModelPayload = targetModel.payload;
|
|
19222
|
+
targetModelResolution = {
|
|
19223
|
+
element_id: targetModel.elementId,
|
|
19224
|
+
version_id: targetModel.versionId,
|
|
19225
|
+
chain_index: targetModel.chainIndex,
|
|
19226
|
+
head: targetModel.head,
|
|
19227
|
+
shadowed_retired: targetModel.shadowedRetired.map((entry) => ({
|
|
19228
|
+
element_id: entry.elementId,
|
|
19229
|
+
context_id: entry.contextId
|
|
19230
|
+
}))
|
|
19231
|
+
};
|
|
19232
|
+
for (const uebergangen of targetModel.shadowedRetired) {
|
|
19233
|
+
assumptions.push(
|
|
19234
|
+
`Ein stillgelegtes target_model (${uebergangen.elementId}, Kontext ${uebergangen.contextId ?? "global"}) wurde uebergangen; verwendet wird ${targetModel.elementId} von Kettenglied ${targetModel.chainIndex}.`
|
|
19235
|
+
);
|
|
18634
19236
|
}
|
|
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
|
-
);
|
|
19237
|
+
if (targetModel.head.kind === "selected" && targetModel.head.stale) {
|
|
19238
|
+
assumptions.push(
|
|
19239
|
+
`Die Auswahl des Zielmodell-Heads (${targetModel.versionId}) ist veraltet \u2014 es gibt neuere Heads. Die Auswahl gilt, weil sie getroffen wurde (D-36).`
|
|
19240
|
+
);
|
|
19241
|
+
}
|
|
19242
|
+
}
|
|
18646
19243
|
}
|
|
18647
19244
|
const overrides = /* @__PURE__ */ new Map();
|
|
18648
|
-
for (const entry of
|
|
18649
|
-
if (
|
|
19245
|
+
for (const entry of setup ? asArray3(setup.payload.node_overrides) : []) {
|
|
19246
|
+
if (isObject11(entry) && typeof entry.node_id === "string") overrides.set(entry.node_id, entry);
|
|
18650
19247
|
}
|
|
18651
19248
|
const placements = /* @__PURE__ */ new Map();
|
|
18652
|
-
for (const entry of
|
|
18653
|
-
if (!
|
|
19249
|
+
for (const entry of setup ? asArray3(setup.payload.placements) : []) {
|
|
19250
|
+
if (!isObject11(entry) || typeof entry.node_id !== "string") continue;
|
|
18654
19251
|
placements.set(entry.node_id, {
|
|
18655
|
-
position:
|
|
18656
|
-
...entry.rotation_euler_deg ? { rotation_euler_deg:
|
|
18657
|
-
...entry.scale ? { scale:
|
|
19252
|
+
position: asArray3(entry.position),
|
|
19253
|
+
...entry.rotation_euler_deg ? { rotation_euler_deg: asArray3(entry.rotation_euler_deg) } : {},
|
|
19254
|
+
...entry.scale ? { scale: asArray3(entry.scale) } : {}
|
|
18658
19255
|
});
|
|
18659
19256
|
}
|
|
18660
|
-
const
|
|
18661
|
-
|
|
19257
|
+
const hidden = new Set(
|
|
19258
|
+
asArray3(shotOverrides.hidden_nodes).filter((v) => typeof v === "string")
|
|
19259
|
+
);
|
|
18662
19260
|
const nodes = [];
|
|
18663
|
-
for (const raw of
|
|
18664
|
-
if (!
|
|
19261
|
+
for (const raw of asArray3(scene.payload.nodes)) {
|
|
19262
|
+
if (!isObject11(raw) || typeof raw.node_id !== "string") continue;
|
|
18665
19263
|
const nodeId = raw.node_id;
|
|
18666
19264
|
const contributions = [];
|
|
18667
|
-
for (const [i, ref] of
|
|
19265
|
+
for (const [i, ref] of asArray3(raw.component_refs).entries()) {
|
|
18668
19266
|
const resolved = await refOf(
|
|
18669
19267
|
resolver,
|
|
18670
19268
|
ref,
|
|
18671
19269
|
"scene_component",
|
|
18672
19270
|
`/nodes/${nodeId}/component_refs/${i}`
|
|
18673
19271
|
);
|
|
18674
|
-
if (!resolved.ok)
|
|
19272
|
+
if (!resolved.ok) {
|
|
19273
|
+
ausgelassen(
|
|
19274
|
+
diagnostics,
|
|
19275
|
+
"P-05",
|
|
19276
|
+
`/nodes/${nodeId}/component_refs/${i}`,
|
|
19277
|
+
`${resolved.failure.message} Dieser Beitrag entfaellt; der Knoten bleibt mit seinen uebrigen Beitraegen im Prompt.`
|
|
19278
|
+
);
|
|
19279
|
+
continue;
|
|
19280
|
+
}
|
|
18675
19281
|
const payload = resolved.version.payload;
|
|
18676
19282
|
contributions.push({
|
|
18677
19283
|
source: "component",
|
|
18678
19284
|
element_id: resolved.version.element_id,
|
|
18679
19285
|
version_id: resolved.version.version_id,
|
|
18680
|
-
role: str(
|
|
18681
|
-
rank: num(
|
|
19286
|
+
role: str(isObject11(ref) ? ref.role : null),
|
|
19287
|
+
rank: num(isObject11(ref) ? ref.rank : null) ?? 0,
|
|
18682
19288
|
locale: str(payload.locale),
|
|
18683
19289
|
text: str(payload.text) ?? ""
|
|
18684
19290
|
});
|
|
18685
19291
|
}
|
|
18686
|
-
const semantic =
|
|
19292
|
+
const semantic = isObject11(raw.semantic) ? raw.semantic : null;
|
|
18687
19293
|
if (semantic && str(semantic.description)) {
|
|
18688
19294
|
contributions.push({
|
|
18689
19295
|
source: "node_semantic",
|
|
@@ -18697,12 +19303,12 @@ async function resolveShotPayload(input) {
|
|
|
18697
19303
|
});
|
|
18698
19304
|
}
|
|
18699
19305
|
const override = overrides.get(nodeId);
|
|
18700
|
-
const overrideSemantic = override &&
|
|
18701
|
-
if (overrideSemantic && str(overrideSemantic.description)) {
|
|
19306
|
+
const overrideSemantic = override && isObject11(override.semantic) ? override.semantic : null;
|
|
19307
|
+
if (overrideSemantic && str(overrideSemantic.description) && setup) {
|
|
18702
19308
|
contributions.push({
|
|
18703
19309
|
source: "setup_override",
|
|
18704
|
-
element_id:
|
|
18705
|
-
version_id:
|
|
19310
|
+
element_id: setup.element_id,
|
|
19311
|
+
version_id: setup.version_id,
|
|
18706
19312
|
role: null,
|
|
18707
19313
|
rank: Number.MAX_SAFE_INTEGER,
|
|
18708
19314
|
locale: null,
|
|
@@ -18711,8 +19317,8 @@ async function resolveShotPayload(input) {
|
|
|
18711
19317
|
}
|
|
18712
19318
|
contributions.sort((a, b) => a.rank - b.rank);
|
|
18713
19319
|
const properties = {
|
|
18714
|
-
...
|
|
18715
|
-
...
|
|
19320
|
+
...isObject11(semantic?.properties) ? semantic.properties : {},
|
|
19321
|
+
...isObject11(overrideSemantic?.properties) ? overrideSemantic.properties : {}
|
|
18716
19322
|
};
|
|
18717
19323
|
nodes.push({
|
|
18718
19324
|
node_id: nodeId,
|
|
@@ -18723,9 +19329,6 @@ async function resolveShotPayload(input) {
|
|
|
18723
19329
|
hidden: hidden.has(nodeId)
|
|
18724
19330
|
});
|
|
18725
19331
|
}
|
|
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
19332
|
const shotInstruction = str(settings.user_instruction);
|
|
18730
19333
|
if (userInstruction && shotInstruction && userInstruction !== shotInstruction) {
|
|
18731
19334
|
assumptions.push(
|
|
@@ -18739,92 +19342,40 @@ async function resolveShotPayload(input) {
|
|
|
18739
19342
|
kind: "resolved",
|
|
18740
19343
|
report,
|
|
18741
19344
|
input: {
|
|
18742
|
-
shot: {
|
|
18743
|
-
version_id:
|
|
18744
|
-
element_id:
|
|
18745
|
-
camera_id:
|
|
19345
|
+
shot: shot ? {
|
|
19346
|
+
version_id: shot.version_id,
|
|
19347
|
+
element_id: shot.element_id,
|
|
19348
|
+
camera_id: camera ? camera.camera_id : null,
|
|
18746
19349
|
shot_concept: shotConcept,
|
|
18747
19350
|
// Der Aufrufer darf die im Shot hinterlegte Anweisung ueberschreiben
|
|
18748
19351
|
// (§4.1). Beide Herkuenfte sind unterschiedliche Sachverhalte, deshalb
|
|
18749
19352
|
// wird der Fall in `assumptions` benannt statt still ersetzt.
|
|
18750
|
-
user_instruction: userInstruction ??
|
|
19353
|
+
user_instruction: userInstruction ?? shotInstruction,
|
|
18751
19354
|
text_override: str(shotOverrides.text)
|
|
18752
|
-
},
|
|
19355
|
+
} : null,
|
|
19356
|
+
setup: setup ? { version_id: setup.version_id, element_id: setup.element_id } : null,
|
|
18753
19357
|
scene: {
|
|
18754
|
-
|
|
19358
|
+
element_id: scene.element_id,
|
|
19359
|
+
version_id: scene.version_id,
|
|
18755
19360
|
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
|
|
19361
|
+
relations: asArray3(scene.payload.relations),
|
|
19362
|
+
environment: scene.payload.environment ?? null,
|
|
19363
|
+
unit_system: scene.payload.unit_system ?? null
|
|
18769
19364
|
},
|
|
19365
|
+
camera,
|
|
18770
19366
|
styles,
|
|
18771
19367
|
policies,
|
|
18772
19368
|
fragments,
|
|
18773
|
-
target_model:
|
|
19369
|
+
target_model: targetModelPayload,
|
|
18774
19370
|
localization_notes: [],
|
|
18775
19371
|
assumptions,
|
|
18776
|
-
|
|
18777
|
-
|
|
18778
|
-
can_render_prompt: report.can_render_prompt.state,
|
|
18779
|
-
can_place: report.can_place.state
|
|
18780
|
-
},
|
|
19372
|
+
diagnostics,
|
|
19373
|
+
capabilities: eingefroreneFaehigkeiten,
|
|
18781
19374
|
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
|
-
}
|
|
19375
|
+
target_model_resolution: targetModelResolution
|
|
18792
19376
|
}
|
|
18793
19377
|
};
|
|
18794
19378
|
}
|
|
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
19379
|
|
|
18829
19380
|
// src/lib/szenen/freezeDraftChain.ts
|
|
18830
19381
|
function ladeKnoten(sicht, elementId, erwarteterTyp) {
|
|
@@ -18960,9 +19511,117 @@ async function freezeDraftChain(input) {
|
|
|
18960
19511
|
...shot.chain.source_recovery_id ? { sourceRecoveryId: shot.chain.source_recovery_id } : {}
|
|
18961
19512
|
};
|
|
18962
19513
|
}
|
|
19514
|
+
function ladeSzene(sicht, elementId, contextChain) {
|
|
19515
|
+
const gelesen = sicht.getElement(elementId);
|
|
19516
|
+
if (gelesen.kind !== "ok") {
|
|
19517
|
+
return {
|
|
19518
|
+
fehler: gelesen.message ?? `Element ${elementId} konnte nicht gelesen werden.`,
|
|
19519
|
+
technisch: true
|
|
19520
|
+
};
|
|
19521
|
+
}
|
|
19522
|
+
const snapshot = gelesen.value;
|
|
19523
|
+
if (!snapshot) return { fehler: `Element ${elementId} ist unbekannt.` };
|
|
19524
|
+
if (snapshot.element.type !== "scene") {
|
|
19525
|
+
return {
|
|
19526
|
+
fehler: `Element ${elementId} ist vom Typ "${snapshot.element.type}", erwartet "scene".`
|
|
19527
|
+
};
|
|
19528
|
+
}
|
|
19529
|
+
if (snapshot.draftFork) {
|
|
19530
|
+
return {
|
|
19531
|
+
fehler: `Element ${elementId} hat parallele Entwuerfe. Solange sie nicht aufgeloest sind, gibt es keinen eindeutigen Arbeitsstand (D-29).`
|
|
19532
|
+
};
|
|
19533
|
+
}
|
|
19534
|
+
if (snapshot.draft) {
|
|
19535
|
+
return {
|
|
19536
|
+
element_id: elementId,
|
|
19537
|
+
draft_id: snapshot.draft.draft_id,
|
|
19538
|
+
revision: snapshot.draft.revision,
|
|
19539
|
+
version_id: null,
|
|
19540
|
+
payload: snapshot.draft.payload
|
|
19541
|
+
};
|
|
19542
|
+
}
|
|
19543
|
+
const versionen = snapshot.versions ?? [];
|
|
19544
|
+
if (versionen.length === 0) {
|
|
19545
|
+
return {
|
|
19546
|
+
fehler: `Element ${elementId} hat weder einen Entwurf noch eine veroeffentlichte Version. Es gibt nichts einzufrieren.`
|
|
19547
|
+
};
|
|
19548
|
+
}
|
|
19549
|
+
const kopf = effectivePreferredHeadSafe(
|
|
19550
|
+
{ element: snapshot.element, versions: versionen, preferredHeads: snapshot.preferredHeads },
|
|
19551
|
+
contextChain
|
|
19552
|
+
);
|
|
19553
|
+
if (kopf.kind === "dag_fehler") {
|
|
19554
|
+
return { fehler: `Der Versionsgraph von Element ${elementId} ist nicht aufbaubar: ${kopf.message}` };
|
|
19555
|
+
}
|
|
19556
|
+
const versionId = usableHeadVersionId(resolutionOf(kopf));
|
|
19557
|
+
if (!versionId) {
|
|
19558
|
+
return {
|
|
19559
|
+
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.`
|
|
19560
|
+
};
|
|
19561
|
+
}
|
|
19562
|
+
const version2 = versionen.find((v) => v.version_id === versionId);
|
|
19563
|
+
if (!version2) {
|
|
19564
|
+
return {
|
|
19565
|
+
fehler: `Die wirksame Version ${versionId} von Element ${elementId} steht nicht in der gelesenen Momentaufnahme.`
|
|
19566
|
+
};
|
|
19567
|
+
}
|
|
19568
|
+
return {
|
|
19569
|
+
element_id: elementId,
|
|
19570
|
+
draft_id: null,
|
|
19571
|
+
revision: null,
|
|
19572
|
+
version_id: versionId,
|
|
19573
|
+
payload: version2.payload
|
|
19574
|
+
};
|
|
19575
|
+
}
|
|
19576
|
+
async function freezeSceneWorkingState(input) {
|
|
19577
|
+
const { sceneElementId, store, resolver, contextChain, userInstruction } = input;
|
|
19578
|
+
const a = await store.readSnapshot({ fresh: false });
|
|
19579
|
+
const szene = ladeSzene(a, sceneElementId, contextChain);
|
|
19580
|
+
if ("fehler" in szene) return ausfallErgebnis(szene);
|
|
19581
|
+
const b = await store.readSnapshot({ fresh: true });
|
|
19582
|
+
const erneut = ladeSzene(b, sceneElementId, contextChain);
|
|
19583
|
+
if ("fehler" in erneut) return ausfallErgebnis(erneut);
|
|
19584
|
+
if (erneut.draft_id !== szene.draft_id || erneut.revision !== szene.revision || erneut.version_id !== szene.version_id) {
|
|
19585
|
+
return {
|
|
19586
|
+
kind: "conflict",
|
|
19587
|
+
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.`,
|
|
19588
|
+
node: { type: "scene", element_id: sceneElementId, draft_id: szene.draft_id ?? "" },
|
|
19589
|
+
expectedRevision: szene.revision ?? 0,
|
|
19590
|
+
actualRevision: erneut.revision ?? 0
|
|
19591
|
+
};
|
|
19592
|
+
}
|
|
19593
|
+
const aufgeloest = await resolveScenePayload({
|
|
19594
|
+
scenePayload: szene.payload,
|
|
19595
|
+
sceneElementId: szene.element_id,
|
|
19596
|
+
// Ein Entwurf hat keine Version — und bekommt hier auch keine erfundene
|
|
19597
|
+
// (D-98/D-75).
|
|
19598
|
+
sceneVersionId: szene.version_id ?? "",
|
|
19599
|
+
resolver,
|
|
19600
|
+
contextChain,
|
|
19601
|
+
userInstruction
|
|
19602
|
+
});
|
|
19603
|
+
if (aufgeloest.kind !== "resolved") {
|
|
19604
|
+
return {
|
|
19605
|
+
kind: "rejected",
|
|
19606
|
+
message: aufgeloest.failure.message,
|
|
19607
|
+
failure: aufgeloest.failure
|
|
19608
|
+
};
|
|
19609
|
+
}
|
|
19610
|
+
return {
|
|
19611
|
+
kind: "ok",
|
|
19612
|
+
scene: {
|
|
19613
|
+
element_id: szene.element_id,
|
|
19614
|
+
draft_id: szene.draft_id,
|
|
19615
|
+
revision: szene.revision,
|
|
19616
|
+
version_id: szene.version_id
|
|
19617
|
+
},
|
|
19618
|
+
input: aufgeloest.input
|
|
19619
|
+
};
|
|
19620
|
+
}
|
|
18963
19621
|
|
|
18964
19622
|
// src/lib/szenen/promptRun.ts
|
|
18965
19623
|
function buildSystemInstruction2(input) {
|
|
19624
|
+
const ohneZielmodell = input.target_model === null || input.target_model === void 0;
|
|
18966
19625
|
const model = input.target_model ?? {};
|
|
18967
19626
|
const sprache = typeof model.prompt_language === "string" ? model.prompt_language : "en";
|
|
18968
19627
|
const negativ = model.supports_negative_prompt === true;
|
|
@@ -18983,7 +19642,11 @@ function buildSystemInstruction2(input) {
|
|
|
18983
19642
|
"",
|
|
18984
19643
|
`Der Prompt wird in der Sprache "${sprache}" formuliert.`
|
|
18985
19644
|
];
|
|
18986
|
-
if (
|
|
19645
|
+
if (ohneZielmodell) {
|
|
19646
|
+
zeilen.push(
|
|
19647
|
+
'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".'
|
|
19648
|
+
);
|
|
19649
|
+
} else if (!negativ) {
|
|
18987
19650
|
zeilen.push(
|
|
18988
19651
|
'Das Zielmodell kennt KEIN Negativ-Prompt-Feld. "negative" bleibt null; was mit negativen Fragmenten geschehen ist, gehoert in "notes".'
|
|
18989
19652
|
);
|
|
@@ -19012,6 +19675,14 @@ function buildSystemInstruction2(input) {
|
|
|
19012
19675
|
'Widersprechen sie einander, nenne den Widerspruch mit beiden Quellen in "notes" \u2014',
|
|
19013
19676
|
"waehle nicht still eine Seite."
|
|
19014
19677
|
);
|
|
19678
|
+
if (input.camera === null) {
|
|
19679
|
+
zeilen.push(
|
|
19680
|
+
"",
|
|
19681
|
+
"Es ist KEINE Kamera angegeben. Erfinde keine Brennweite, keinen Bildausschnitt",
|
|
19682
|
+
"und keine Kameraposition. Wo eine Kameraaussage noetig waere, formuliere sie",
|
|
19683
|
+
'als Annahme und nenne sie in "notes".'
|
|
19684
|
+
);
|
|
19685
|
+
}
|
|
19015
19686
|
if (input.capabilities.can_place !== "yes") {
|
|
19016
19687
|
zeilen.push(
|
|
19017
19688
|
"",
|
|
@@ -19025,7 +19696,7 @@ function buildSystemInstruction2(input) {
|
|
|
19025
19696
|
function buildUserPrompt2(input) {
|
|
19026
19697
|
return JSON.stringify(input, null, 2);
|
|
19027
19698
|
}
|
|
19028
|
-
var
|
|
19699
|
+
var isObject12 = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
|
|
19029
19700
|
function parseRunResponse(raw) {
|
|
19030
19701
|
const text = raw.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, "").trim();
|
|
19031
19702
|
if (text.length === 0) return { ok: false, message: "Die Antwort war leer." };
|
|
@@ -19039,7 +19710,7 @@ function parseRunResponse(raw) {
|
|
|
19039
19710
|
}
|
|
19040
19711
|
}
|
|
19041
19712
|
function checkRunResponse(value, input) {
|
|
19042
|
-
if (!
|
|
19713
|
+
if (!isObject12(value)) {
|
|
19043
19714
|
return { ok: false, message: `Die Antwort ist kein Objekt, sondern ${Array.isArray(value) ? "array" : typeof value}.` };
|
|
19044
19715
|
}
|
|
19045
19716
|
if (typeof value.positive !== "string" || value.positive.trim().length === 0) {
|
|
@@ -19057,11 +19728,11 @@ function checkRunResponse(value, input) {
|
|
|
19057
19728
|
if (negative !== null && !negativErlaubt) {
|
|
19058
19729
|
return {
|
|
19059
19730
|
ok: false,
|
|
19060
|
-
message: `Das Zielmodell fuehrt kein Negativ-Prompt-Feld (supports_negative_prompt = false), die Antwort liefert aber eines.`
|
|
19731
|
+
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
19732
|
};
|
|
19062
19733
|
}
|
|
19063
19734
|
const visibility = value.visibility;
|
|
19064
|
-
if (!
|
|
19735
|
+
if (!isObject12(visibility)) {
|
|
19065
19736
|
return { ok: false, message: '"visibility" fehlt \u2014 die Pflichtdiagnosen aus D-21.' };
|
|
19066
19737
|
}
|
|
19067
19738
|
if (typeof visibility.basis !== "string") {
|
|
@@ -19073,7 +19744,7 @@ function checkRunResponse(value, input) {
|
|
|
19073
19744
|
const genannt = /* @__PURE__ */ new Set();
|
|
19074
19745
|
const nodes = [];
|
|
19075
19746
|
for (const eintrag of visibility.nodes) {
|
|
19076
|
-
if (!
|
|
19747
|
+
if (!isObject12(eintrag) || typeof eintrag.node_id !== "string" || typeof eintrag.state !== "string") {
|
|
19077
19748
|
return { ok: false, message: 'Ein Eintrag in "visibility.nodes" hat keine node_id oder keinen state.' };
|
|
19078
19749
|
}
|
|
19079
19750
|
genannt.add(eintrag.node_id);
|
|
@@ -19218,6 +19889,23 @@ function createEventLogRunPersistence(channel) {
|
|
|
19218
19889
|
return queryError(error, `Laeufe der Kette ${chainId} konnten nicht gelesen werden`);
|
|
19219
19890
|
}
|
|
19220
19891
|
},
|
|
19892
|
+
async listForScene(sceneElementId) {
|
|
19893
|
+
try {
|
|
19894
|
+
const events = await channel.readEvents();
|
|
19895
|
+
return {
|
|
19896
|
+
kind: "ok",
|
|
19897
|
+
value: collectPromptRuns(events).filter((run) => {
|
|
19898
|
+
const quelle = sourceOf(run);
|
|
19899
|
+
return quelle.kind === "scene_direct" && quelle.scene.element_id === sceneElementId;
|
|
19900
|
+
})
|
|
19901
|
+
};
|
|
19902
|
+
} catch (error) {
|
|
19903
|
+
return queryError(
|
|
19904
|
+
error,
|
|
19905
|
+
`Laeufe der Szene ${sceneElementId} konnten nicht gelesen werden`
|
|
19906
|
+
);
|
|
19907
|
+
}
|
|
19908
|
+
},
|
|
19221
19909
|
async record(record) {
|
|
19222
19910
|
try {
|
|
19223
19911
|
await channel.appendEvent(SZENEN_EVENT_TYPES.promptRunRecorded, record);
|
|
@@ -19304,13 +19992,21 @@ function createClientRunPort(options) {
|
|
|
19304
19992
|
return { kind: "error", message: resolved.failure.message, retryable: false };
|
|
19305
19993
|
}
|
|
19306
19994
|
const outcome = await runPromptDerivation(resolved.input, text);
|
|
19995
|
+
if (!resolved.input.shot) {
|
|
19996
|
+
return {
|
|
19997
|
+
kind: "error",
|
|
19998
|
+
message: `Die Aufloesung der Shot-Version ${input.shotVersionId} lieferte eine Eingabe ohne Shot. Das ist ein Programmfehler, kein Lauf.`,
|
|
19999
|
+
retryable: false
|
|
20000
|
+
};
|
|
20001
|
+
}
|
|
19307
20002
|
const record = {
|
|
19308
20003
|
run_id: newRunId(),
|
|
19309
20004
|
shot_version_id: input.shotVersionId,
|
|
19310
20005
|
shot_element_id: resolved.input.shot.element_id,
|
|
19311
20006
|
scene_setup_version_id: resolved.input.scene.version_id,
|
|
19312
|
-
|
|
19313
|
-
|
|
20007
|
+
// Leer heisst „kein Wert", nicht „Wert unbekannt" (D-75/D-135).
|
|
20008
|
+
camera_id: resolved.input.shot.camera_id ?? "",
|
|
20009
|
+
target_model_version_id: resolved.input.target_model_resolution?.version_id ?? "",
|
|
19314
20010
|
provider: outcome.provider,
|
|
19315
20011
|
model_id: outcome.model_id,
|
|
19316
20012
|
system_prompt: outcome.system_prompt,
|
|
@@ -19382,8 +20078,8 @@ function createClientRunPort(options) {
|
|
|
19382
20078
|
shot_version_id: "",
|
|
19383
20079
|
shot_element_id: input.shotElementId,
|
|
19384
20080
|
scene_setup_version_id: "",
|
|
19385
|
-
camera_id: eingefroren.input.shot
|
|
19386
|
-
target_model_version_id: eingefroren.input.target_model_resolution
|
|
20081
|
+
camera_id: eingefroren.input.shot?.camera_id ?? "",
|
|
20082
|
+
target_model_version_id: eingefroren.input.target_model_resolution?.version_id ?? "",
|
|
19387
20083
|
provider: outcome.provider,
|
|
19388
20084
|
model_id: outcome.model_id,
|
|
19389
20085
|
system_prompt: outcome.system_prompt,
|
|
@@ -19417,6 +20113,95 @@ function createClientRunPort(options) {
|
|
|
19417
20113
|
async listRunsForChain(chainId) {
|
|
19418
20114
|
const alle = await runs.listForChain(chainId);
|
|
19419
20115
|
return alle;
|
|
20116
|
+
},
|
|
20117
|
+
// ── Der Lauf direkt aus einer Szene (D-135) ───────────────────────────
|
|
20118
|
+
//
|
|
20119
|
+
// Bewusst **derselbe** Ablauf wie oben: Kontext ermitteln, Kette
|
|
20120
|
+
// aufloesen, einfrieren, dann erst rufen. Was sich unterscheidet, ist
|
|
20121
|
+
// ausschliesslich, **was** eingefroren wird — ein Szenen-Arbeitsstand
|
|
20122
|
+
// statt einer Drei-Knoten-Kette.
|
|
20123
|
+
async startRunFromScene(input) {
|
|
20124
|
+
try {
|
|
20125
|
+
let contextId = input.contextId;
|
|
20126
|
+
if (contextId === void 0) {
|
|
20127
|
+
const element = await elements.getElement(input.sceneElementId);
|
|
20128
|
+
if (element.kind !== "ok") {
|
|
20129
|
+
return { kind: "error", message: element.message, retryable: element.retryable };
|
|
20130
|
+
}
|
|
20131
|
+
if (element.value === null) {
|
|
20132
|
+
return {
|
|
20133
|
+
kind: "error",
|
|
20134
|
+
message: `Element ${input.sceneElementId} ist unbekannt.`,
|
|
20135
|
+
retryable: false
|
|
20136
|
+
};
|
|
20137
|
+
}
|
|
20138
|
+
contextId = element.value.element.context_id;
|
|
20139
|
+
}
|
|
20140
|
+
const chain = await context.chainFor(contextId ?? null);
|
|
20141
|
+
if (chain.kind !== "ok") {
|
|
20142
|
+
return { kind: "error", message: chain.message, retryable: chain.retryable };
|
|
20143
|
+
}
|
|
20144
|
+
const eingefroren = await freezeSceneWorkingState({
|
|
20145
|
+
sceneElementId: input.sceneElementId,
|
|
20146
|
+
store: elements,
|
|
20147
|
+
resolver,
|
|
20148
|
+
contextChain: chain.value,
|
|
20149
|
+
userInstruction: input.userInstruction ?? null
|
|
20150
|
+
});
|
|
20151
|
+
if (eingefroren.kind === "conflict") {
|
|
20152
|
+
return {
|
|
20153
|
+
kind: "conflict",
|
|
20154
|
+
message: eingefroren.message,
|
|
20155
|
+
node: eingefroren.node,
|
|
20156
|
+
expectedRevision: eingefroren.expectedRevision,
|
|
20157
|
+
actualRevision: eingefroren.actualRevision
|
|
20158
|
+
};
|
|
20159
|
+
}
|
|
20160
|
+
if (eingefroren.kind === "error") {
|
|
20161
|
+
return { kind: "error", message: eingefroren.message, retryable: eingefroren.retryable };
|
|
20162
|
+
}
|
|
20163
|
+
if (eingefroren.kind !== "ok") {
|
|
20164
|
+
return { kind: "rejected", message: eingefroren.message };
|
|
20165
|
+
}
|
|
20166
|
+
const outcome = await runPromptDerivation(eingefroren.input, text);
|
|
20167
|
+
const record = {
|
|
20168
|
+
run_id: newRunId(),
|
|
20169
|
+
// Keine fingierten Kennungen (D-98/D-75). Was es nicht gibt, bleibt
|
|
20170
|
+
// leer — die Herkunft steht in `source`.
|
|
20171
|
+
shot_version_id: "",
|
|
20172
|
+
shot_element_id: "",
|
|
20173
|
+
scene_setup_version_id: "",
|
|
20174
|
+
camera_id: "",
|
|
20175
|
+
target_model_version_id: eingefroren.input.target_model_resolution?.version_id ?? "",
|
|
20176
|
+
provider: outcome.provider,
|
|
20177
|
+
model_id: outcome.model_id,
|
|
20178
|
+
system_prompt: outcome.system_prompt,
|
|
20179
|
+
input_payload: eingefroren.input,
|
|
20180
|
+
status: outcome.status,
|
|
20181
|
+
failure: outcome.status === "failed" ? outcome.failure : null,
|
|
20182
|
+
output: outcome.status === "succeeded" ? outcome.output : null,
|
|
20183
|
+
raw_output: outcome.raw_output,
|
|
20184
|
+
source: { kind: "scene_direct", scene: eingefroren.scene },
|
|
20185
|
+
created_at: now().toISOString()
|
|
20186
|
+
};
|
|
20187
|
+
return await runs.record(record);
|
|
20188
|
+
} catch (error) {
|
|
20189
|
+
return {
|
|
20190
|
+
kind: "error",
|
|
20191
|
+
message: `Prompt-Lauf aus der Szene ${input.sceneElementId} ist fehlgeschlagen: ${error instanceof Error ? error.message : String(error)}`,
|
|
20192
|
+
retryable: true
|
|
20193
|
+
};
|
|
20194
|
+
}
|
|
20195
|
+
},
|
|
20196
|
+
async listRunsForScene(sceneElementId) {
|
|
20197
|
+
try {
|
|
20198
|
+
return await runs.listForScene(sceneElementId);
|
|
20199
|
+
} catch (error) {
|
|
20200
|
+
return queryError(
|
|
20201
|
+
error,
|
|
20202
|
+
`Laeufe der Szene ${sceneElementId} konnten nicht gelesen werden`
|
|
20203
|
+
);
|
|
20204
|
+
}
|
|
19420
20205
|
}
|
|
19421
20206
|
};
|
|
19422
20207
|
}
|
|
@@ -19655,7 +20440,7 @@ function createFlowImageProvider(generateImage) {
|
|
|
19655
20440
|
}
|
|
19656
20441
|
|
|
19657
20442
|
// src/lib/szenen/imageGenerationOrderStore.ts
|
|
19658
|
-
function
|
|
20443
|
+
function istText4(wert) {
|
|
19659
20444
|
return typeof wert === "string" && wert.trim().length > 0;
|
|
19660
20445
|
}
|
|
19661
20446
|
function collectImageGenerationOrders(events) {
|
|
@@ -19663,7 +20448,7 @@ function collectImageGenerationOrders(events) {
|
|
|
19663
20448
|
for (const event of events) {
|
|
19664
20449
|
if (event.type !== SZENEN_EVENT_TYPES.imageGenerationStarted) continue;
|
|
19665
20450
|
const payload = event.payload;
|
|
19666
|
-
if (!payload || !
|
|
20451
|
+
if (!payload || !istText4(payload.generation_batch_id) || !istText4(payload.prompt_run_id)) continue;
|
|
19667
20452
|
if (byBatchId.has(payload.generation_batch_id)) continue;
|
|
19668
20453
|
byBatchId.set(payload.generation_batch_id, {
|
|
19669
20454
|
generation_batch_id: payload.generation_batch_id,
|
|
@@ -19677,7 +20462,7 @@ function collectImageGenerationOrders(events) {
|
|
|
19677
20462
|
for (const event of events) {
|
|
19678
20463
|
if (event.type !== SZENEN_EVENT_TYPES.imageGenerationFinished) continue;
|
|
19679
20464
|
const payload = event.payload;
|
|
19680
|
-
if (!payload || !
|
|
20465
|
+
if (!payload || !istText4(payload.generation_batch_id)) continue;
|
|
19681
20466
|
const auftrag = byBatchId.get(payload.generation_batch_id);
|
|
19682
20467
|
if (!auftrag) continue;
|
|
19683
20468
|
if (auftrag.status !== "started") continue;
|
|
@@ -19698,18 +20483,18 @@ function ordersForPromptRun(events, runId) {
|
|
|
19698
20483
|
}
|
|
19699
20484
|
|
|
19700
20485
|
// src/lib/szenen/imageBatchStore.ts
|
|
19701
|
-
var
|
|
20486
|
+
var istText5 = (wert) => typeof wert === "string" && wert.trim().length > 0;
|
|
19702
20487
|
function alsBilder(rohe) {
|
|
19703
20488
|
if (!Array.isArray(rohe)) return [];
|
|
19704
|
-
return rohe.filter((b) => !!b && typeof b === "object").filter((b) =>
|
|
20489
|
+
return rohe.filter((b) => !!b && typeof b === "object").filter((b) => istText5(b.media_ref) && typeof b.position === "number").map((b) => ({
|
|
19705
20490
|
media_ref: b.media_ref,
|
|
19706
20491
|
position: b.position,
|
|
19707
|
-
...
|
|
20492
|
+
...istText5(b.asset_id) ? { asset_id: b.asset_id } : {},
|
|
19708
20493
|
// Der bestätigte MIME-Typ (Review 2026-08-18 §5 P2) muss durch das
|
|
19709
20494
|
// Rücklesen hindurch: Genau hier braucht ihn der Lesepfad, um den
|
|
19710
20495
|
// Dateipfad `images/<id>.<ext>` zu bilden, statt ihn zu erraten. Nur
|
|
19711
20496
|
// gesetzt, wenn er im Ereignis steht — ältere Batches tragen ihn nicht.
|
|
19712
|
-
...
|
|
20497
|
+
...istText5(b.mime_type) ? { mime_type: b.mime_type } : {},
|
|
19713
20498
|
model: b.model ?? null,
|
|
19714
20499
|
seed: b.seed ?? null,
|
|
19715
20500
|
width: b.width ?? null,
|
|
@@ -19721,7 +20506,7 @@ function collectImageBatches(events) {
|
|
|
19721
20506
|
for (const event of events) {
|
|
19722
20507
|
if (event.type !== SZENEN_EVENT_TYPES.imageBatchPersisted) continue;
|
|
19723
20508
|
const payload = event.payload;
|
|
19724
|
-
if (!payload || !
|
|
20509
|
+
if (!payload || !istText5(payload.item_id) || !istText5(payload.prompt_run_id) || !istText5(payload.generation_batch_id)) continue;
|
|
19725
20510
|
if (payload.source_kind !== "generated_in_app" && payload.source_kind !== "external_import") continue;
|
|
19726
20511
|
const bestehend = byItemId.get(payload.item_id);
|
|
19727
20512
|
if (bestehend?.generation_batch_ids.includes(payload.generation_batch_id)) continue;
|
|
@@ -19732,7 +20517,7 @@ function collectImageBatches(events) {
|
|
|
19732
20517
|
prompt_run_id: payload.prompt_run_id,
|
|
19733
20518
|
generation_batch_ids: [payload.generation_batch_id],
|
|
19734
20519
|
source_kind: payload.source_kind,
|
|
19735
|
-
title:
|
|
20520
|
+
title: istText5(payload.title) ? payload.title : `Batch aus Lauf ${payload.prompt_run_id}`,
|
|
19736
20521
|
images: bilder
|
|
19737
20522
|
});
|
|
19738
20523
|
continue;
|
|
@@ -20209,7 +20994,7 @@ function createFlowSzenenViewPort(options) {
|
|
|
20209
20994
|
...options.now ? { now: options.now } : {}
|
|
20210
20995
|
}) : void 0;
|
|
20211
20996
|
const bildProvider = options.imageProvider ?? (options.generateImage ? createFlowImageProvider(options.generateImage) : void 0);
|
|
20212
|
-
const bildFaehigkeit = options.imageCapability ?? { environment_id: "flow", execution_paths: [FLOW_EXECUTION_PATH] };
|
|
20997
|
+
const bildFaehigkeit = options.imageCapability ?? { environment_id: "flow", execution_paths: [{ execution_path: FLOW_EXECUTION_PATH, provider: "google" }] };
|
|
20213
20998
|
const imageGeneration = bildProvider && imageBatchWrite ? createImageGenerationPort({
|
|
20214
20999
|
runs: { async getRun(runId) {
|
|
20215
21000
|
return runs.getRun(runId);
|
|
@@ -20301,7 +21086,7 @@ function resolveBootstrapTarget(input) {
|
|
|
20301
21086
|
// src/components/AvatarArchitectApp.tsx
|
|
20302
21087
|
var import_jsx_runtime47 = require("react/jsx-runtime");
|
|
20303
21088
|
function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onSelectMedia, buildInfo, initialHfToken, hfNamespace, allowDevNamespace, requireWorkspaceSelection = false, serverBaseUrl, onFetchServerProjects, onServerSave, onServerLoad, onServerDelete }) {
|
|
20304
|
-
(0,
|
|
21089
|
+
(0, import_react49.useEffect)(() => {
|
|
20305
21090
|
const id = "flow-styles";
|
|
20306
21091
|
if (!document.getElementById(id)) {
|
|
20307
21092
|
const style = document.createElement("style");
|
|
@@ -20310,36 +21095,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20310
21095
|
document.head.appendChild(style);
|
|
20311
21096
|
}
|
|
20312
21097
|
}, []);
|
|
20313
|
-
const [showStart, setShowStart] = (0,
|
|
20314
|
-
const [showSzenen, setShowSzenen] = (0,
|
|
20315
|
-
const [layoutChoice, setLayoutChoice] = (0,
|
|
21098
|
+
const [showStart, setShowStart] = (0, import_react49.useState)(true);
|
|
21099
|
+
const [showSzenen, setShowSzenen] = (0, import_react49.useState)(false);
|
|
21100
|
+
const [layoutChoice, setLayoutChoice] = (0, import_react49.useState)(() => {
|
|
20316
21101
|
try {
|
|
20317
21102
|
return localStorage.getItem("aa-layout") || null;
|
|
20318
21103
|
} catch {
|
|
20319
21104
|
return null;
|
|
20320
21105
|
}
|
|
20321
21106
|
});
|
|
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,
|
|
21107
|
+
const [projectLoaded, setProjectLoaded] = (0, import_react49.useState)(false);
|
|
21108
|
+
const [hfToken, setHfToken] = (0, import_react49.useState)(initialHfToken || "");
|
|
21109
|
+
const [hfTokenInput, setHfTokenInput] = (0, import_react49.useState)(initialHfToken || "");
|
|
21110
|
+
const [isLoadingFromHF, setIsLoadingFromHF] = (0, import_react49.useState)(false);
|
|
21111
|
+
const [hfNamespaceLocal, setHfNamespaceLocal] = (0, import_react49.useState)(() => {
|
|
20327
21112
|
try {
|
|
20328
21113
|
return normalizeSelectableNamespace(localStorage.getItem("aa-hf-namespace"));
|
|
20329
21114
|
} catch {
|
|
20330
21115
|
return DEFAULT_NAMESPACE;
|
|
20331
21116
|
}
|
|
20332
21117
|
});
|
|
20333
|
-
const [hfNamespaceFromServer, setHfNamespaceFromServer] = (0,
|
|
20334
|
-
const [serverProbeFailed, setServerProbeFailed] = (0,
|
|
20335
|
-
(0,
|
|
21118
|
+
const [hfNamespaceFromServer, setHfNamespaceFromServer] = (0, import_react49.useState)(null);
|
|
21119
|
+
const [serverProbeFailed, setServerProbeFailed] = (0, import_react49.useState)(false);
|
|
21120
|
+
(0, import_react49.useEffect)(() => {
|
|
20336
21121
|
if (hfNamespace !== void 0 || !serverBaseUrl) return;
|
|
20337
21122
|
fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
|
|
20338
21123
|
if (typeof d.hfNamespace === "string" && d.hfNamespace) setHfNamespaceFromServer(d.hfNamespace);
|
|
20339
21124
|
else setServerProbeFailed(true);
|
|
20340
21125
|
}).catch(() => setServerProbeFailed(true));
|
|
20341
21126
|
}, [hfNamespace, serverBaseUrl]);
|
|
20342
|
-
const [targetConfirmed, setTargetConfirmed] = (0,
|
|
21127
|
+
const [targetConfirmed, setTargetConfirmed] = (0, import_react49.useState)(false);
|
|
20343
21128
|
const isDialogTarget = hfNamespace === void 0 && hfNamespaceFromServer === null && (!serverBaseUrl || serverProbeFailed);
|
|
20344
21129
|
const isProbingServer = hfNamespace === void 0 && !!serverBaseUrl && hfNamespaceFromServer === null && !serverProbeFailed;
|
|
20345
21130
|
const bootstrapTarget = resolveBootstrapTarget({
|
|
@@ -20350,8 +21135,8 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20350
21135
|
isStartDialogOpen: isDialogTarget && !targetConfirmed
|
|
20351
21136
|
});
|
|
20352
21137
|
const effectiveNamespace = bootstrapTarget.namespace ?? "";
|
|
20353
|
-
const kontextRef = (0,
|
|
20354
|
-
const szenenPort = (0,
|
|
21138
|
+
const kontextRef = (0, import_react49.useRef)(null);
|
|
21139
|
+
const szenenPort = (0, import_react49.useMemo)(() => hfToken && effectiveNamespace ? createFlowSzenenViewPort({
|
|
20355
21140
|
generateText: onGeneratePrompt,
|
|
20356
21141
|
token: hfToken,
|
|
20357
21142
|
namespace: effectiveNamespace,
|
|
@@ -20373,10 +21158,10 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20373
21158
|
const tagBaseResult = useTagBase(hfToken, effectiveNamespace);
|
|
20374
21159
|
const szenenKontextId = tagBaseResult.selectedContextId === null ? null : String(tagBaseResult.selectedContextId);
|
|
20375
21160
|
kontextRef.current = szenenKontextId;
|
|
20376
|
-
const [imageUploadStatus, setImageUploadStatus] = (0,
|
|
20377
|
-
const [bootstrapLog, setBootstrapLog] = (0,
|
|
20378
|
-
const [isBootstrapping, setIsBootstrapping] = (0,
|
|
20379
|
-
const [hfMissingImages, setHfMissingImages] = (0,
|
|
21161
|
+
const [imageUploadStatus, setImageUploadStatus] = (0, import_react49.useState)(/* @__PURE__ */ new Map());
|
|
21162
|
+
const [bootstrapLog, setBootstrapLog] = (0, import_react49.useState)([]);
|
|
21163
|
+
const [isBootstrapping, setIsBootstrapping] = (0, import_react49.useState)(false);
|
|
21164
|
+
const [hfMissingImages, setHfMissingImages] = (0, import_react49.useState)([]);
|
|
20380
21165
|
const syncTopSlot = /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_jsx_runtime47.Fragment, { children: [
|
|
20381
21166
|
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
21167
|
"\u26A0 ",
|
|
@@ -20426,7 +21211,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20426
21211
|
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
21212
|
] })
|
|
20428
21213
|
] });
|
|
20429
|
-
const wsInputRef = (0,
|
|
21214
|
+
const wsInputRef = (0, import_react49.useRef)(null);
|
|
20430
21215
|
const startApp = (choice) => {
|
|
20431
21216
|
try {
|
|
20432
21217
|
localStorage.setItem("aa-layout", choice);
|
|
@@ -20436,18 +21221,18 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20436
21221
|
setTargetConfirmed(true);
|
|
20437
21222
|
setShowStart(false);
|
|
20438
21223
|
};
|
|
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,
|
|
21224
|
+
const [nodes, setNodes] = (0, import_react49.useState)([{ id: "1", type: "custom", position: { x: 0, y: 0 }, data: { label: "Fine Art Project", placeholder: "Name..." } }]);
|
|
21225
|
+
const [edges, setEdges] = (0, import_react49.useState)([]);
|
|
21226
|
+
const [history, setHistory] = (0, import_react49.useState)([]);
|
|
21227
|
+
const [galleryItems, setGalleryItems] = (0, import_react49.useState)([]);
|
|
21228
|
+
const galleryItemsRef = (0, import_react49.useRef)([]);
|
|
21229
|
+
(0, import_react49.useEffect)(() => {
|
|
20445
21230
|
galleryItemsRef.current = galleryItems;
|
|
20446
21231
|
}, [galleryItems]);
|
|
20447
|
-
const hfImageNotFoundRef = (0,
|
|
20448
|
-
const [galleryVisibleCount, setGalleryVisibleCount] = (0,
|
|
20449
|
-
const [historyVisibleCount, setHistoryVisibleCount] = (0,
|
|
20450
|
-
const loadThumbnailsForEntries = (0,
|
|
21232
|
+
const hfImageNotFoundRef = (0, import_react49.useRef)(/* @__PURE__ */ new Map());
|
|
21233
|
+
const [galleryVisibleCount, setGalleryVisibleCount] = (0, import_react49.useState)(20);
|
|
21234
|
+
const [historyVisibleCount, setHistoryVisibleCount] = (0, import_react49.useState)(20);
|
|
21235
|
+
const loadThumbnailsForEntries = (0, import_react49.useCallback)(async (entries) => {
|
|
20451
21236
|
for (const entry of entries) {
|
|
20452
21237
|
if (galleryItemsRef.current.find((g) => g.id === entry.id)?.base64) continue;
|
|
20453
21238
|
if (hfImageNotFoundRef.current.has(entry.id)) continue;
|
|
@@ -20466,7 +21251,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20466
21251
|
}
|
|
20467
21252
|
}
|
|
20468
21253
|
}, [hfToken, effectiveNamespace]);
|
|
20469
|
-
(0,
|
|
21254
|
+
(0, import_react49.useEffect)(() => {
|
|
20470
21255
|
if (!hfState) return;
|
|
20471
21256
|
if (hfState.tags?.by_category) setWorkspaceTags(hfState.tags);
|
|
20472
21257
|
const hfIds = new Set(hfState.metadata.map((m) => m.id));
|
|
@@ -20493,36 +21278,36 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20493
21278
|
return [...localOnly, ...merged].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
20494
21279
|
});
|
|
20495
21280
|
}, [hfState]);
|
|
20496
|
-
(0,
|
|
21281
|
+
(0, import_react49.useEffect)(() => {
|
|
20497
21282
|
if (!hfState) return;
|
|
20498
21283
|
const sortedMeta = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
20499
21284
|
const skeletons = sortedMeta.map((m) => ({ id: m.id, prompt: m.prompt, timestamp: m.timestamp, status: "done", nodeId: m.id, tags: m.tags || [] }));
|
|
20500
21285
|
const repIds = new Set(groupByPrompt(skeletons).slice(0, galleryVisibleCount).map((g) => g.representative.id));
|
|
20501
21286
|
loadThumbnailsForEntries(sortedMeta.filter((e) => repIds.has(e.id)));
|
|
20502
21287
|
}, [hfState, galleryVisibleCount, loadThumbnailsForEntries]);
|
|
20503
|
-
(0,
|
|
21288
|
+
(0, import_react49.useEffect)(() => {
|
|
20504
21289
|
if (!hfState) return;
|
|
20505
21290
|
const sortedMeta = [...hfState.metadata].sort((a, b) => (b.timestamp ?? 0) - (a.timestamp ?? 0));
|
|
20506
21291
|
loadThumbnailsForEntries(sortedMeta.slice(0, historyVisibleCount));
|
|
20507
21292
|
}, [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,
|
|
21293
|
+
const [activePrompt, setActivePrompt] = (0, import_react49.useState)("");
|
|
21294
|
+
const [isSynthesizing, setIsSynthesizing] = (0, import_react49.useState)(false);
|
|
21295
|
+
const [activeGenerationsCount, setActiveGenerationsCount] = (0, import_react49.useState)(0);
|
|
21296
|
+
const [currentResult, setCurrentResult] = (0, import_react49.useState)(null);
|
|
21297
|
+
const [focusedNodeId, setFocusedNodeId] = (0, import_react49.useState)(null);
|
|
21298
|
+
const [leftTab, setLeftTab] = (0, import_react49.useState)("prompt");
|
|
21299
|
+
const [promptFeedback, setPromptFeedback] = (0, import_react49.useState)(null);
|
|
21300
|
+
const [lastPromptPayload, setLastPromptPayload] = (0, import_react49.useState)(null);
|
|
21301
|
+
const [isPromptTabGenerating, setIsPromptTabGenerating] = (0, import_react49.useState)(false);
|
|
21302
|
+
const [activeTab, setActiveTab] = (0, import_react49.useState)("history");
|
|
21303
|
+
const [mobileTab, setMobileTab] = (0, import_react49.useState)("stage");
|
|
21304
|
+
const [middlePanel, setMiddlePanel] = (0, import_react49.useState)("stage");
|
|
21305
|
+
const [recentLabItems, setRecentLabItems] = (0, import_react49.useState)([]);
|
|
21306
|
+
const [aspectRatio, setAspectRatio] = (0, import_react49.useState)("1:1");
|
|
21307
|
+
const [selectedModel, setSelectedModel] = (0, import_react49.useState)("\u{1F34C} Nano Banana Pro");
|
|
21308
|
+
const [seed, setSeed] = (0, import_react49.useState)(Math.floor(Math.random() * 1e6));
|
|
21309
|
+
const [seedMode, setSeedMode] = (0, import_react49.useState)("random");
|
|
21310
|
+
const [imageCount, setImageCount] = (0, import_react49.useState)(() => {
|
|
20526
21311
|
try {
|
|
20527
21312
|
const v = parseInt(localStorage.getItem("aa-image-count") || "", 10);
|
|
20528
21313
|
return v >= 1 && v <= 8 ? v : 4;
|
|
@@ -20544,45 +21329,45 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20544
21329
|
{ label: "4 Bilder", value: "4" },
|
|
20545
21330
|
{ label: "8 Bilder", value: "8" }
|
|
20546
21331
|
];
|
|
20547
|
-
const [isLeftCollapsed, setIsLeftCollapsed] = (0,
|
|
20548
|
-
const [isRightCollapsed, setIsRightCollapsed] = (0,
|
|
20549
|
-
const [leftPanelWidth, setLeftPanelWidth] = (0,
|
|
21332
|
+
const [isLeftCollapsed, setIsLeftCollapsed] = (0, import_react49.useState)(false);
|
|
21333
|
+
const [isRightCollapsed, setIsRightCollapsed] = (0, import_react49.useState)(false);
|
|
21334
|
+
const [leftPanelWidth, setLeftPanelWidth] = (0, import_react49.useState)(() => {
|
|
20550
21335
|
try {
|
|
20551
21336
|
return parseInt(localStorage.getItem("aa-left-width") || "260", 10);
|
|
20552
21337
|
} catch {
|
|
20553
21338
|
return 260;
|
|
20554
21339
|
}
|
|
20555
21340
|
});
|
|
20556
|
-
const [rightPanelWidth, setRightPanelWidth] = (0,
|
|
21341
|
+
const [rightPanelWidth, setRightPanelWidth] = (0, import_react49.useState)(() => {
|
|
20557
21342
|
try {
|
|
20558
21343
|
return parseInt(localStorage.getItem("aa-right-width") || "320", 10);
|
|
20559
21344
|
} catch {
|
|
20560
21345
|
return 320;
|
|
20561
21346
|
}
|
|
20562
21347
|
});
|
|
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,
|
|
21348
|
+
const [isPromptCollapsed, setIsPromptCollapsed] = (0, import_react49.useState)(false);
|
|
21349
|
+
const [projectActionState, setProjectActionState] = (0, import_react49.useState)("idle");
|
|
21350
|
+
const syncServerDataRef = (0, import_react49.useRef)(null);
|
|
21351
|
+
const [workspaceTags, setWorkspaceTags] = (0, import_react49.useState)(null);
|
|
21352
|
+
const [serverProjects, setServerProjects] = (0, import_react49.useState)([]);
|
|
21353
|
+
const [isLoadingFromServer, setIsLoadingFromServer] = (0, import_react49.useState)(false);
|
|
21354
|
+
const [highContrast, setHighContrast] = (0, import_react49.useState)(() => {
|
|
20570
21355
|
try {
|
|
20571
21356
|
return localStorage.getItem("aa-contrast") === "high";
|
|
20572
21357
|
} catch {
|
|
20573
21358
|
return false;
|
|
20574
21359
|
}
|
|
20575
21360
|
});
|
|
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,
|
|
21361
|
+
const [activeReferenceId, setActiveReferenceId] = (0, import_react49.useState)(null);
|
|
21362
|
+
const [activeReferenceThumbnail, setActiveReferenceThumbnail] = (0, import_react49.useState)(null);
|
|
21363
|
+
const [isScanningImage, setIsScanningImage] = (0, import_react49.useState)(false);
|
|
21364
|
+
const [touchStartX, setTouchStartX] = (0, import_react49.useState)(null);
|
|
21365
|
+
const [isFullscreen, setIsFullscreen] = (0, import_react49.useState)(false);
|
|
21366
|
+
const [zoomScale, setZoomScale] = (0, import_react49.useState)(1);
|
|
21367
|
+
const [zoomOffset, setZoomOffset] = (0, import_react49.useState)({ x: 0, y: 0 });
|
|
21368
|
+
const lastPinchDist = (0, import_react49.useRef)(null);
|
|
21369
|
+
const lastTapTime = (0, import_react49.useRef)(0);
|
|
21370
|
+
const dragStart = (0, import_react49.useRef)(null);
|
|
20586
21371
|
const openFullscreen = () => {
|
|
20587
21372
|
setIsFullscreen(true);
|
|
20588
21373
|
setZoomScale(1);
|
|
@@ -20645,7 +21430,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20645
21430
|
setActiveReferenceId(null);
|
|
20646
21431
|
setActiveReferenceThumbnail(null);
|
|
20647
21432
|
};
|
|
20648
|
-
const labServices = (0,
|
|
21433
|
+
const labServices = (0, import_react49.useMemo)(() => {
|
|
20649
21434
|
const available = groupGenerationsToLabItems([...galleryItems, ...history]);
|
|
20650
21435
|
return {
|
|
20651
21436
|
availableItems: available,
|
|
@@ -20725,14 +21510,14 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20725
21510
|
setIsScanningImage(false);
|
|
20726
21511
|
}
|
|
20727
21512
|
};
|
|
20728
|
-
const currentIndex = (0,
|
|
20729
|
-
const goToPrev = (0,
|
|
21513
|
+
const currentIndex = (0, import_react49.useMemo)(() => history.findIndex((h) => h.id === currentResult?.id), [history, currentResult]);
|
|
21514
|
+
const goToPrev = (0, import_react49.useCallback)(() => {
|
|
20730
21515
|
if (currentIndex > 0) setCurrentResult(history[currentIndex - 1]);
|
|
20731
21516
|
}, [currentIndex, history]);
|
|
20732
|
-
const goToNext = (0,
|
|
21517
|
+
const goToNext = (0, import_react49.useCallback)(() => {
|
|
20733
21518
|
if (currentIndex < history.length - 1) setCurrentResult(history[currentIndex + 1]);
|
|
20734
21519
|
}, [currentIndex, history]);
|
|
20735
|
-
const handleGallerySelect = (0,
|
|
21520
|
+
const handleGallerySelect = (0, import_react49.useCallback)((g) => {
|
|
20736
21521
|
setCurrentResult(g);
|
|
20737
21522
|
setMobileTab("stage");
|
|
20738
21523
|
if (g.hasThumb && g.filename && hfToken && !g.fullBase64) {
|
|
@@ -20745,7 +21530,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20745
21530
|
});
|
|
20746
21531
|
}
|
|
20747
21532
|
}, [hfToken, effectiveNamespace]);
|
|
20748
|
-
const handleTitleSet = (0,
|
|
21533
|
+
const handleTitleSet = (0, import_react49.useCallback)((id) => {
|
|
20749
21534
|
const ts = Date.now();
|
|
20750
21535
|
setGalleryItems((prev) => prev.map((g) => g.id === id ? { ...g, titleTs: ts } : g));
|
|
20751
21536
|
setHistory((prev) => prev.map((g) => g.id === id ? { ...g, titleTs: ts } : g));
|
|
@@ -20754,13 +21539,13 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20754
21539
|
});
|
|
20755
21540
|
}
|
|
20756
21541
|
}, [hfToken, effectiveNamespace, hfWriteEvent]);
|
|
20757
|
-
const currentGroup = (0,
|
|
21542
|
+
const currentGroup = (0, import_react49.useMemo)(() => {
|
|
20758
21543
|
if (!currentResult?.prompt) return [];
|
|
20759
21544
|
const groups = groupByPrompt(galleryItems.filter((g) => g.status === "done" && !!g.base64));
|
|
20760
21545
|
const group = groups.find((gr) => gr.prompt === currentResult.prompt);
|
|
20761
21546
|
return group ? group.items : [];
|
|
20762
21547
|
}, [galleryItems, currentResult?.prompt]);
|
|
20763
|
-
(0,
|
|
21548
|
+
(0, import_react49.useEffect)(() => {
|
|
20764
21549
|
if (!currentResult?.prompt || !hfToken || !effectiveNamespace || !hfState) return;
|
|
20765
21550
|
const siblings = galleryItemsRef.current.filter(
|
|
20766
21551
|
(g) => g.prompt === currentResult.prompt && !g.base64 && !hfImageNotFoundRef.current.has(g.id)
|
|
@@ -20799,7 +21584,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20799
21584
|
}
|
|
20800
21585
|
) : null;
|
|
20801
21586
|
useKeyboardNavigation(history, currentResult, setCurrentResult);
|
|
20802
|
-
const getSubtreeFormat = (0,
|
|
21587
|
+
const getSubtreeFormat = (0, import_react49.useCallback)((nodeId, depth = 0) => {
|
|
20803
21588
|
const node = nodes.find((n) => n.id === nodeId);
|
|
20804
21589
|
if (!node) return "";
|
|
20805
21590
|
const childrenIds = edges.filter((e) => e.source === nodeId).map((e) => e.target);
|
|
@@ -20807,7 +21592,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
20807
21592
|
return `${indent}- ${node.data.label || "(unbenannt)"}
|
|
20808
21593
|
` + childrenIds.map((id) => getSubtreeFormat(id, depth + 1)).join("");
|
|
20809
21594
|
}, [nodes, edges]);
|
|
20810
|
-
const activePath = (0,
|
|
21595
|
+
const activePath = (0, import_react49.useMemo)(() => {
|
|
20811
21596
|
if (!focusedNodeId) return /* @__PURE__ */ new Set();
|
|
20812
21597
|
const path = /* @__PURE__ */ new Set([focusedNodeId]);
|
|
20813
21598
|
let currId = focusedNodeId;
|
|
@@ -21173,7 +21958,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
21173
21958
|
setTimeout(() => setProjectActionState("idle"), 4e3);
|
|
21174
21959
|
}
|
|
21175
21960
|
};
|
|
21176
|
-
(0,
|
|
21961
|
+
(0, import_react49.useEffect)(() => {
|
|
21177
21962
|
if (activeTab === "setup" || activeTab === "sync") fetchServerProjects();
|
|
21178
21963
|
}, [activeTab]);
|
|
21179
21964
|
const mergeWorkspaceTags = (local, remote) => {
|
|
@@ -22205,7 +22990,7 @@ function AvatarArchitectApp({ onGenerateImage, onGeneratePrompt, onDownload, onS
|
|
|
22205
22990
|
}
|
|
22206
22991
|
|
|
22207
22992
|
// src/components/FaApp.tsx
|
|
22208
|
-
var
|
|
22993
|
+
var import_react50 = require("react");
|
|
22209
22994
|
var import_jsx_runtime48 = require("react/jsx-runtime");
|
|
22210
22995
|
function FaApp({
|
|
22211
22996
|
onGenerateImage,
|
|
@@ -22225,8 +23010,8 @@ function FaApp({
|
|
|
22225
23010
|
onServerDelete,
|
|
22226
23011
|
buildInfo
|
|
22227
23012
|
}) {
|
|
22228
|
-
const [hfNamespace, setHfNamespace] = (0,
|
|
22229
|
-
(0,
|
|
23013
|
+
const [hfNamespace, setHfNamespace] = (0, import_react50.useState)(void 0);
|
|
23014
|
+
(0, import_react50.useEffect)(() => {
|
|
22230
23015
|
if (!serverBaseUrl) return;
|
|
22231
23016
|
fetch(`${serverBaseUrl}/api/status`).then((r) => r.json()).then((d) => {
|
|
22232
23017
|
if (typeof d.hfNamespace === "string") setHfNamespace(d.hfNamespace);
|
|
@@ -22491,15 +23276,15 @@ function createInMemoryWorkspacePersistence(now = () => Date.now()) {
|
|
|
22491
23276
|
}
|
|
22492
23277
|
|
|
22493
23278
|
// node_modules/zustand/esm/react.mjs
|
|
22494
|
-
var
|
|
23279
|
+
var import_react51 = __toESM(require("react"), 1);
|
|
22495
23280
|
var identity = (arg) => arg;
|
|
22496
23281
|
function useStore(api, selector = identity) {
|
|
22497
|
-
const slice =
|
|
23282
|
+
const slice = import_react51.default.useSyncExternalStore(
|
|
22498
23283
|
api.subscribe,
|
|
22499
|
-
|
|
22500
|
-
|
|
23284
|
+
import_react51.default.useCallback(() => selector(api.getState()), [api, selector]),
|
|
23285
|
+
import_react51.default.useCallback(() => selector(api.getInitialState()), [api, selector])
|
|
22501
23286
|
);
|
|
22502
|
-
|
|
23287
|
+
import_react51.default.useDebugValue(slice);
|
|
22503
23288
|
return slice;
|
|
22504
23289
|
}
|
|
22505
23290
|
|