@syntrologie/adapt-chatbot 2.55.1 → 2.57.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.
Files changed (75) hide show
  1. package/dist/AdaptiveChatBar.d.ts +18 -0
  2. package/dist/AdaptiveChatBar.d.ts.map +1 -1
  3. package/dist/AdaptiveChatBar.interleave.test.d.ts +9 -0
  4. package/dist/AdaptiveChatBar.interleave.test.d.ts.map +1 -0
  5. package/dist/AdaptiveChatBar.js +5 -4
  6. package/dist/AdaptiveChatBarMountable.d.ts +28 -17
  7. package/dist/AdaptiveChatBarMountable.d.ts.map +1 -1
  8. package/dist/AdaptiveChatTrail.d.ts.map +1 -1
  9. package/dist/AdaptiveChatTrail.js +4 -3
  10. package/dist/AdaptiveChipsStrip.d.ts +20 -20
  11. package/dist/AdaptiveChipsStrip.js +3 -3
  12. package/dist/ChatAssistantLit.d.ts.map +1 -1
  13. package/dist/ChatAssistantLit.js +5 -4
  14. package/dist/ChatTransport.d.ts +6 -1
  15. package/dist/ChatTransport.d.ts.map +1 -1
  16. package/dist/cdn.d.ts +1 -0
  17. package/dist/cdn.d.ts.map +1 -1
  18. package/dist/chunk-4V5L7IRV.js +4711 -0
  19. package/dist/chunk-4V5L7IRV.js.map +7 -0
  20. package/dist/{chunk-EXDL3OKE.js → chunk-AIQMQZBV.js} +314 -908
  21. package/dist/{chunk-EXDL3OKE.js.map → chunk-AIQMQZBV.js.map} +4 -4
  22. package/dist/{chunk-TZA7572J.js → chunk-GN7Z5IVP.js} +2 -2
  23. package/dist/{chunk-ETDHHQS3.js → chunk-HV52LYST.js} +12 -12
  24. package/dist/{chunk-ETDHHQS3.js.map → chunk-HV52LYST.js.map} +1 -1
  25. package/dist/{chunk-LJEPZI6Y.js → chunk-LFJ54PIF.js} +27 -8
  26. package/dist/chunk-LFJ54PIF.js.map +7 -0
  27. package/dist/chunk-LY5AGXVD.js +21 -0
  28. package/dist/chunk-VIRIVP7H.js +898 -0
  29. package/dist/chunk-VIRIVP7H.js.map +7 -0
  30. package/dist/{chunk-VFWA5W56.js → chunk-XPUHW2YO.js} +44 -7
  31. package/dist/chunk-XPUHW2YO.js.map +7 -0
  32. package/dist/editor-lit.js +1 -1
  33. package/dist/element-session.d.ts +3 -0
  34. package/dist/element-session.d.ts.map +1 -0
  35. package/dist/element-session.js +9 -0
  36. package/dist/element-session.js.map +7 -0
  37. package/dist/elements/ElementInstanceStore.d.ts +15 -1
  38. package/dist/elements/ElementInstanceStore.d.ts.map +1 -1
  39. package/dist/elements/ElementSessionController.d.ts +37 -0
  40. package/dist/elements/ElementSessionController.d.ts.map +1 -0
  41. package/dist/elements/ElementSessionController.test.d.ts +2 -0
  42. package/dist/elements/ElementSessionController.test.d.ts.map +1 -0
  43. package/dist/elements/TileHandler.d.ts.map +1 -1
  44. package/dist/elements/createElementStore.d.ts +11 -0
  45. package/dist/elements/createElementStore.d.ts.map +1 -0
  46. package/dist/elements/tileLifecycleProps.d.ts +13 -0
  47. package/dist/elements/tileLifecycleProps.d.ts.map +1 -0
  48. package/dist/elements/types.d.ts +7 -0
  49. package/dist/elements/types.d.ts.map +1 -1
  50. package/dist/hostAgentController.d.ts +65 -0
  51. package/dist/hostAgentController.d.ts.map +1 -0
  52. package/dist/hostAgentController.test.d.ts +2 -0
  53. package/dist/hostAgentController.test.d.ts.map +1 -0
  54. package/dist/observer/wire.d.ts +54 -0
  55. package/dist/observer/wire.d.ts.map +1 -0
  56. package/dist/observer/wire.test.d.ts +2 -0
  57. package/dist/observer/wire.test.d.ts.map +1 -0
  58. package/dist/runtime.d.ts +3 -0
  59. package/dist/runtime.d.ts.map +1 -1
  60. package/dist/runtime.js +824 -163
  61. package/dist/runtime.js.map +4 -4
  62. package/dist/schema.d.ts +66 -66
  63. package/dist/schema.d.ts.map +1 -1
  64. package/dist/schema.js +113 -75
  65. package/dist/schema.js.map +3 -3
  66. package/dist/types.d.ts +17 -0
  67. package/dist/types.d.ts.map +1 -1
  68. package/package.json +9 -7
  69. package/dist/chunk-LJEPZI6Y.js.map +0 -7
  70. package/dist/chunk-NGV35N4T.js +0 -474
  71. package/dist/chunk-NGV35N4T.js.map +0 -7
  72. package/dist/chunk-UVKRO5ER.js +0 -13
  73. package/dist/chunk-VFWA5W56.js.map +0 -7
  74. /package/dist/{chunk-TZA7572J.js.map → chunk-GN7Z5IVP.js.map} +0 -0
  75. /package/dist/{chunk-UVKRO5ER.js.map → chunk-LY5AGXVD.js.map} +0 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/elements/tileLifecycleProps.ts", "../src/elements/ElementInstanceStore.ts", "../src/elements/TileHandler.ts", "../src/elements/ActionHandler.ts", "../src/elements/ItemHandler.ts", "../src/elements/createElementStore.ts", "../src/elements/ElementSessionController.ts"],
4
+ "sourcesContent": ["import { parseTileLayout, type TileLifecycleMountProps } from '@syntrologie/sdk-contracts';\nimport type { MountedElement, SlotPlacement } from './types';\n\n/**\n * The one builder for an `element.tile_mounted` / `element.tile_patched`\n * payload. The runtime rebuilds a tile from the LATEST event for its id, so\n * every site that publishes one (the handler's mount and patch, the store's\n * replays) must send the same fields: a replay built by hand dropped the\n * agent's placement plan and ungrouped the tiles it had just placed.\n */\nexport function tileMountProps(\n instance: MountedElement & { placement: SlotPlacement },\n widget: string\n): TileLifecycleMountProps {\n const layout = parseTileLayout(instance.layout);\n return {\n slot: instance.placement.slot,\n instance_id: instance.instance_id,\n widget,\n props: (instance.content ?? {}) as Record<string, unknown>,\n ...(layout ? { layout } : {}),\n };\n}\n", "/**\n * Type-neutral store for LLM-authored UI element instances \u2014 Phase 6.\n *\n * On SDK boot:\n * 1. Caller fetches `/api/adaptive/mounted_elements` (see `fetcher.ts`).\n * 2. Calls `store.hydrate(response.mounted_elements)`.\n * 3. The store iterates each instance, looks up its handler, and\n * either mounts (stateful) or skips (imperative already-applied).\n *\n * During chat turns:\n * - AGUI `syntro.element.mutation` envelopes arrive via\n * `AgUiTransport.onA2UIEvent`. The transport caller decodes the\n * envelope and invokes `store.apply(envelope.mutations)`.\n *\n * Concurrency / dedup:\n * - Per-instance `version` is the dedup key. A mutation whose version\n * is `<= currentVersion` is treated as already-applied and silently\n * dropped \u2014 handles the SSE-during-boot-fetch race per the design\n * doc (the live mutation might arrive before the boot snapshot does,\n * and the snapshot is then a no-op).\n * - The store is single-threaded by Node/browser convention; no\n * cross-tab sync in v1.\n *\n * The store delegates all DOM work to per-type handlers\n * (`ElementTypeHandler`). It owns the registry, the in-memory state,\n * and the dispatch logic.\n */\n\nimport {\n TILE_MOUNTED_EVENT,\n TILE_REPLAY_REQUEST_EVENT,\n TILE_UNMOUNTED_EVENT,\n} from '@syntrologie/sdk-contracts';\n\nimport type { ActionEngine } from '../types';\nimport type { ElementHandlerContext, ElementTypeHandler } from './ElementTypeHandler';\nimport { tileMountProps } from './tileLifecycleProps';\nimport type { ElementMutation, MountedElement } from './types';\n\nconst COMPOSITIONAL_REPLAY_REQUEST_EVENT = 'element.compositional_replay_request';\nconst COMPOSITIONAL_APPEND_EVENT = 'element.compositional_append';\n\n/**\n * Slot name reserved for tiles the backend wants rendered INLINE IN THE\n * CHAT TRAIL (in the conversation flow, like a rich message) rather than\n * in the canvas deck. The reco carousel uses this: the deck tile mounts\n * BEHIND the open chat panel, so the visitor never sees it. The backend\n * owns the placement decision \u2014 `adaptive_agent.py` emits\n * `SlotPlacement(slot=\"chat-inline\")` for the reco mount. On the chat\n * side these tiles:\n * - surface via {@link ElementInstanceStore.listInlineWidgets} so the\n * trail can mount the widget element inline; and\n * - are SUPPRESSED from {@link ElementInstanceStore.listTileReceipts}\n * (a receipt chip would be a redundant, weaker affordance for a\n * widget already visible in the trail).\n * Every other slot keeps its existing deck + receipt-chip behavior.\n */\nexport const CHAT_INLINE_SLOT = 'chat-inline';\n\n/** One inline-rendered widget for the chat trail \u2014 a `chat-inline` tile. */\nexport interface InlineWidget {\n instanceId: string;\n /** Custom-element tag to mount (e.g. `syntro-product-reco-carousel`). */\n tag: string;\n /** Payload assigned to the mounted element as ONE `props` object property\n * (`el.props = props` \u2014 the standard tile-widget mount contract; never\n * spread as individual per-key properties). */\n props: Record<string, unknown>;\n /** `mounted_by.turn_id` \u2014 lets the chat trail restore the widget to its\n * original transcript position after a reload. */\n turnId?: string;\n /** `tool_call_id` of the mount call \u2014 pins the restored widget to the exact\n * transcript message hosting that call; `turnId` is the coarser fallback. */\n toolCallId?: string;\n}\n\nexport interface ElementInstanceStoreOptions {\n actions: ActionEngine;\n /** Runtime's event bus. ItemHandler publishes\n * `element.compositional_append` events here so container widgets\n * (chips strip, FAQ accordion, nav tips) can subscribe and inject\n * LLM-authored items into their compositional-actions lists.\n *\n * When `subscribe` is also provided, the store listens for\n * `element.compositional_replay_request` events. A container widget\n * publishes this event with its `tile_id` whenever it subscribes\n * (e.g. on first mount AND on SPA-navigation remount); the store\n * responds by re-publishing `element.compositional_append` for every\n * matching item still in its in-memory map. This is what makes\n * LLM-authored items persist across navigations within the page\n * session \u2014 the store survives chat-bar unmount/remount, container\n * widgets re-pull on each fresh mount.\n */\n events?: {\n publish: (name: string, props?: Record<string, unknown>) => void;\n /**\n * Overloaded to match the runtime SDK's `EventBus.subscribe`:\n * pass `{names:[...]}` to filter, or a callback to receive every\n * event. The store uses the filtered form so it doesn't fan\n * unrelated traffic (PostHog autocapture, every action lifecycle\n * event) into a string-compare on each delivery.\n */\n subscribe?: {\n (\n filter: { names?: string[] },\n handler: (event: { name: string; props?: Record<string, unknown> }) => void\n ): () => void;\n (handler: (event: { name: string; props?: Record<string, unknown> }) => void): () => void;\n };\n };\n handlers?: ElementTypeHandler[];\n /** Override the logger \u2014 used by tests to capture log output. */\n logger?: Pick<Console, 'info' | 'warn' | 'error'>;\n /**\n * Optional template\u2192widget resolver used by the rehydrate replay.\n * Without this, replayed tile mounts emit ``widget: template_id``,\n * which only works when the admin's template ids match the widget\n * registry (e.g. ``adaptive-faq:accordion``). When an admin uses a\n * friendly id like ``product-card`` mapping to widget\n * ``adaptive-product:card``, the rehydrate path needs the resolver\n * to match the live mount path.\n *\n * Same shape as ``TileHandler``'s resolver \u2014 pass the same function\n * to both so live mounts and replays agree on the widget id.\n */\n resolveTileWidget?: (templateId: string) => string | undefined;\n}\n\nexport interface ApplyReport {\n ok: boolean;\n rejectedInstanceIds: string[];\n}\n\n/** First non-empty string among the candidates. */\nfunction firstText(...candidates: unknown[]): string | undefined {\n for (const c of candidates) if (typeof c === 'string' && c.trim()) return c.trim();\n return undefined;\n}\n\n/**\n * The receipt chip's label, read from what the tile SHOWS: a product's name,\n * the tile's title or heading, an untitled FAQ's first question, an untitled\n * comparison or carousel named as a set. Never the template id, prettified or not: a\n * title-less canvas-faq mount once read \"Canvas Faq\" to a live iGlow visitor\n * (2026-10-13). When the content names nothing, a neutral word stands in.\n */\nfunction receiptTitle(raw: unknown): string {\n const c = (raw ?? {}) as {\n product?: { name?: unknown };\n title?: unknown;\n heading?: unknown; // comparisons/reco carry `heading`, not `title`\n questions?: Array<{ question?: unknown }>;\n actions?: Array<{ config?: { question?: unknown } }>;\n items?: Array<{ name?: unknown }>;\n products?: Array<{ name?: unknown }>;\n };\n const list = <T>(v: T[] | undefined): T[] => (Array.isArray(v) ? v : []);\n return (\n firstText(\n c.product?.name,\n c.title,\n c.heading,\n ...list(c.questions).map((q) => q?.question),\n ...list(c.actions).map((a) => a?.config?.question),\n setTitle(list(c.products), ' vs '),\n setTitle(list(c.items), null)\n ) ?? 'Details'\n );\n}\n\n/**\n * A multi-item tile is labelled as a set, never as one of its products: a\n * chip reading \"Emface\" looks like a single-product card but brings back a\n * whole carousel. Two items joined by `pair` (\"Botox vs Jeuveau\"), otherwise\n * \"First + N more\"; one item is just its name.\n */\nfunction setTitle(entries: Array<{ name?: unknown }>, pair: string | null): string | undefined {\n const names = entries\n .map((e) => e?.name)\n .filter((n): n is string => typeof n === 'string' && n.trim().length > 0)\n .map((n) => n.trim());\n if (names.length === 0) return undefined;\n if (names.length === 1) return names[0];\n if (names.length === 2 && pair) return `${names[0]}${pair}${names[1]}`;\n return `${names[0]} + ${names.length - 1} more`;\n}\n\nexport class ElementInstanceStore {\n private readonly _actions: ActionEngine;\n private readonly _events: ElementInstanceStoreOptions['events'];\n private readonly _handlers: Map<string, ElementTypeHandler>;\n private readonly _instances: Map<string, MountedElement> = new Map();\n private readonly _logger: Pick<Console, 'info' | 'warn' | 'error'>;\n private readonly _resolveTileWidget?: (templateId: string) => string | undefined;\n /** Active TTL timeout \u2014 replaced on each call to `scheduleClientTtl`. */\n private _ttlTimer: ReturnType<typeof setTimeout> | null = null;\n private _unsubscribeReplay?: () => void;\n private _disposed = false;\n private _disposing = false;\n /** Instance IDs the client has dismissed. Persists across canvas remounts\n * so a dismissed tile never silently reappears on replay/broadcast. */\n private readonly _dismissedIds: Set<string> = new Set();\n\n constructor(options: ElementInstanceStoreOptions) {\n this._actions = options.actions;\n this._events = options.events;\n this._resolveTileWidget = options.resolveTileWidget;\n this._handlers = new Map();\n for (const handler of options.handlers ?? []) {\n this._handlers.set(handler.typeName, handler);\n }\n this._logger = options.logger ?? console;\n this._subscribeReplayRequests();\n }\n\n /**\n * Listen for `element.compositional_replay_request` from container\n * widgets and re-publish `element.compositional_append` for every\n * matching item still tracked in `_instances`. This keeps LLM-authored\n * items visible across SPA navigations: the store is a module-level\n * singleton that survives chat-bar unmount/remount, so when a fresh\n * chips-strip mounts and subscribes, asking for a replay re-populates\n * its chip array.\n */\n private _subscribeReplayRequests(): void {\n const subscribe = this._events?.subscribe;\n const publish = this._events?.publish;\n if (!subscribe || !publish) return;\n this._unsubscribeReplay = subscribe(\n {\n names: [\n COMPOSITIONAL_REPLAY_REQUEST_EVENT,\n TILE_REPLAY_REQUEST_EVENT,\n TILE_UNMOUNTED_EVENT,\n ],\n },\n (event) => {\n if (this._disposed) return;\n if (event.name === TILE_UNMOUNTED_EVENT) {\n // Client dismiss: keep the instance + content, mark it dismissed so\n // replay/broadcast skip it (fixes the zombie-tile reappearance bug).\n const id = String(event.props?.instance_id ?? '');\n if (id) this._dismissedIds.add(id);\n return;\n }\n if (event.name === COMPOSITIONAL_REPLAY_REQUEST_EVENT) {\n const tileId = String(event.props?.tile_id ?? '');\n if (!tileId) return;\n this._replayItems(tileId, publish);\n return;\n }\n if (event.name === TILE_REPLAY_REQUEST_EVENT) {\n // SmartCanvasElementLit asks for every active LLM-authored tile\n // so it can merge them into its `_tiles` array on (re)mount.\n this._replayTiles(publish);\n return;\n }\n }\n );\n }\n\n private _replayItems(\n tileId: string,\n publish: (name: string, props?: Record<string, unknown>) => void\n ): void {\n for (const instance of this._instances.values()) {\n if (this._disposed) return;\n if (instance.element_type !== 'item') continue;\n if (instance.placement.type !== 'parent_tile') continue;\n if (instance.placement.tile_id !== tileId) continue;\n if (instance.state !== 'active') continue;\n publish(COMPOSITIONAL_APPEND_EVENT, {\n tile_id: tileId,\n instance_id: instance.instance_id,\n item: instance.content,\n position: instance.placement.position,\n });\n }\n }\n\n private _replayTiles(publish: (name: string, props?: Record<string, unknown>) => void): void {\n for (const instance of this._instances.values()) {\n if (this._disposed) return;\n if (instance.element_type !== 'tile') continue;\n if (instance.placement.type !== 'slot') continue;\n if (instance.state !== 'active') continue;\n if (this._dismissedIds.has(instance.instance_id)) continue;\n const props = tileMountProps(\n { ...instance, placement: instance.placement },\n this._resolveTileWidget?.(instance.template_id) ?? instance.template_id\n );\n publish(TILE_MOUNTED_EVENT, props as unknown as Record<string, unknown>);\n }\n }\n\n registerHandler(handler: ElementTypeHandler): void {\n this._handlers.set(handler.typeName, handler);\n }\n\n isDismissed(instanceId: string): boolean {\n return this._dismissedIds.has(instanceId);\n }\n\n getDismissedIds(): ReadonlySet<string> {\n return this._dismissedIds;\n }\n\n /** Store-driven receipt source for the chat trail (one per active slot-tile). */\n listTileReceipts(): Array<\n | {\n kind: 'tile';\n instanceId: string;\n title: string;\n dismissed: boolean;\n turnId?: string;\n toolCallId?: string;\n imageUrl?: string;\n }\n | { kind: 'alert'; instanceId: string; title: string; turnId?: string; toolCallId?: string }\n > {\n const out: Array<\n | {\n kind: 'tile';\n instanceId: string;\n title: string;\n dismissed: boolean;\n turnId?: string;\n toolCallId?: string;\n imageUrl?: string;\n }\n | { kind: 'alert'; instanceId: string; title: string; turnId?: string; toolCallId?: string }\n > = [];\n for (const inst of this._instances.values()) {\n if (inst.element_type !== 'tile' || inst.placement.type !== 'slot') continue;\n if (inst.state !== 'active') continue; // reverted/expired \u2192 no chip\n // chat-inline tiles are rendered inline in the trail (see\n // listInlineWidgets) \u2014 a receipt chip would be a redundant, weaker\n // affordance for something already visible in the conversation.\n if (inst.placement.slot === CHAT_INLINE_SLOT) continue;\n const title = receiptTitle(inst.content);\n // COI-037: the chip's leading visual is a tiny product thumbnail when\n // the mount carries one \u2014 the decorative stack glyph read as a BROKEN\n // image next to a product name (2026-07-24 tester screenshots). One\n // extraction per mount shape: product card \u2192 product.image.src; reco\n // carousel \u2192 first item's image_url; comparison \u2192 first product's image.\n const imgContent = inst.content as {\n product?: { image?: { src?: unknown } };\n products?: Array<{ image?: { src?: unknown } }>;\n items?: Array<{ image_url?: unknown }>;\n };\n const imageCandidate =\n imgContent?.product?.image?.src ??\n imgContent?.items?.[0]?.image_url ??\n imgContent?.products?.[0]?.image?.src;\n const imageUrl =\n typeof imageCandidate === 'string' && imageCandidate.trim() ? imageCandidate : undefined;\n // Alert-slot tiles are nudges \u2192 a distinct, navigating chat chip (kind:'alert').\n // Everything else is a recallable deck tile (kind:'tile') with dismiss state.\n if (inst.placement.slot === 'alert') {\n out.push({\n kind: 'alert',\n instanceId: inst.instance_id,\n title,\n turnId: inst.mounted_by?.turn_id,\n toolCallId: inst.tool_call_id ?? undefined,\n });\n } else {\n out.push({\n kind: 'tile',\n instanceId: inst.instance_id,\n title,\n dismissed: this._dismissedIds.has(inst.instance_id),\n turnId: inst.mounted_by?.turn_id,\n toolCallId: inst.tool_call_id ?? undefined,\n ...(imageUrl ? { imageUrl } : {}),\n });\n }\n }\n return out;\n }\n\n /**\n * Store-driven inline-widget source for the chat trail \u2014 one entry per\n * active `chat-inline` slot-tile. The trail mounts each entry's widget\n * element (by tag name, via `document.createElement`) inline in the\n * conversation flow. Distinct from {@link listTileReceipts}: those are\n * chips that recall a deck tile; these ARE the rendered widget.\n */\n listInlineWidgets(): InlineWidget[] {\n const out: InlineWidget[] = [];\n for (const inst of this._instances.values()) {\n if (inst.element_type !== 'tile' || inst.placement.type !== 'slot') continue;\n if (inst.placement.slot !== CHAT_INLINE_SLOT) continue;\n if (inst.state !== 'active') continue; // reverted/expired \u2192 not rendered\n if (this._dismissedIds.has(inst.instance_id)) continue;\n out.push({\n instanceId: inst.instance_id,\n tag: this._resolveTileWidget?.(inst.template_id) ?? inst.template_id,\n props: (inst.content ?? {}) as Record<string, unknown>,\n turnId: inst.mounted_by?.turn_id,\n toolCallId: inst.tool_call_id ?? undefined,\n });\n }\n return out;\n }\n\n /** Clear a client dismissal and re-publish the tile's mount from retained content. */\n recreate(instanceId: string): void {\n if (this._disposed) return;\n const instance = this._instances.get(instanceId);\n const publish = this._events?.publish;\n if (\n !instance ||\n instance.element_type !== 'tile' ||\n instance.placement.type !== 'slot' ||\n !publish\n ) {\n return;\n }\n this._dismissedIds.delete(instanceId);\n const props = tileMountProps(\n { ...instance, placement: instance.placement },\n this._resolveTileWidget?.(instance.template_id) ?? instance.template_id\n );\n publish(TILE_MOUNTED_EVENT, props as unknown as Record<string, unknown>);\n }\n\n /**\n * Apply the server-provided boot snapshot. For each instance:\n * - stateful: validated + mounted via the type handler;\n * - imperative + already-applied: recorded only (no DOM action);\n * - any: tracked in the in-memory map for future patches.\n *\n * Safe to call once on SDK init. Calling again would re-mount\n * stateful instances; callers should not.\n */\n async hydrate(snapshot: MountedElement[]): Promise<void> {\n await this._hydrateWithReport(snapshot);\n }\n\n private async _hydrateWithReport(\n snapshot: MountedElement[],\n reconcile = false\n ): Promise<ApplyReport> {\n const rejectedInstanceIds: string[] = [];\n for (const instance of snapshot) {\n if (this._disposed) return { ok: false, rejectedInstanceIds };\n // Version-dedup against newer live state. Mirrors _applyOne's\n // guard so the apply-before-hydrate race (live mutation lands\n // first, slow boot snapshot resolves after) is genuinely a\n // no-op as the class header promises \u2014 without this, a stale\n // snapshot would clobber the in-memory version and re-render\n // older content. See test\n // \"hydrate honors version dedup when newer state already applied\".\n const existing = this._instances.get(instance.instance_id);\n if (\n existing &&\n (existing.version > instance.version ||\n (existing.version === instance.version &&\n (!reconcile || existing.state === instance.state)))\n ) {\n continue;\n }\n if (reconcile && existing?.state !== 'active')\n this._dismissedIds.delete(instance.instance_id);\n const handler = this._handlers.get(instance.element_type);\n if (!handler) {\n rejectedInstanceIds.push(instance.instance_id);\n this._logger.warn('elements: hydrate skipped \u2014 unknown element_type', {\n element_type: instance.element_type,\n instance_id: instance.instance_id,\n });\n continue;\n }\n this._instances.set(instance.instance_id, instance);\n if (handler.lifecycle === 'imperative') {\n // Don't re-fire scroll/navigate on page reload.\n continue;\n }\n if (instance.state !== 'active') {\n // Reverted / expired / applied stateful \u2014 record only.\n continue;\n }\n if (!(await this._mount(handler, instance))) {\n rejectedInstanceIds.push(instance.instance_id);\n if (!this._disposed) {\n if (existing) this._instances.set(instance.instance_id, existing);\n else this._instances.delete(instance.instance_id);\n }\n }\n }\n // Belt-and-suspenders: after every per-instance handler.mount() has\n // run, publish one more pass for each active LLM-authored tile/item\n // so any subscriber that was wired between the per-handler publishes\n // (or any handler that skipped publish for any reason) still ends\n // up with the right state. Receivers dedup by `instance_id` so the\n // double-emit is idempotent.\n //\n // Items also rely on a per-tile_id replay request (the container\n // widget publishes the request on its own mount), so the explicit\n // replay sweep is the boot-time backstop and the request-driven\n // replay is the SPA-nav backstop.\n this._broadcastActive();\n return { ok: !this._disposed && rejectedInstanceIds.length === 0, rejectedInstanceIds };\n }\n\n /**\n * Re-publish `element.tile_mounted` / `element.compositional_append`\n * for every active LLM-authored instance in the store. Idempotent \u2014\n * receivers key by `instance_id` (tiles) or by widget identity\n * (items via tile_id filter).\n */\n private _broadcastActive(): void {\n if (this._disposed) return;\n const publish = this._events?.publish;\n if (!publish) return;\n this._replayTiles(publish);\n // Items: group by tile_id so each receiver's filter still matches.\n const itemTileIds = new Set<string>();\n for (const instance of this._instances.values()) {\n if (instance.element_type !== 'item') continue;\n if (instance.placement.type !== 'parent_tile') continue;\n if (instance.state !== 'active') continue;\n itemTileIds.add(instance.placement.tile_id);\n }\n for (const tileId of itemTileIds) {\n this._replayItems(tileId, publish);\n }\n }\n\n /**\n * Apply a batch of mutations, atomically per-batch. Each mutation is\n * version-checked (mount: must not conflict with existing instance;\n * patch: resulting_version must be > current; unmount: idempotent).\n */\n async apply(mutations: ElementMutation[]): Promise<void> {\n await this.applyWithReport(mutations);\n }\n\n async applyWithReport(mutations: ElementMutation[]): Promise<ApplyReport> {\n return this._applyWithReport(mutations, false);\n }\n\n private async _applyWithReport(\n mutations: ElementMutation[],\n authoritative: boolean\n ): Promise<ApplyReport> {\n const rejectedInstanceIds: string[] = [];\n for (const mutation of mutations) {\n if (this._disposed) return { ok: false, rejectedInstanceIds };\n const id =\n (mutation?.op === 'mount' ? mutation.instance?.instance_id : mutation?.instance_id) ??\n '<invalid>';\n try {\n if (!(await this._applyOne(mutation, authoritative))) rejectedInstanceIds.push(id);\n } catch {\n rejectedInstanceIds.push(id);\n // Mutations are independent \u2014 one failing should not abort the\n // rest. Log loudly so the failure surfaces.\n this._logger.error('elements: mutation failed', { instance_id: id });\n }\n }\n return { ok: !this._disposed && rejectedInstanceIds.length === 0, rejectedInstanceIds };\n }\n\n /** Read-only snapshot of currently-known instances. */\n getInstances(): MountedElement[] {\n return Array.from(this._instances.values());\n }\n\n getInstance(instance_id: string): MountedElement | undefined {\n return this._instances.get(instance_id);\n }\n\n /** Replace a host-provided complete UI snapshot; never replay imperative actions. */\n async reconcileSnapshot(snapshot: MountedElement[]): Promise<ApplyReport> {\n const rejected = new Set<string>();\n if (this._disposed) return { ok: false, rejectedInstanceIds: [] };\n const active = snapshot.filter(\n (instance) => instance.state === 'active' && instance.element_type !== 'action'\n );\n const ids = new Set(active.map((instance) => instance.instance_id));\n for (const instance of this._instances.values()) {\n if (this._disposed) return { ok: false, rejectedInstanceIds: [...rejected] };\n if (ids.has(instance.instance_id)) continue;\n if (instance.state === 'active') {\n const report = await this.applyWithReport([\n { op: 'unmount', instance_id: instance.instance_id },\n ]);\n if (!report.ok) {\n rejected.add(instance.instance_id);\n continue;\n }\n }\n if (this._disposed) return { ok: false, rejectedInstanceIds: [...rejected] };\n this._instances.delete(instance.instance_id);\n this._dismissedIds.delete(instance.instance_id);\n }\n // Existing containers deduplicate append events. New content must travel\n // through patch so an already-visible FAQ/chip receives its new version.\n for (const instance of active) {\n if (this._disposed) return { ok: false, rejectedInstanceIds: [...rejected] };\n const existing = this._instances.get(instance.instance_id);\n if (!existing || existing.state !== 'active' || existing.version === instance.version)\n continue;\n // A failed delta may have advanced individual instances without advancing\n // the view revision. Only authoritative reconciliation may roll those back.\n const report = await this._applyWithReport(\n [\n {\n op: 'patch',\n instance_id: instance.instance_id,\n patches: [],\n expected_version: existing.version,\n resulting_version: instance.version,\n resulting_content: instance.content,\n },\n ],\n true\n );\n for (const id of report.rejectedInstanceIds) rejected.add(id);\n }\n const report = await this._hydrateWithReport(\n active.filter((instance) => !rejected.has(instance.instance_id)),\n true\n );\n for (const id of report.rejectedInstanceIds) rejected.add(id);\n return { ok: report.ok && rejected.size === 0, rejectedInstanceIds: [...rejected] };\n }\n\n /** Release page-lifetime listeners and timers; queued work becomes inert. */\n dispose(unmount = false): void {\n if (this._disposed || this._disposing) return;\n this._disposing = true;\n if (unmount) {\n for (const instance of this._instances.values()) {\n const handler = this._handlers.get(instance.element_type);\n if (instance.state === 'active' && handler?.lifecycle !== 'imperative') {\n void handler?.unmount(instance, this._ctx()).catch(() => {});\n }\n }\n }\n this._disposed = true;\n this._disposing = false;\n this._unsubscribeReplay?.();\n this._unsubscribeReplay = undefined;\n if (this._ttlTimer !== null) clearTimeout(this._ttlTimer);\n this._ttlTimer = null;\n this._instances.clear();\n this._dismissedIds.clear();\n }\n\n /**\n * Schedule a client-side TTL that unmounts every active stateful\n * instance when the server-side session expires. Replaces any\n * previously-scheduled TTL.\n *\n * Avoids the orphan-window where session-expired tiles linger on the\n * page until manual refresh \u2014 the server forgets at the 24h mark and\n * the SDK tears down concurrently. Re-schedule on each boot fetch /\n * mutation event that carries a refreshed `session_expires_at`.\n *\n * Pass `null` to clear the existing timer without scheduling a new one.\n * Pass a past timestamp to trigger cleanup immediately.\n */\n scheduleClientTtl(session_expires_at: string | null): void {\n if (this._disposed) return;\n if (this._ttlTimer !== null) {\n clearTimeout(this._ttlTimer);\n this._ttlTimer = null;\n }\n if (session_expires_at === null) return;\n\n const expiryMs = Date.parse(session_expires_at);\n if (Number.isNaN(expiryMs)) {\n this._logger.warn('elements: invalid session_expires_at', { session_expires_at });\n return;\n }\n const delay = Math.max(0, expiryMs - Date.now());\n this._ttlTimer = setTimeout(() => {\n this._ttlTimer = null;\n void this._handleSessionExpiry();\n }, delay);\n }\n\n // -------------------------------------------------------------------\n // Internals\n // -------------------------------------------------------------------\n\n private async _handleSessionExpiry(): Promise<void> {\n // Tear down every active stateful instance \u2014 server has already\n // forgotten this session so no further mutations can arrive.\n const unmounts: ElementMutation[] = [];\n for (const instance of this._instances.values()) {\n if (instance.state !== 'active') continue;\n const handler = this._handlers.get(instance.element_type);\n if (!handler || handler.lifecycle === 'imperative') continue;\n unmounts.push({ op: 'unmount', instance_id: instance.instance_id });\n }\n if (unmounts.length > 0) {\n this._logger.info('elements: client TTL fired \u2014 unmounting active instances', {\n count: unmounts.length,\n });\n await this.apply(unmounts);\n }\n }\n\n private async _applyOne(mutation: ElementMutation, authoritative = false): Promise<boolean> {\n if (mutation.op === 'mount') {\n const existing = this._instances.get(mutation.instance.instance_id);\n if (existing && existing.version >= mutation.instance.version) {\n // Already applied (likely the boot snapshot beat the SSE event).\n return true;\n }\n const handler = this._handlers.get(mutation.instance.element_type);\n if (!handler) {\n this._logger.warn('elements: mount dropped \u2014 unknown element_type', {\n element_type: mutation.instance.element_type,\n });\n return false;\n }\n // Active stateful mounts and applied imperative mounts both fire\n // the handler; everything else is a record-only entry (matches\n // hydrate()'s rules).\n const isActiveStateful =\n mutation.instance.state === 'active' && handler.lifecycle !== 'imperative';\n const isAppliedImperative =\n mutation.instance.state === 'applied' && handler.lifecycle === 'imperative';\n if (isActiveStateful || isAppliedImperative) {\n // Commit to the map BEFORE firing the handler \u2014 mirrors hydrate()'s\n // set-before-mount ordering. handler.mount() publishes TILE_MOUNTED\n // SYNCHRONOUSLY, and a subscriber invoked from inside that publish\n // (the chat-bar's inline-widget refresh reads listInlineWidgets())\n // must see this instance. With set-AFTER-mount, that read returned\n // empty and no later event re-fired, so a live chat-inline carousel\n // never reached the trail. If the mount is rejected or throws, roll\n // the map back to its prior entry so a rejected/throwing mount does\n // not leave the map advanced \u2014 the version-dedup guard above would\n // otherwise drop the corrective re-send at the same version.\n this._instances.set(mutation.instance.instance_id, mutation.instance);\n const applied = await this._mount(handler, mutation.instance);\n if (this._disposed) return false;\n if (!applied) {\n if (existing) {\n this._instances.set(mutation.instance.instance_id, existing);\n } else {\n this._instances.delete(mutation.instance.instance_id);\n }\n }\n return applied;\n }\n this._instances.set(mutation.instance.instance_id, mutation.instance);\n return true;\n }\n\n if (mutation.op === 'patch') {\n const existing = this._instances.get(mutation.instance_id);\n if (!existing) {\n this._logger.warn('elements: patch dropped \u2014 unknown instance', {\n instance_id: mutation.instance_id,\n });\n return false;\n }\n // BUG-1783567300: a malformed envelope (backend wire drift \u2014 the\n // deployed backend spent months sending patches WITHOUT\n // resulting_content/resulting_version) must be dropped LOUDLY, never\n // committed. Committing `content: undefined` re-rendered the patched\n // tile as a blank white card; `undefined <= version` is false, so the\n // stale guard alone can't catch it.\n if (\n typeof mutation.resulting_version !== 'number' ||\n mutation.resulting_content == null ||\n typeof mutation.resulting_content !== 'object'\n ) {\n this._logger.warn('elements: patch dropped \u2014 malformed envelope (missing resulting_*)', {\n instance_id: mutation.instance_id,\n });\n return false;\n }\n if (!authoritative && mutation.resulting_version <= existing.version) {\n // Stale patch \u2014 already applied or older than current.\n return true;\n }\n const patched: MountedElement = {\n ...existing,\n content: mutation.resulting_content,\n version: mutation.resulting_version,\n };\n const handler = this._handlers.get(patched.element_type);\n if (handler) {\n const validation = handler.validate(patched, this._ctx());\n if (!validation.accepted) {\n // Critical: do NOT commit to _instances here. The version-dedup\n // guard above would otherwise drop a corrective re-send at the\n // same version, leaving the map permanently divergent from the\n // DOM.\n this._logger.warn('elements: patch validation failed', {\n instance_id: mutation.instance_id,\n reason: validation.reason,\n });\n return false;\n }\n try {\n await handler.patch(patched, this._ctx());\n } catch (err) {\n // Same reasoning as validation failure \u2014 a throwing handler\n // must not leave _instances advanced ahead of the DOM.\n this._logger.warn('elements: handler.patch threw', {\n instance_id: mutation.instance_id,\n err,\n });\n return false;\n }\n }\n if (this._disposed) return false;\n this._instances.set(mutation.instance_id, patched);\n return true;\n }\n\n if (mutation.op === 'unmount') {\n const existing = this._instances.get(mutation.instance_id);\n if (!existing) {\n // Idempotent \u2014 never-knew-it or already unmounted is fine.\n return true;\n }\n const reverted: MountedElement = { ...existing, state: 'reverted' };\n this._instances.set(mutation.instance_id, reverted);\n const handler = this._handlers.get(existing.element_type);\n if (handler) {\n try {\n await handler.unmount(reverted, this._ctx());\n } catch (err) {\n // Keep the pre-handler commit for synchronous event subscribers, but\n // restore the prior state if cleanup fails so projections remain\n // aligned with the still-mounted DOM and a retry remains meaningful.\n if (!this._disposed) this._instances.set(mutation.instance_id, existing);\n this._logger.warn('elements: handler.unmount threw', {\n instance_id: mutation.instance_id,\n err,\n });\n return false;\n }\n }\n return !this._disposed;\n }\n return false;\n }\n\n private async _mount(handler: ElementTypeHandler, instance: MountedElement): Promise<boolean> {\n try {\n const validation = handler.validate(instance, this._ctx());\n if (!validation.accepted) {\n this._logger.warn('elements: mount validation failed', {\n instance_id: instance.instance_id,\n reason: validation.reason,\n detail: validation.detail,\n });\n return false;\n }\n await handler.mount(instance, this._ctx());\n } catch (err) {\n // Mirror the patch branch \u2014 a throwing handler must not leave the\n // map advanced ahead of the DOM, otherwise the dedup guard drops\n // corrective re-sends.\n this._logger.warn('elements: handler.mount threw', {\n instance_id: instance.instance_id,\n err,\n });\n return false;\n }\n return !this._disposed;\n }\n\n private _ctx(): ElementHandlerContext {\n return {\n actions: this._actions,\n events: this._events && {\n publish: (name, props) => {\n if (!this._disposed) this._events?.publish(name, props);\n },\n },\n };\n }\n}\n", "/**\n * Tile element handler \u2014 translates `slot`-placed mount/patch/unmount\n * mutations into pub/sub events that the runtime SDK subscribes to.\n *\n * The runtime SDK's `SmartCanvasElementLit` already routes config-driven\n * tiles to inline slots via `tile.slot === slotName`. LLM-authored tiles\n * use the same path: we publish a TileConfig-shaped envelope and the\n * runtime merges it into its tile array, then existing routing renders\n * it inside the slot's `<syntro-tile-stack>` alongside any config tiles.\n *\n * Why pub/sub instead of `core:mountWidget` via ActionEngine?\n *\n * - `Surfaces.mount` is exclusive per slot \u2014 a second LLM tile to the\n * same slot would displace the first.\n * - `Surfaces` only knows built-in slot names; inline slots resolve\n * anchors via SyntroInlineSlot, not via Surfaces.\n * - Tiles need the SyntroTileCard chrome (chromeless handling, theme\n * overrides, dismiss control) that `core:mountWidget` skips.\n *\n * Container widgets stay dumb: the runtime owns one tile array per slot\n * and renders it the same way regardless of provenance. Subscribers\n * filter on `slot === this.name`.\n *\n * Event names + payload types live in `@syntrologie/sdk-contracts` so\n * both packages share the contract. Renaming a field there is a TS\n * error here and in the runtime subscriber \u2014 no silent drift.\n */\n\nimport {\n TILE_MOUNTED_EVENT,\n TILE_PATCHED_EVENT,\n TILE_UNMOUNTED_EVENT,\n type TileLifecycleUnmountProps,\n} from '@syntrologie/sdk-contracts';\n\nimport type {\n ElementHandlerContext,\n ElementTypeHandler,\n ValidateResult,\n} from './ElementTypeHandler';\nimport { tileMountProps } from './tileLifecycleProps';\nimport type { MountedElement, SlotPlacement } from './types';\n\nexport {\n TILE_MOUNTED_EVENT,\n TILE_PATCHED_EVENT,\n TILE_UNMOUNTED_EVENT,\n} from '@syntrologie/sdk-contracts';\n\n/**\n * Optional template\u2192widget resolver. ``uiTemplates`` declares both\n * the LLM-facing ``id`` (e.g. ``\"product-card\"``) and the runtime\n * widget the chrome should render (e.g. ``\"adaptive-product:card\"``).\n * Without this resolver, the handler falls back to ``template_id`` as\n * the widget id \u2014 which only works when the admin chose ids matching\n * the widget registry, and silently mounts to \"Widget not available\"\n * when they don't.\n */\nexport type TileTemplateWidgetResolver = (templateId: string) => string | undefined;\n\nexport class TileHandler implements ElementTypeHandler {\n readonly typeName = 'tile' as const;\n readonly lifecycle = 'stateful' as const;\n\n constructor(private readonly resolveWidget?: TileTemplateWidgetResolver) {}\n\n private _widgetFor(instance: MountedElement): string {\n return this.resolveWidget?.(instance.template_id) ?? instance.template_id;\n }\n\n validate(instance: MountedElement, _ctx: ElementHandlerContext): ValidateResult {\n if (instance.element_type !== 'tile') {\n return { accepted: false, reason: 'wrong_element_type', detail: instance.element_type };\n }\n if (instance.placement.type !== 'slot') {\n return {\n accepted: false,\n reason: 'tile_requires_slot_placement',\n detail: `got placement.type=${instance.placement.type}`,\n };\n }\n if (typeof instance.template_id !== 'string' || instance.template_id.length === 0) {\n return { accepted: false, reason: 'missing_template_id' };\n }\n // When a resolver is configured, the template_id MUST resolve to a known\n // widget. Falling back to the raw template_id as a widget id (see\n // `_widgetFor`) mounts to a widget the registry will never have, which\n // renders as a permanently blank card in the canvas deck (the sc-mount\n // body stays empty). Reject loudly instead so the mount never enters the\n // tile pipeline \u2014 matching the repo's \"fail loudly, no silent defaults\"\n // rule \u2014 which surfaces the unknown template_id back to the caller.\n if (this.resolveWidget && this.resolveWidget(instance.template_id) === undefined) {\n return { accepted: false, reason: 'unknown_template_id', detail: instance.template_id };\n }\n return { accepted: true };\n }\n\n async mount(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n if (!ctx.events) return;\n const placement = instance.placement as SlotPlacement;\n const props = tileMountProps({ ...instance, placement }, this._widgetFor(instance));\n ctx.events.publish(TILE_MOUNTED_EVENT, props as unknown as Record<string, unknown>);\n }\n\n async patch(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n if (!ctx.events) return;\n const placement = instance.placement as SlotPlacement;\n const props = tileMountProps({ ...instance, placement }, this._widgetFor(instance));\n ctx.events.publish(TILE_PATCHED_EVENT, props as unknown as Record<string, unknown>);\n }\n\n async unmount(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n if (!ctx.events) return;\n const placement = instance.placement as SlotPlacement;\n const props: TileLifecycleUnmountProps = {\n slot: placement.slot,\n instance_id: instance.instance_id,\n };\n ctx.events.publish(TILE_UNMOUNTED_EVENT, props as unknown as Record<string, unknown>);\n }\n}\n", "/**\n * Action element handler \u2014 dispatches an ActionStep through\n * `ActionEngine.applyBatch`.\n *\n * The `content` field of an action `MountedElement` carries the action's\n * params; the executor `kind` comes from the template (which the SDK\n * doesn't have locally yet \u2014 for v1 the template's `kind` is encoded\n * into `content.__kind`, set by the backend tool). When proper\n * template loading lands on the SDK side, this handler resolves the\n * kind from the loaded template instead.\n *\n * **Imperative actions never re-fire on boot.** The `lifecycle` field\n * here is `imperative` \u2014 `ElementInstanceStore` skips boot rehydrate\n * for imperative instances with `state === 'applied'`. The backend\n * record exists for audit; replaying a scroll/navigate on every page\n * load would be visibly wrong.\n *\n * Stateful actions (e.g. `content:insertHtml`, `content:setText`,\n * `content:addClass` once Phase 7's renderer lands) ARE re-applied on\n * boot. v1 supports the imperative shape; stateful action handling\n * waits on the Portable Text renderer.\n */\n\nimport type { ActionStep } from '../types';\nimport type {\n ElementHandlerContext,\n ElementTypeHandler,\n ValidateResult,\n} from './ElementTypeHandler';\nimport type { MountedElement } from './types';\n\nexport class ActionHandler implements ElementTypeHandler {\n readonly typeName = 'action' as const;\n // v1: only imperative actions are wired. Stateful content-mutation\n // actions arrive with Phase 7 (Portable Text renderer).\n readonly lifecycle = 'imperative' as const;\n\n validate(instance: MountedElement, _ctx: ElementHandlerContext): ValidateResult {\n if (instance.element_type !== 'action') {\n return { accepted: false, reason: 'wrong_element_type' };\n }\n const kind = (instance.content as { __kind?: unknown }).__kind;\n if (typeof kind !== 'string' || kind.length === 0) {\n return { accepted: false, reason: 'missing_action_kind' };\n }\n return { accepted: true };\n }\n\n async mount(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n const action = this._actionFromInstance(instance);\n await ctx.actions.applyBatch([action]);\n }\n\n async patch(_instance: MountedElement, _ctx: ElementHandlerContext): Promise<void> {\n // Stateful actions re-apply on patch. Imperative actions don't\n // support patch (the backend rejects), but if one slips through\n // we treat it as a no-op rather than crash.\n }\n\n async unmount(_instance: MountedElement, _ctx: ElementHandlerContext): Promise<void> {\n // Imperative actions can't be unmounted \u2014 the scroll/navigate\n // already happened. The store calls this for completeness; no-op is\n // correct. Stateful actions (Phase 7) will need real reverter logic.\n }\n\n private _actionFromInstance(instance: MountedElement): ActionStep {\n const { __kind, ...params } = instance.content as { __kind: string } & Record<string, unknown>;\n // Selector-targeted templates (e.g. `content:setText`) declare their\n // anchor via the template's `allowed_targets`, which lands on the\n // mounted instance as `placement: {type: \"selector\", selector, position}`.\n // The runtime executors expect a full `AnchorId` object on the\n // action params, so translate placement \u2192 anchorId here. Imperative\n // navigation actions use `placement: {type: \"none\"}` and skip this.\n const placement = instance.placement;\n const anchorOverride: Partial<Record<string, unknown>> =\n placement.type === 'selector'\n ? { anchorId: { selector: placement.selector, route: '**' } }\n : {};\n // Imperative templates (e.g. `navigation:scrollTo`) declare the\n // anchor as a string `EnumField` named `anchorId` in the template\n // fields \u2014 that's the only field shape the agent can author, since\n // EnumField is string-only. The runtime executor still wants an\n // `AnchorId` object (`{selector, route}`), so wrap any string we\n // receive on `anchorId` here. Without this wrap the executor's\n // `resolveAnchor` returns null on a non-object and silently\n // refuses to scroll. `route: '**'` matches every page \u2014 the\n // agent's enum already enumerates the legal selectors, so the\n // route check would be redundant.\n if (typeof params.anchorId === 'string') {\n params.anchorId = { selector: params.anchorId, route: '**' };\n }\n return {\n kind: __kind,\n ...params,\n ...anchorOverride,\n label: `action:${instance.template_id}:${instance.instance_id}`,\n } as unknown as ActionStep;\n }\n}\n", "/**\n * Item element handler \u2014 translates `parent_tile`-placed mount/patch/\n * unmount mutations into pub/sub events that container widgets subscribe\n * to.\n *\n * Container widgets (chips strip, FAQ accordion, nav tips) declare\n * themselves participants by implementing the `CompositionalContainer`\n * contract and subscribing to `runtime.events` with\n * `element.compositional_append` / `element.compositional_patch` /\n * `element.compositional_remove`. Each container filters by\n * `props.tile_id === this.tileId`.\n *\n * Why pub/sub rather than DOM lookup? The runtime's event bus is\n * domain-agnostic and already exists. Container widgets that aren't\n * mounted yet (slow inline-slot wrapper hydration) miss the event,\n * but the next subscribe-then-replay pass at container mount time picks\n * up the durable session state from the LLM's `mounted_elements`. No\n * DOM crawling, no MutationObserver wiring, no ordering assumption.\n *\n * The handler is dumb: it forwards the wire `content` as the `item`\n * payload. The backend wrote that content as a fully-formed\n * compositional-item envelope (`{kind, config: {id, title, payload}}`)\n * so the receiving container can append it verbatim.\n */\n\nimport type {\n ElementHandlerContext,\n ElementTypeHandler,\n ValidateResult,\n} from './ElementTypeHandler';\nimport type { MountedElement, ParentTilePlacement } from './types';\n\n/** Event names. Kept as module constants so subscribers can import them\n * instead of memorizing strings. */\nexport const COMPOSITIONAL_APPEND_EVENT = 'element.compositional_append';\nexport const COMPOSITIONAL_PATCH_EVENT = 'element.compositional_patch';\nexport const COMPOSITIONAL_REMOVE_EVENT = 'element.compositional_remove';\n\nexport interface CompositionalAppendEvent {\n /** Parent tile id from the mount's placement. Receivers filter on this. */\n tile_id: string;\n /** Unique id of the mounted item \u2014 the receiving container should also\n * set this on the item's DOM as `data-syntro-element-id`. */\n instance_id: string;\n /** Wire shape constructed by the backend \u2014 `{kind, config: {\u2026}}`. */\n item: Record<string, unknown>;\n /** Insertion position \u2014 receivers honor this when appending. */\n position: 'append' | 'prepend';\n}\n\nexport interface CompositionalPatchEvent {\n tile_id: string;\n instance_id: string;\n item: Record<string, unknown>;\n}\n\nexport interface CompositionalRemoveEvent {\n tile_id: string;\n instance_id: string;\n}\n\nexport class ItemHandler implements ElementTypeHandler {\n readonly typeName = 'item' as const;\n readonly lifecycle = 'stateful' as const;\n\n validate(instance: MountedElement, _ctx: ElementHandlerContext): ValidateResult {\n if (instance.element_type !== 'item') {\n return {\n accepted: false,\n reason: 'wrong_element_type',\n detail: instance.element_type,\n };\n }\n if (instance.placement.type !== 'parent_tile') {\n return {\n accepted: false,\n reason: 'item_requires_parent_tile_placement',\n detail: `got placement.type=${instance.placement.type}`,\n };\n }\n if (typeof instance.template_id !== 'string' || instance.template_id.length === 0) {\n return { accepted: false, reason: 'missing_template_id' };\n }\n return { accepted: true };\n }\n\n async mount(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n if (!ctx.events) return; // no bus \u2192 no-op, validate already passed\n const placement = instance.placement as ParentTilePlacement;\n ctx.events.publish(COMPOSITIONAL_APPEND_EVENT, {\n tile_id: placement.tile_id,\n instance_id: instance.instance_id,\n item: instance.content,\n position: placement.position,\n } satisfies CompositionalAppendEvent as unknown as Record<string, unknown>);\n }\n\n async patch(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n if (!ctx.events) return;\n const placement = instance.placement as ParentTilePlacement;\n ctx.events.publish(COMPOSITIONAL_PATCH_EVENT, {\n tile_id: placement.tile_id,\n instance_id: instance.instance_id,\n item: instance.content,\n } satisfies CompositionalPatchEvent as unknown as Record<string, unknown>);\n }\n\n async unmount(instance: MountedElement, ctx: ElementHandlerContext): Promise<void> {\n if (!ctx.events) return;\n const placement = instance.placement as ParentTilePlacement;\n ctx.events.publish(COMPOSITIONAL_REMOVE_EVENT, {\n tile_id: placement.tile_id,\n instance_id: instance.instance_id,\n } satisfies CompositionalRemoveEvent as unknown as Record<string, unknown>);\n }\n}\n", "import type { ChatbotWidgetRuntime } from '../types';\nimport { ActionHandler } from './ActionHandler';\nimport { ElementInstanceStore } from './ElementInstanceStore';\nimport { ItemHandler } from './ItemHandler';\nimport { TileHandler, type TileTemplateWidgetResolver } from './TileHandler';\n\n/** Independent template state shared by live mounts and replay in one surface. */\nexport function createTemplateWidgetResolver() {\n const widgets = new Map<string, string>();\n return {\n resolve: (templateId: string): string | undefined => widgets.get(templateId),\n refresh(uiTemplates: Record<string, unknown> | undefined): void {\n widgets.clear();\n // Backend-originated recommendation tiles are valid without an admin alias.\n widgets.set('syntro-product-reco-carousel', 'syntro-product-reco-carousel');\n const tiles = uiTemplates?.tiles;\n if (!Array.isArray(tiles)) return;\n for (const template of tiles) {\n if (\n typeof template?.id === 'string' &&\n template.id &&\n typeof template?.widget === 'string' &&\n template.widget\n ) {\n widgets.set(template.id, template.widget);\n }\n }\n },\n };\n}\n\n/** UI-free store construction; the owning surface controls its lifetime. */\nexport function createElementStore(\n runtime: Pick<ChatbotWidgetRuntime, 'actions' | 'events'>,\n resolveTileWidget: TileTemplateWidgetResolver\n): ElementInstanceStore {\n return new ElementInstanceStore({\n actions: runtime.actions,\n events: {\n publish: runtime.events.publish.bind(runtime.events),\n subscribe: runtime.events.subscribe?.bind(runtime.events),\n },\n handlers: [new TileHandler(resolveTileWidget), new ActionHandler(), new ItemHandler()],\n resolveTileWidget,\n });\n}\n", "import type { SnapshotFrame } from '@syntrologie/runtime-contracts';\nimport type { ChatbotWidgetRuntime } from '../types';\nimport { createElementStore, createTemplateWidgetResolver } from './createElementStore';\nimport type { ElementInstanceStore } from './ElementInstanceStore';\nimport type { MountedElement, MountedElementsResponse, MutationEnvelope } from './types';\n\nexport type ApplyOutcome =\n | { status: 'applied' | 'duplicate'; resultId: string }\n | { status: 'rejected'; reason: 'invalid' | 'wrong_scope' | 'disposed' | 'projection_failed' };\n\nexport interface ElementSessionController {\n configureTemplates(templates: Record<string, unknown> | undefined): void;\n acceptHostFrame(payload: unknown): Promise<ApplyOutcome>;\n applyLegacyEnvelope(envelope: MutationEnvelope): Promise<void>;\n hydrateLegacy(instances: MountedElement[], expiresAt: string | null): Promise<void>;\n dispose(): Promise<void>;\n}\n\nexport interface ElementSessionOptions extends Pick<ChatbotWidgetRuntime, 'actions' | 'events'> {\n templates?: Record<string, unknown>;\n /** The older standalone assistant accepted template IDs as widget IDs. */\n legacyTemplateFallback?: boolean;\n /** The one conversation this owner renders. A frame for any other is refused. */\n hostScope?: { sessionRef: string };\n}\n\n/** Compatibility accessors belong to this owner, never a module-wide store. */\nexport interface OwnedElementSession extends ElementSessionController {\n readonly store: ElementInstanceStore;\n resolveTileWidget(templateId: string): string | undefined;\n whenIdle(): Promise<void>;\n hydrateOnce(load: () => Promise<MountedElementsResponse | null>): void;\n listen(target: EventTarget, name: string, listener: EventListener): () => void;\n}\n\nfunction record(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\nfunction text(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0;\n}\nfunction integer(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;\n}\nfunction expiry(value: unknown): value is string | null {\n return value === null || (typeof value === 'string' && Number.isFinite(Date.parse(value)));\n}\n\n/** Validate boundary inputs against generated contracts before any action runs. */\nfunction instance(value: unknown): value is MountedElement {\n if (\n !record(value) ||\n !text(value.instance_id) ||\n !text(value.template_id) ||\n !record(value.content) ||\n !record(value.placement) ||\n !record(value.mounted_by) ||\n !text(value.mounted_by.agent_id) ||\n !text(value.mounted_by.turn_id) ||\n typeof value.mounted_at !== 'string' ||\n !Number.isFinite(Date.parse(value.mounted_at)) ||\n !integer(value.version) ||\n value.version < 1 ||\n typeof value.state !== 'string' ||\n !['active', 'applied', 'reverted', 'expired'].includes(value.state)\n )\n return false;\n if (value.element_type === 'tile')\n return value.placement.type === 'slot' && text(value.placement.slot);\n if (value.element_type === 'item')\n return (\n value.placement.type === 'parent_tile' &&\n text(value.placement.tile_id) &&\n typeof value.placement.position === 'string' &&\n ['append', 'prepend'].includes(value.placement.position)\n );\n if (value.element_type !== 'action') return false;\n return (\n value.placement.type === 'none' ||\n (value.placement.type === 'selector' &&\n text(value.placement.selector) &&\n typeof value.placement.position === 'string' &&\n ['beforebegin', 'afterbegin', 'beforeend', 'afterend', 'replace', 'modify'].includes(\n value.placement.position\n ))\n );\n}\n\nfunction frame(value: unknown): value is SnapshotFrame & { mounted_elements: MountedElement[] } {\n if (\n !record(value) ||\n value.schema_version !== 'v1' ||\n value.kind !== 'snapshot' ||\n !text(value.session_ref) ||\n !text(value.result_id) ||\n !expiry(value.session_expires_at) ||\n !Array.isArray(value.mounted_elements) ||\n !value.mounted_elements.every(instance)\n )\n return false;\n return (\n new Set(value.mounted_elements.map((item) => item.instance_id)).size ===\n value.mounted_elements.length\n );\n}\n\n/**\n * How many applied turn ids this owner remembers.\n *\n * A host replays the tool results it still holds whenever the card remounts,\n * and it does not promise an order, so an id has to stay refused after newer\n * ones have landed. 32 covers any replay window a host actually has; past\n * that the oldest is forgotten, and a turn that far back is one no host is\n * still holding.\n */\nconst APPLIED_HISTORY = 32;\n\n/** The UI-independent owner for ordered projection, replay and teardown. */\nexport function createElementSessionController(\n options: ElementSessionOptions\n): OwnedElementSession {\n const templates = createTemplateWidgetResolver();\n templates.refresh(options.templates);\n const resolveTileWidget = (id: string): string | undefined =>\n templates.resolve(id) ??\n (options.legacyTemplateFallback && !options.hostScope ? id : undefined);\n const store = createElementStore(options, resolveTileWidget);\n const cleanups = new Set<() => void>();\n const scope = options.hostScope;\n let generation = 0;\n let disposed = false;\n let hydrated = false;\n let pending: Promise<void> = Promise.resolve();\n let lastAppliedResultId: string | undefined;\n /** Every result id this owner has applied, newest last, capped. */\n const appliedResultIds = new Set<string>();\n\n function enqueue<T>(operation: () => Promise<T>): Promise<T> {\n const next = pending.then(operation);\n pending = next.then(\n () => {},\n () => {}\n );\n return next;\n }\n const rejected = (\n reason: Extract<ApplyOutcome, { status: 'rejected' }>['reason']\n ): ApplyOutcome => ({ status: 'rejected', reason });\n\n return {\n store,\n resolveTileWidget,\n whenIdle: () => pending,\n configureTemplates(next) {\n if (!disposed) templates.refresh(next);\n },\n acceptHostFrame(payload) {\n return enqueue(async () => {\n if (disposed) return rejected('disposed');\n if (!frame(payload)) return rejected('invalid');\n if (!scope || payload.session_ref !== scope.sessionRef) return rejected('wrong_scope');\n // The whole of the dedup. A frame is a complete snapshot, so a turn\n // this owner has already applied has nothing left to say: not the one\n // on screen arriving a second time down the other delivery channel,\n // and not an older one the host re-pushes after a newer turn landed,\n // which would otherwise roll the card back or empty it.\n if (payload.result_id === lastAppliedResultId || appliedResultIds.has(payload.result_id))\n return { status: 'duplicate', resultId: payload.result_id };\n const report = await store.reconcileSnapshot(payload.mounted_elements);\n if (disposed) return rejected('disposed');\n // Nothing to recover from and nothing to ask for: the next snapshot\n // the host delivers is already the whole truth.\n if (!report.ok) return rejected('projection_failed');\n lastAppliedResultId = payload.result_id;\n appliedResultIds.add(payload.result_id);\n if (appliedResultIds.size > APPLIED_HISTORY) {\n appliedResultIds.delete(appliedResultIds.values().next().value as string);\n }\n store.scheduleClientTtl(payload.session_expires_at);\n return { status: 'applied', resultId: payload.result_id };\n });\n },\n applyLegacyEnvelope(envelope) {\n return enqueue(async () => {\n if (!disposed) await store.apply(envelope.mutations);\n });\n },\n hydrateLegacy(instances, expiresAt) {\n return enqueue(async () => {\n if (disposed) return;\n await store.hydrate(instances);\n if (!disposed) store.scheduleClientTtl(expiresAt);\n });\n },\n hydrateOnce(load) {\n if (hydrated || disposed) return;\n hydrated = true;\n const started = generation;\n void load()\n .then((response) => {\n if (disposed || started !== generation || !response) return;\n return enqueue(async () => {\n if (disposed || started !== generation) return;\n await store.hydrate(response.mounted_elements);\n if (!disposed) store.scheduleClientTtl(response.session_expires_at);\n });\n })\n .catch(() => {});\n },\n listen(target, name, listener) {\n if (disposed) return () => {};\n target.addEventListener(name, listener);\n const remove = () => {\n target.removeEventListener(name, listener);\n cleanups.delete(remove);\n };\n cleanups.add(remove);\n return remove;\n },\n dispose() {\n if (!disposed) {\n disposed = true;\n generation++;\n for (const cleanup of cleanups) cleanup();\n store.dispose(true);\n templates.refresh(undefined);\n }\n return pending;\n },\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["instance", "instance", "report", "instance", "instance", "COMPOSITIONAL_APPEND_EVENT", "instance"]
7
+ }
@@ -4,7 +4,11 @@ import {
4
4
  import {
5
5
  createDictation,
6
6
  isDictationSupported
7
- } from "./chunk-TZA7572J.js";
7
+ } from "./chunk-GN7Z5IVP.js";
8
+ import {
9
+ __privateAdd,
10
+ __privateGet
11
+ } from "./chunk-LY5AGXVD.js";
8
12
 
9
13
  // src/AdaptiveChatBar.ts
10
14
  import { html, LitElement, nothing, svg } from "lit";
@@ -32,9 +36,11 @@ function pickPersona(roster) {
32
36
  // src/AdaptiveChatBar.ts
33
37
  var DEFAULT_PLACEHOLDER = "Ask, find, or navigate\u2026";
34
38
  var DEFAULT_ASSISTANT_NAME = "Assistant";
39
+ var _AdaptiveChatBar_instances, trailVisible_get;
35
40
  var AdaptiveChatBar = class extends LitElement {
36
41
  constructor() {
37
42
  super(...arguments);
43
+ __privateAdd(this, _AdaptiveChatBar_instances);
38
44
  this.messages = [];
39
45
  /**
40
46
  * Mirrored from the chat session by the mountable. The bar keeps no
@@ -43,6 +49,16 @@ var AdaptiveChatBar = class extends LitElement {
43
49
  */
44
50
  this.turn = 0;
45
51
  this.maximized = false;
52
+ /**
53
+ * Which trailing control the bar renders.
54
+ *
55
+ * An explicit literal, never inferred from the presence of a prop: a canvas
56
+ * that forgot to inject it would otherwise silently get the wrong control.
57
+ * Default keeps velvet's behaviour untouched.
58
+ */
59
+ this.chatControl = "maximize";
60
+ /** Reflected state for the interleave control. Owned by the canvas. */
61
+ this.interleaved = false;
46
62
  this.tileReceipts = [];
47
63
  /** Widgets rendered inline in the trail (reco carousel), sourced from
48
64
  * the store's `chat-inline` slot mounts. Forwarded to the trail. */
@@ -183,6 +199,11 @@ var AdaptiveChatBar = class extends LitElement {
183
199
  this._onMaximizeToggle = () => {
184
200
  this.dispatchEvent(new CustomEvent("chat-maximize-toggle", { bubbles: true, composed: true }));
185
201
  };
202
+ this._onInterleaveToggle = () => {
203
+ this.dispatchEvent(
204
+ new CustomEvent("chat-interleave-toggle", { bubbles: true, composed: true })
205
+ );
206
+ };
186
207
  /**
187
208
  * Visitor tapped the intro suggestion button in the empty-state
188
209
  * trail. Submit the configured prompt through the same channel as
@@ -280,8 +301,8 @@ var AdaptiveChatBar = class extends LitElement {
280
301
  render() {
281
302
  return html`
282
303
  <div style=${styleMap(rootStyles(this.forceExpanded))}>
283
- ${this.forceExpanded ? renderHeader(this.assistantName, this._persona) : nothing}
284
- <adaptive-chat-trail
304
+ ${this.forceExpanded && __privateGet(this, _AdaptiveChatBar_instances, trailVisible_get) ? renderHeader(this.assistantName, this._persona) : nothing}
305
+ ${__privateGet(this, _AdaptiveChatBar_instances, trailVisible_get) ? html`<adaptive-chat-trail
285
306
  .messages=${this.messages}
286
307
  .greeting=${this._persona?.intro_line ?? this.greeting}
287
308
  .forceExpanded=${this.forceExpanded}
@@ -295,14 +316,22 @@ var AdaptiveChatBar = class extends LitElement {
295
316
  .mountInlineWidget=${this.mountInlineWidget}
296
317
  @trail-intro-suggestion=${this._onIntroSuggestion}
297
318
  @trail-suggested-reply=${this._onSuggestedReply}
298
- ></adaptive-chat-trail>
319
+ ></adaptive-chat-trail>` : nothing}
299
320
  <div
300
321
  style=${styleMap(rowStyles(this.forceExpanded, this._composerFocused))}
301
322
  data-chat-row
302
323
  @focusin=${this._onComposerFocusIn}
303
324
  @focusout=${this._onComposerFocusOut}
304
325
  >
305
- <button
326
+ ${this.chatControl === "interleave" ? html`<button
327
+ type="button"
328
+ data-chat-interleave
329
+ @click=${this._onInterleaveToggle}
330
+ aria-label=${this.interleaved ? "Hide the conversation" : "Show the conversation"}
331
+ title=${this.interleaved ? "Hide the conversation" : "Show the conversation"}
332
+ aria-pressed=${this.interleaved ? "true" : "false"}
333
+ style=${styleMap(maximizeStyles(this.interleaved))}
334
+ >${this.interleaved ? TRANSCRIPT_ON_ICON : TRANSCRIPT_OFF_ICON}</button>` : html`<button
306
335
  type="button"
307
336
  data-chat-maximize
308
337
  @click=${this._onMaximizeToggle}
@@ -310,7 +339,7 @@ var AdaptiveChatBar = class extends LitElement {
310
339
  title=${this.maximized ? "Exit full screen" : "Maximize"}
311
340
  aria-pressed=${this.maximized ? "true" : "false"}
312
341
  style=${styleMap(maximizeStyles(this.maximized))}
313
- >${this.maximized ? MINIMIZE_ICON : MAXIMIZE_ICON}</button>
342
+ >${this.maximized ? MINIMIZE_ICON : MAXIMIZE_ICON}</button>`}
314
343
  <input
315
344
  data-chat-input
316
345
  type="text"
@@ -346,6 +375,10 @@ var AdaptiveChatBar = class extends LitElement {
346
375
  `;
347
376
  }
348
377
  };
378
+ _AdaptiveChatBar_instances = new WeakSet();
379
+ trailVisible_get = function() {
380
+ return this.chatControl !== "interleave" || this.interleaved;
381
+ };
349
382
  AdaptiveChatBar.properties = {
350
383
  personas: { attribute: false },
351
384
  _persona: { state: true },
@@ -359,6 +392,8 @@ AdaptiveChatBar.properties = {
359
392
  introSuggestion: { attribute: false },
360
393
  forceExpanded: { type: Boolean, reflect: true },
361
394
  maximized: { type: Boolean },
395
+ chatControl: { type: String },
396
+ interleaved: { type: Boolean },
362
397
  tileReceipts: { attribute: false },
363
398
  inlineWidgets: { attribute: false },
364
399
  mountInlineWidget: { attribute: false },
@@ -498,6 +533,8 @@ var MIC_RING_STYLES = html`<style>
498
533
  }
499
534
  </style>`;
500
535
  var MAXIMIZE_ICON = svg`<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" y1="3" x2="14" y2="10"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>`;
536
+ var TRANSCRIPT_OFF_ICON = svg`<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>`;
537
+ var TRANSCRIPT_ON_ICON = svg`<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z"></path></svg>`;
501
538
  var MINIMIZE_ICON = svg`<svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2.25" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="4 14 10 14 10 20"></polyline><polyline points="20 10 14 10 14 4"></polyline><line x1="14" y1="10" x2="21" y2="3"></line><line x1="3" y1="21" x2="10" y2="14"></line></svg>`;
502
539
  function maximizeStyles(maximized) {
503
540
  return {
@@ -647,4 +684,4 @@ export {
647
684
  pickPersona,
648
685
  AdaptiveChatBar
649
686
  };
650
- //# sourceMappingURL=chunk-VFWA5W56.js.map
687
+ //# sourceMappingURL=chunk-XPUHW2YO.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/AdaptiveChatBar.ts", "../src/personas.ts"],
4
+ "sourcesContent": ["/**\n * AdaptiveChatBar \u2014 the canvas lid composition for the chat-canvas\n * experience. Renders the bubble-up trail on top and an always-visible\n * input row below.\n *\n * Wiring contract (events out):\n * - `chat-message-sent` ({ text, via, turn }): the user submitted text\n * via Enter, the send button, an intro suggestion, or a reply pill.\n * The owning code is responsible for pushing this into the\n * conversation history and producing a reply.\n *\n * Wiring contract (props in):\n * - `messages`: the conversation trail, passed straight through to\n * `<adaptive-chat-trail>`.\n * - `placeholder`: input placeholder copy. Defaults to a generic\n * \"Ask, find, or navigate\u2026\" \u2014 the host (typically the slot's lid\n * widget mount) can override to a context-specific string.\n *\n * Light DOM. Glassmorphism is applied at the input-row level so the\n * trail above floats over the host page without chrome. See PRD \u00A74.4.\n */\n\nimport { createDictation, type DictationController, isDictationSupported } from '@syntrologie/chat';\nimport type { ChatSendVia } from '@syntrologie/sdk-contracts';\nimport { html, LitElement, nothing, svg } from 'lit';\nimport { styleMap } from 'lit/directives/style-map.js';\nimport { type ChatPersona, pickPersona } from './personas.js';\n\nimport './AdaptiveChatTrail.js';\nimport type {\n InlineTrailWidget,\n InlineWidgetMounter,\n TileReceipt,\n TrailMessage,\n} from './AdaptiveChatTrail.js';\nimport { getElementInstanceStore } from './elements/store-singleton.js';\n\nconst DEFAULT_PLACEHOLDER = 'Ask, find, or navigate\u2026';\nconst DEFAULT_ASSISTANT_NAME = 'Assistant';\n\nexport class AdaptiveChatBar extends LitElement {\n static override properties = {\n personas: { attribute: false },\n _persona: { state: true },\n messages: { attribute: false },\n placeholder: { type: String },\n assistantName: { type: String },\n greeting: { type: String },\n inFlight: { type: Boolean, reflect: true },\n turn: { type: Number },\n thinkingText: { attribute: false },\n introSuggestion: { attribute: false },\n forceExpanded: { type: Boolean, reflect: true },\n maximized: { type: Boolean },\n chatControl: { type: String },\n interleaved: { type: Boolean },\n tileReceipts: { attribute: false },\n inlineWidgets: { attribute: false },\n mountInlineWidget: { attribute: false },\n voiceInput: { type: Boolean },\n _input: { state: true },\n _composerFocused: { state: true },\n _micListening: { state: true },\n _micDisabled: { state: true },\n };\n\n messages: TrailMessage[] = [];\n /**\n * Mirrored from the chat session by the mountable. The bar keeps no\n * counter of its own \u2014 this is the number of sends already committed;\n * a send this bar makes opens turn `this.turn + 1`.\n */\n turn = 0;\n maximized = false;\n\n /**\n * Which trailing control the bar renders.\n *\n * An explicit literal, never inferred from the presence of a prop: a canvas\n * that forgot to inject it would otherwise silently get the wrong control.\n * Default keeps velvet's behaviour untouched.\n */\n chatControl: 'maximize' | 'interleave' = 'maximize';\n\n /** Reflected state for the interleave control. Owned by the canvas. */\n interleaved = false;\n tileReceipts: TileReceipt[] = [];\n /** Widgets rendered inline in the trail (reco carousel), sourced from\n * the store's `chat-inline` slot mounts. Forwarded to the trail. */\n inlineWidgets: InlineTrailWidget[] = [];\n /** Registry-backed mounter for inline widgets whose id is not their\n * custom-element tag (product card, comparison, FAQ). Set by the\n * mountable from `runtime.widgets`; forwarded to the trail. */\n mountInlineWidget: InlineWidgetMounter | undefined = undefined;\n\n /**\n * Live reasoning narration from the model \u2014 streamed in via\n * AG-UI THINKING_TEXT_MESSAGE_CONTENT events and forwarded by\n * the ChatSession subscription on the host (mountable).\n * Forwarded verbatim to the trail, which renders it in place of\n * the silent loading dots between turns. Empty string when no\n * thinking turn is active.\n */\n thinkingText = '';\n /**\n * Pre-conversation suggestion button \u2014 forwarded to the trail's\n * empty-state pane. When the visitor clicks it the trail emits\n * `trail-intro-suggestion`; we catch that here and submit the\n * configured prompt through the normal send path.\n */\n introSuggestion: { label: string; prompt: string } | undefined = undefined;\n\n /** Pass-through to {@link AdaptiveChatTrail}'s ``forceExpanded`` prop.\n * Hosts that mount the chat-bar in a full-screen surface (mobile\n * panel, agent app, etc.) set this to skip the collapse affordance\n * \u2014 there is no smaller state to fall back to. */\n forceExpanded = false;\n placeholder = DEFAULT_PLACEHOLDER;\n /**\n * Name shown in the (forceExpanded) header. Defaults to a generic\n * \"Assistant\". Hosts can override per-workspace (e.g. Vela sets\n * \"Vela Concierge\") without inventing new SDK surface \u2014 it threads\n * through the same mount config the placeholder does.\n */\n assistantName = DEFAULT_ASSISTANT_NAME;\n /** Persona roster from config (FEAT-1784917430); one is sticky-assigned. */\n personas: ChatPersona[] | null = null;\n /** @internal \u2014 the visitor's sticky persona, resolved from the roster. */\n _persona: ChatPersona | null = null;\n\n /**\n * Initial assistant message shown before any real conversation\n * starts. Renders inside the trail as a phantom assistant chip\n * when messages.length === 0; auto-disappears as soon as the\n * first user message lands. Mirrors ChatAssistantLit's greeting.\n */\n greeting: string | undefined = undefined;\n /**\n * Whether a chat round-trip is in flight (request sent, awaiting\n * reply). The single send/stop button morphs accordingly: \u2191 when\n * ready, \u23F9 when in-flight. Parent owns this state \u2014 set true after\n * `chat-message-sent` fires, false when the reply lands or the\n * request is aborted. Enter is inert while in-flight.\n */\n inFlight = false;\n /** Show a dictation mic when the Web Speech API is available. Config-gated, default off. */\n voiceInput = false;\n _input = '';\n _micListening = false;\n _micDisabled = false;\n private _micBase = '';\n private _micNetworkErrors = 0;\n private _dictation: DictationController | null = null;\n /** True while focus is inside the composer row \u2014 drives the accent\n * focus ring so the active text-entry surface is unmistakable on any\n * theme (the idle pill is deliberately subtle). */\n _composerFocused = false;\n\n override createRenderRoot(): HTMLElement {\n return this;\n }\n\n override connectedCallback(): void {\n super.connectedCallback();\n // Listen on the host element so that `tile-receipt-activate` events\n // dispatched directly on this element (as well as bubbling up from the\n // trail child) are handled in one place.\n this.addEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.addEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n override disconnectedCallback(): void {\n super.disconnectedCallback();\n this.removeEventListener('tile-receipt-activate', this._onTileReceiptActivate);\n this.removeEventListener('alert-receipt-activate', this._onAlertReceiptActivate);\n }\n\n // Host-level styling (display, width, height, flex, etc.) is owned\n // by the container \u2014 SDK shadow root provides default rules, panel\n // overrides via design tokens (--sc-chat-bar-host-*). This adaptive\n // never sets inline styles on itself. See SmartCanvasElementLit's\n // static styles for the rule.\n\n private _onInput = (e: Event): void => {\n // Typing wins: the user taking over the input ends dictation so a\n // late transcript can't clobber their edit.\n if (this._micListening) this._dictation?.stop();\n this._input = (e.target as HTMLInputElement).value;\n };\n\n private _onMicClick = (): void => {\n if (this._micListening) {\n this._dictation?.stop();\n return;\n }\n this._micBase = this._input;\n this._dictation = createDictation({\n onTranscript: (text) => {\n this._micNetworkErrors = 0;\n this._input = this._micBase + (this._micBase ? ' ' : '') + text;\n },\n onEnd: () => {\n this._micListening = false;\n },\n onError: (code) => {\n this._micListening = false;\n if (code === 'not-allowed') this._micDisabled = true;\n if (code === 'network' && ++this._micNetworkErrors >= 2) this._micDisabled = true;\n },\n });\n this._dictation.start();\n // Mirror the controller: if start() bailed (support vanished, engine\n // threw), don't paint a listening state that can never end.\n this._micListening = this._dictation.listening;\n };\n\n private _onKeyDown = (e: KeyboardEvent): void => {\n if (e.key === 'Enter' && !e.shiftKey) {\n e.preventDefault();\n // Enter is the send affordance \u2014 while in-flight there's nothing\n // to send, so it's a no-op. Interrupt requires the explicit\n // \u23F9 click to avoid surprise-aborting on a stray keystroke.\n if (this.inFlight) return;\n this._send();\n }\n };\n\n // Single button. Click delegates to send-or-interrupt based on\n // current state. Same DOM node, different behavior \u2014 discoverability\n // wins from the user not having to scan for which control is active.\n private _onSendOrInterrupt = (): void => {\n if (this.inFlight) {\n // Stop means stop: discard any chip tap queued during this run \u2014\n // otherwise the interrupt flips inFlight false and the queue flush\n // would fire a NEW turn the instant the user pressed stop.\n this._queuedSuggestedReply = null;\n this.dispatchEvent(new CustomEvent('chat-interrupt', { bubbles: true, composed: true }));\n return;\n }\n this._send();\n };\n\n private _onTileReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n getElementInstanceStore()?.recreate(instanceId);\n this.dispatchEvent(\n new CustomEvent('tile-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onAlertReceiptActivate = (e: Event): void => {\n const { instanceId } = (e as CustomEvent<{ instanceId: string }>).detail;\n this.dispatchEvent(\n new CustomEvent('alert-recall', { detail: { instanceId }, bubbles: true, composed: true })\n );\n };\n\n private _onComposerFocusIn = (): void => {\n this._composerFocused = true;\n };\n\n private _onComposerFocusOut = (): void => {\n this._composerFocused = false;\n };\n\n private _onMaximizeToggle = (): void => {\n this.dispatchEvent(new CustomEvent('chat-maximize-toggle', { bubbles: true, composed: true }));\n };\n\n /**\n * Should the conversation render at all?\n *\n * Only a canvas that opted into the interleave control can hide it, and only\n * by setting `interleaved: false`. Every other surface \u2014 velvet, the drawer,\n * inline \u2014 is untouched: `chatControl` defaults to 'maximize', so this is\n * always true for them.\n */\n get #trailVisible(): boolean {\n return this.chatControl !== 'interleave' || this.interleaved;\n }\n\n private _onInterleaveToggle = (): void => {\n this.dispatchEvent(\n new CustomEvent('chat-interleave-toggle', { bubbles: true, composed: true })\n );\n };\n\n /** The one channel every send path uses; `turn` is the turn this send opens. */\n private _dispatchSent(text: string, via: ChatSendVia): void {\n this.dispatchEvent(\n new CustomEvent<{ text: string; via: ChatSendVia; turn: number }>('chat-message-sent', {\n detail: { text, via, turn: this.turn + 1 },\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private _send(): void {\n // Sending supersedes dictation \u2014 stop first so a late final transcript\n // can't resurrect the just-sent text into the emptied input.\n if (this._micListening) this._dictation?.stop();\n const text = this._input.trim();\n if (!text) return;\n // A typed message is the user's NEWEST intent \u2014 it supersedes any chip\n // tap still queued from the run tail (defense: Enter is currently inert\n // while inFlight, but this guard must not depend on that staying true).\n this._queuedSuggestedReply = null;\n this._dispatchSent(text, 'typed');\n this._input = '';\n // Drop the input value too \u2014 the input's bound value is `this._input`\n // via the render, but jsdom's two-way binding via property only takes\n // effect after the next render, so set it imperatively for the test\n // and for browser symmetry (most browsers do the right thing here\n // anyway because Lit re-renders on the state change).\n const input = this.querySelector<HTMLInputElement>('input[data-chat-input]');\n if (input) input.value = '';\n }\n\n /**\n * Visitor tapped the intro suggestion button in the empty-state\n * trail. Submit the configured prompt through the same channel as\n * a typed message so listeners (mountable \u2192 chatSession.send) see\n * a uniform shape \u2014 no need for a parallel \"suggestion-sent\" path.\n * The trail's intro pane auto-disappears the moment the first\n * message lands, so this also closes the empty state in one go.\n */\n private _onIntroSuggestion = (e: Event): void => {\n const detail = (e as CustomEvent<{ prompt: string }>).detail;\n if (!detail?.prompt) return;\n e.stopPropagation();\n if (this.inFlight) return;\n // Latch in-flight optimistically. `inFlight` is owned by the parent\n // mountable and only pushed back down after it handles\n // `chat-message-sent` + a Lit render cycle. Two taps in the same frame\n // both see inFlight===false otherwise, double-dispatching one intended\n // reply (C3). Set it true synchronously here; the parent confirms/owns\n // it from the next render and clears it when the reply lands.\n this.inFlight = true;\n this._dispatchSent(detail.prompt, 'intro_suggestion');\n };\n\n /**\n * Reply-chip tap that arrived during the run TAIL. Chips render the\n * moment the reply text lands, but `inFlight` (which includes\n * `runActive` \u2014 typing events, tool tail, RUN_FINISHED) can lag for\n * seconds. The old `if (this.inFlight) return;` guard silently ATE\n * those taps \u2014 the visitor's chosen reply never appeared as their\n * message (live repro, deployed vela 2026-07-08). Now the tap queues\n * (latest wins) and dispatches when `inFlight` clears.\n */\n private _queuedSuggestedReply: string | null = null;\n\n protected override willUpdate(changed: Map<string, unknown>): void {\n super.willUpdate?.(changed);\n if (changed.has('personas')) {\n this._persona = pickPersona(this.personas);\n }\n if (\n changed.has('inFlight') &&\n changed.get('inFlight') === true &&\n !this.inFlight &&\n this._queuedSuggestedReply\n ) {\n const text = this._queuedSuggestedReply;\n this._queuedSuggestedReply = null;\n // Same latch + channel as a direct tap.\n this.inFlight = true;\n this._dispatchSent(text, 'pill');\n }\n }\n\n /**\n * Visitor tapped an inline `suggest_replies` chip in the trail. Submit\n * the chip text through the SAME `chat-message-sent` channel a typed\n * message uses, so the reply rides the existing send path (mountable \u2192\n * chatSession.send \u2192 transport) \u2014 no fabricated AG-UI events. The\n * trail clears the chips on its own once the reply lands and a newer\n * assistant turn becomes the latest.\n *\n * A tap while the previous run is still closing is QUEUED, never\n * dropped \u2014 see `_queuedSuggestedReply`.\n */\n private _onSuggestedReply = (e: Event): void => {\n const detail = (e as CustomEvent<{ text: string }>).detail;\n if (!detail?.text) return;\n e.stopPropagation();\n if (this.inFlight) {\n this._queuedSuggestedReply = detail.text;\n return;\n }\n // Latch in-flight optimistically \u2014 same race as `_onIntroSuggestion`\n // (C3). The parent owns `inFlight` and only re-asserts it after a render\n // cycle, so a same-frame double tap would otherwise fire two\n // `chat-message-sent` events for one chip.\n this.inFlight = true;\n this._dispatchSent(detail.text, 'pill');\n };\n\n override render() {\n return html`\n <div style=${styleMap(rootStyles(this.forceExpanded))}>\n ${this.forceExpanded && this.#trailVisible ? renderHeader(this.assistantName, this._persona) : nothing}\n ${\n this.#trailVisible\n ? html`<adaptive-chat-trail\n .messages=${this.messages}\n .greeting=${this._persona?.intro_line ?? this.greeting}\n .forceExpanded=${this.forceExpanded}\n .inFlight=${this.inFlight}\n .thinkingText=${this.thinkingText}\n .personaName=${this._persona?.name ?? ''}\n .personaAvatarSm=${this._persona?.avatar?.sm ?? ''}\n .introSuggestion=${this.introSuggestion}\n .tileReceipts=${this.tileReceipts}\n .inlineWidgets=${this.inlineWidgets}\n .mountInlineWidget=${this.mountInlineWidget}\n @trail-intro-suggestion=${this._onIntroSuggestion}\n @trail-suggested-reply=${this._onSuggestedReply}\n ></adaptive-chat-trail>`\n : nothing\n }\n <div\n style=${styleMap(rowStyles(this.forceExpanded, this._composerFocused))}\n data-chat-row\n @focusin=${this._onComposerFocusIn}\n @focusout=${this._onComposerFocusOut}\n >\n ${\n this.chatControl === 'interleave'\n ? html`<button\n type=\"button\"\n data-chat-interleave\n @click=${this._onInterleaveToggle}\n aria-label=${this.interleaved ? 'Hide the conversation' : 'Show the conversation'}\n title=${this.interleaved ? 'Hide the conversation' : 'Show the conversation'}\n aria-pressed=${this.interleaved ? 'true' : 'false'}\n style=${styleMap(maximizeStyles(this.interleaved))}\n >${this.interleaved ? TRANSCRIPT_ON_ICON : TRANSCRIPT_OFF_ICON}</button>`\n : html`<button\n type=\"button\"\n data-chat-maximize\n @click=${this._onMaximizeToggle}\n aria-label=${this.maximized ? 'Exit full screen' : 'Maximize chat'}\n title=${this.maximized ? 'Exit full screen' : 'Maximize'}\n aria-pressed=${this.maximized ? 'true' : 'false'}\n style=${styleMap(maximizeStyles(this.maximized))}\n >${this.maximized ? MINIMIZE_ICON : MAXIMIZE_ICON}</button>`\n }\n <input\n data-chat-input\n type=\"text\"\n placeholder=${this._micListening ? 'Listening \u2014 tap the mic to stop' : this.placeholder}\n .value=${this._input}\n @input=${this._onInput}\n @keydown=${this._onKeyDown}\n style=${styleMap(inputStyles())}\n aria-label=\"Chat input\"\n />\n ${\n this.voiceInput && isDictationSupported()\n ? html`${MIC_RING_STYLES}<button\n type=\"button\"\n data-chat-mic\n data-listening=${this._micListening ? 'true' : 'false'}\n ?disabled=${this._micDisabled}\n @click=${this._onMicClick}\n aria-pressed=${this._micListening ? 'true' : 'false'}\n aria-label=${this._micListening ? 'Stop dictation' : 'Start dictation'}\n title=${this._micDisabled ? 'Microphone blocked' : this._micListening ? 'Stop dictation' : 'Dictate'}\n style=${styleMap(micStyles(this._micListening, this._micDisabled))}\n >${MIC_ICON}</button>`\n : nothing\n }\n <button\n type=\"button\"\n data-chat-send\n data-state=${this.inFlight ? 'in-flight' : 'ready'}\n @click=${this._onSendOrInterrupt}\n aria-label=${this.inFlight ? 'Stop' : 'Send message'}\n title=${this.inFlight ? 'Interrupt' : 'Send'}\n style=${styleMap(sendStyles(this.inFlight))}\n >${this.inFlight ? '\u25A0' : '\u2191'}</button>\n </div>\n </div>\n `;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Styles \u2014 kept inline (Lit styleMap) so they participate in light-DOM\n// rendering and pick up host CSS variables (e.g. --sc-tile-background).\n// ---------------------------------------------------------------------------\n\nfunction rootStyles(forceExpanded: boolean): Record<string, string> {\n // When the host expects the chat to fill its container (full-screen\n // panel, agent app), we grow vertically AND wrap the whole widget in\n // its own chrome card \u2014 trail + input read as one cohesive surface\n // instead of a naked trail above a chrome'd input. Floating mounts\n // (bottom-right pinned, etc.) stay chrome-less here because their\n // chrome is owned by the host's positioned wrapper.\n if (!forceExpanded) {\n return {\n display: 'flex',\n flexDirection: 'column',\n gap: '6px',\n width: '100%',\n pointerEvents: 'auto',\n };\n }\n // Input is ABSOLUTELY positioned at the bottom of this chrome card\n // (see rowStyles forceExpanded mode). That guarantees the input is\n // always visible \u2014 even when the lid region is tighter than the\n // chat-bar would naturally want. The flex column above holds\n // header + trail; padding-bottom reserves the input's footprint so\n // trail content can never overlap.\n //\n // Priority of \"what disappears when space is tight\":\n // Trail (shrinks to 0 first via flex: 1 1 0)\n // Header (can shrink via default flex: 0 1 auto)\n // Input (NEVER \u2014 it's positioned absolute, always at the bottom)\n return {\n position: 'relative',\n display: 'flex',\n flexDirection: 'column',\n gap: '8px',\n width: '100%',\n height: '100%',\n boxSizing: 'border-box',\n flex: '1 1 auto',\n minHeight: '0',\n overflow: 'hidden',\n pointerEvents: 'auto',\n background: 'var(--sc-tile-background, rgba(255, 255, 255, 0.92))',\n border: 'var(--sc-tile-border, 1px solid rgba(0, 0, 0, 0.06))',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n boxShadow: 'var(--sc-tile-shadow, 0 12px 32px -16px rgba(0, 0, 0, 0.18))',\n // Reserves room for the absolute-positioned input pill (36px high\n // + 12px from bottom) plus a 16px visual gap above the input.\n padding: '0.75rem 0.75rem calc(36px + 1.75rem)',\n color: 'var(--sc-tile-title-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n // Override the trail's host-layout tokens so the trail (a flex item\n // of this column) fills a definite-height parent AND contributes its\n // content height in an indefinite one. basis AUTO (not 0) is\n // load-bearing: grow:1 still fills a full-screen panel, but basis auto\n // also lets the trail's content height propagate up the fill chain so a\n // SHRINK-WRAP host (velvet's bottom sheet) hugs the content with no void.\n // A basis-0 layer anywhere in the chain reports 0 min-content and\n // collapses the sheet to header+input. shrink:1 + min-height:0 still lets\n // the trail yield first when space is tight (input is absolute-pinned).\n // The SDK-level rule in SmartCanvasElementLit consumes these tokens on\n // adaptive-chat-trail's host element. Containers OWN host styling\n // via tokens; the adaptive never sets inline styles on its host.\n ['--sc-chat-trail-host-display']: 'flex',\n ['--sc-chat-trail-host-flex-direction']: 'column',\n ['--sc-chat-trail-host-flex']: '1 1 auto',\n ['--sc-chat-trail-host-min-height']: '0',\n ['--sc-chat-trail-host-overflow']: 'hidden',\n };\n}\n\n// Focus ring shared by both composer variants: while focus is inside the\n// row, the border switches to the accent so the active text-entry surface\n// is unmistakable regardless of theme.\nconst COMPOSER_FOCUS_BORDER = '1px solid hsl(var(--sc-accent-color) / 0.6)';\n\nfunction rowStyles(forceExpanded: boolean, focused: boolean): Record<string, string> {\n // forceExpanded \u2014 root container already carries the chrome; row\n // becomes a flat input-pill inside that chrome (subtle border + soft\n // background, no shadow/blur).\n if (forceExpanded) {\n // Absolute-pinned to the chrome card's bottom edge so it never\n // disappears under any container size. The chrome reserves\n // padding-bottom equal to this row's footprint so flex content\n // above (header + trail) can't overlap.\n //\n // The pill's tint derives from currentColor (the theme's text color),\n // NOT a hardcoded black alpha: rgba(0,0,0,.04) over a near-black card\n // is invisible \u2014 on dark themes visitors couldn't find the text entry\n // at all. color-mix keeps one declaration correct on every theme, and\n // the --sc-chat-composer-* tokens let a workspace override the tint.\n return {\n position: 'absolute',\n left: '0.75rem',\n right: '0.75rem',\n bottom: '0.75rem',\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '6px 14px',\n borderRadius: '9999px',\n background:\n 'var(--sc-chat-composer-background, color-mix(in srgb, currentColor 8%, transparent))',\n border: focused\n ? COMPOSER_FOCUS_BORDER\n : '1px solid var(--sc-chat-composer-border, color-mix(in srgb, currentColor 22%, transparent))',\n color: 'var(--sc-content-text-color, inherit)',\n fontFamily: 'var(--sc-font-family, inherit)',\n minHeight: '36px',\n };\n }\n // Floating mount \u2014 keeps the original tile-chrome look.\n return {\n display: 'flex',\n alignItems: 'center',\n gap: '8px',\n padding: '10px 12px',\n borderRadius: 'var(--sc-tile-border-radius, 14px)',\n background: 'var(--sc-tile-background, rgba(15, 19, 24, 0.6))',\n backdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n WebkitBackdropFilter: 'var(--sc-chat-bar-blur, blur(24px) saturate(140%))',\n border: focused\n ? COMPOSER_FOCUS_BORDER\n : 'var(--sc-tile-border, 1px solid rgba(255, 255, 255, 0.08))',\n boxShadow: 'var(--sc-tile-shadow, 0 2px 12px rgba(0, 0, 0, 0.3))',\n color: 'var(--sc-tile-title-color, #fafafa)',\n fontFamily: 'var(--sc-font-family, inherit)',\n };\n}\n\n// Maximize / restore toggle in the chat bar. Two hard-won legibility rules\n// live here:\n// 1. The glyph is an inline SVG, never a Unicode arrow (`\u2922`/`\u2921`): glyph\n// metrics vary per platform font, so the character rendered small and\n// visibly off-center inside the circular chip.\n// 2. The chip mirrors the send button's filled-accent language but at\n// 32px, so the expand/collapse control reads as a control \u2014 the ACTIVE\n// (maximized) state is a filled chip, idle is a ringed chip.\n// Expand: arrows pointing out to opposite corners (Lucide maximize-2).\nconst MIC_ICON = svg`<svg viewBox=\"0 0 16 16\" width=\"16\" height=\"16\" fill=\"none\" aria-hidden=\"true\"><rect x=\"6\" y=\"1.5\" width=\"4\" height=\"8\" rx=\"2\" stroke=\"currentColor\" stroke-width=\"1.6\"></rect><path d=\"M3.5 7.5a4.5 4.5 0 0 0 9 0M8 12v2.5\" stroke=\"currentColor\" stroke-width=\"1.6\" stroke-linecap=\"round\"></path></svg>`;\n\nfunction micStyles(listening: boolean, disabled: boolean): Record<string, string> {\n return {\n display: 'inline-flex',\n 'align-items': 'center',\n 'justify-content': 'center',\n width: '32px',\n height: '32px',\n border: 'none',\n 'border-radius': '50%',\n // Listening is a MODE: the mic flips to a filled primary chip with a\n // ripple ring (MIC_RING_STYLES) so recording is unmissable, and the\n // input placeholder says how to end it.\n background: listening ? 'var(--sc-color-primary, #6a59ce)' : 'transparent',\n color: listening ? 'var(--sc-color-primary-text, #ffffff)' : 'currentColor',\n opacity: disabled ? '0.3' : listening ? '1' : '0.65',\n cursor: disabled ? 'not-allowed' : 'pointer',\n transition: 'color 150ms ease, background 150ms ease, opacity 150ms ease',\n 'flex-shrink': '0',\n };\n}\n\n// Ripple keyframes can't ride styleMap (light DOM, no stylesheet of our\n// own) \u2014 rendered once next to the mic button. Scoped to [data-chat-mic]\n// inside the canvas shadow root, so nothing leaks to the host page.\nconst MIC_RING_STYLES = html`<style>\n [data-chat-mic][data-listening='true'] {\n animation: sc-chatbar-mic-ring 1.5s ease-out infinite;\n }\n @keyframes sc-chatbar-mic-ring {\n 0% {\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sc-color-primary, #6a59ce) 45%, transparent);\n transform: scale(1);\n }\n 50% { transform: scale(1.08); }\n 70% { box-shadow: 0 0 0 12px transparent; }\n 100% {\n box-shadow: 0 0 0 0 transparent;\n transform: scale(1);\n }\n }\n @media (prefers-reduced-motion: reduce) {\n [data-chat-mic][data-listening='true'] {\n animation: none;\n box-shadow: 0 0 0 3px color-mix(in srgb, var(--sc-color-primary, #6a59ce) 35%, transparent);\n }\n }\n</style>`;\n\nconst MAXIMIZE_ICON = svg`<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"15 3 21 3 21 9\"></polyline><polyline points=\"9 21 3 21 3 15\"></polyline><line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\"></line><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"></line></svg>`;\n\n// Interleave OFF: speech bubbles outlined \u2014 \"show the conversation\".\nconst TRANSCRIPT_OFF_ICON = svg`<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\"></path></svg>`;\n\n// Interleave ON: the same bubble, filled \u2014 \"hide the conversation\".\nconst TRANSCRIPT_ON_ICON = svg`<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"currentColor\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><path d=\"M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z\"></path></svg>`;\n\n// Collapse: arrows pointing in toward the center (Lucide minimize-2).\nconst MINIMIZE_ICON = svg`<svg viewBox=\"0 0 24 24\" width=\"16\" height=\"16\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.25\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\"><polyline points=\"4 14 10 14 10 20\"></polyline><polyline points=\"20 10 14 10 14 4\"></polyline><line x1=\"14\" y1=\"10\" x2=\"21\" y2=\"3\"></line><line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\"></line></svg>`;\n\nfunction maximizeStyles(maximized: boolean): Record<string, string> {\n return {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '32px',\n height: '32px',\n borderRadius: '9999px',\n // Active (maximized): filled accent chip. Idle: subtle accent chip with a\n // visible ring. Colour is full-opacity in both states (no 0.95 ghosting).\n background: maximized\n ? 'hsl(var(--sc-accent-color) / 0.85)'\n : 'hsl(var(--sc-accent-color) / 0.15)',\n border: maximized ? 'none' : '1px solid hsl(var(--sc-accent-color) / 0.45)',\n color: maximized ? 'var(--sc-accent-foreground, #fff)' : 'hsl(var(--sc-accent-color))',\n flexShrink: '0',\n lineHeight: '1',\n padding: '0',\n cursor: 'pointer',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\nfunction inputStyles(): Record<string, string> {\n return {\n flex: '1',\n minWidth: '0',\n background: 'transparent',\n border: 'none',\n outline: 'none',\n color: 'inherit',\n // MUST be >= 16px. iOS Safari auto-zooms the page when a focused input has a\n // font-size below 16px, then does NOT zoom back out on blur \u2014 so the composer\n // zoomed in, the input ended up behind the keyboard (the zoom breaks the\n // visualViewport keyboard-lift math), and tapping \"Done\" left the whole site\n // stuck zoomed in. 16px is the standard, accessibility-safe fix (no\n // user-scalable=no / maximum-scale hacks that would kill pinch-zoom).\n fontSize: '16px',\n // WCAG 2.2 AA, 2.5.8 \u2014 every pointer target is at least 24x24 CSS px, and\n // an input's own box is what gets measured, not the bar it sits inside\n // (BUG-1787284957: the manual keyboard walk measured 278x20 while the bar\n // around it looked perfectly comfortable). A bare 16px input's line box is\n // ~20px, so the floor has to be declared.\n //\n // Painted height is UNCHANGED in both composer variants: the pinned pill\n // is already `min-height: 36px` with 6px block padding (24 + 12 = 36,\n // exactly the floor it was already holding), and the floating row's\n // tallest child is the 32px mic.\n //\n // The fallback is what carries the guarantee, and only for the UNSET case:\n // a workspace that never publishes --sc-chat-input-min-height gets 24px and\n // meets AA. A workspace that DOES publish it can set anything, including a\n // value below 24 \u2014 CSS has no floor to enforce here. Catching that belongs\n // at authoring time, in `validate-config.mjs` alongside the contrast\n // warnings, per the repo's validators-at-authoring-time law; tracked\n // follow-up, not something this declaration can promise.\n minHeight: 'var(--sc-chat-input-min-height, 24px)',\n };\n}\n\nfunction sendStyles(inFlight: boolean): Record<string, string> {\n return {\n width: '28px',\n height: '28px',\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderRadius: '9999px',\n // Ready: filled accent (send is the affordance). In-flight: hollow\n // ring + accent ring (stop is a one-of-a-kind disruptive action,\n // styled differently so the user reads \"this isn't just send\").\n background: inFlight ? 'transparent' : 'hsl(var(--sc-accent-color) / 0.85)',\n color: inFlight ? 'hsl(var(--sc-accent-color) / 0.95)' : 'var(--sc-accent-foreground, #fff)',\n border: inFlight ? '1px solid hsl(var(--sc-accent-color) / 0.55)' : 'none',\n cursor: 'pointer',\n flexShrink: '0',\n transition: 'background 150ms ease, color 150ms ease, border-color 150ms ease',\n };\n}\n\n/**\n * Compact single-line chat header. Prior version stacked the name over a\n * two-line status block inside a flex-column wrapper with a 28px avatar and\n * `padding: 4px 4px 12px`, which wasted a lot of vertical space (user\n * feedback: \"bad use of vertical space\"). This is now ONE inline row \u2014\n * small avatar dot \u00B7 name \u00B7 live-status dot \u00B7 short status \u2014 at roughly half\n * the height. All surfaces share this chrome.\n */\nfunction renderHeader(assistantName: string, persona: ChatPersona | null) {\n const headerStyles: Record<string, string> = {\n // Container-owned visibility: velvet's collapsed strip (V3 tight +\n // deck focus) sets --sc-chat-bar-header-display: none so the strip is\n // JUST the text entry (the header painted over the absolute-pinned\n // input when the region was clamped to the strip height). Expanded\n // chat keeps the header \u2014 the AI-disclosure microline must stay\n // wherever a conversation is actually visible.\n display: 'var(--sc-chat-bar-header-display, flex)',\n alignItems: 'center',\n gap: '7px',\n // Halved vertical footprint: 6px total block padding vs the old 16px\n // (4px top + 12px bottom). Horizontal padding unchanged.\n padding: '3px 4px',\n borderBottom: '1px solid var(--sc-content-divider-color, rgba(0, 0, 0, 0.08))',\n flex: '0 0 auto',\n };\n // Small brand dot \u2014 shrunk from a 28px avatar to a 16px chip so the\n // whole header collapses to a single text line. Still tracks the\n // workspace brand primary so it matches the rest of the canvas chrome.\n const avatar: Record<string, string> = {\n display: 'inline-flex',\n alignItems: 'center',\n justifyContent: 'center',\n width: '16px',\n height: '16px',\n borderRadius: '9999px',\n background:\n 'var(--sc-tile-icon-background, linear-gradient(135deg, var(--sc-color-primary, #5faf7d) 0%, var(--sc-color-primary-hover, #3d8a5e) 100%))',\n color: '#fff',\n flexShrink: '0',\n fontSize: '9px',\n lineHeight: '1',\n };\n const name: Record<string, string> = {\n fontSize: '0.8rem',\n fontWeight: '600',\n color: 'var(--sc-content-text-color, inherit)',\n lineHeight: '1.2',\n flexShrink: '0',\n };\n // No status line or presence dot (\"Online \u00B7 understands your session\") \u2014\n // user feedback: that's chrome a visitor doesn't need. Avatar + name only.\n // Persona mode (FEAT-1784917430): the brand dot becomes the persona's face,\n // the name becomes the persona's name, and an explicit \"AI concierge\"\n // microline rides alongside \u2014 a photoreal face + human name must never\n // imply a human agent (Moffatt/R-001 lineage, CA B.O.T./EU AI Act).\n const personaImg: Record<string, string> = {\n width: '22px',\n height: '22px',\n borderRadius: '9999px',\n objectFit: 'cover',\n flexShrink: '0',\n };\n const disclosure: Record<string, string> = {\n fontSize: '0.62rem',\n fontWeight: '500',\n color: 'var(--sc-content-text-color, inherit)',\n opacity: '0.55',\n lineHeight: '1.2',\n flexShrink: '0',\n };\n return html`\n <div style=${styleMap(headerStyles)} data-chat-header>\n ${\n persona?.avatar?.md || persona?.avatar?.sm\n ? html`<img\n style=${styleMap(personaImg)}\n src=${persona.avatar.md ?? persona.avatar.sm ?? ''}\n alt=\"\"\n data-persona-avatar\n />`\n : html`<span style=${styleMap(avatar)} aria-hidden=\"true\">\u2726</span>`\n }\n <span style=${styleMap(name)} data-persona-name>${persona?.name ?? assistantName}</span>\n ${persona ? html`<span style=${styleMap(disclosure)} data-persona-disclosure>\u00B7 AI concierge</span>` : nothing}\n </div>\n `;\n}\n\nif (!customElements.get('adaptive-chat-bar')) {\n customElements.define('adaptive-chat-bar', AdaptiveChatBar);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'adaptive-chat-bar': AdaptiveChatBar;\n }\n}\n", "/**\n * Chat personas \u2014 the \"human face\" of the concierge (FEAT-1784917430).\n *\n * A workspace ships a persona ROSTER in the chat-bar's props (plain config,\n * like assistantName). Assignment is 50:50 sticky-random per visitor: first\n * visit picks uniformly, the pick persists in localStorage, and every later\n * session reuses it \u2014 consistency reads as a real team member, not a slot\n * machine. An invalid/vanished persisted id re-picks (roster changes are\n * config changes; visitors must never be stranded on a ghost).\n *\n * The persona never claims to be human: the header carries an explicit\n * \"AI concierge\" microline (see renderHeader) and the server threads the\n * no-human-claim rule into the prompt (Moffatt/R-001 lineage).\n */\n\nexport interface PersonaAvatar {\n sm?: string;\n md?: string;\n lg?: string;\n}\n\nexport interface ChatPersona {\n id: string;\n name: string;\n role_title?: string;\n pronouns?: string;\n avatar?: PersonaAvatar;\n intro_line?: string;\n}\n\nconst STORAGE_KEY = 'syntro:persona';\n\n/** Pick (or recall) the visitor's sticky persona from the roster. */\nexport function pickPersona(roster: ChatPersona[] | undefined | null): ChatPersona | null {\n if (!Array.isArray(roster) || roster.length === 0) return null;\n let storedId: string | null = null;\n try {\n storedId = localStorage.getItem(STORAGE_KEY);\n } catch {\n // Storage unavailable (private mode) \u2014 session-scoped random pick.\n }\n const stored = storedId ? roster.find((p) => p.id === storedId) : undefined;\n if (stored) return stored;\n const pick = roster[Math.floor(Math.random() * roster.length)]!;\n try {\n localStorage.setItem(STORAGE_KEY, pick.id);\n } catch {\n /* non-persistent pick is fine */\n }\n return pick;\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;AAwBA,SAAS,MAAM,YAAY,SAAS,WAAW;AAC/C,SAAS,gBAAgB;;;ACKzB,IAAM,cAAc;AAGb,SAAS,YAAY,QAA8D;AACxF,MAAI,CAAC,MAAM,QAAQ,MAAM,KAAK,OAAO,WAAW,EAAG,QAAO;AAC1D,MAAI,WAA0B;AAC9B,MAAI;AACF,eAAW,aAAa,QAAQ,WAAW;AAAA,EAC7C,QAAQ;AAAA,EAER;AACA,QAAM,SAAS,WAAW,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ,IAAI;AAClE,MAAI,OAAQ,QAAO;AACnB,QAAM,OAAO,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,OAAO,MAAM,CAAC;AAC7D,MAAI;AACF,iBAAa,QAAQ,aAAa,KAAK,EAAE;AAAA,EAC3C,QAAQ;AAAA,EAER;AACA,SAAO;AACT;;;ADbA,IAAM,sBAAsB;AAC5B,IAAM,yBAAyB;AAtC/B;AAwCO,IAAM,kBAAN,cAA8B,WAAW;AAAA,EAAzC;AAAA;AAAA;AA0BL,oBAA2B,CAAC;AAM5B;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAO;AACP,qBAAY;AASZ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,uBAAyC;AAGzC;AAAA,uBAAc;AACd,wBAA8B,CAAC;AAG/B;AAAA;AAAA,yBAAqC,CAAC;AAItC;AAAA;AAAA;AAAA,6BAAqD;AAUrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAe;AAOf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,2BAAiE;AAMjE;AAAA;AAAA;AAAA;AAAA,yBAAgB;AAChB,uBAAc;AAOd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAAgB;AAEhB;AAAA,oBAAiC;AAEjC;AAAA,oBAA+B;AAQ/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA+B;AAQ/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAW;AAEX;AAAA,sBAAa;AACb,kBAAS;AACT,yBAAgB;AAChB,wBAAe;AACf,SAAQ,WAAW;AACnB,SAAQ,oBAAoB;AAC5B,SAAQ,aAAyC;AAIjD;AAAA;AAAA;AAAA,4BAAmB;AA2BnB;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,WAAW,CAAC,MAAmB;AAGrC,UAAI,KAAK,cAAe,MAAK,YAAY,KAAK;AAC9C,WAAK,SAAU,EAAE,OAA4B;AAAA,IAC/C;AAEA,SAAQ,cAAc,MAAY;AAChC,UAAI,KAAK,eAAe;AACtB,aAAK,YAAY,KAAK;AACtB;AAAA,MACF;AACA,WAAK,WAAW,KAAK;AACrB,WAAK,aAAa,gBAAgB;AAAA,QAChC,cAAc,CAAC,SAAS;AACtB,eAAK,oBAAoB;AACzB,eAAK,SAAS,KAAK,YAAY,KAAK,WAAW,MAAM,MAAM;AAAA,QAC7D;AAAA,QACA,OAAO,MAAM;AACX,eAAK,gBAAgB;AAAA,QACvB;AAAA,QACA,SAAS,CAAC,SAAS;AACjB,eAAK,gBAAgB;AACrB,cAAI,SAAS,cAAe,MAAK,eAAe;AAChD,cAAI,SAAS,aAAa,EAAE,KAAK,qBAAqB,EAAG,MAAK,eAAe;AAAA,QAC/E;AAAA,MACF,CAAC;AACD,WAAK,WAAW,MAAM;AAGtB,WAAK,gBAAgB,KAAK,WAAW;AAAA,IACvC;AAEA,SAAQ,aAAa,CAAC,MAA2B;AAC/C,UAAI,EAAE,QAAQ,WAAW,CAAC,EAAE,UAAU;AACpC,UAAE,eAAe;AAIjB,YAAI,KAAK,SAAU;AACnB,aAAK,MAAM;AAAA,MACb;AAAA,IACF;AAKA;AAAA;AAAA;AAAA,SAAQ,qBAAqB,MAAY;AACvC,UAAI,KAAK,UAAU;AAIjB,aAAK,wBAAwB;AAC7B,aAAK,cAAc,IAAI,YAAY,kBAAkB,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AACvF;AAAA,MACF;AACA,WAAK,MAAM;AAAA,IACb;AAEA,SAAQ,yBAAyB,CAAC,MAAmB;AACnD,YAAM,EAAE,WAAW,IAAK,EAA0C;AAClE,8BAAwB,GAAG,SAAS,UAAU;AAC9C,WAAK;AAAA,QACH,IAAI,YAAY,eAAe,EAAE,QAAQ,EAAE,WAAW,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,MAC1F;AAAA,IACF;AAEA,SAAQ,0BAA0B,CAAC,MAAmB;AACpD,YAAM,EAAE,WAAW,IAAK,EAA0C;AAClE,WAAK;AAAA,QACH,IAAI,YAAY,gBAAgB,EAAE,QAAQ,EAAE,WAAW,GAAG,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,MAC3F;AAAA,IACF;AAEA,SAAQ,qBAAqB,MAAY;AACvC,WAAK,mBAAmB;AAAA,IAC1B;AAEA,SAAQ,sBAAsB,MAAY;AACxC,WAAK,mBAAmB;AAAA,IAC1B;AAEA,SAAQ,oBAAoB,MAAY;AACtC,WAAK,cAAc,IAAI,YAAY,wBAAwB,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC,CAAC;AAAA,IAC/F;AAcA,SAAQ,sBAAsB,MAAY;AACxC,WAAK;AAAA,QACH,IAAI,YAAY,0BAA0B,EAAE,SAAS,MAAM,UAAU,KAAK,CAAC;AAAA,MAC7E;AAAA,IACF;AA0CA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,qBAAqB,CAAC,MAAmB;AAC/C,YAAM,SAAU,EAAsC;AACtD,UAAI,CAAC,QAAQ,OAAQ;AACrB,QAAE,gBAAgB;AAClB,UAAI,KAAK,SAAU;AAOnB,WAAK,WAAW;AAChB,WAAK,cAAc,OAAO,QAAQ,kBAAkB;AAAA,IACtD;AAWA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,wBAAuC;AAgC/C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,SAAQ,oBAAoB,CAAC,MAAmB;AAC9C,YAAM,SAAU,EAAoC;AACpD,UAAI,CAAC,QAAQ,KAAM;AACnB,QAAE,gBAAgB;AAClB,UAAI,KAAK,UAAU;AACjB,aAAK,wBAAwB,OAAO;AACpC;AAAA,MACF;AAKA,WAAK,WAAW;AAChB,WAAK,cAAc,OAAO,MAAM,MAAM;AAAA,IACxC;AAAA;AAAA,EA/OS,mBAAgC;AACvC,WAAO;AAAA,EACT;AAAA,EAES,oBAA0B;AACjC,UAAM,kBAAkB;AAIxB,SAAK,iBAAiB,yBAAyB,KAAK,sBAAsB;AAC1E,SAAK,iBAAiB,0BAA0B,KAAK,uBAAuB;AAAA,EAC9E;AAAA,EAES,uBAA6B;AACpC,UAAM,qBAAqB;AAC3B,SAAK,oBAAoB,yBAAyB,KAAK,sBAAsB;AAC7E,SAAK,oBAAoB,0BAA0B,KAAK,uBAAuB;AAAA,EACjF;AAAA;AAAA,EAiHQ,cAAc,MAAc,KAAwB;AAC1D,SAAK;AAAA,MACH,IAAI,YAA8D,qBAAqB;AAAA,QACrF,QAAQ,EAAE,MAAM,KAAK,MAAM,KAAK,OAAO,EAAE;AAAA,QACzC,SAAS;AAAA,QACT,UAAU;AAAA,MACZ,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEQ,QAAc;AAGpB,QAAI,KAAK,cAAe,MAAK,YAAY,KAAK;AAC9C,UAAM,OAAO,KAAK,OAAO,KAAK;AAC9B,QAAI,CAAC,KAAM;AAIX,SAAK,wBAAwB;AAC7B,SAAK,cAAc,MAAM,OAAO;AAChC,SAAK,SAAS;AAMd,UAAM,QAAQ,KAAK,cAAgC,wBAAwB;AAC3E,QAAI,MAAO,OAAM,QAAQ;AAAA,EAC3B;AAAA,EAoCmB,WAAW,SAAqC;AACjE,UAAM,aAAa,OAAO;AAC1B,QAAI,QAAQ,IAAI,UAAU,GAAG;AAC3B,WAAK,WAAW,YAAY,KAAK,QAAQ;AAAA,IAC3C;AACA,QACE,QAAQ,IAAI,UAAU,KACtB,QAAQ,IAAI,UAAU,MAAM,QAC5B,CAAC,KAAK,YACN,KAAK,uBACL;AACA,YAAM,OAAO,KAAK;AAClB,WAAK,wBAAwB;AAE7B,WAAK,WAAW;AAChB,WAAK,cAAc,MAAM,MAAM;AAAA,IACjC;AAAA,EACF;AAAA,EA6BS,SAAS;AAChB,WAAO;AAAA,mBACQ,SAAS,WAAW,KAAK,aAAa,CAAC,CAAC;AAAA,UACjD,KAAK,iBAAiB,mBAAK,gDAAgB,aAAa,KAAK,eAAe,KAAK,QAAQ,IAAI,OAAO;AAAA,UAEpG,mBAAK,gDACD;AAAA,sBACQ,KAAK,QAAQ;AAAA,sBACb,KAAK,UAAU,cAAc,KAAK,QAAQ;AAAA,2BACrC,KAAK,aAAa;AAAA,sBACvB,KAAK,QAAQ;AAAA,0BACT,KAAK,YAAY;AAAA,yBAClB,KAAK,UAAU,QAAQ,EAAE;AAAA,6BACrB,KAAK,UAAU,QAAQ,MAAM,EAAE;AAAA,6BAC/B,KAAK,eAAe;AAAA,0BACvB,KAAK,YAAY;AAAA,2BAChB,KAAK,aAAa;AAAA,+BACd,KAAK,iBAAiB;AAAA,oCACjB,KAAK,kBAAkB;AAAA,mCACxB,KAAK,iBAAiB;AAAA,mCAE3C,OACN;AAAA;AAAA,kBAEU,SAAS,UAAU,KAAK,eAAe,KAAK,gBAAgB,CAAC,CAAC;AAAA;AAAA,qBAE3D,KAAK,kBAAkB;AAAA,sBACtB,KAAK,mBAAmB;AAAA;AAAA,YAGlC,KAAK,gBAAgB,eACjB;AAAA;AAAA;AAAA,qBAGK,KAAK,mBAAmB;AAAA,yBACpB,KAAK,cAAc,0BAA0B,uBAAuB;AAAA,oBACzE,KAAK,cAAc,0BAA0B,uBAAuB;AAAA,2BAC7D,KAAK,cAAc,SAAS,OAAO;AAAA,oBAC1C,SAAS,eAAe,KAAK,WAAW,CAAC,CAAC;AAAA,aACjD,KAAK,cAAc,qBAAqB,mBAAmB,cACxD;AAAA;AAAA;AAAA,qBAGK,KAAK,iBAAiB;AAAA,yBAClB,KAAK,YAAY,qBAAqB,eAAe;AAAA,oBAC1D,KAAK,YAAY,qBAAqB,UAAU;AAAA,2BACzC,KAAK,YAAY,SAAS,OAAO;AAAA,oBACxC,SAAS,eAAe,KAAK,SAAS,CAAC,CAAC;AAAA,aAC/C,KAAK,YAAY,gBAAgB,aAAa,WACjD;AAAA;AAAA;AAAA;AAAA,0BAIgB,KAAK,gBAAgB,yCAAoC,KAAK,WAAW;AAAA,qBAC9E,KAAK,MAAM;AAAA,qBACX,KAAK,QAAQ;AAAA,uBACX,KAAK,UAAU;AAAA,oBAClB,SAAS,YAAY,CAAC,CAAC;AAAA;AAAA;AAAA,YAI/B,KAAK,cAAc,qBAAqB,IACpC,OAAO,eAAe;AAAA;AAAA;AAAA,mCAGH,KAAK,gBAAgB,SAAS,OAAO;AAAA,8BAC1C,KAAK,YAAY;AAAA,2BACpB,KAAK,WAAW;AAAA,iCACV,KAAK,gBAAgB,SAAS,OAAO;AAAA,+BACvC,KAAK,gBAAgB,mBAAmB,iBAAiB;AAAA,0BAC9D,KAAK,eAAe,uBAAuB,KAAK,gBAAgB,mBAAmB,SAAS;AAAA,0BAC5F,SAAS,UAAU,KAAK,eAAe,KAAK,YAAY,CAAC,CAAC;AAAA,mBACjE,QAAQ,cACX,OACN;AAAA;AAAA;AAAA;AAAA,yBAIe,KAAK,WAAW,cAAc,OAAO;AAAA,qBACzC,KAAK,kBAAkB;AAAA,yBACnB,KAAK,WAAW,SAAS,cAAc;AAAA,oBAC5C,KAAK,WAAW,cAAc,MAAM;AAAA,oBACpC,SAAS,WAAW,KAAK,QAAQ,CAAC,CAAC;AAAA,aAC1C,KAAK,WAAW,WAAM,QAAG;AAAA;AAAA;AAAA;AAAA,EAIpC;AACF;AA/bO;AA6OD,mBAAa,WAAY;AAC3B,SAAO,KAAK,gBAAgB,gBAAgB,KAAK;AACnD;AA/OW,gBACK,aAAa;AAAA,EAC3B,UAAU,EAAE,WAAW,MAAM;AAAA,EAC7B,UAAU,EAAE,OAAO,KAAK;AAAA,EACxB,UAAU,EAAE,WAAW,MAAM;AAAA,EAC7B,aAAa,EAAE,MAAM,OAAO;AAAA,EAC5B,eAAe,EAAE,MAAM,OAAO;AAAA,EAC9B,UAAU,EAAE,MAAM,OAAO;AAAA,EACzB,UAAU,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,EACzC,MAAM,EAAE,MAAM,OAAO;AAAA,EACrB,cAAc,EAAE,WAAW,MAAM;AAAA,EACjC,iBAAiB,EAAE,WAAW,MAAM;AAAA,EACpC,eAAe,EAAE,MAAM,SAAS,SAAS,KAAK;AAAA,EAC9C,WAAW,EAAE,MAAM,QAAQ;AAAA,EAC3B,aAAa,EAAE,MAAM,OAAO;AAAA,EAC5B,aAAa,EAAE,MAAM,QAAQ;AAAA,EAC7B,cAAc,EAAE,WAAW,MAAM;AAAA,EACjC,eAAe,EAAE,WAAW,MAAM;AAAA,EAClC,mBAAmB,EAAE,WAAW,MAAM;AAAA,EACtC,YAAY,EAAE,MAAM,QAAQ;AAAA,EAC5B,QAAQ,EAAE,OAAO,KAAK;AAAA,EACtB,kBAAkB,EAAE,OAAO,KAAK;AAAA,EAChC,eAAe,EAAE,OAAO,KAAK;AAAA,EAC7B,cAAc,EAAE,OAAO,KAAK;AAC9B;AA8aF,SAAS,WAAW,eAAgD;AAOlE,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,eAAe;AAAA,MACf,KAAK;AAAA,MACL,OAAO;AAAA,MACP,eAAe;AAAA,IACjB;AAAA,EACF;AAYA,SAAO;AAAA,IACL,UAAU;AAAA,IACV,SAAS;AAAA,IACT,eAAe;AAAA,IACf,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,MAAM;AAAA,IACN,WAAW;AAAA,IACX,UAAU;AAAA,IACV,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA;AAAA;AAAA,IAGX,SAAS;AAAA,IACT,OAAO;AAAA,IACP,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAaZ,CAAC,8BAA8B,GAAG;AAAA,IAClC,CAAC,qCAAqC,GAAG;AAAA,IACzC,CAAC,2BAA2B,GAAG;AAAA,IAC/B,CAAC,iCAAiC,GAAG;AAAA,IACrC,CAAC,+BAA+B,GAAG;AAAA,EACrC;AACF;AAKA,IAAM,wBAAwB;AAE9B,SAAS,UAAU,eAAwB,SAA0C;AAInF,MAAI,eAAe;AAWjB,WAAO;AAAA,MACL,UAAU;AAAA,MACV,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,YAAY;AAAA,MACZ,KAAK;AAAA,MACL,SAAS;AAAA,MACT,cAAc;AAAA,MACd,YACE;AAAA,MACF,QAAQ,UACJ,wBACA;AAAA,MACJ,OAAO;AAAA,MACP,YAAY;AAAA,MACZ,WAAW;AAAA,IACb;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA,IACL,SAAS;AAAA,IACT,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,sBAAsB;AAAA,IACtB,QAAQ,UACJ,wBACA;AAAA,IACJ,WAAW;AAAA,IACX,OAAO;AAAA,IACP,YAAY;AAAA,EACd;AACF;AAWA,IAAM,WAAW;AAEjB,SAAS,UAAU,WAAoB,UAA2C;AAChF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,eAAe;AAAA,IACf,mBAAmB;AAAA,IACnB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,iBAAiB;AAAA;AAAA;AAAA;AAAA,IAIjB,YAAY,YAAY,qCAAqC;AAAA,IAC7D,OAAO,YAAY,0CAA0C;AAAA,IAC7D,SAAS,WAAW,QAAQ,YAAY,MAAM;AAAA,IAC9C,QAAQ,WAAW,gBAAgB;AAAA,IACnC,YAAY;AAAA,IACZ,eAAe;AAAA,EACjB;AACF;AAKA,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAwBxB,IAAM,gBAAgB;AAGtB,IAAM,sBAAsB;AAG5B,IAAM,qBAAqB;AAG3B,IAAM,gBAAgB;AAEtB,SAAS,eAAe,WAA4C;AAClE,SAAO;AAAA,IACL,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA;AAAA;AAAA,IAGd,YAAY,YACR,uCACA;AAAA,IACJ,QAAQ,YAAY,SAAS;AAAA,IAC7B,OAAO,YAAY,sCAAsC;AAAA,IACzD,YAAY;AAAA,IACZ,YAAY;AAAA,IACZ,SAAS;AAAA,IACT,QAAQ;AAAA,IACR,YAAY;AAAA,EACd;AACF;AAEA,SAAS,cAAsC;AAC7C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOP,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAmBV,WAAW;AAAA,EACb;AACF;AAEA,SAAS,WAAW,UAA2C;AAC7D,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,cAAc;AAAA;AAAA;AAAA;AAAA,IAId,YAAY,WAAW,gBAAgB;AAAA,IACvC,OAAO,WAAW,uCAAuC;AAAA,IACzD,QAAQ,WAAW,iDAAiD;AAAA,IACpE,QAAQ;AAAA,IACR,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACF;AAUA,SAAS,aAAa,eAAuB,SAA6B;AACxE,QAAM,eAAuC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAO3C,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,KAAK;AAAA;AAAA;AAAA,IAGL,SAAS;AAAA,IACT,cAAc;AAAA,IACd,MAAM;AAAA,EACR;AAIA,QAAM,SAAiC;AAAA,IACrC,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,YACE;AAAA,IACF,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,UAAU;AAAA,IACV,YAAY;AAAA,EACd;AACA,QAAM,OAA+B;AAAA,IACnC,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AAOA,QAAM,aAAqC;AAAA,IACzC,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,cAAc;AAAA,IACd,WAAW;AAAA,IACX,YAAY;AAAA,EACd;AACA,QAAM,aAAqC;AAAA,IACzC,UAAU;AAAA,IACV,YAAY;AAAA,IACZ,OAAO;AAAA,IACP,SAAS;AAAA,IACT,YAAY;AAAA,IACZ,YAAY;AAAA,EACd;AACA,SAAO;AAAA,iBACQ,SAAS,YAAY,CAAC;AAAA,QAE/B,SAAS,QAAQ,MAAM,SAAS,QAAQ,KACpC;AAAA,sBACU,SAAS,UAAU,CAAC;AAAA,oBACtB,QAAQ,OAAO,MAAM,QAAQ,OAAO,MAAM,EAAE;AAAA;AAAA;AAAA,kBAIpD,mBAAmB,SAAS,MAAM,CAAC,8BACzC;AAAA,oBACc,SAAS,IAAI,CAAC,sBAAsB,SAAS,QAAQ,aAAa;AAAA,QAC9E,UAAU,mBAAmB,SAAS,UAAU,CAAC,mDAAmD,OAAO;AAAA;AAAA;AAGnH;AAEA,IAAI,CAAC,eAAe,IAAI,mBAAmB,GAAG;AAC5C,iBAAe,OAAO,qBAAqB,eAAe;AAC5D;",
6
+ "names": []
7
+ }
@@ -1,4 +1,4 @@
1
- import "./chunk-UVKRO5ER.js";
1
+ import "./chunk-LY5AGXVD.js";
2
2
 
3
3
  // src/editor-lit.ts
4
4
  import { html, LitElement } from "lit";
@@ -0,0 +1,3 @@
1
+ export type { ApplyOutcome, ElementSessionController, ElementSessionOptions, } from './elements/ElementSessionController';
2
+ export { createElementSessionController } from './elements/ElementSessionController';
3
+ //# sourceMappingURL=element-session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"element-session.d.ts","sourceRoot":"","sources":["../src/element-session.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,YAAY,EACZ,wBAAwB,EACxB,qBAAqB,GACtB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import {
2
+ createElementSessionController
3
+ } from "./chunk-VIRIVP7H.js";
4
+ import "./chunk-4V5L7IRV.js";
5
+ import "./chunk-LY5AGXVD.js";
6
+ export {
7
+ createElementSessionController
8
+ };
9
+ //# sourceMappingURL=element-session.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }
@@ -116,6 +116,10 @@ export interface ElementInstanceStoreOptions {
116
116
  */
117
117
  resolveTileWidget?: (templateId: string) => string | undefined;
118
118
  }
119
+ export interface ApplyReport {
120
+ ok: boolean;
121
+ rejectedInstanceIds: string[];
122
+ }
119
123
  export declare class ElementInstanceStore {
120
124
  private readonly _actions;
121
125
  private readonly _events;
@@ -125,6 +129,9 @@ export declare class ElementInstanceStore {
125
129
  private readonly _resolveTileWidget?;
126
130
  /** Active TTL timeout — replaced on each call to `scheduleClientTtl`. */
127
131
  private _ttlTimer;
132
+ private _unsubscribeReplay?;
133
+ private _disposed;
134
+ private _disposing;
128
135
  /** Instance IDs the client has dismissed. Persists across canvas remounts
129
136
  * so a dismissed tile never silently reappears on replay/broadcast. */
130
137
  private readonly _dismissedIds;
@@ -180,6 +187,7 @@ export declare class ElementInstanceStore {
180
187
  * stateful instances; callers should not.
181
188
  */
182
189
  hydrate(snapshot: MountedElement[]): Promise<void>;
190
+ private _hydrateWithReport;
183
191
  /**
184
192
  * Re-publish `element.tile_mounted` / `element.compositional_append`
185
193
  * for every active LLM-authored instance in the store. Idempotent —
@@ -193,16 +201,22 @@ export declare class ElementInstanceStore {
193
201
  * patch: resulting_version must be > current; unmount: idempotent).
194
202
  */
195
203
  apply(mutations: ElementMutation[]): Promise<void>;
204
+ applyWithReport(mutations: ElementMutation[]): Promise<ApplyReport>;
205
+ private _applyWithReport;
196
206
  /** Read-only snapshot of currently-known instances. */
197
207
  getInstances(): MountedElement[];
198
208
  getInstance(instance_id: string): MountedElement | undefined;
209
+ /** Replace a host-provided complete UI snapshot; never replay imperative actions. */
210
+ reconcileSnapshot(snapshot: MountedElement[]): Promise<ApplyReport>;
211
+ /** Release page-lifetime listeners and timers; queued work becomes inert. */
212
+ dispose(unmount?: boolean): void;
199
213
  /**
200
214
  * Schedule a client-side TTL that unmounts every active stateful
201
215
  * instance when the server-side session expires. Replaces any
202
216
  * previously-scheduled TTL.
203
217
  *
204
218
  * Avoids the orphan-window where session-expired tiles linger on the
205
- * page until manual refresh — the server forgets at the 4h mark and
219
+ * page until manual refresh — the server forgets at the 24h mark and
206
220
  * the SDK tears down concurrently. Re-schedule on each boot fetch /
207
221
  * mutation event that carries a refreshed `session_expires_at`.
208
222
  *
@@ -1 +1 @@
1
- {"version":3,"file":"ElementInstanceStore.d.ts","sourceRoot":"","sources":["../../src/elements/ElementInstanceStore.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ElementInstanceStore.d.ts","sourceRoot":"","sources":["../../src/elements/ElementInstanceStore.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,KAAK,EAAyB,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAK/D;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C,4EAA4E;AAC5E,MAAM,WAAW,YAAY;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,yEAAyE;IACzE,GAAG,EAAE,MAAM,CAAC;IACZ;;mDAE+C;IAC/C,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B;sDACkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;iFAC6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,YAAY,CAAC;IACtB;;;;;;;;;;;;;;OAcG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;QACjE;;;;;;WAMG;QACH,SAAS,CAAC,EAAE;YACV,CACE,MAAM,EAAE;gBAAE,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;aAAE,EAC5B,OAAO,EAAE,CAAC,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;aAAE,KAAK,IAAI,GAC1E,MAAM,IAAI,CAAC;YACd,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;aAAE,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;SAC3F,CAAC;KACH,CAAC;IACF,QAAQ,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAChC,iEAAiE;IACjE,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC;IAClD;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,CAAC;CAChE;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC/B;AAwDD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA0C;IACrE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA2C;IACnE,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAA6C;IACjF,yEAAyE;IACzE,OAAO,CAAC,SAAS,CAA8C;IAC/D,OAAO,CAAC,kBAAkB,CAAC,CAAa;IACxC,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;IAC3B;4EACwE;IACxE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAA0B;gBAE5C,OAAO,EAAE,2BAA2B;IAYhD;;;;;;;;OAQG;IACH,OAAO,CAAC,wBAAwB;IAqChC,OAAO,CAAC,YAAY;IAmBpB,OAAO,CAAC,YAAY;IAepB,eAAe,CAAC,OAAO,EAAE,kBAAkB,GAAG,IAAI;IAIlD,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAIxC,eAAe,IAAI,WAAW,CAAC,MAAM,CAAC;IAItC,iFAAiF;IACjF,gBAAgB,IAAI,KAAK,CACrB;QACE,IAAI,EAAE,MAAM,CAAC;QACb,UAAU,EAAE,MAAM,CAAC;QACnB,KAAK,EAAE,MAAM,CAAC;QACd,SAAS,EAAE,OAAO,CAAC;QACnB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GACD;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE,CAC7F;IA8DD;;;;;;OAMG;IACH,iBAAiB,IAAI,YAAY,EAAE;IAkBnC,sFAAsF;IACtF,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAoBlC;;;;;;;;OAQG;IACG,OAAO,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAI1C,kBAAkB;IAkEhC;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAkBxB;;;;OAIG;IACG,KAAK,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlD,eAAe,CAAC,SAAS,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;YAI3D,gBAAgB;IAsB9B,uDAAuD;IACvD,YAAY,IAAI,cAAc,EAAE;IAIhC,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS;IAI5D,qFAAqF;IAC/E,iBAAiB,CAAC,QAAQ,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAuDzE,6EAA6E;IAC7E,OAAO,CAAC,OAAO,UAAQ,GAAG,IAAI;IAqB9B;;;;;;;;;;;;OAYG;IACH,iBAAiB,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;YAwB5C,oBAAoB;YAkBpB,SAAS;YA6IT,MAAM;IAyBpB,OAAO,CAAC,IAAI;CAUb"}