@getrheo/flow-runtime 1.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/agentPrompt/index.d.ts +72 -0
- package/dist/agentPrompt/index.js +739 -0
- package/dist/agentPrompt/index.js.map +1 -0
- package/dist/aiFlowGenerationMerge.d.ts +32 -0
- package/dist/aiFlowGenerationMerge.js +120 -0
- package/dist/aiFlowGenerationMerge.js.map +1 -0
- package/dist/animations.d.ts +110 -0
- package/dist/animations.js +312 -0
- package/dist/animations.js.map +1 -0
- package/dist/assignment.d.ts +7 -0
- package/dist/assignment.js +25 -0
- package/dist/assignment.js.map +1 -0
- package/dist/brandGradient.d.ts +57 -0
- package/dist/brandGradient.js +137 -0
- package/dist/brandGradient.js.map +1 -0
- package/dist/brandGradientManifestIssues.d.ts +11 -0
- package/dist/brandGradientManifestIssues.js +302 -0
- package/dist/brandGradientManifestIssues.js.map +1 -0
- package/dist/buildFlowPreview.d.ts +7 -0
- package/dist/buildFlowPreview.js +81 -0
- package/dist/buildFlowPreview.js.map +1 -0
- package/dist/buttonVariantChrome.d.ts +26 -0
- package/dist/buttonVariantChrome.js +59 -0
- package/dist/buttonVariantChrome.js.map +1 -0
- package/dist/checkboxGlyphStyle.d.ts +31 -0
- package/dist/checkboxGlyphStyle.js +241 -0
- package/dist/checkboxGlyphStyle.js.map +1 -0
- package/dist/choiceOptionSelection.d.ts +11 -0
- package/dist/choiceOptionSelection.js +120 -0
- package/dist/choiceOptionSelection.js.map +1 -0
- package/dist/colorAlpha.d.ts +8 -0
- package/dist/colorAlpha.js +48 -0
- package/dist/colorAlpha.js.map +1 -0
- package/dist/counterLayer.d.ts +42 -0
- package/dist/counterLayer.js +95 -0
- package/dist/counterLayer.js.map +1 -0
- package/dist/decisionEval.d.ts +27 -0
- package/dist/decisionEval.js +197 -0
- package/dist/decisionEval.js.map +1 -0
- package/dist/dropShadow.d.ts +26 -0
- package/dist/dropShadow.js +76 -0
- package/dist/dropShadow.js.map +1 -0
- package/dist/emailPasswordAuthValidation.d.ts +16 -0
- package/dist/emailPasswordAuthValidation.js +25 -0
- package/dist/emailPasswordAuthValidation.js.map +1 -0
- package/dist/flowBuilderRules.d.ts +15 -0
- package/dist/flowBuilderRules.js +368 -0
- package/dist/flowBuilderRules.js.map +1 -0
- package/dist/flowGraph.d.ts +19 -0
- package/dist/flowGraph.js +373 -0
- package/dist/flowGraph.js.map +1 -0
- package/dist/hyperlinkLabel.d.ts +19 -0
- package/dist/hyperlinkLabel.js +232 -0
- package/dist/hyperlinkLabel.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +4200 -0
- package/dist/index.js.map +1 -0
- package/dist/interpolateTemplate.d.ts +44 -0
- package/dist/interpolateTemplate.js +188 -0
- package/dist/interpolateTemplate.js.map +1 -0
- package/dist/layerRotate.d.ts +10 -0
- package/dist/layerRotate.js +9 -0
- package/dist/layerRotate.js.map +1 -0
- package/dist/layerTypography.d.ts +36 -0
- package/dist/layerTypography.js +68 -0
- package/dist/layerTypography.js.map +1 -0
- package/dist/layers.d.ts +69 -0
- package/dist/layers.js +257 -0
- package/dist/layers.js.map +1 -0
- package/dist/layout/index.d.ts +57 -0
- package/dist/layout/index.js +151 -0
- package/dist/layout/index.js.map +1 -0
- package/dist/manifestBillingSlice.d.ts +17 -0
- package/dist/manifestBillingSlice.js +102 -0
- package/dist/manifestBillingSlice.js.map +1 -0
- package/dist/prepareAiGeneratedScreen.d.ts +17 -0
- package/dist/prepareAiGeneratedScreen.js +99 -0
- package/dist/prepareAiGeneratedScreen.js.map +1 -0
- package/dist/publish-exports.json +166 -0
- package/dist/responsive/breakpoints.d.ts +34 -0
- package/dist/responsive/breakpoints.js +52 -0
- package/dist/responsive/breakpoints.js.map +1 -0
- package/dist/responsive/index.d.ts +8 -0
- package/dist/responsive/index.js +307 -0
- package/dist/responsive/index.js.map +1 -0
- package/dist/responsive/layerResolve.d.ts +43 -0
- package/dist/responsive/layerResolve.js +168 -0
- package/dist/responsive/layerResolve.js.map +1 -0
- package/dist/responsive/merge.d.ts +19 -0
- package/dist/responsive/merge.js +74 -0
- package/dist/responsive/merge.js.map +1 -0
- package/dist/responsive/previewSafeAreaInsets.d.ts +14 -0
- package/dist/responsive/previewSafeAreaInsets.js +24 -0
- package/dist/responsive/previewSafeAreaInsets.js.map +1 -0
- package/dist/responsive/screenContainerResolve.d.ts +11 -0
- package/dist/responsive/screenContainerResolve.js +122 -0
- package/dist/responsive/screenContainerResolve.js.map +1 -0
- package/dist/responsive/screenShellInsets.d.ts +11 -0
- package/dist/responsive/screenShellInsets.js +26 -0
- package/dist/responsive/screenShellInsets.js.map +1 -0
- package/dist/restingMotion.d.ts +167 -0
- package/dist/restingMotion.js +484 -0
- package/dist/restingMotion.js.map +1 -0
- package/dist/rheoAgentManifestMerge.d.ts +33 -0
- package/dist/rheoAgentManifestMerge.js +55 -0
- package/dist/rheoAgentManifestMerge.js.map +1 -0
- package/dist/scaleInputStyle.d.ts +35 -0
- package/dist/scaleInputStyle.js +77 -0
- package/dist/scaleInputStyle.js.map +1 -0
- package/dist/scaleValidation.d.ts +9 -0
- package/dist/scaleValidation.js +21 -0
- package/dist/scaleValidation.js.map +1 -0
- package/dist/stateMachine.d.ts +105 -0
- package/dist/stateMachine.js +674 -0
- package/dist/stateMachine.js.map +1 -0
- package/dist/stepResponse-BXgoZ7o-.d.ts +112 -0
- package/dist/textInputValidation.d.ts +14 -0
- package/dist/textInputValidation.js +46 -0
- package/dist/textInputValidation.js.map +1 -0
- package/dist/translationPlaceholders.d.ts +9 -0
- package/dist/translationPlaceholders.js +52 -0
- package/dist/translationPlaceholders.js.map +1 -0
- package/dist/validation.d.ts +31 -0
- package/dist/validation.js +233 -0
- package/dist/validation.js.map +1 -0
- package/package.json +242 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/agentPrompt/capabilitySurface.ts","../../src/agentPrompt/minimalExamples.ts","../../src/agentPrompt/templates.ts","../../src/agentPrompt/screenSchemaRules.ts","../../src/layers.ts","../../src/flowBuilderRules.ts","../../src/agentPrompt/builderRulesFragment.ts","../../src/agentPrompt/layerStyling.ts","../../src/agentPrompt/flowGenWorkflow.ts","../../src/agentPrompt/manifestContext.ts","../../src/validation.ts","../../src/agentPrompt/validate.ts"],"names":["LAYER_KINDS","INPUT_LAYER_KINDS","isInputLayer"],"mappings":"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","file":"index.js","sourcesContent":["import {\n BUTTON_LAYER_VARIANTS,\n ButtonActionSchema,\n EMAIL_PASSWORD_AUTH_MODES,\n FIELD_CLASSIFICATIONS,\n ICON_FAMILIES,\n INPUT_LAYER_KINDS,\n LAYER_KINDS,\n MANIFEST_SCHEMA_VERSION,\n NORMALIZED_SURFACE_OUTCOMES,\n OAUTH_LOGIN_PRESETS,\n OS_PERMISSION_KEYS,\n TEXT_INPUT_TYPES,\n} from '@getrheo/contracts';\n\n/** Button/back-button action `kind` literals, read straight from the contract schema. */\nexport const buttonActionKinds = (): string[] =>\n ButtonActionSchema.options.map((option) => option.shape.kind.value as string);\n\nconst list = (values: readonly string[]): string => values.map((value) => `\\`${value}\\``).join(', ');\n\nconst bullets = (values: readonly string[]): string =>\n values.map((value) => `- \\`${value}\\``).join('\\n');\n\n/** Compact capability surface for in-product AI system prompts (runtime, contract-derived). */\nexport const buildCapabilitySurfaceFragment = (): string =>\n [\n `Manifest schema version: ${MANIFEST_SCHEMA_VERSION}`,\n '',\n 'Valid layer kinds (only these; typos fail parse):',\n LAYER_KINDS.join(', '),\n '',\n `Input layers (at most one per screen): ${INPUT_LAYER_KINDS.join(', ')}`,\n '',\n 'Valid button action.kind values:',\n bullets(buttonActionKinds()),\n '',\n '- go_to_step requires screenId.',\n '- go_back_one_screen accepts optional fallbackScreenId.',\n '- request_os_permission requires permissionKey and outcomes (granted/denied/blocked).',\n '- play_media requires targetLayerIds (≥1) pointing at Lottie/video layers on the same screen.',\n '- request_app_review is allowed; requires screen.next.default. Do not emit unless the user asks.',\n '- back_button takes no action (back navigation is built in).',\n '',\n `Button/back_button variants: ${list(BUTTON_LAYER_VARIANTS)}.`,\n '',\n 'OS permission keys for request_os_permission:',\n bullets(OS_PERMISSION_KEYS),\n '',\n `- text_input types: ${list(TEXT_INPUT_TYPES)}.`,\n `- text_input classification: ${list(FIELD_CLASSIFICATIONS)}.`,\n `- oauth_login preset providers: ${list(OAUTH_LOGIN_PRESETS)}.`,\n `- email_password_auth modes: ${list(EMAIL_PASSWORD_AUTH_MODES)}.`,\n `- icon families: ${list(ICON_FAMILIES)}.`,\n '',\n `External surface outcome keys: ${list(NORMALIZED_SURFACE_OUTCOMES)}. Every external surface needs fallback.`,\n ].join('\\n');\n","import { LAYER_KINDS, minimalLayerExamples } from '@getrheo/contracts/layers';\n\n/** One-line JSON examples per layer kind for agent prompts. */\nexport const buildLayerExamplesFragment = (): string => {\n const byKind = minimalLayerExamples();\n const lines = LAYER_KINDS.map((kind) => {\n const json = JSON.stringify(byKind[kind]);\n return `- ${kind}: ${json}`;\n });\n return ['Minimal valid layer JSON per kind (from schema fixtures):', ...lines].join('\\n');\n};\n","import { INPUT_LAYER_KINDS, LAYER_KINDS } from '@getrheo/contracts/layers';\n\n/** Static structural prose for screen authoring (enums interpolated at compose time). */\nexport const buildScreenStructuralRules = (screenLeadIn: string): string => `Screen object (Zod ScreenSchema — invalid shapes are rejected):\n${screenLeadIn}\n- id: /^scr_[a-z0-9_]+$/i (new id; never reuse ids from the anchor or manifest list you are given).\n- name: 1–80 chars.\n- regions: { body: StackLayer required; header?: StackLayer; footer?: StackLayer }.\n- regions.body MUST be kind \"stack\" with direction (\"vertical\"|\"horizontal\"), gap (0–200 int), children: Layer[].\n- Stack layout: direction + gap live on the stack node. style on stacks is padding/margin/background/border/etc. only — not direction/gap.\n- Child spacing (gap) defaults: body/content stacks gap 12; choice (single_choice/multiple_choice) and identity (oauth_login/email_password_auth) containers gap 8. Omit gap only when you want the standard spacing; otherwise set it explicitly.\n- Explicit sizing: ALWAYS set style.width and style.height on every layer (no implicit/omitted sizing). Width values: \"full\" (fill parent), \"auto\" (hug content), a fraction (\"1/2\"|\"1/3\"|\"2/3\"|\"1/4\"|\"3/4\"), or a pixel number. Height values: \"fill\", \"auto\", or a pixel number (no fractions). Use these per-kind defaults unless the design needs otherwise:\n - stack, text_input, scale_input, oauth_login, email_password_auth, email_password_field, progress, loader → width \"full\", height \"fill\"\n - button, back_button, oauth_provider, email_password_submit, checkbox, single_choice, multiple_choice → width \"full\", height \"auto\"\n - text, counter, icon, hyperlink → width \"auto\", height \"auto\"\n - image, lottie, video → width \"full\", height a pixel number (e.g. 160)\n - carousel → no style sizing on the outer layer\n- next: { \"default\": null } for inserted screens (server rewires the default path).\n- animations / stagger / transition / containerStyle: omit unless you are sure; invalid clip targets fail manifest validation. When setting shell chrome, use containerStyle.backgroundFill: { kind: \"color\"|\"image\"|\"video\", ... } (not legacy background).\n\nLayer discriminant \"kind\" MUST be one of these strings exactly (case-sensitive; any other string fails parse):\n${LAYER_KINDS.join(', ')}\n\nFORBIDDEN kind aliases (models often hallucinate these — they are NOT valid):\n- NEVER \"selection\", \"radio\", \"picker\", \"form\", \"input\", \"choices\". For pick-one UI use kind \"single_choice\"; for pick-many use \"multiple_choice\".\n\nPer-screen manifest rules (enforced after Zod — violations cause retry):\n- **At most ONE input layer per screen**, counting only: ${INPUT_LAYER_KINDS.map((k) => `\"${k}\"`).join(', ')}. You cannot stack a text_input and a single_choice on the same screen, and you cannot output two choice layers. If the user asks for \"every layer\" or a \"showcase\", pick **one** input primitive OR none; use non-input layers (text, button, image, …) for the rest.\n- Do **not** combine identity capture with other inputs on the same screen: if you include \"oauth_login\" or \"email_password_auth\", omit single_choice, multiple_choice, text_input, and scale_input on that screen (product/editor rule).\n- fieldKey on input layers and checkbox: /^[a-z][a-z0-9_]*$/ (snake_case, starts with letter). Each fieldKey must be unique in the merged flow when that layer captures data.\n\nRepresentative shapes (read carefully — nested kinds must match):\n\n- **text**: id, kind \"text\", text: LocalizedText { default: string, translations?: { … } }. style.fontWeight is a NUMBER (400, 700). Text align is style.align: \"left\"|\"center\"|\"right\" — never textAlign.\n\n- **button**: kind \"button\", variant \"primary\"|\"secondary\"|\"ghost\"|\"destructive\", action (discriminated on action.kind): continue | skip | end_flow | go_back_one_screen (optional fallbackScreenId scr_*) | go_to_step { screenId } | request_os_permission { permissionKey, outcomes: { granted, denied, blocked } each a scr_* id, \"continue\", or \"end\" } | play_media { targetLayerIds } | request_app_review | none. children: Layer[] — label is always nested text layer(s), never a bare string on the button.\n\n- **back_button**: kind \"back_button\", variant, children (same button chrome pattern as button; used for back affordance).\n\n- **hyperlink**: kind \"hyperlink\", href (https: or mailto: URL string), children min 1 (link label lives in nested layers, usually text).\n\n- **image** / **lottie** / **video**: kind, optional media ref; lottie and video optional loop, autoPlay, triggerLayerId, onComplete; video optional audioEnabled; button action play_media with targetLayerIds.\n\n- **icon**: kind \"icon\", family \"ionicons\", iconName non-empty (Ionicons kebab-case, e.g. \"star-outline\").\n\n- **progress**: kind \"progress\"; optional height (bar thickness in px, defaults to 6), trackColor, fillColor.\n\n- **loader**: kind \"loader\"; optional variant \"linear\"|\"circular\", align \"start\"|\"center\"|\"end\", timing fields, onComplete discriminated { mode: \"none\"|\"next\"|\"screen\", screenId? }.\n\n- **counter**: kind \"counter\", startValue and endValue required numbers; optional displayKind \"number\"|\"time\", timeFormat if time.\n\n- **checkbox**: kind \"checkbox\", fieldKey, optional blocking and glyph styles.\n\n- **single_choice** / **multiple_choice**: kind, fieldKey, children: **array of stack layers, minimum 2** (one stack per option). optionBindings: same length as children; each entry { optionId: string, rootLayerId: <that option stack's id> }. Option stacks may use style (default) and selectedStyle (selected). branching: { enabled: boolean, conditions: [{ choiceId, goTo }] }; use enabled:false and conditions:[] unless you emit real branch targets that exist in the flow (for a brand-new inserted screen, default false/empty is safest).\n\n- **text_input**: kind, fieldKey, classification \"safe\"|\"sensitive\", optional placeholder / inputType (\"plain\"|\"email\"|\"phone\"|\"url\"|\"multiline\") / required / lengths, optional children.\n\n- **scale_input**: kind, fieldKey, classification, numeric min and max (max > min), optional step, defaultValue, labels, optional children.\n\n- **oauth_login**: kind, children: one or more **oauth_provider** layers only. Each oauth_provider is either variant \"preset\" with provider \"google\"|\"github\"|\"apple\" and optional label LocalizedText, OR variant \"custom\" with rowId (UUID string), buttonVariant, and children (icon/text like a button).\n\n- **email_password_auth**: kind, mode \"sign_in\"|\"sign_up\", fieldKey, children mixing **email_password_field** (slot \"email\"|\"password\"|\"confirm\" — sign_up needs confirm, sign_in must not include confirm slot) and exactly one **email_password_submit** (buttonVariant + children with nested text).\n\n- **carousel**: kind, slides: array of stack layers (min 1 slide).\n\nWhen the user wants a dense demo: prefer a vertical body stack with decorative layers + **at most one** of: a choice layer, text_input, scale_input, oauth_login, or email_password_auth — not several of those capture types together.`;\n","import { minimalDecisionNodeExample, minimalExternalSurfaceExample } from '@getrheo/contracts/__fixtures__/agentGraphExamples';\nimport { buildCapabilitySurfaceFragment } from './capabilitySurface.js';\nimport { buildLayerExamplesFragment } from './minimalExamples.js';\nimport { buildScreenStructuralRules } from './templates.js';\n\nexport type CanvasScreenSchemaRulesOpts = {\n /** flowGenStep uses { done, screen } instead of { screen } envelope. */\n envelope?: 'screen' | 'flowGenStep';\n};\n\nexport const buildCanvasScreenSchemaRules = (opts?: CanvasScreenSchemaRulesOpts): string => {\n const envelope = opts?.envelope ?? 'screen';\n const screenLeadIn =\n envelope === 'flowGenStep'\n ? '- Each screen in { \"done\": false, \"screen\": <Screen> } follows ScreenSchema.'\n : 'JSON envelope (exactly one top-level key): { \"screen\": <Screen> }';\n\n return [\n buildScreenStructuralRules(screenLeadIn),\n '',\n buildLayerExamplesFragment(),\n '',\n buildCapabilitySurfaceFragment(),\n ].join('\\n');\n};\n\nexport const buildFlowManifestPatchRules = (): string => {\n const screenRules = buildScreenStructuralRules('Each screen object follows ScreenSchema:');\n\n return `You edit a Rheo flow manifest via natural language. The server holds the authoritative draft and merges your output onto it.\n\nOutput format (strict):\n1. A short confirmation in plain language — written as if the changes are already live on the canvas. The user only sees this text AFTER the server applies your manifest patch, so use past tense (\"I updated…\", \"Added…\") and briefly summarize what changed.\n2. On its own line: ---MANIFEST---\n3. One JSON object — prefer the PATCH envelope below.\n\nPATCH envelope (default — emit ONLY what changed):\n{ \"mode\": \"patch\", \"patch\": { \"screens\": [ /* only new or edited screens */ ] } }\n\nPatch rules:\n- Include in patch.screens ONLY the screens you create or modify; never re-emit unchanged screens.\n- patch.removeScreenIds: array of scr_* ids to delete.\n- patch.decisionNodes / patch.externalSurfaceNodes: include ONLY nodes you add or change (upserted by id). Omit to leave them unchanged.\n- patch.entryScreenId: include only when the flow entry changes.\n- patch.sdkAttributeKeys: include only when adding/removing keys (replaces the full list).\n- Include a screen's next links only when that screen's wiring changed; otherwise leave the screen out of the patch.\n- Never emit builderMeta, flowId, defaultLocale, locales, theme, or version — the server owns these.\n\nFULL envelope (fallback — only when restructuring the entire flow, or after a patch fails validation twice):\n{ \"manifest\": <FlowManifest without builderMeta> }\n- Include every screen, decision node, external surface, and graph wiring the draft needs after your edit.\n- Keep manifest.flowId, defaultLocale, locales, theme, and version unchanged from the current draft.\n- entryScreenId must reference an existing screen id when set.\n\nScreen rules (each screen in patch.screens[] or manifest.screens[]):\n${screenRules}\n- You MAY change screen.next links when the user asks to wire flows; otherwise preserve existing next wiring.\n- New screens need unique scr_* ids; new layers need unique lyr_* ids across the entire manifest.`;\n};\n\nexport const buildDecisionSurfaceRules = (): string => {\n const decision = JSON.stringify(minimalDecisionNodeExample(), null, 2);\n const surface = JSON.stringify(minimalExternalSurfaceExample(), null, 2);\n\n return `Decision nodes and external surfaces (patch.decisionNodes / patch.externalSurfaceNodes):\n\nDecision node ids: dec_* (e.g. dec_platform). Cases branch on builtin (locale, platform), sdk.* keys, or field keys. Non-reserved sdk.* keys used in decisions must appear in sdkAttributeKeys.\n\nMinimal decision node example:\n${decision}\n\nExternal surface ids: surf_* (e.g. surf_paywall). config.provider is revenuecat or unspecified. outcomes map normalized keys to jump targets; fallback is required.\n\nMinimal external surface example:\n${surface}`;\n};\n\n/** Rheo Agent full system prompt schema section. */\nexport const buildRheoAgentSchemaRules = (): string =>\n [\n buildFlowManifestPatchRules(),\n '',\n buildDecisionSurfaceRules(),\n ].join('\\n');\n","import type { Branding } from '@getrheo/contracts/dashboard';\nimport type { FlowManifest, Theme } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport {\n brandGradientFromThemedColor,\n brandGradientNativeLinear,\n brandGradientSolidFallback,\n isStoredLinearGradientCss,\n nativeLinearFromAngleAndStops,\n parseLinearGradientCss,\n resolveBrandGradientToken,\n type BrandGradientNativeLinear,\n} from './brandGradient';\nimport type {\n InputLayer,\n Layer,\n MultipleChoiceLayer,\n ScaleInputLayer,\n SingleChoiceLayer,\n StackLayer,\n TextInputLayer,\n ThemedColor,\n} from '@getrheo/contracts/layers';\nimport type { LocalizedText } from '@getrheo/contracts/localized';\nimport { resolveLocalizedText } from '@getrheo/contracts/localized';\nimport { isInputLayer } from '@getrheo/contracts/layers';\n\n/** Walk a layer tree depth-first. */\nexport const walkLayers = (root: Layer, fn: (l: Layer, depth: number) => void): void => {\n const visit = (l: Layer, depth: number): void => {\n fn(l, depth);\n if (l.kind === 'stack') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'carousel') l.slides.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'button') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'back_button') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'hyperlink') l.children.forEach((c) => visit(c, depth + 1));\n else if (l.kind === 'single_choice' || l.kind === 'multiple_choice') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'text_input' || l.kind === 'scale_input') {\n l.children?.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'oauth_login') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'oauth_provider' && l.variant === 'custom') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_auth') {\n l.children.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_field') {\n l.children?.forEach((c) => visit(c, depth + 1));\n } else if (l.kind === 'email_password_submit') {\n l.children.forEach((c) => visit(c, depth + 1));\n }\n };\n visit(root, 0);\n};\n\n/** Walk every layer in a screen's regions (header → body → footer). */\nexport const walkScreen = (screen: Screen, fn: (l: Layer) => void): void => {\n if (screen.regions.header) walkLayers(screen.regions.header, fn);\n walkLayers(screen.regions.body, fn);\n if (screen.regions.footer) walkLayers(screen.regions.footer, fn);\n};\n\n/** Find the screen's lone input layer (if any). Schema enforces ≤1. */\nexport const findInputLayer = (screen: Screen): InputLayer | null => {\n let found: InputLayer | null = null;\n walkScreen(screen, (l) => {\n if (!found && isInputLayer(l)) found = l;\n });\n return found;\n};\n\n/** Input kinds that use a screen draft and require an explicit Continue to submit. */\nexport const findManualSubmitInputLayer = (\n screen: Screen,\n): MultipleChoiceLayer | TextInputLayer | ScaleInputLayer | null => {\n const input = findInputLayer(screen);\n if (!input) return null;\n if (input.kind === 'multiple_choice' || input.kind === 'text_input' || input.kind === 'scale_input') {\n return input;\n }\n return null;\n};\n\n/**\n * Whether the screen contains any Button layer that submits the screen\n * (i.e. `action.kind === 'continue'`). Used by input layers to decide\n * between auto-submit-on-tap (legacy behaviour for choice-only screens)\n * and writing into the screen-level draft for a Button to submit.\n */\nexport const screenHasContinueButton = (screen: Screen): boolean => {\n let found = false;\n walkScreen(screen, (l) => {\n if (l.kind === 'button' && l.action.kind === 'continue') found = true;\n });\n return found;\n};\n\n/**\n * Resolve a choice layer's option stack by stable optionId via its\n * binding. Returns null when the binding is missing or the bound child\n * was removed (manifest validation rejects that, but runtime stays safe).\n */\nexport const findOptionStackForChoice = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n optionId: string,\n): StackLayer | null => {\n const binding = layer.optionBindings.find((b) => b.optionId === optionId);\n if (!binding) return null;\n const stack = layer.children.find((c) => c.id === binding.rootLayerId);\n return stack ?? null;\n};\n\n/**\n * Best-effort textual label for a choice option, used by interpolation\n * (e.g. `{{ goal }}` rendering the chosen option's label) and by editor\n * surfaces that show option rows. Walks the option's child subtree\n * depth-first and returns the first `text` layer's content; falls back\n * to the option's stable id when no text is present.\n */\nexport const choiceOptionLabel = (\n layer: SingleChoiceLayer | MultipleChoiceLayer,\n optionId: string,\n locale: string,\n): string => {\n const stack = findOptionStackForChoice(layer, optionId);\n if (!stack) return '';\n let foundText: LocalizedText | null = null;\n walkLayers(stack, (l) => {\n if (foundText) return;\n if (l.kind === 'text') foundText = l.text;\n });\n if (foundText) return resolveLocalizedText(foundText, locale);\n return optionId;\n};\n\n/** Find a layer in a screen by id, including nested children/slides. */\nexport const findLayerById = (screen: Screen, id: string): Layer | null => {\n let found: Layer | null = null;\n walkScreen(screen, (l) => {\n if (!found && l.id === id) found = l;\n });\n return found;\n};\n\n/** Collect all input fieldKeys across a manifest. */\nexport const collectFieldKeys = (manifest: FlowManifest): { fieldKey: string; screenId: string }[] => {\n const out: { fieldKey: string; screenId: string }[] = [];\n for (const screen of manifest.screens) {\n walkScreen(screen as unknown as Screen, (l) => {\n if (isInputLayer(l)) out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n if (l.kind === 'checkbox') out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n if (l.kind === 'email_password_auth') {\n out.push({ fieldKey: l.fieldKey, screenId: screen.id });\n }\n });\n }\n return out;\n};\n\n/**\n * Pick a snake_case field key starting from `base` that is not in `used`\n * (e.g. `text` → `text_2` → `text_3` when `text` is taken).\n */\nexport const nextUniqueFieldKey = (base: string, used: Iterable<string>): string => {\n const set = used instanceof Set ? used : new Set(used);\n if (!set.has(base)) return base;\n let n = 2;\n while (set.has(`${base}_${n}`)) n += 1;\n return `${base}_${n}`;\n};\n\n/**\n * Resolve a token reference like `$primary` to a literal value from `theme`.\n * Pass-through for non-token strings; returns undefined for `undefined`.\n */\nexport const resolveTokens = <T extends string | undefined>(\n theme: Theme | undefined,\n value: T,\n): T | string => {\n if (value === undefined) return value;\n if (typeof value !== 'string' || !value.startsWith('$')) return value;\n const key = value.slice(1) as keyof Theme;\n const literal = theme?.[key];\n if (typeof literal === 'string') return literal;\n return value;\n};\n\n/**\n * Resolve a layer color for the current appearance (`light` | `dark`).\n * Plain string uses `resolveTokens` for both modes (legacy). Object form\n * picks `light` / `dark` with fallback to the other key when one is omitted.\n */\nexport const resolveThemedColor = (\n theme: Theme | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') return resolveTokens(theme, value) as string;\n const raw = palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n if (raw === undefined) return undefined;\n return resolveTokens(theme, raw) as string;\n};\n\n/**\n * Resolve a themed value used for CSS `background` (or RN background fill).\n * Supports `$brandGradient:<uuid>` when branding presets are provided; other values match {@link resolveThemedColor}.\n */\nexport const resolveThemedBackground = (\n theme: Theme | undefined,\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): string | undefined => {\n if (value === undefined) return undefined;\n if (typeof value === 'string') {\n if (value.startsWith('$brandGradient:')) {\n return resolveBrandGradientToken(branding, value);\n }\n return resolveTokens(theme, value) as string;\n }\n const raw = palette === 'dark' ? (value.dark ?? value.light) : (value.light ?? value.dark);\n if (raw === undefined) return undefined;\n if (raw.startsWith('$brandGradient:')) {\n return resolveBrandGradientToken(branding, raw);\n }\n return resolveTokens(theme, raw) as string;\n};\n\nexport const nativeBrandBackgroundFromThemedColor = (\n theme: Theme | undefined,\n branding: Branding | undefined,\n palette: 'light' | 'dark',\n value: ThemedColor | undefined,\n): { solid?: string; linear?: BrandGradientNativeLinear } => {\n const preset = brandGradientFromThemedColor(branding, palette, value);\n if (preset) {\n const lin = brandGradientNativeLinear(preset);\n if (lin) return { linear: lin };\n return { solid: brandGradientSolidFallback(preset) };\n }\n const bg = resolveThemedBackground(theme, branding, palette, value) as string | undefined;\n if (!bg) return {};\n const parsed = parseLinearGradientCss(bg);\n if (parsed) {\n return {\n linear: nativeLinearFromAngleAndStops(\n parsed.angleDeg,\n parsed.stops.map((s) => ({ color: s.color, offsetPct: s.offsetPct })),\n ),\n };\n }\n if (isStoredLinearGradientCss(bg)) {\n const first = bg.match(/#[0-9a-fA-F]{3,8}/);\n return { solid: first ? first[0] : '#808080' };\n }\n return { solid: bg };\n};\n","import type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { Screen, ScreenBackgroundVideoFill } from '@getrheo/contracts';\nimport { isScreenBackgroundPlaybackId, screenBackgroundPlaybackId } from '@getrheo/contracts';\nimport {\n isInputLayer,\n OS_PERMISSION_OUTCOME_CONTINUE,\n OS_PERMISSION_OUTCOME_END,\n type ButtonLayer,\n type IconLayer,\n type LottieLayer,\n type TextLayer,\n type VideoLayer,\n} from '@getrheo/contracts/layers';\nimport { findLayerById, walkScreen } from './layers';\n\n/** Agent-facing bullets for rules enforced by {@link collectFlowBuilderIssues}. Keep in sync with checks below. */\nexport const BUILDER_RULES_AGENT_BULLETS: readonly string[] = [\n 'Connect flow entry on the canvas before publishing (entryScreenId must exist when screens are present).',\n 'Every text and icon layer needs explicit style.color (including nested button label text — native does not inherit colors).',\n 'Screens with text_input, multiple_choice, or scale_input need a button with action.kind \"continue\".',\n 'At most one input layer per screen (single_choice, multiple_choice, text_input, scale_input).',\n 'Do not combine oauth_login or email_password_auth with other input layers on the same screen.',\n 'Only one oauth_login and one email_password_auth per screen; never both on the same screen.',\n 'fieldKey values must be unique snake_case across the flow.',\n 'Choice branch goTo and go_to_step screenId must reference existing screen ids.',\n 'request_app_review buttons require screen.next.default wired to a valid target.',\n 'request_os_permission outcomes must target existing screens, \"continue\", or \"end\".',\n 'Lottie/video with autoPlay false needs a button with action.kind \"play_media\" targeting that layer (or screen background video id).',\n 'play_media targetLayerIds must reference Lottie/video layers on the same screen or the screen background video playback id.',\n];\n\nconst FIELD_KEY_RE = /^[a-z][a-z0-9_]*$/;\n\nconst styleBucketHasColor = (s: { color?: unknown } | undefined): boolean =>\n s !== undefined && s.color !== undefined;\n\n/** Text must carry explicit `color` (base or any breakpoint) so native SDK matches canvas without CSS inheritance. */\nexport const textLayerHasAuthoringColor = (l: TextLayer): boolean => {\n if (styleBucketHasColor(l.style)) return true;\n const bp = l.styleBreakpoints;\n if (!bp) return false;\n return (\n styleBucketHasColor(bp.sm) ||\n styleBucketHasColor(bp.md) ||\n styleBucketHasColor(bp.lg) ||\n styleBucketHasColor(bp.xl) ||\n styleBucketHasColor(bp['2xl'])\n );\n};\n\nexport const iconLayerHasAuthoringColor = (l: IconLayer): boolean => {\n if (styleBucketHasColor(l.style)) return true;\n const bp = l.styleBreakpoints;\n if (!bp) return false;\n return (\n styleBucketHasColor(bp.sm) ||\n styleBucketHasColor(bp.md) ||\n styleBucketHasColor(bp.lg) ||\n styleBucketHasColor(bp.xl) ||\n styleBucketHasColor(bp['2xl'])\n );\n};\n\n/**\n * Builder / dashboard semantic checks beyond {@link FlowManifestSchema}.\n * Kept in flow-runtime so seeds, API, and the web editor share one definition.\n */\nexport const collectFlowBuilderIssues = (manifest: FlowManifest): string[] => {\n const issues: string[] = [];\n const fieldKeyOwners = new Map<string, string[]>();\n const screenIds = new Set(manifest.screens.map((s) => s.id));\n const jumpTargetIds = new Set<string>([\n ...screenIds,\n ...manifest.decisionNodes.map((d) => d.id),\n ...(manifest.externalSurfaceNodes ?? []).map((n) => n.id),\n ]);\n\n if (manifest.entryScreenId == null) {\n if (manifest.screens.length > 0) {\n issues.push(\n 'Connect the flow entry node on the canvas to where the flow starts (a screen, decision, or integration step).',\n );\n }\n } else if (!jumpTargetIds.has(manifest.entryScreenId)) {\n issues.push(`Flow entry target \"${manifest.entryScreenId}\" does not exist.`);\n }\n\n for (const screen of manifest.screens as unknown as Screen[]) {\n let inputCount = 0;\n let oauthLoginLayerCount = 0;\n let emailPasswordAuthLayerCount = 0;\n let needsManualSubmit = false;\n let hasContinueButton = false;\n const screenLabel = screen.name || screen.id;\n const mediaLayerIds = new Set<string>();\n const buttonLayerIds = new Set<string>();\n const shellPlaybackId = screenBackgroundPlaybackId(screen.id);\n const shellFill = screen.containerStyle?.backgroundFill;\n const shellVideoFill =\n shellFill?.kind === 'video' ? (shellFill as ScreenBackgroundVideoFill) : undefined;\n\n walkScreen(screen, (l) => {\n if (l.kind === 'button') buttonLayerIds.add(l.id);\n });\n\n if (shellFill?.kind === 'image' || shellFill?.kind === 'video') {\n if (!shellFill.media?.mediaAssetId) {\n issues.push(\n `Screen \"${screenLabel}\" ${shellFill.kind} background needs a media asset.`,\n );\n }\n }\n\n if (shellVideoFill) {\n if (shellVideoFill.autoPlay === false) {\n const triggerId = shellVideoFill.triggerLayerId?.trim();\n if (!triggerId) {\n issues.push(\n `Screen \"${screenLabel}\" background video needs a trigger button when auto-play is off.`,\n );\n } else if (!buttonLayerIds.has(triggerId)) {\n issues.push(\n `Screen \"${screenLabel}\" background video references a missing trigger button \"${triggerId}\".`,\n );\n } else {\n const btn = findLayerById(screen, triggerId) as ButtonLayer | null;\n if (!btn || btn.kind !== 'button') {\n issues.push(\n `Screen \"${screenLabel}\" background video trigger must be a button layer.`,\n );\n } else if (btn.action.kind !== 'play_media') {\n issues.push(\n `Screen \"${screenLabel}\" background video trigger button must use On Tap → Play media.`,\n );\n } else if (!btn.action.targetLayerIds.includes(shellPlaybackId)) {\n issues.push(\n `Screen \"${screenLabel}\" background video is not listed on trigger button \"${triggerId}\".`,\n );\n }\n }\n } else if (shellVideoFill.triggerLayerId) {\n const btn = findLayerById(screen, shellVideoFill.triggerLayerId);\n if (\n btn?.kind === 'button' &&\n btn.action.kind === 'play_media' &&\n !btn.action.targetLayerIds.includes(shellPlaybackId)\n ) {\n issues.push(\n `Screen \"${screenLabel}\" background video trigger button does not target the screen background.`,\n );\n }\n }\n }\n\n walkScreen(screen, (l) => {\n if (l.kind === 'lottie' || l.kind === 'video') mediaLayerIds.add(l.id);\n if (l.kind === 'oauth_login') {\n oauthLoginLayerCount += 1;\n }\n if (l.kind === 'email_password_auth') {\n emailPasswordAuthLayerCount += 1;\n }\n if (l.kind === 'button' && l.action.kind === 'continue') {\n hasContinueButton = true;\n }\n if (isInputLayer(l)) {\n inputCount += 1;\n if (l.kind === 'multiple_choice' || l.kind === 'text_input' || l.kind === 'scale_input') {\n needsManualSubmit = true;\n }\n const key = l.fieldKey;\n const label = screen.name || screen.id;\n if (!key || key.length === 0) {\n issues.push(`Screen \"${label}\" is missing a variable name (fieldKey).`);\n } else if (!FIELD_KEY_RE.test(key)) {\n issues.push(\n `Screen \"${label}\" has an invalid variable name \"${key}\" — use snake_case (a–z, 0–9, _).`,\n );\n } else {\n const owners = fieldKeyOwners.get(key) ?? [];\n owners.push(label);\n fieldKeyOwners.set(key, owners);\n }\n\n if (l.kind === 'single_choice' || l.kind === 'multiple_choice') {\n for (const cond of l.branching.conditions) {\n if (!screenIds.has(cond.goTo)) {\n issues.push(\n `Screen \"${label}\" branches choice \"${cond.choiceId}\" to a missing screen \"${cond.goTo}\".`,\n );\n }\n }\n }\n }\n if (l.kind === 'button' && l.action.kind === 'go_to_step') {\n if (!screenIds.has(l.action.screenId)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" targets a missing screen \"${l.action.screenId}\".`,\n );\n }\n }\n if (l.kind === 'button' && l.action.kind === 'request_app_review') {\n const def = screen.next?.default;\n if (def == null) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" requests app review but the screen has no default next step.`,\n );\n } else if (!screenIds.has(def) && !manifest.decisionNodes?.some((d) => d.id === def)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" requests app review but default next \"${def}\" is missing.`,\n );\n }\n }\n if (l.kind === 'button' && l.action.kind === 'request_os_permission') {\n const o = l.action.outcomes;\n for (const slot of ['granted', 'denied', 'blocked'] as const) {\n const sid = o[slot];\n if (sid === OS_PERMISSION_OUTCOME_END) {\n continue;\n }\n if (sid === OS_PERMISSION_OUTCOME_CONTINUE) {\n const def = screen.next?.default;\n if (def == null) {\n continue;\n }\n if (!screenIds.has(def) && !manifest.decisionNodes?.some((d) => d.id === def)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" (${slot}) continues to missing target \"${def}\".`,\n );\n }\n continue;\n }\n if (!screenIds.has(sid)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" (${slot}) targets a missing screen \"${sid}\".`,\n );\n }\n }\n }\n if (l.kind === 'back_button' && l.fallbackScreenId && !screenIds.has(l.fallbackScreenId)) {\n issues.push(\n `Back button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" uses a missing fallback screen \"${l.fallbackScreenId}\".`,\n );\n }\n if (l.kind === 'button' && l.action.kind === 'go_back_one_screen' && l.action.fallbackScreenId) {\n if (!screenIds.has(l.action.fallbackScreenId)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screen.name || screen.id}\" uses a missing fallback screen \"${l.action.fallbackScreenId}\".`,\n );\n }\n }\n if (l.kind === 'lottie' || l.kind === 'video') {\n const media = l as LottieLayer | VideoLayer;\n if (media.autoPlay === false) {\n const triggerId = media.triggerLayerId?.trim();\n if (!triggerId) {\n issues.push(\n `${media.kind === 'video' ? 'Video' : 'Lottie'} \"${media.name || media.id}\" on screen \"${screenLabel}\" needs a trigger button when auto-play is off.`,\n );\n } else if (!buttonLayerIds.has(triggerId)) {\n issues.push(\n `${media.kind === 'video' ? 'Video' : 'Lottie'} \"${media.name || media.id}\" on screen \"${screenLabel}\" references a missing trigger button \"${triggerId}\".`,\n );\n } else {\n const btn = findLayerById(screen, triggerId) as ButtonLayer | null;\n if (!btn || btn.kind !== 'button') {\n issues.push(\n `${media.kind === 'video' ? 'Video' : 'Lottie'} \"${media.name || media.id}\" on screen \"${screenLabel}\" trigger must be a button layer.`,\n );\n } else if (btn.action.kind !== 'play_media') {\n issues.push(\n `${media.kind === 'video' ? 'Video' : 'Lottie'} \"${media.name || media.id}\" on screen \"${screenLabel}\" trigger button must use On Tap → Play media (or pick the trigger again from this screen).`,\n );\n } else if (!btn.action.targetLayerIds.includes(media.id)) {\n issues.push(\n `${media.kind === 'video' ? 'Video' : 'Lottie'} \"${media.name || media.id}\" on screen \"${screenLabel}\" is not listed on trigger button \"${triggerId}\".`,\n );\n }\n }\n } else if (media.triggerLayerId) {\n const btn = findLayerById(screen, media.triggerLayerId);\n if (btn?.kind === 'button' && btn.action.kind === 'play_media' && !btn.action.targetLayerIds.includes(media.id)) {\n issues.push(\n `${media.kind === 'video' ? 'Video' : 'Lottie'} \"${media.name || media.id}\" on screen \"${screenLabel}\" trigger button does not target this layer.`,\n );\n }\n }\n }\n if (l.kind === 'button' && l.action.kind === 'play_media') {\n for (const targetId of l.action.targetLayerIds) {\n if (targetId === shellPlaybackId) {\n if (!shellVideoFill) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screenLabel}\" targets screen background video, but this screen has no video background.`,\n );\n }\n continue;\n }\n if (isScreenBackgroundPlaybackId(targetId)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screenLabel}\" play-media target \"${targetId}\" is not valid for this screen.`,\n );\n continue;\n }\n if (!mediaLayerIds.has(targetId)) {\n issues.push(\n `Button \"${l.name || l.id}\" on screen \"${screenLabel}\" play-media target \"${targetId}\" must be a Lottie or video layer on this screen, or screen background video.`,\n );\n }\n }\n }\n });\n\n if (oauthLoginLayerCount > 0 && inputCount > 0) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" cannot combine OAuth Login with input layers (${inputCount}). Split them onto separate screens.`,\n );\n }\n\n if (emailPasswordAuthLayerCount > 0 && inputCount > 0) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" cannot combine Email / password login with input layers (${inputCount}). Split them onto separate screens.`,\n );\n }\n\n if (oauthLoginLayerCount > 0 && emailPasswordAuthLayerCount > 0) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" cannot combine OAuth Login with Email / password login. Use one login block per screen.`,\n );\n }\n\n if (emailPasswordAuthLayerCount > 1) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" has ${emailPasswordAuthLayerCount} Email / password login layers; only one is allowed per screen.`,\n );\n }\n\n if (oauthLoginLayerCount > 1) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" has ${oauthLoginLayerCount} OAuth Login layers; only one is allowed per screen.`,\n );\n }\n\n if (inputCount > 1) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" has ${inputCount} input layers; only one is allowed.`,\n );\n }\n\n if (needsManualSubmit && !hasContinueButton) {\n issues.push(\n `Screen \"${screen.name || screen.id}\" has a multiple_choice, text_input, or scale_input but no Button with action \"continue\". Add a Continue button so users can submit.`,\n );\n }\n }\n\n for (const [key, owners] of fieldKeyOwners) {\n if (owners.length > 1) {\n issues.push(`Variable name \"${key}\" is used by multiple screens: ${owners.join(', ')}.`);\n }\n }\n\n for (const screen of manifest.screens as unknown as Screen[]) {\n walkScreen(screen, (l) => {\n const screenLabel = screen.name || screen.id;\n if (l.kind === 'text' && !textLayerHasAuthoringColor(l)) {\n issues.push(\n `Screen \"${screenLabel}\": text layer \"${l.id}\" must set style.color for light and dark (CSS inheritance does not apply on native).`,\n );\n }\n if (l.kind === 'icon' && !iconLayerHasAuthoringColor(l)) {\n issues.push(\n `Screen \"${screenLabel}\": icon layer \"${l.id}\" must set style.color for light and dark.`,\n );\n }\n });\n }\n\n return issues;\n};\n","import { BUILDER_RULES_AGENT_BULLETS } from '../flowBuilderRules.js';\n\nexport const buildBuilderRulesFragment = (): string =>\n [\n 'Builder publish rules (enforced on merge — fix violations before retry):',\n ...BUILDER_RULES_AGENT_BULLETS.map((b) => `- ${b}`),\n ].join('\\n');\n","/**\n * Styling rules for AI system prompts: models must emit schema fields the sim actually renders.\n * Buttons use variant defaults unless style.background / style.color override (web + native).\n */\nexport const buildLayerStylingRules = (): string => `Colors and custom styling (required when the user asks for specific colors, contrast, or different light vs dark appearance):\n- Layers may include a \"style\" object. For fills and foregrounds use schema keys \"background\" and \"color\" only — never backgroundColor, borderColor, or CSS kebab-case.\n- Values: hex strings (e.g. \"#2563eb\", \"#ffffff\") or per-appearance objects: { \"light\": \"#...\", \"dark\": \"#...\" } with at least one key. When the user wants different colors in light vs dark mode, prefer the object form for \"background\" and \"color\".\n- Example solid blue CTA on a button layer: \"variant\":\"primary\",\"style\":{\"background\":\"#2563eb\",\"color\":\"#ffffff\"} (variant still required; style overrides the preset fill/label colors in the sim).\n- Buttons: always set \"variant\" (primary|secondary|ghost|destructive). Preset variants are monochrome; when the user names a color (e.g. blue), add \"style\": { \"background\": \"<hex or {light,dark}>\", \"color\": \"<readable contrast>\" } on the button. You may instead set \"color\" on the nested text child inside button \"children\" for label tint.\n- Text / stack / icon: \"style\".background, \"style\".color, \"style\".border, \"style\".radius work the same (ThemedColor for colored fields).\n- Text alignment stays \"align\": left|center|right — never textAlign.`;\n","/** AI flow generation step workflow (orchestration — not schema). */\nexport const buildFlowGenWorkflowRules = (): string => `You are an expert mobile onboarding flow designer for Rheo.\nReply with ONE JSON object only (no markdown, no prose). Shape: { \"done\": boolean, \"screen\"?: <Screen> }\nIf done=true, omit \"screen\". If done=false, include a complete \"screen\".\n\nPreferred pattern: one regions.body stack (vertical), padding only in body.style (CommonStyle), gap/direction on the stack itself.\nMinimal valid screen (IDs are examples — use unique scr_/lyr_ ids):\n{\"id\":\"scr_intro\",\"name\":\"Intro\",\"regions\":{\"body\":{\"id\":\"lyr_body\",\"kind\":\"stack\",\"direction\":\"vertical\",\"gap\":16,\"style\":{\"width\":\"full\",\"height\":\"fill\",\"padding\":{\"t\":24,\"r\":20,\"b\":24,\"l\":20}},\"children\":[\n {\"id\":\"lyr_title\",\"kind\":\"text\",\"text\":{\"default\":\"Welcome\"},\"style\":{\"width\":\"auto\",\"height\":\"auto\",\"fontSize\":24,\"fontWeight\":700,\"align\":\"center\",\"color\":\"#0f172a\"}},\n {\"id\":\"lyr_sub\",\"kind\":\"text\",\"text\":{\"default\":\"Short subtitle.\"},\"style\":{\"width\":\"auto\",\"height\":\"auto\",\"fontSize\":16,\"fontWeight\":400,\"align\":\"center\",\"color\":\"#64748b\"}},\n {\"id\":\"lyr_next\",\"kind\":\"button\",\"variant\":\"primary\",\"action\":{\"kind\":\"continue\"},\"direction\":\"horizontal\",\"align\":\"center\",\"distribution\":\"center\",\"style\":{\"width\":\"full\",\"height\":\"auto\"},\"children\":[\n {\"id\":\"lyr_next_t\",\"kind\":\"text\",\"text\":{\"default\":\"Continue\"},\"style\":{\"width\":\"auto\",\"height\":\"auto\",\"color\":\"#ffffff\"}}\n ]}\n]}},\"next\":{\"default\":null}}\n\nWorkflow rules:\n- Mirror the user's language in default copy.\n- Never change manifest.flowId, defaultLocale, locales, theme, version from the prompt payload.\n- Screen/layer ids: /^scr_[a-z0-9_]+$/i and /^lyr_[a-z0-9_]+$/i only (letters, numbers, underscores).\n- regions.body is required and must be kind \"stack\". Omit header/footer unless you need them.\n- screen.next.default must be null — the server chains screens on the default path.\n- Avoid carousel and branching choices unless necessary — they are easier to get wrong.\n\nPlaceholder scr_blank still present → done=false with first real screen replacing it.\nUser flow complete on default path → done=true.\n\nNever done=true until a real screen exists (not before replacing scr_blank).`;\n","import type { RheoAgentSelection } from '@getrheo/contracts/dashboard';\nimport type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\n\nconst themeSummary = (manifest: FlowManifest): string => {\n const t = manifest.theme;\n if (!t) return 'theme: (default)';\n const parts: string[] = [];\n if (t.primary) parts.push(`primary=${t.primary}`);\n if (t.background) parts.push(`background=${t.background}`);\n if (t.foreground) parts.push(`foreground=${t.foreground}`);\n if (t.fontFamily) parts.push(`fontFamily=${t.fontFamily}`);\n return parts.length > 0 ? `theme: ${parts.join(', ')}` : 'theme: (partial/default)';\n};\n\nconst graphSummary = (manifest: FlowManifest): string => {\n const screenLines = manifest.screens\n .map((s) => `- ${s.id}: ${s.name}${s.next.default ? ` → ${s.next.default}` : ' → (end)'}`)\n .join('\\n');\n const decisionIds = (manifest.decisionNodes ?? []).map((n) => n.id);\n const surfaceIds = (manifest.externalSurfaceNodes ?? []).map((n) => n.id);\n const sdkKeys = manifest.sdkAttributeKeys ?? [];\n return [\n `schemaVersion: ${manifest.schemaVersion ?? '(unset)'}`,\n `defaultLocale: ${manifest.defaultLocale}`,\n themeSummary(manifest),\n `sdkAttributeKeys: ${sdkKeys.length ? sdkKeys.join(', ') : '(none)'}`,\n `entryScreenId: ${manifest.entryScreenId ?? '(unset)'}`,\n `screens:\\n${screenLines || '(none)'}`,\n `decisionNodes: ${decisionIds.length ? decisionIds.join(', ') : '(none)'}`,\n `externalSurfaceNodes: ${surfaceIds.length ? surfaceIds.join(', ') : '(none)'}`,\n ].join('\\n');\n};\n\nconst focusedDecisionIds = (selection: NonNullable<RheoAgentSelection>): string[] => {\n if (selection.decisionIds?.length) return selection.decisionIds;\n if (selection.decisionId) return [selection.decisionId];\n return [];\n};\n\nconst focusedScreenIds = (selection: NonNullable<RheoAgentSelection>): string[] => {\n if (selection.screenIds?.length) return selection.screenIds;\n if (selection.screenId) return [selection.screenId];\n return [];\n};\n\nconst screensJson = (manifest: FlowManifest, ids: string[]): Screen[] =>\n manifest.screens.filter((s) => ids.includes(s.id));\n\n/**\n * Builds the manifest context block for the Rheo Agent system prompt. When the\n * canvas has a focused selection, embeds full JSON only for the focused\n * screens/nodes plus a graph summary for everything else.\n */\nexport const slimManifestForRheoAgentPrompt = (\n manifest: FlowManifest,\n selection?: RheoAgentSelection,\n): string => {\n const summary = graphSummary(manifest);\n\n if (!selection) {\n return `Flow graph summary (server holds the full draft — emit patch entries only for what you change):\\n${summary}`;\n }\n\n const screenIds = focusedScreenIds(selection);\n if (screenIds.length > 0) {\n const focused = screensJson(manifest, screenIds);\n return `Focused screens (full JSON for the canvas selection):\\n${JSON.stringify(focused)}\\n\\nRest of the flow (graph summary — emit patch entries only for screens/nodes you change):\\n${summary}`;\n }\n\n const decisionIds = focusedDecisionIds(selection);\n if (decisionIds.length > 0) {\n const focused = (manifest.decisionNodes ?? []).filter((n) => decisionIds.includes(n.id));\n return `Focused decision nodes (full JSON):\\n${JSON.stringify(focused)}\\n\\nRest of the flow (graph summary):\\n${summary}`;\n }\n\n if (selection.externalSurfaceId) {\n const node = (manifest.externalSurfaceNodes ?? []).find(\n (n) => n.id === selection.externalSurfaceId,\n );\n return `Focused external surface node (full JSON):\\n${JSON.stringify(node ?? null)}\\n\\nRest of the flow (graph summary):\\n${summary}`;\n }\n\n return `Flow graph summary (server holds the full draft — emit patch entries only for what you change):\\n${summary}`;\n};\n\nexport const buildRheoAgentSystemPrompt = (\n draftManifest: FlowManifest,\n selection: RheoAgentSelection | undefined,\n parts: {\n schemaRules: string;\n builderRules: string;\n layerStyling: string;\n canvasGatesLine?: string;\n selectionBlock: string;\n },\n): string => {\n const gatesBlock = parts.canvasGatesLine\n ? `\\nApp-specific canvas editor policy (must comply):\\n${parts.canvasGatesLine}\\n`\n : '';\n\n return `You are Rheo Agent — an in-builder assistant that edits mobile onboarding flow manifests.\n\n${parts.schemaRules}\n\n${parts.builderRules}\n\n${parts.layerStyling}\n${gatesBlock}\nCurrent draft (builderMeta omitted — do not invent builderMeta):\n${slimManifestForRheoAgentPrompt(draftManifest, selection)}\n\n${parts.selectionBlock}\n\nWhen the user attaches screenshot(s), treat them as visual reference for layout, copy, colors, and styling.`;\n};\n","import type { z } from 'zod';\nimport { FlowManifestSchema, migrateLegacyManifest } from '@getrheo/contracts';\nimport type { FlowManifest } from '@getrheo/contracts';\nimport type { Screen } from '@getrheo/contracts/screens';\nimport { OS_PERMISSION_OUTCOME_CONTINUE, OS_PERMISSION_OUTCOME_END } from '@getrheo/contracts/layers';\nimport { EXTERNAL_SURFACE_NO_NEXT } from '@getrheo/contracts/decisions';\nimport { findInputLayer, walkScreen } from './layers';\n\nexport type ManifestValidationIssue = {\n /** Screen id when the issue is screen-scoped, null otherwise. Field name kept as `stepId` for back-compat with API/dashboard wire types. */\n stepId?: string | null;\n path: (string | number)[];\n message: string;\n code: string;\n};\n\nexport const validateManifest = (\n data: unknown,\n):\n | { ok: true; manifest: FlowManifest }\n | { ok: false; issues: ManifestValidationIssue[] } => {\n const migrated = migrateLegacyManifest(data);\n const result = FlowManifestSchema.safeParse(migrated);\n if (result.success) return { ok: true, manifest: result.data };\n return {\n ok: false,\n issues: result.error.issues.map((i: z.ZodIssue) => {\n const screenIdx = i.path[1];\n const screenId =\n typeof screenIdx === 'number' && Array.isArray((data as FlowManifest)?.screens)\n ? (data as FlowManifest).screens[screenIdx]?.id\n : undefined;\n return {\n stepId: screenId ?? null,\n path: [...i.path],\n message: i.message,\n code: i.code,\n };\n }),\n };\n};\n\nexport type ValidatePublishableResult = {\n /** False when there are blocking {@link issues} (empty flow or no completion path). */\n ok: boolean;\n /** Blocking publish issues. */\n issues: ManifestValidationIssue[];\n /**\n * Non-blocking notices (e.g. screens not on any path from entry). The runtime\n * only serves the reachable subgraph; orphans stay in the draft but are not shown.\n */\n warnings: ManifestValidationIssue[];\n};\n\n/** Publish-time gate. Runs semantic checks beyond the schema. */\nexport const validatePublishable = (manifest: FlowManifest): ValidatePublishableResult => {\n const issues: ManifestValidationIssue[] = [];\n const warnings: ManifestValidationIssue[] = [];\n\n if (manifest.screens.length === 0) {\n issues.push({\n path: ['screens'],\n message: 'flow must have at least one screen',\n code: 'flow.no_screens',\n });\n }\n\n if (manifest.entryScreenId == null && manifest.screens.length > 0) {\n issues.push({\n path: ['entryScreenId'],\n message:\n 'flow entry is not connected — connect the entry node on the canvas to a screen, decision, or integration step before publishing',\n code: 'flow.no_entry',\n });\n }\n\n const screenMap = new Map(\n manifest.screens.map((s) => [s.id, s as unknown as Screen] as const),\n );\n const decisionMap = new Map((manifest.decisionNodes ?? []).map((d) => [d.id, d] as const));\n const surfaceMap = new Map((manifest.externalSurfaceNodes ?? []).map((s) => [s.id, s] as const));\n\n const enqueueGraphNode = (t: string | null | undefined): void => {\n if (t === null || t === undefined) return;\n if (screenMap.has(t) || decisionMap.has(t) || surfaceMap.has(t)) {\n queue.push(t);\n }\n };\n\n // Reachability: BFS from entry across screens, decision vertices, and external surfaces (e.g. RevenueCat paywall).\n const reachable = new Set<string>();\n const queue: string[] = [];\n if (manifest.entryScreenId != null) {\n queue.push(manifest.entryScreenId);\n }\n let canTerminate = false;\n while (queue.length) {\n const id = queue.shift()!;\n if (reachable.has(id)) continue;\n reachable.add(id);\n\n const decision = decisionMap.get(id);\n if (decision) {\n for (const c of decision.cases) {\n if (c.next != null) enqueueGraphNode(c.next);\n }\n if (decision.elseNext != null) enqueueGraphNode(decision.elseNext);\n continue;\n }\n\n const surface = surfaceMap.get(id);\n if (surface) {\n const outcomeTargets = Object.values(surface.outcomes);\n if (\n outcomeTargets.some((t) => t === EXTERNAL_SURFACE_NO_NEXT) ||\n surface.fallback === EXTERNAL_SURFACE_NO_NEXT\n ) {\n canTerminate = true;\n }\n if (surface.fallback != null && surface.fallback !== EXTERNAL_SURFACE_NO_NEXT) {\n enqueueGraphNode(surface.fallback);\n }\n for (const t of outcomeTargets) {\n if (t != null && t !== EXTERNAL_SURFACE_NO_NEXT) enqueueGraphNode(t);\n }\n continue;\n }\n\n const screen = screenMap.get(id);\n if (!screen) continue;\n const targets: (string | null)[] = [];\n targets.push(screen.next.default);\n const input = findInputLayer(screen);\n if (\n input &&\n (input.kind === 'single_choice' || input.kind === 'multiple_choice') &&\n input.branching.enabled\n ) {\n for (const c of input.branching.conditions) targets.push(c.goTo);\n }\n walkScreen(screen, (l) => {\n if (l.kind === 'button' && l.action.kind === 'go_to_step') {\n targets.push(l.action.screenId);\n }\n if (l.kind === 'button' && l.action.kind === 'end_flow') {\n targets.push(null);\n }\n if (l.kind === 'button' && l.action.kind === 'request_app_review') {\n targets.push(screen.next.default);\n }\n if (l.kind === 'button' && l.action.kind === 'request_os_permission') {\n const o = l.action.outcomes;\n for (const t of [o.granted, o.denied, o.blocked]) {\n if (t === OS_PERMISSION_OUTCOME_END) {\n targets.push(null);\n } else if (t === OS_PERMISSION_OUTCOME_CONTINUE) {\n targets.push(screen.next.default);\n } else {\n targets.push(t);\n }\n }\n }\n if (l.kind === 'button' && l.action.kind === 'go_back_one_screen' && l.action.fallbackScreenId) {\n targets.push(l.action.fallbackScreenId);\n }\n if (l.kind === 'back_button' && l.fallbackScreenId) {\n targets.push(l.fallbackScreenId);\n }\n });\n if (targets.every((t) => t === null || t === undefined)) {\n canTerminate = true;\n }\n for (const t of targets) {\n if (t === null || t === undefined) {\n canTerminate = true;\n } else {\n enqueueGraphNode(t);\n }\n }\n }\n\n if (manifest.entryScreenId != null && !canTerminate) {\n issues.push({\n path: ['screens'],\n message: 'no path from entry screen reaches completion',\n code: 'flow.no_completion_path',\n });\n }\n\n for (const screen of manifest.screens) {\n if (manifest.entryScreenId != null && !reachable.has(screen.id)) {\n warnings.push({\n stepId: screen.id,\n path: ['screens', screen.id],\n message: `screen \"${screen.id}\" is not reachable from entry`,\n code: 'screen.unreachable',\n });\n }\n }\n\n for (const sn of manifest.externalSurfaceNodes ?? []) {\n if (manifest.entryScreenId != null && !reachable.has(sn.id)) {\n warnings.push({\n stepId: null,\n path: ['externalSurfaceNodes', sn.id],\n message: `external surface \"${sn.name ?? sn.id}\" is not reachable from entry`,\n code: 'external_surface.unreachable',\n });\n }\n }\n\n for (const dn of manifest.decisionNodes ?? []) {\n if (manifest.entryScreenId != null && !reachable.has(dn.id)) {\n warnings.push({\n stepId: null,\n path: ['decisionNodes', dn.id],\n message: `decision \"${dn.id}\" is not reachable from entry`,\n code: 'decision.unreachable',\n });\n }\n for (const c of dn.cases) {\n if (c.next == null) {\n issues.push({\n stepId: null,\n path: ['decisionNodes', dn.id, 'cases', c.id],\n message: `decision \"${dn.id}\" segment \"${c.name ?? c.id}\" must have a next step before publishing`,\n code: 'decision.incomplete_branches',\n });\n }\n }\n if (dn.elseNext == null) {\n issues.push({\n stepId: null,\n path: ['decisionNodes', dn.id, 'elseNext'],\n message: `decision \"${dn.id}\" needs an \"everyone else\" branch connected before publishing`,\n code: 'decision.incomplete_branches',\n });\n }\n }\n\n return { ok: issues.length === 0, issues, warnings };\n};\n","import {\n collectCanvasGateViolations,\n type ResolvedCanvasEditorGates,\n} from '@getrheo/contracts/canvasEditorGates';\nimport type { FlowManifest } from '@getrheo/contracts/manifest';\nimport { collectFlowBuilderIssues } from '../flowBuilderRules.js';\nimport { validateManifest, type ManifestValidationIssue } from '../validation.js';\n\nexport type AgentManifestValidationIssue = ManifestValidationIssue | {\n path: (string | number)[];\n message: string;\n code: string;\n stepId?: string | null;\n};\n\nexport type ValidateAgentManifestOutputOpts = {\n canvasGates?: ResolvedCanvasEditorGates;\n includeBuilderRules?: boolean;\n};\n\nexport type ValidateAgentManifestOutputResult =\n | { ok: true; manifest: FlowManifest }\n | { ok: false; issues: AgentManifestValidationIssue[] };\n\nexport const validateAgentManifestOutput = (\n data: unknown,\n opts?: ValidateAgentManifestOutputOpts,\n): ValidateAgentManifestOutputResult => {\n const validated = validateManifest(data);\n if (!validated.ok) {\n return { ok: false, issues: validated.issues };\n }\n\n const issues: AgentManifestValidationIssue[] = [];\n\n if (opts?.includeBuilderRules !== false) {\n for (const message of collectFlowBuilderIssues(validated.manifest)) {\n issues.push({\n path: [],\n message,\n code: 'builder.rule',\n stepId: null,\n });\n }\n }\n\n if (opts?.canvasGates) {\n for (const message of collectCanvasGateViolations(validated.manifest, opts.canvasGates)) {\n issues.push({\n path: [],\n message,\n code: 'canvas.gate',\n stepId: null,\n });\n }\n }\n\n if (issues.length > 0) {\n return { ok: false, issues };\n }\n\n return { ok: true, manifest: validated.manifest };\n};\n\nexport const formatAgentManifestIssues = (\n issues: AgentManifestValidationIssue[],\n max = 18,\n): string =>\n JSON.stringify(\n issues.slice(0, max).map((i) => ({\n path: i.path.join('.'),\n message: i.message,\n code: i.code,\n })),\n );\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { FlowManifest } from '@getrheo/contracts/manifest';
|
|
2
|
+
import { Screen } from '@getrheo/contracts/screens';
|
|
3
|
+
|
|
4
|
+
/** Blank seed from {@link buildBlankManifest}: single empty screen awaiting AI replacement. */
|
|
5
|
+
declare const AI_FLOW_PLACEHOLDER_SCREEN_ID = "scr_blank";
|
|
6
|
+
declare const isAiFlowPlaceholderManifest: (manifest: FlowManifest) => boolean;
|
|
7
|
+
/** Last screen on the default-next chain starting at entry (linear v1 assumption for AI expansion). */
|
|
8
|
+
declare const findDefaultPathTailScreen: (manifest: FlowManifest) => Screen | undefined;
|
|
9
|
+
declare const ensureLayoutNodes: (manifest: FlowManifest) => FlowManifest;
|
|
10
|
+
/**
|
|
11
|
+
* Insert a model-generated screen into a draft manifest.
|
|
12
|
+
* — Replaces the blank placeholder as the first screen when still on the initial seed.
|
|
13
|
+
* — Otherwise appends after the default-path tail and wires `next`.
|
|
14
|
+
*/
|
|
15
|
+
declare const mergeAiGeneratedScreenIntoManifest: (manifest: FlowManifest, screen: Screen) => FlowManifest;
|
|
16
|
+
/**
|
|
17
|
+
* Appends a model-generated screen without changing any existing screen's `next` links.
|
|
18
|
+
* The new screen always ends with `next: { default: null }` (canvas: user wires edges manually).
|
|
19
|
+
*/
|
|
20
|
+
declare const appendGeneratedScreenToManifest: (manifest: FlowManifest, newScreen: Screen) => FlowManifest;
|
|
21
|
+
/**
|
|
22
|
+
* Inserts `newScreen` immediately after `anchorScreenId` on the default-next chain:
|
|
23
|
+
* anchor → newScreen → (previous successor of anchor, if any).
|
|
24
|
+
*/
|
|
25
|
+
declare const insertScreenAfterAnchorInManifest: (manifest: FlowManifest, anchorScreenId: string, newScreen: Screen) => FlowManifest;
|
|
26
|
+
/**
|
|
27
|
+
* Applies a slim model manifest onto the authoritative draft while preserving
|
|
28
|
+
* `builderMeta` (canvas layout) and ensuring layout nodes exist for new screens.
|
|
29
|
+
*/
|
|
30
|
+
declare const mergeSlimManifestPreservingBuilderMeta: (draft: FlowManifest, slim: FlowManifest) => FlowManifest;
|
|
31
|
+
|
|
32
|
+
export { AI_FLOW_PLACEHOLDER_SCREEN_ID, appendGeneratedScreenToManifest, ensureLayoutNodes, findDefaultPathTailScreen, insertScreenAfterAnchorInManifest, isAiFlowPlaceholderManifest, mergeAiGeneratedScreenIntoManifest, mergeSlimManifestPreservingBuilderMeta };
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
// src/aiFlowGenerationMerge.ts
|
|
2
|
+
var AI_FLOW_PLACEHOLDER_SCREEN_ID = "scr_blank";
|
|
3
|
+
var bodyStackChildrenLen = (screen) => {
|
|
4
|
+
const body = screen.regions.body;
|
|
5
|
+
if (body.kind !== "stack") return -1;
|
|
6
|
+
return body.children.length;
|
|
7
|
+
};
|
|
8
|
+
var isAiFlowPlaceholderManifest = (manifest) => manifest.screens.length === 1 && manifest.screens[0]?.id === AI_FLOW_PLACEHOLDER_SCREEN_ID && bodyStackChildrenLen(manifest.screens[0]) === 0;
|
|
9
|
+
var findDefaultPathTailScreen = (manifest) => {
|
|
10
|
+
const map = new Map(manifest.screens.map((s) => [s.id, s]));
|
|
11
|
+
const startId = manifest.entryScreenId ?? manifest.screens[0]?.id;
|
|
12
|
+
let cur = startId ? map.get(startId) : void 0;
|
|
13
|
+
const seen = /* @__PURE__ */ new Set();
|
|
14
|
+
let last;
|
|
15
|
+
while (cur && !seen.has(cur.id)) {
|
|
16
|
+
seen.add(cur.id);
|
|
17
|
+
last = cur;
|
|
18
|
+
const n = cur.next.default;
|
|
19
|
+
if (!n) break;
|
|
20
|
+
cur = map.get(n);
|
|
21
|
+
}
|
|
22
|
+
return last;
|
|
23
|
+
};
|
|
24
|
+
var ensureLayoutNodes = (manifest) => {
|
|
25
|
+
const existing = new Map(
|
|
26
|
+
(manifest.builderMeta?.layout?.nodes ?? []).map((n) => [n.id, n])
|
|
27
|
+
);
|
|
28
|
+
const nodes = manifest.screens.map((s, idx) => {
|
|
29
|
+
const hit = existing.get(s.id);
|
|
30
|
+
if (hit) return { ...hit };
|
|
31
|
+
return { id: s.id, x: 80 + idx * 360, y: 120 };
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
...manifest,
|
|
35
|
+
builderMeta: {
|
|
36
|
+
...manifest.builderMeta ?? {},
|
|
37
|
+
layout: {
|
|
38
|
+
...manifest.builderMeta?.layout ?? {},
|
|
39
|
+
nodes
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
var mergeAiGeneratedScreenIntoManifest = (manifest, screen) => {
|
|
45
|
+
if (isAiFlowPlaceholderManifest(manifest)) {
|
|
46
|
+
const screens2 = [{ ...screen, next: { default: null } }];
|
|
47
|
+
let builderMeta = manifest.builderMeta;
|
|
48
|
+
const oldEntry = manifest.entryScreenId;
|
|
49
|
+
if (builderMeta?.layout?.nodes?.length) {
|
|
50
|
+
builderMeta = {
|
|
51
|
+
...builderMeta,
|
|
52
|
+
layout: {
|
|
53
|
+
...builderMeta.layout,
|
|
54
|
+
nodes: builderMeta.layout.nodes.map(
|
|
55
|
+
(n) => n.id === oldEntry ? { ...n, id: screen.id } : { ...n }
|
|
56
|
+
)
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
const merged2 = {
|
|
61
|
+
...manifest,
|
|
62
|
+
screens: screens2,
|
|
63
|
+
entryScreenId: screen.id,
|
|
64
|
+
builderMeta
|
|
65
|
+
};
|
|
66
|
+
return ensureLayoutNodes(merged2);
|
|
67
|
+
}
|
|
68
|
+
const tail = findDefaultPathTailScreen(manifest);
|
|
69
|
+
if (!tail) {
|
|
70
|
+
throw new Error("mergeAiGeneratedScreenIntoManifest: no tail on default path");
|
|
71
|
+
}
|
|
72
|
+
if (tail.next.default !== null) {
|
|
73
|
+
throw new Error("mergeAiGeneratedScreenIntoManifest: tail must end the default path (next is null)");
|
|
74
|
+
}
|
|
75
|
+
const screens = manifest.screens.map(
|
|
76
|
+
(s) => s.id === tail.id ? { ...s, next: { default: screen.id } } : s
|
|
77
|
+
);
|
|
78
|
+
screens.push({ ...screen, next: { default: null } });
|
|
79
|
+
const merged = { ...manifest, screens };
|
|
80
|
+
return ensureLayoutNodes(merged);
|
|
81
|
+
};
|
|
82
|
+
var appendGeneratedScreenToManifest = (manifest, newScreen) => {
|
|
83
|
+
const wiredNew = {
|
|
84
|
+
...newScreen,
|
|
85
|
+
next: { default: null }
|
|
86
|
+
};
|
|
87
|
+
const merged = {
|
|
88
|
+
...manifest,
|
|
89
|
+
screens: [...manifest.screens, wiredNew]
|
|
90
|
+
};
|
|
91
|
+
return ensureLayoutNodes(merged);
|
|
92
|
+
};
|
|
93
|
+
var insertScreenAfterAnchorInManifest = (manifest, anchorScreenId, newScreen) => {
|
|
94
|
+
const anchor = manifest.screens.find((s) => s.id === anchorScreenId);
|
|
95
|
+
if (!anchor) {
|
|
96
|
+
throw new Error("insertScreenAfterAnchorInManifest: anchor screen not found");
|
|
97
|
+
}
|
|
98
|
+
const forwarded = anchor.next.default;
|
|
99
|
+
const wiredNew = {
|
|
100
|
+
...newScreen,
|
|
101
|
+
next: { default: forwarded ?? null }
|
|
102
|
+
};
|
|
103
|
+
const screens = manifest.screens.map(
|
|
104
|
+
(s) => s.id === anchorScreenId ? { ...s, next: { default: wiredNew.id } } : s
|
|
105
|
+
);
|
|
106
|
+
screens.push(wiredNew);
|
|
107
|
+
const merged = { ...manifest, screens };
|
|
108
|
+
return ensureLayoutNodes(merged);
|
|
109
|
+
};
|
|
110
|
+
var mergeSlimManifestPreservingBuilderMeta = (draft, slim) => {
|
|
111
|
+
const merged = {
|
|
112
|
+
...slim,
|
|
113
|
+
builderMeta: draft.builderMeta
|
|
114
|
+
};
|
|
115
|
+
return ensureLayoutNodes(merged);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
export { AI_FLOW_PLACEHOLDER_SCREEN_ID, appendGeneratedScreenToManifest, ensureLayoutNodes, findDefaultPathTailScreen, insertScreenAfterAnchorInManifest, isAiFlowPlaceholderManifest, mergeAiGeneratedScreenIntoManifest, mergeSlimManifestPreservingBuilderMeta };
|
|
119
|
+
//# sourceMappingURL=aiFlowGenerationMerge.js.map
|
|
120
|
+
//# sourceMappingURL=aiFlowGenerationMerge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/aiFlowGenerationMerge.ts"],"names":["screens","merged"],"mappings":"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","file":"aiFlowGenerationMerge.js","sourcesContent":["import type { FlowManifest } from '@getrheo/contracts/manifest';\nimport type { Screen } from '@getrheo/contracts/screens';\n\n/** Blank seed from {@link buildBlankManifest}: single empty screen awaiting AI replacement. */\nexport const AI_FLOW_PLACEHOLDER_SCREEN_ID = 'scr_blank';\n\nconst bodyStackChildrenLen = (screen: Screen): number => {\n const body = screen.regions.body;\n if (body.kind !== 'stack') return -1;\n return body.children.length;\n};\n\nexport const isAiFlowPlaceholderManifest = (manifest: FlowManifest): boolean =>\n manifest.screens.length === 1 &&\n manifest.screens[0]?.id === AI_FLOW_PLACEHOLDER_SCREEN_ID &&\n bodyStackChildrenLen(manifest.screens[0]) === 0;\n\n/** Last screen on the default-next chain starting at entry (linear v1 assumption for AI expansion). */\nexport const findDefaultPathTailScreen = (manifest: FlowManifest): Screen | undefined => {\n const map = new Map(manifest.screens.map((s) => [s.id, s]));\n const startId = manifest.entryScreenId ?? manifest.screens[0]?.id;\n let cur = startId ? map.get(startId) : undefined;\n const seen = new Set<string>();\n let last: Screen | undefined;\n while (cur && !seen.has(cur.id)) {\n seen.add(cur.id);\n last = cur;\n const n = cur.next.default;\n if (!n) break;\n cur = map.get(n);\n }\n return last;\n};\n\nexport const ensureLayoutNodes = (manifest: FlowManifest): FlowManifest => {\n const existing = new Map(\n (manifest.builderMeta?.layout?.nodes ?? []).map((n) => [n.id, n] as const),\n );\n const nodes = manifest.screens.map((s, idx) => {\n const hit = existing.get(s.id);\n if (hit) return { ...hit };\n return { id: s.id, x: 80 + idx * 360, y: 120 };\n });\n return {\n ...manifest,\n builderMeta: {\n ...(manifest.builderMeta ?? {}),\n layout: {\n ...(manifest.builderMeta?.layout ?? {}),\n nodes,\n },\n },\n };\n};\n\n/**\n * Insert a model-generated screen into a draft manifest.\n * — Replaces the blank placeholder as the first screen when still on the initial seed.\n * — Otherwise appends after the default-path tail and wires `next`.\n */\nexport const mergeAiGeneratedScreenIntoManifest = (\n manifest: FlowManifest,\n screen: Screen,\n): FlowManifest => {\n if (isAiFlowPlaceholderManifest(manifest)) {\n const screens: Screen[] = [{ ...screen, next: { default: null } }];\n let builderMeta = manifest.builderMeta;\n const oldEntry = manifest.entryScreenId;\n if (builderMeta?.layout?.nodes?.length) {\n builderMeta = {\n ...builderMeta,\n layout: {\n ...builderMeta.layout,\n nodes: builderMeta.layout.nodes.map((n) =>\n n.id === oldEntry ? { ...n, id: screen.id } : { ...n },\n ),\n },\n };\n }\n const merged: FlowManifest = {\n ...manifest,\n screens,\n entryScreenId: screen.id,\n builderMeta,\n };\n return ensureLayoutNodes(merged);\n }\n\n const tail = findDefaultPathTailScreen(manifest);\n if (!tail) {\n throw new Error('mergeAiGeneratedScreenIntoManifest: no tail on default path');\n }\n if (tail.next.default !== null) {\n throw new Error('mergeAiGeneratedScreenIntoManifest: tail must end the default path (next is null)');\n }\n\n const screens: Screen[] = manifest.screens.map((s) =>\n s.id === tail.id ? { ...s, next: { default: screen.id } } : s,\n );\n screens.push({ ...screen, next: { default: null } });\n const merged: FlowManifest = { ...manifest, screens };\n return ensureLayoutNodes(merged);\n};\n\n/**\n * Appends a model-generated screen without changing any existing screen's `next` links.\n * The new screen always ends with `next: { default: null }` (canvas: user wires edges manually).\n */\nexport const appendGeneratedScreenToManifest = (manifest: FlowManifest, newScreen: Screen): FlowManifest => {\n const wiredNew: Screen = {\n ...newScreen,\n next: { default: null },\n };\n const merged: FlowManifest = {\n ...manifest,\n screens: [...manifest.screens, wiredNew],\n };\n return ensureLayoutNodes(merged);\n};\n\n/**\n * Inserts `newScreen` immediately after `anchorScreenId` on the default-next chain:\n * anchor → newScreen → (previous successor of anchor, if any).\n */\nexport const insertScreenAfterAnchorInManifest = (\n manifest: FlowManifest,\n anchorScreenId: string,\n newScreen: Screen,\n): FlowManifest => {\n const anchor = manifest.screens.find((s) => s.id === anchorScreenId);\n if (!anchor) {\n throw new Error('insertScreenAfterAnchorInManifest: anchor screen not found');\n }\n\n const forwarded = anchor.next.default;\n const wiredNew: Screen = {\n ...newScreen,\n next: { default: forwarded ?? null },\n };\n\n const screens: Screen[] = manifest.screens.map((s) =>\n s.id === anchorScreenId ? { ...s, next: { default: wiredNew.id } } : s,\n );\n screens.push(wiredNew);\n const merged: FlowManifest = { ...manifest, screens };\n return ensureLayoutNodes(merged);\n};\n\n/**\n * Applies a slim model manifest onto the authoritative draft while preserving\n * `builderMeta` (canvas layout) and ensuring layout nodes exist for new screens.\n */\nexport const mergeSlimManifestPreservingBuilderMeta = (\n draft: FlowManifest,\n slim: FlowManifest,\n): FlowManifest => {\n const merged: FlowManifest = {\n ...slim,\n builderMeta: draft.builderMeta,\n };\n return ensureLayoutNodes(merged);\n};\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { EasingToken, AnimatableProperty, AnimationClip, KeyframeTrack } from '@getrheo/contracts/animations';
|
|
2
|
+
import { Layer, LayerKind } from '@getrheo/contracts/layers';
|
|
3
|
+
import { Screen } from '@getrheo/contracts/screens';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Cubic-bezier control points for every named easing token. The exact
|
|
7
|
+
* numbers are shared between web (CSS keyframes / `cubic-bezier(...)`)
|
|
8
|
+
* and native (Reanimated `Easing.bezier`) so playback matches sample by
|
|
9
|
+
* sample.
|
|
10
|
+
*/
|
|
11
|
+
declare const EASING_BEZIERS: Record<EasingToken, [number, number, number, number]>;
|
|
12
|
+
/**
|
|
13
|
+
* Map an authoring time `tNorm ∈ [0,1]` to the eased value for a single
|
|
14
|
+
* track. Returns the final value when t ≥ last keyframe and the first
|
|
15
|
+
* value when t ≤ first keyframe so renderers can hold pre/post values
|
|
16
|
+
* without special-casing edges.
|
|
17
|
+
*/
|
|
18
|
+
declare const sampleTrack: (track: KeyframeTrack, tNorm: number) => number;
|
|
19
|
+
type SampledClip = Partial<Record<AnimatableProperty, number>>;
|
|
20
|
+
/** Effective delay for a clip given its owning screen's stagger config. */
|
|
21
|
+
declare const effectiveDelayMs: (clip: AnimationClip, screen: Screen) => number;
|
|
22
|
+
/**
|
|
23
|
+
* Sample every track of a clip at an absolute time `tMs` measured from
|
|
24
|
+
* the clip's mount. Honors `delayMs` (incl. stagger). Always returns the
|
|
25
|
+
* authored property keys, even if the clip has not yet started, so
|
|
26
|
+
* renderers can treat the result as a stable style overlay.
|
|
27
|
+
*/
|
|
28
|
+
declare const sampleClipAt: (clip: AnimationClip, screen: Screen, tMs: number) => SampledClip;
|
|
29
|
+
/** Merge sampled clips: later keys override; only defined keys from `overlay` win. */
|
|
30
|
+
declare const mergeSampledClips: (base: SampledClip, overlay: SampledClip) => SampledClip;
|
|
31
|
+
/**
|
|
32
|
+
* Sample all clips for `layerId` at global screen time `tMs`.
|
|
33
|
+
*
|
|
34
|
+
* Clips are applied in order of increasing start time (`effectiveDelayMs`),
|
|
35
|
+
* then stable `id`. Each clip contributes once its start time has been
|
|
36
|
+
* reached; after it ends, its **final** sampled values stay merged into
|
|
37
|
+
* state so later clips override animating properties. For **mount** and
|
|
38
|
+
* **stagger** clips, while `tMs` is before that clip's delay, we merge its
|
|
39
|
+
* **start** keyframe values unless some **earlier** clip is inside its own
|
|
40
|
+
* `[delay, delay + duration)` window — so a delayed fade-in stays at opacity
|
|
41
|
+
* 0 during the wait, but a move that overlaps the fade's delay still shows
|
|
42
|
+
* default opacity until the fade segment begins. **Unmount** clips never
|
|
43
|
+
* apply pre-delay sampling. This supports multiple appear / hide segments on
|
|
44
|
+
* the same layer (web sim / builder scrub).
|
|
45
|
+
*
|
|
46
|
+
* **Native:** `LayerMotionShell` still uses the first mount + first unmount
|
|
47
|
+
* clip only until RN playback is extended for arbitrary sequences.
|
|
48
|
+
*/
|
|
49
|
+
declare const sampleLayerAnimAt: (screen: Screen, layerId: string, tMs: number) => SampledClip;
|
|
50
|
+
/** True if this layer has any animation clip (mount, unmount, or legacy stagger). */
|
|
51
|
+
declare const layerHasAnimationClips: (screen: Screen | undefined, layerId: string) => boolean;
|
|
52
|
+
/** Total time (ms) before the screen's animations are visually settled. */
|
|
53
|
+
declare const screenAnimationsDurationMs: (screen: Screen) => number;
|
|
54
|
+
/** End of the loader fill segment on the timeline (ms from screen mount), for one loader layer. */
|
|
55
|
+
declare const loaderLayerFillTimelineEndMs: (layer: Extract<Layer, {
|
|
56
|
+
kind: "loader";
|
|
57
|
+
}>) => number;
|
|
58
|
+
/** Latest end time (ms from screen mount) of any loader timed fill on this screen. */
|
|
59
|
+
declare const screenLoaderTimelineExtentMs: (screen: Screen) => number;
|
|
60
|
+
/**
|
|
61
|
+
* Fill progress 0–1 for scrubber / motion clock time `tMs` (linear; no easing).
|
|
62
|
+
*/
|
|
63
|
+
declare const loaderFillProgressAtGlobalMs: (tMs: number, fillDelayMs: number, durationMs: number) => number;
|
|
64
|
+
/** Default timeline play span when a Lottie layer has no {@link durationMs}. */
|
|
65
|
+
declare const DEFAULT_LOTTIE_PLAY_DURATION_MS = 2000;
|
|
66
|
+
/** Duration (ms) from Lottie JSON `ip` / `op` / `fr` when present. */
|
|
67
|
+
declare const lottieJsonDurationMs: (animationData: object) => number;
|
|
68
|
+
/**
|
|
69
|
+
* @deprecated Prefer {@link workbenchTimelineTotalMs} from `@getrheo/flow-runtime/restingMotion`.
|
|
70
|
+
* Kept for tests; returns mount/unmount clip extent only (no 10s floor).
|
|
71
|
+
*/
|
|
72
|
+
declare const MIN_ANIMATION_TIMELINE_AUTHORING_SPAN_MS = 10000;
|
|
73
|
+
/** Mount/unmount clip extent only — does not include loader/Lottie/video/resting spans. */
|
|
74
|
+
declare const animationTimelineAuthoringEndMs: (screen: Screen) => number;
|
|
75
|
+
/**
|
|
76
|
+
* Convert legacy `stagger` clips to `mount` with combined delay and drop
|
|
77
|
+
* `screen.stagger` so authoring uses a single delay per clip.
|
|
78
|
+
*/
|
|
79
|
+
declare const migrateStaggerClipsToMount: (screen: Screen) => Screen;
|
|
80
|
+
/**
|
|
81
|
+
* Reassigns `staggerIndex` on every stagger clip from **direct child order**
|
|
82
|
+
* under each {@link StackLayer}. Matches how authors think about sibling
|
|
83
|
+
* sequencing in the layer tree.
|
|
84
|
+
*/
|
|
85
|
+
declare const applyStaggerIndicesFromTreeOrder: (screen: Screen) => Screen;
|
|
86
|
+
/**
|
|
87
|
+
* Index clips by `targetLayerId` so renderers don't re-walk the full
|
|
88
|
+
* animations array per layer per frame.
|
|
89
|
+
*/
|
|
90
|
+
declare const clipsByLayerId: (screen: Screen) => Map<string, AnimationClip[]>;
|
|
91
|
+
/**
|
|
92
|
+
* Reduced-motion policy used by every runtime. The default behavior is
|
|
93
|
+
* conservative: animations snap to their final keyframe (no movement),
|
|
94
|
+
* and screen transitions become instantaneous. Authors who want more
|
|
95
|
+
* latitude can extend this in the future without diverging the
|
|
96
|
+
* renderers.
|
|
97
|
+
*/
|
|
98
|
+
type ReducedMotionPolicy = 'play' | 'snap-to-end';
|
|
99
|
+
declare const applyReducedMotion: (clip: AnimationClip, policy: ReducedMotionPolicy) => AnimationClip;
|
|
100
|
+
/**
|
|
101
|
+
* Whitelist of animatable properties per layer kind. Keep this in sync
|
|
102
|
+
* with renderer support so the editor can disable unsupported tracks
|
|
103
|
+
* before they hit the manifest. Today every layer supports the same
|
|
104
|
+
* style-token subset; we keep the function shape so future layer kinds
|
|
105
|
+
* can opt-in / opt-out without schema changes.
|
|
106
|
+
*/
|
|
107
|
+
declare const listAnimatablePropsForLayerKind: (_kind: LayerKind) => readonly AnimatableProperty[];
|
|
108
|
+
declare const isPropertyAllowedOnLayer: (layer: Layer, property: AnimatableProperty) => boolean;
|
|
109
|
+
|
|
110
|
+
export { DEFAULT_LOTTIE_PLAY_DURATION_MS, EASING_BEZIERS, MIN_ANIMATION_TIMELINE_AUTHORING_SPAN_MS, type ReducedMotionPolicy, type SampledClip, animationTimelineAuthoringEndMs, applyReducedMotion, applyStaggerIndicesFromTreeOrder, clipsByLayerId, effectiveDelayMs, isPropertyAllowedOnLayer, layerHasAnimationClips, listAnimatablePropsForLayerKind, loaderFillProgressAtGlobalMs, loaderLayerFillTimelineEndMs, lottieJsonDurationMs, mergeSampledClips, migrateStaggerClipsToMount, sampleClipAt, sampleLayerAnimAt, sampleTrack, screenAnimationsDurationMs, screenLoaderTimelineExtentMs };
|