@opengeni/react 5.0.5-canary.3 → 5.2.0-canary.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 (81) hide show
  1. package/README.md +13 -1
  2. package/dist/artifacts.d.ts +2 -0
  3. package/dist/artifacts.js +1391 -2
  4. package/dist/artifacts.js.map +1 -1
  5. package/dist/chunk-2TKI3WEG.js +73 -0
  6. package/dist/chunk-2TKI3WEG.js.map +1 -0
  7. package/dist/{chunk-V3WX3TQG.js → chunk-45XEUVTK.js} +2 -2
  8. package/dist/{chunk-M2HNWZYR.js → chunk-IHQII5WO.js} +69 -18
  9. package/dist/chunk-IHQII5WO.js.map +1 -0
  10. package/dist/{chunk-HUMIRRYI.js → chunk-IYCR4343.js} +19 -19
  11. package/dist/{chunk-HUMIRRYI.js.map → chunk-IYCR4343.js.map} +1 -1
  12. package/dist/{chunk-6J56T3MG.js → chunk-NYESIADM.js} +14 -5
  13. package/dist/chunk-NYESIADM.js.map +1 -0
  14. package/dist/{chunk-7S2KWUJD.js → chunk-QXJCNVSD.js} +2283 -2215
  15. package/dist/chunk-QXJCNVSD.js.map +1 -0
  16. package/dist/{chunk-BV5A4OTE.js → chunk-T5FRXMC3.js} +21 -2
  17. package/dist/{chunk-BV5A4OTE.js.map → chunk-T5FRXMC3.js.map} +1 -1
  18. package/dist/{chunk-BRFMGY4L.js → chunk-UGMKPUEM.js} +28 -3
  19. package/dist/chunk-UGMKPUEM.js.map +1 -0
  20. package/dist/components/artifacts/inline-html-document.d.ts +2 -0
  21. package/dist/components/artifacts/published-html-artifact-frame.d.ts +2 -0
  22. package/dist/components/artifacts/visualization-assets.gen.d.ts +2 -0
  23. package/dist/components/markdown.d.ts +13 -1
  24. package/dist/components/message-timeline.d.ts +4 -1
  25. package/dist/components/session-conversation.d.ts +3 -0
  26. package/dist/components/user-message-body.d.ts +10 -1
  27. package/dist/composer.js +2 -2
  28. package/dist/{computer-viewer-7TEZC6Y2.js → computer-viewer-AA4JH2AP.js} +2 -2
  29. package/dist/connect.js +1 -1
  30. package/dist/index.d.ts +3 -2
  31. package/dist/index.js +9 -6
  32. package/dist/index.js.map +1 -1
  33. package/dist/interaction.js +1 -1
  34. package/dist/{platform-activity-row-27LKAWZD.js → platform-activity-row-UW4UVVM4.js} +6 -3
  35. package/dist/platform-activity-row-UW4UVVM4.js.map +1 -0
  36. package/dist/session-ui.d.ts +1 -1
  37. package/dist/session-ui.js +6 -5
  38. package/dist/session-ui.js.map +1 -1
  39. package/dist/session.js +2 -2
  40. package/dist/sites-ui.d.ts +2 -1
  41. package/dist/sites.js +12 -4
  42. package/dist/sites.js.map +1 -1
  43. package/dist/timeline/activity-rail.d.ts +1 -0
  44. package/dist/timeline/platform-activity-row.d.ts +1 -1
  45. package/dist/timeline/retained-image.d.ts +16 -0
  46. package/dist/timeline/rolling-activity.d.ts +9 -0
  47. package/dist/timeline/shared.d.ts +4 -1
  48. package/dist/timeline/turn-summary.d.ts +4 -1
  49. package/package.json +4 -4
  50. package/src/artifacts.ts +2 -0
  51. package/src/components/artifacts/inline-html-document.ts +24 -0
  52. package/src/components/artifacts/published-html-artifact-frame.tsx +32 -2
  53. package/src/components/artifacts/visualization-assets/base.css +1015 -0
  54. package/src/components/artifacts/visualization-assets/helpers.html +349 -0
  55. package/src/components/artifacts/visualization-assets.gen.ts +3 -0
  56. package/src/components/copy-button.tsx +7 -2
  57. package/src/components/markdown.tsx +111 -34
  58. package/src/components/message-timeline.tsx +61 -4
  59. package/src/components/session-conversation.tsx +5 -0
  60. package/src/components/user-message-body.tsx +20 -2
  61. package/src/hooks/use-composer.ts +15 -2
  62. package/src/hooks/use-computer-session.ts +36 -1
  63. package/src/index.ts +10 -2
  64. package/src/session-ui.ts +4 -1
  65. package/src/sites-ui.tsx +23 -6
  66. package/src/timeline/activity-rail.tsx +20 -3
  67. package/src/timeline/platform-activity-row.tsx +5 -2
  68. package/src/timeline/retained-image.ts +91 -0
  69. package/src/timeline/rolling-activity.tsx +83 -0
  70. package/src/timeline/shared.tsx +33 -12
  71. package/src/timeline/tool-renderers.tsx +7 -91
  72. package/src/timeline/turn-summary.tsx +21 -15
  73. package/styles/compiled.css +122 -0
  74. package/styles/index.css +49 -0
  75. package/dist/chunk-6J56T3MG.js.map +0 -1
  76. package/dist/chunk-7S2KWUJD.js.map +0 -1
  77. package/dist/chunk-BRFMGY4L.js.map +0 -1
  78. package/dist/chunk-M2HNWZYR.js.map +0 -1
  79. package/dist/platform-activity-row-27LKAWZD.js.map +0 -1
  80. /package/dist/{chunk-V3WX3TQG.js.map → chunk-45XEUVTK.js.map} +0 -0
  81. /package/dist/{computer-viewer-7TEZC6Y2.js.map → computer-viewer-AA4JH2AP.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/artifacts/editable-artifact-workbench.tsx"],"sourcesContent":["import {\n createBrowserEditableArtifactSession,\n type CreateBrowserEditableArtifactSessionOptions,\n type EditableArtifactBrowserRuntime,\n type EditableArtifactSession,\n} from \"@opengeni/sdk/editable-artifacts\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { EditableArtifactMessage } from \"./editable-artifact-ui\";\nimport {\n EditableDocumentArtifactSurface,\n type EditableDocumentArtifactSurfaceProps,\n} from \"./editable-document\";\nimport {\n EditablePresentationArtifactSurface,\n type EditablePresentationArtifactSurfaceProps,\n} from \"./editable-presentation\";\nimport {\n EditableSpreadsheetArtifactSurface,\n type EditableSpreadsheetArtifactSurfaceProps,\n} from \"./editable-spreadsheet\";\n\nexport type EditableArtifactWorkbenchProps = Readonly<{\n session: EditableArtifactSession;\n document?: Omit<EditableDocumentArtifactSurfaceProps, \"session\">;\n spreadsheet?: Omit<EditableSpreadsheetArtifactSurfaceProps, \"session\">;\n presentation?: Omit<EditablePresentationArtifactSurfaceProps, \"session\">;\n}>;\n\nexport type EditableArtifactWorkbenchHostProps = Omit<EditableArtifactWorkbenchProps, \"session\"> &\n Readonly<{\n /**\n * Complete identity of the browser session authority. Change this when the\n * artifact, deployment, principal, or authorization epoch changes.\n */\n sessionKey: string;\n /** Called for the active keyed lifecycle and again only after replacement or retry. */\n createSession: () => EditableArtifactSession;\n }>;\n\ntype DefaultBrowserArtifactTransport = Omit<\n NonNullable<CreateBrowserEditableArtifactSessionOptions[\"transport\"]>,\n \"apiKey\" | \"fetch\" | \"headers\" | \"webSocketFactory\"\n> &\n Readonly<{\n /** Static deployment auth headers; rotate authorizationEpoch when they change. */\n headers?: Readonly<Record<string, string>>;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchOptions = Omit<\n CreateBrowserEditableArtifactSessionOptions,\n \"runtime\" | \"storage\" | \"transport\"\n> &\n Readonly<{\n /** Default module Worker only; custom Worker hosts use EditableArtifactWorkbenchHost. */\n runtime: Omit<EditableArtifactBrowserRuntime, \"workerFactory\">;\n /** Default fetch/WebSocket only; static deployment auth headers are supported. */\n transport?: DefaultBrowserArtifactTransport;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchProps = Omit<\n EditableArtifactWorkbenchProps,\n \"session\"\n> &\n Readonly<{ options: BrowserEditableArtifactWorkbenchOptions }>;\n\n/**\n * One modality-neutral SDK workbench. Embedding hosts keep one route/component;\n * each artifact still renders through its complete first-party editor surface.\n */\nexport function EditableArtifactWorkbench({\n session,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchProps) {\n switch (session.modality) {\n case \"document\":\n return (\n <EditableDocumentArtifactSurface\n {...document}\n session={session}\n title={document?.title ?? \"Document\"}\n />\n );\n case \"spreadsheet\":\n return <EditableSpreadsheetArtifactSurface {...spreadsheet} session={session} />;\n case \"presentation\":\n return <EditablePresentationArtifactSurface {...presentation} session={session} />;\n }\n}\n\n/**\n * Route/embed composition that owns exactly one SDK session. The host supplies\n * the authenticated SDK factory; React guarantees replacement and teardown.\n */\nexport function EditableArtifactWorkbenchHost({\n sessionKey,\n createSession,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchHostProps) {\n const createSessionRef = useRef(createSession);\n const [retryEpoch, setRetryEpoch] = useState(0);\n const [state, setState] = useState<\n | Readonly<{ key: string; session: EditableArtifactSession; error: null }>\n | Readonly<{ key: string | null; session: null; error: Error | null }>\n >({ key: null, session: null, error: null });\n\n useEffect(() => {\n createSessionRef.current = createSession;\n }, [createSession]);\n\n useEffect(() => {\n let owned: EditableArtifactSession | null = null;\n setState({ key: sessionKey, session: null, error: null });\n try {\n owned = createSessionRef.current();\n setState({ key: sessionKey, session: owned, error: null });\n } catch (cause) {\n setState({\n key: sessionKey,\n session: null,\n error: cause instanceof Error ? cause : new Error(\"Could not create artifact session\"),\n });\n }\n return () => {\n const closing = owned;\n owned = null;\n if (closing) void closing.close().catch(() => undefined);\n };\n }, [retryEpoch, sessionKey]);\n\n const retry = useCallback(() => setRetryEpoch((value) => value + 1), []);\n const currentError = state.key === sessionKey ? state.error : null;\n if (state.key === sessionKey && state.session) {\n return (\n <EditableArtifactWorkbench\n session={state.session}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n }\n return (\n <EditableArtifactMessage\n title={currentError ? \"Could not open this artifact\" : \"Opening artifact\"}\n detail={currentError?.message ?? \"Starting the secure editing session…\"}\n retry={currentError ? retry : undefined}\n />\n );\n}\n\n/**\n * Complete default-browser composition for embedders: verified WASM Worker,\n * durable IndexedDB state, authenticated live sync, teardown, and the matching\n * first-party editor. Advanced/custom transports compose the lower-level host.\n */\nexport function BrowserEditableArtifactWorkbench({\n options,\n document,\n spreadsheet,\n presentation,\n}: BrowserEditableArtifactWorkbenchProps) {\n const sessionKey = browserSessionKey(options);\n const createSession = useCallback(() => createBrowserEditableArtifactSession(options), [options]);\n return (\n <EditableArtifactWorkbenchHost\n sessionKey={sessionKey}\n createSession={createSession}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n}\n\nfunction browserSessionKey(options: BrowserEditableArtifactWorkbenchOptions): string {\n const transport = options.transport\n ? {\n ...options.transport,\n // Credentials must not be copied into React lifecycle keys. The\n // authorization epoch is the explicit credential/grant rotation fence.\n headers: options.transport.headers\n ? Object.keys(options.transport.headers).sort()\n : undefined,\n }\n : null;\n return JSON.stringify(\n {\n baseUrl: options.baseUrl,\n workspaceId: options.workspaceId,\n artifact: { id: options.artifact.id, modality: options.artifact.modality },\n storageAuthority: options.storageAuthority,\n runtime: options.runtime,\n replicaId: options.replicaId ?? null,\n transport,\n },\n (_key, value: unknown) => (value instanceof URL ? value.href : value),\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/components/artifacts/visualization-assets.gen.ts","../src/components/artifacts/inline-html-document.ts","../src/components/artifacts/editable-artifact-workbench.tsx"],"sourcesContent":["// Generated by scripts/generate-visualization-assets.ts.\nexport const VISUALIZATION_CSS = \"/* Adapted from Codex visualize 1.0.32; shared with the OpenGeni visualization skill. */\\n:root {\\n color-scheme: light dark;\\n background-color: var(\\n --background,\\n var(--color-background-primary, light-dark(rgb(255 255 255), rgb(24 24 24)))\\n ) !important;\\n\\n /* Agent-facing contract; keep in sync with SKILL.md. */\\n --background: var(\\n --color-background-primary,\\n light-dark(rgb(255 255 255), rgb(24 24 24))\\n );\\n --foreground: var(\\n --color-text-primary,\\n light-dark(rgb(26 28 31), rgb(255 255 255))\\n );\\n --card: color-mix(in oklab, var(--foreground) 5%, var(--background));\\n --card-foreground: var(\\n --color-text-primary,\\n light-dark(rgb(26 28 31), rgb(255 255 255))\\n );\\n --popover: var(\\n --color-background-secondary,\\n light-dark(rgb(255 255 255), rgb(45 45 45))\\n );\\n --popover-foreground: var(\\n --color-text-primary,\\n light-dark(rgb(26 28 31), rgb(255 255 255))\\n );\\n --primary: var(\\n --color-text-info,\\n light-dark(rgb(51 156 255), rgb(131 195 255))\\n );\\n --primary-foreground: var(\\n --color-text-inverse,\\n light-dark(rgb(255 255 255), rgb(13 13 13))\\n );\\n --secondary: var(\\n --color-background-secondary,\\n light-dark(rgb(255 255 255 / 96%), rgb(54 54 54 / 96%))\\n );\\n --secondary-foreground: var(\\n --color-text-primary,\\n light-dark(rgb(26 28 31), rgb(255 255 255))\\n );\\n --muted: color-mix(in srgb, var(--foreground) 10%, transparent);\\n --muted-foreground: var(\\n --color-text-secondary,\\n light-dark(rgb(26 28 31 / 49.4%), rgb(255 255 255 / 49.8%))\\n );\\n --accent: var(\\n --color-background-info,\\n light-dark(rgb(229 242 255), rgb(13 39 63))\\n );\\n --accent-foreground: var(\\n --color-text-info,\\n light-dark(rgb(51 156 255), rgb(131 195 255))\\n );\\n --destructive: var(\\n --color-text-warning,\\n light-dark(rgb(226 85 7), rgb(255 133 73))\\n );\\n --border: var(\\n --color-border-secondary,\\n light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))\\n );\\n --input: var(\\n --color-border-primary,\\n light-dark(\\n rgb(26 28 31 / 11.8%),\\n color-mix(in oklab, rgb(0 0 0) 10%, transparent)\\n )\\n );\\n --ring: var(\\n --color-ring-primary,\\n light-dark(rgb(51 156 255), rgb(131 195 255 / 76%))\\n );\\n --font-size-base: var(--font-text-md-size, 14px);\\n --blue: light-dark(rgb(51 156 255), rgb(51 156 255));\\n --orange: light-dark(rgb(226 85 7), rgb(251 106 34));\\n --green: light-dark(rgb(0 162 64), rgb(64 201 119));\\n --red: light-dark(rgb(224 46 42), rgb(255 103 100));\\n --purple: light-dark(rgb(146 79 247), rgb(173 123 249));\\n --yellow: light-dark(rgb(255 195 0), rgb(255 210 64));\\n --viz-series-1: var(--primary);\\n --viz-series-2: light-dark(rgb(243 136 59), rgb(245 154 86));\\n --viz-series-3: light-dark(rgb(93 201 119), rgb(116 213 139));\\n --viz-series-4: light-dark(rgb(235 119 177), rgb(240 143 192));\\n --viz-series-5: light-dark(rgb(155 121 236), rgb(170 145 239));\\n --viz-series-6: light-dark(rgb(58 185 177), rgb(90 203 194));\\n\\n /* Internal implementation variables; not part of the agent contract. */\\n --font-sans: -apple-system, system-ui, \\\"Segoe UI\\\", sans-serif;\\n --font-mono:\\n ui-monospace, SFMono-Regular, \\\"SF Mono\\\", Menlo, Consolas, \\\"Liberation Mono\\\",\\n monospace;\\n --font-size-normal: max(11px, var(--font-size-base));\\n --font-size-tooltip: calc(var(--font-size-base) - 1px);\\n --font-size-small: max(11px, calc(var(--font-size-base) - 2px));\\n --font-size-h1: calc(var(--font-size-normal) * 1.7142857143);\\n --font-size-h2: calc(var(--font-size-normal) * 1.4285714286);\\n --font-size-h3: calc(var(--font-size-normal) * 1.2857142857);\\n --font-weight-normal: 430;\\n --font-weight-medium: 500;\\n --icon-size: 16px;\\n --line-height-normal: calc(var(--font-size-normal) * 1.5);\\n --line-height-tooltip: calc(var(--font-size-tooltip) * 1.4285714286);\\n --line-height-small: calc(var(--font-size-small) + 4px);\\n --corner-shape: round;\\n --radius: var(--border-radius-lg, 10px);\\n --radius-sm: calc(var(--radius) * 0.6);\\n --radius-md: calc(var(--radius) * 0.8);\\n --radius-lg: var(--radius);\\n --radius-2xl: calc(var(--radius) * 1.6);\\n --radius-full: 9999px;\\n --shadow-sm: 0 1px 2px -1px rgb(0 0 0 / 8%);\\n --checkmark-image: url(\\\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 17 17'%3E%3Cpath d='M 12.8961 3.64101C13.1297 3.41418 13.4984 3.37523 13.7779 3.56581C14.0571 3.75635 14.1554 4.11331 14.0299 4.41347L13.9615 4.53847L7.71151 13.7045C7.59411 13.8767 7.4063 13.9877 7.19881 14.0072C6.99136 14.0267 6.78564 13.9533 6.63826 13.806L2.88826 10.056L2.79842 9.9457C2.6192 9.67407 2.64927 9.30496 2.88826 9.06581C3.12738 8.82669 3.49647 8.79676 3.76815 8.97597L3.8785 9.06581L7.03084 12.2182L12.8053 3.74941L12.8961 3.64101Z'/%3E%3C/svg%3E\\\");\\n\\n /* Legacy aliases; not part of the current agent contract. */\\n --viz-bg: transparent;\\n --viz-panel: var(--card);\\n --viz-border: var(--border);\\n --viz-text: var(--foreground);\\n --viz-muted: var(--muted-foreground);\\n --viz-accent: var(--primary);\\n --viz-accent-text: var(--primary-foreground);\\n --viz-accent-bg: var(--accent);\\n --viz-font-size: var(--font-size-base);\\n --viz-warning: var(--destructive);\\n}\\n\\n:root[data-theme=\\\"light\\\"] {\\n color-scheme: light;\\n}\\n\\n:root[data-theme=\\\"dark\\\"] {\\n color-scheme: dark;\\n}\\n\\n* {\\n box-sizing: border-box;\\n}\\n\\nhtml > body {\\n /* Preserve MCP aliases for older inline renderers without creating :root cycles. */\\n --color-background-primary: var(\\n --background,\\n light-dark(rgb(255 255 255), rgb(24 24 24))\\n );\\n --color-text-primary: var(\\n --foreground,\\n light-dark(rgb(26 28 31), rgb(255 255 255))\\n );\\n --color-border-secondary: var(\\n --border,\\n light-dark(rgb(26 28 31 / 8%), rgb(255 255 255 / 8.2%))\\n );\\n\\n margin: 0;\\n padding: var(--visualize-paint-gutter, 16px);\\n color: var(--foreground);\\n background: transparent !important;\\n font-family: var(--font-sans) !important;\\n font-size: var(--font-size-normal);\\n font-weight: var(--font-weight-normal);\\n line-height: var(--line-height-normal);\\n}\\n\\na {\\n color: color-mix(in srgb, var(--viz-accent) 80%, var(--viz-text) 20%);\\n cursor: pointer;\\n font-weight: var(--font-weight-medium, 500);\\n text-decoration: none;\\n text-underline-offset: 2px;\\n}\\n\\na:is(:hover, :focus-visible) {\\n text-decoration-line: underline;\\n text-decoration-style: dashed;\\n text-decoration-thickness: 0.5px;\\n}\\n\\nh1,\\nh2,\\nh3,\\nh4,\\nh5,\\nh6,\\np {\\n margin-block: 0;\\n}\\n\\nh1 {\\n font-size: var(--font-size-h1);\\n font-weight: var(--font-weight-medium);\\n line-height: 1.25;\\n}\\n\\nh2 {\\n font-size: var(--font-size-h2);\\n font-weight: var(--font-weight-medium);\\n line-height: 1.25;\\n}\\n\\nh3,\\nh4,\\nh5,\\nh6 {\\n font-size: var(--font-size-h3);\\n font-weight: var(--font-weight-medium);\\n line-height: 1.3;\\n}\\n\\nb,\\nstrong,\\nth {\\n font-weight: var(--font-weight-medium);\\n}\\n\\ncode:not(pre code) {\\n display: inline;\\n padding: 1px 6px;\\n border-radius: var(--radius-sm);\\n corner-shape: var(--corner-shape);\\n background: var(--muted);\\n font-family: var(--font-mono);\\n font-size: 0.92em;\\n overflow-wrap: anywhere;\\n -webkit-box-decoration-break: clone;\\n box-decoration-break: clone;\\n word-break: break-word;\\n}\\n\\n.table-responsive {\\n width: 100%;\\n overflow-x: auto;\\n scrollbar-width: thin;\\n}\\n\\n.table {\\n width: 100%;\\n border-collapse: collapse;\\n color: var(--foreground);\\n font: inherit;\\n text-align: start;\\n}\\n\\n.table :is(th, td) {\\n padding-block: 10px;\\n padding-inline: 0 24px;\\n overflow-wrap: anywhere;\\n border-bottom: 1px solid var(--border);\\n text-align: start;\\n vertical-align: top;\\n}\\n\\n.table-responsive > .table :is(th, td) {\\n overflow-wrap: break-word;\\n}\\n\\n.table :is(th, td):last-child {\\n padding-inline-end: 0;\\n}\\n\\n.table :is(caption, thead th) {\\n font-weight: 600;\\n}\\n\\n.table thead th {\\n padding-block: 8px;\\n border-bottom-color: color-mix(in srgb, var(--foreground) 16%, transparent);\\n}\\n\\n.table tbody tr:last-child :is(th, td) {\\n border-bottom: 0;\\n}\\n\\n.table.table-sm :is(th, td) {\\n padding-block: 6px;\\n}\\n\\n.table.table-sm :is(th, td):not(:last-child) {\\n padding-inline-end: 16px;\\n}\\n\\n.table :is(.text-end, [align=\\\"right\\\"]) {\\n text-align: end;\\n font-variant-numeric: tabular-nums;\\n}\\n\\n.table :is(.text-center, [align=\\\"center\\\"]) {\\n text-align: center;\\n}\\n\\n.table .text-nowrap {\\n white-space: nowrap;\\n}\\n\\n#widget {\\n display: flex;\\n flex-direction: column;\\n gap: 12px;\\n width: 100%;\\n padding: 0;\\n background: transparent !important;\\n}\\n\\n.card {\\n min-width: 0;\\n padding: 12px;\\n overflow: hidden;\\n overflow-wrap: break-word;\\n border-radius: var(--radius-2xl);\\n corner-shape: var(--corner-shape);\\n color: var(--card-foreground);\\n background: var(--card);\\n}\\n\\n#widget > :not(.card, .progress) {\\n width: 100% !important;\\n max-width: none !important;\\n margin: 0 !important;\\n padding: 0 !important;\\n border: 0 !important;\\n border-radius: 0 !important;\\n background: transparent !important;\\n box-shadow: none !important;\\n}\\n\\n.tooltip {\\n position: fixed;\\n z-index: 50;\\n top: 0;\\n left: 0;\\n width: max-content;\\n max-width: min(\\n 20rem,\\n var(--tooltip-available-width, calc(100vw - 10px)),\\n calc(100vw - 10px)\\n );\\n max-height: min(\\n var(--tooltip-available-height, calc(100vh - 10px)),\\n calc(100vh - 10px)\\n );\\n padding: 4px 8px;\\n border: 1px solid var(--border);\\n border-radius: var(--radius-lg);\\n corner-shape: var(--corner-shape);\\n color: var(--popover-foreground);\\n background: var(--popover);\\n box-shadow: none;\\n font-size: var(--font-size-tooltip);\\n line-height: var(--line-height-tooltip);\\n overflow-wrap: break-word;\\n white-space: normal;\\n pointer-events: none;\\n user-select: none;\\n}\\n\\n.viz-grid {\\n display: grid;\\n grid-template-columns: repeat(auto-fit, minmax(max(180px, 24%), 1fr));\\n gap: 10px;\\n}\\n\\n.viz-stat {\\n display: flex;\\n flex-direction: column;\\n gap: 2px;\\n}\\n\\n.viz-stat-value {\\n font-size: var(--font-size-h2);\\n font-weight: var(--font-weight-medium);\\n line-height: 1.25;\\n}\\n\\n.viz-row {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: 10px;\\n}\\n\\nhr {\\n width: 100%;\\n height: 1px;\\n margin-block: 6px;\\n border: 0;\\n background: var(--border);\\n}\\n\\n.nav {\\n display: flex;\\n min-width: 0;\\n align-items: center;\\n gap: 4px;\\n}\\n\\n.progress {\\n display: flex;\\n height: 8px;\\n margin-block: calc((var(--line-height-normal, 1.5em) - 8px) / 2);\\n overflow: hidden;\\n border: 0;\\n border-radius: var(--radius-full);\\n background: var(--muted);\\n}\\n\\n.progress-bar:only-child {\\n border-radius: var(--radius-full);\\n}\\n\\n.progress-bar {\\n height: 100%;\\n flex-shrink: 0;\\n border: 0;\\n background: var(--viz-series-1);\\n}\\n\\n.viz-badge {\\n padding: 3px 8px;\\n border-radius: var(--radius-full);\\n color: var(--accent-foreground);\\n background: var(--accent);\\n font-weight: var(--font-weight-medium);\\n}\\n\\nsmall,\\n.text-small,\\n.viz-badge {\\n font-size: var(--font-size-small);\\n line-height: var(--line-height-small);\\n}\\n\\n.text-muted {\\n color: var(--muted-foreground);\\n}\\n\\n.tabular-nums {\\n font-variant-numeric: tabular-nums;\\n}\\n\\n.sr-only {\\n position: absolute;\\n width: 1px;\\n height: 1px;\\n padding: 0;\\n overflow: hidden;\\n clip: rect(0, 0, 0, 0);\\n white-space: nowrap;\\n border: 0;\\n}\\n\\n.viz-controls {\\n display: flex;\\n flex-wrap: wrap;\\n align-items: center;\\n gap: 8px;\\n}\\n\\n.viz-controls > .form-label {\\n display: grid;\\n min-width: min(100%, 260px);\\n flex: 1 1 280px;\\n grid-template-columns: minmax(0, 1fr) auto;\\n align-items: baseline;\\n gap: 2px 12px;\\n margin-bottom: 0;\\n}\\n\\n.viz-controls > .form-label > :is(.form-control, .form-range, .form-select) {\\n grid-column: 1 / -1;\\n}\\n\\n.btn,\\n.nav-link,\\n.form-check-input,\\n.form-control,\\n.form-range,\\n.form-select {\\n font: inherit;\\n}\\n\\n.btn,\\n.nav-link {\\n appearance: button;\\n display: inline-flex;\\n inline-size: fit-content;\\n max-inline-size: 100%;\\n min-height: 28px;\\n align-items: center;\\n justify-content: center;\\n gap: 4px;\\n margin: 0;\\n padding: 0 8px;\\n -webkit-app-region: no-drag;\\n border: 1px solid var(--input);\\n border-radius: var(--radius-lg);\\n corner-shape: var(--corner-shape);\\n color: var(--secondary-foreground);\\n background: var(--secondary);\\n cursor: var(--cursor-interaction, pointer);\\n text-align: center;\\n text-decoration: none;\\n white-space: nowrap;\\n user-select: none;\\n -webkit-font-smoothing: antialiased;\\n}\\n\\n.btn:is(.btn-block, .viz-tile) {\\n inline-size: 100%;\\n}\\n\\n.btn.viz-tile {\\n min-width: 0;\\n overflow-wrap: anywhere;\\n white-space: normal;\\n}\\n\\na.btn {\\n cursor: pointer;\\n text-decoration: none;\\n}\\n\\n.btn:not(:disabled):hover,\\n.nav-link:not(:disabled):not([aria-disabled=\\\"true\\\"]):hover {\\n background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\\n}\\n\\n.btn-primary {\\n border-color: transparent;\\n color: var(--primary-foreground);\\n background: var(--foreground);\\n background-clip: padding-box;\\n}\\n\\n.btn-primary .text-muted {\\n color: color-mix(in srgb, var(--primary-foreground) 50%, transparent);\\n}\\n\\n.btn-primary:not(:disabled):hover {\\n background: color-mix(in srgb, var(--foreground) 80%, transparent);\\n background-clip: padding-box;\\n}\\n\\n.btn-ghost {\\n border-color: transparent;\\n color: var(--muted-foreground);\\n background: transparent;\\n}\\n\\n.btn-ghost:not(:disabled):hover {\\n color: var(--foreground);\\n background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\\n}\\n\\n.nav-pills .nav-link {\\n min-width: 0;\\n border-color: transparent;\\n color: var(--muted-foreground);\\n background: transparent;\\n}\\n\\n.nav-justified .nav-link {\\n flex: 1 1 0;\\n overflow-wrap: anywhere;\\n white-space: normal;\\n}\\n\\n.nav-pills .nav-link.active {\\n color: var(--foreground);\\n background: var(--muted);\\n}\\n\\n.btn:disabled,\\n.nav-link:disabled,\\n.nav-link[aria-disabled=\\\"true\\\"] {\\n cursor: not-allowed;\\n opacity: 0.4;\\n}\\n\\n[data-lucide] {\\n stroke-width: 1.6;\\n}\\n\\n.form-label {\\n display: block;\\n margin-bottom: 6px;\\n color: var(--foreground);\\n}\\n\\n.form-control {\\n display: block;\\n width: 100%;\\n min-height: 28px;\\n padding: 0 8px;\\n outline: none;\\n border: 1px solid var(--input);\\n border-radius: var(--radius-lg);\\n corner-shape: var(--corner-shape);\\n color: var(--foreground);\\n background: var(--secondary);\\n}\\n\\n.form-control::placeholder {\\n color: var(--muted-foreground);\\n}\\n\\n.form-control[type=\\\"file\\\"] {\\n padding: 0;\\n overflow: hidden;\\n cursor: var(--cursor-interaction, pointer);\\n}\\n\\n.form-control[type=\\\"file\\\"]::file-selector-button {\\n min-height: 26px;\\n margin-right: 8px;\\n padding: 0 8px;\\n border: 0;\\n border-right: 1px solid var(--input);\\n color: var(--secondary-foreground);\\n background: var(--secondary);\\n cursor: inherit;\\n font: inherit;\\n}\\n\\n.form-control[type=\\\"file\\\"]:not(:disabled):hover::file-selector-button {\\n background: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\\n}\\n\\n.form-control-color[type=\\\"color\\\"] {\\n width: 40px;\\n height: 28px;\\n padding: 3px;\\n cursor: var(--cursor-interaction, pointer);\\n}\\n\\n.form-control-color[type=\\\"color\\\"]::-webkit-color-swatch-wrapper {\\n padding: 0;\\n}\\n\\n.form-control-color[type=\\\"color\\\"]::-webkit-color-swatch {\\n border: 0;\\n border-radius: calc(var(--radius-lg) - 4px);\\n corner-shape: var(--corner-shape);\\n}\\n\\ntextarea.form-control {\\n height: auto;\\n min-height: 72px;\\n padding: 8px 10px;\\n resize: vertical;\\n}\\n\\n.form-control:focus-visible {\\n border-color: var(--ring);\\n box-shadow: inset 0 0 0 1px var(--ring);\\n}\\n\\n.form-control:disabled,\\n.form-select:disabled {\\n cursor: not-allowed;\\n opacity: 0.4;\\n}\\n\\n.form-select {\\n appearance: none;\\n display: block;\\n width: 100%;\\n min-height: 28px;\\n margin: 0;\\n padding: 0 32px 0 8px;\\n outline: none;\\n border: 1px solid var(--input);\\n border-radius: var(--radius-lg);\\n corner-shape: var(--corner-shape);\\n color: var(--foreground);\\n background-color: var(--secondary);\\n background-image:\\n linear-gradient(45deg, transparent 50%, var(--muted-foreground) 50%),\\n linear-gradient(135deg, var(--muted-foreground) 50%, transparent 50%);\\n background-position:\\n calc(100% - 14px) 50%,\\n calc(100% - 10px) 50%;\\n background-repeat: no-repeat;\\n background-size: 4px 4px;\\n cursor: var(--cursor-interaction, default);\\n}\\n\\n.form-select:not(:disabled):hover {\\n background-color: color-mix(in srgb, var(--foreground) 6%, var(--secondary));\\n}\\n\\n.form-select:focus-visible {\\n border-color: var(--ring);\\n box-shadow: inset 0 0 0 1px var(--ring);\\n}\\n\\n.form-check {\\n display: flex;\\n min-height: 20px;\\n align-items: center;\\n gap: 6px;\\n}\\n\\n.form-check-input {\\n appearance: none;\\n width: 14px;\\n height: 14px;\\n flex: 0 0 auto;\\n margin: 0;\\n border: 1px solid var(--input);\\n color: var(--primary-foreground);\\n background-color: transparent;\\n cursor: var(--cursor-interaction, default);\\n transition:\\n background-color 150ms,\\n border-color 150ms,\\n box-shadow 150ms;\\n}\\n\\n.form-check:not(.form-switch) .form-check-input[type=\\\"checkbox\\\"] {\\n border-color: var(--input);\\n border-radius: var(--radius-sm);\\n corner-shape: var(--corner-shape);\\n background-color: var(--secondary);\\n box-shadow: var(--shadow-sm);\\n}\\n\\n.form-check:not(.form-switch)\\n .form-check-input:not(:disabled):not(:checked):hover {\\n background-color: var(--card);\\n}\\n\\n.form-check:not(.form-switch) .form-check-input[type=\\\"checkbox\\\"]:checked {\\n border-color: var(--primary);\\n background-color: var(--primary);\\n}\\n\\n.form-check:not(.form-switch)\\n .form-check-input[type=\\\"checkbox\\\"]:checked::before {\\n display: block;\\n width: 100%;\\n height: 100%;\\n background: var(--primary-foreground);\\n content: \\\"\\\";\\n mask: var(--checkmark-image) center / 12px 12px no-repeat;\\n}\\n\\n.form-check-input[type=\\\"radio\\\"] {\\n width: 14px;\\n height: 14px;\\n border-radius: var(--radius-full);\\n}\\n\\n.form-check-input[type=\\\"radio\\\"]:checked {\\n border: 2px solid var(--primary);\\n background:\\n radial-gradient(circle, var(--primary-foreground) 0 2.5px, transparent 3px),\\n var(--primary);\\n}\\n\\n.form-check:not(.form-switch) .form-check-input:focus-visible {\\n outline: 2px solid var(--ring);\\n outline-offset: 2px;\\n}\\n\\n.form-check:not(.form-switch) .form-check-input:disabled {\\n cursor: not-allowed;\\n pointer-events: none;\\n}\\n\\n.form-check:not(.form-switch) .form-check-input:disabled + .form-check-label {\\n cursor: not-allowed;\\n}\\n\\n.form-switch .form-check-input:disabled,\\n.form-switch .form-check-input:disabled + .form-check-label {\\n cursor: not-allowed;\\n opacity: 0.6;\\n}\\n\\n.form-check-label {\\n color: var(--foreground);\\n cursor: var(--cursor-interaction, default);\\n}\\n\\n.form-switch .form-check-input {\\n position: relative;\\n width: 32px;\\n height: 20px;\\n border: 0;\\n border-radius: var(--radius-full);\\n background: var(--muted);\\n box-shadow: none;\\n transition: background-color 200ms cubic-bezier(0, 0, 0.2, 1);\\n}\\n\\n.form-switch .form-check-input::before {\\n position: absolute;\\n top: 50%;\\n left: 0;\\n width: 16px;\\n height: 16px;\\n box-sizing: border-box;\\n border: 1px solid light-dark(var(--primary-foreground), var(--foreground));\\n border-radius: var(--radius-full);\\n background: light-dark(var(--primary-foreground), var(--foreground));\\n box-shadow: var(--shadow-sm);\\n content: \\\"\\\";\\n transform: translate(2px, -50%);\\n transition: transform 200ms cubic-bezier(0, 0, 0.2, 1);\\n}\\n\\n.form-switch .form-check-input:checked {\\n background: var(--primary);\\n}\\n\\n.form-switch .form-check-input:checked::before {\\n transform: translate(14px, -50%);\\n}\\n\\n.form-switch .form-check-input:focus-visible {\\n box-shadow: 0 0 0 2px var(--ring);\\n}\\n\\n.form-range {\\n appearance: none;\\n display: block;\\n width: 100%;\\n height: 28px;\\n flex: 1;\\n margin: 0;\\n padding: 0;\\n outline: none;\\n border: 0;\\n accent-color: var(--primary);\\n background: linear-gradient(\\n color-mix(in srgb, var(--foreground) 7%, transparent),\\n color-mix(in srgb, var(--foreground) 7%, transparent)\\n )\\n center / 100% 2px no-repeat;\\n}\\n\\n.form-range::-webkit-slider-runnable-track {\\n height: 28px;\\n background: transparent;\\n}\\n\\n.form-range::-webkit-slider-thumb {\\n appearance: none;\\n width: 20px;\\n height: 20px;\\n margin-top: 4px;\\n border: 1px solid var(--border);\\n border-radius: var(--radius-full);\\n background: light-dark(var(--primary-foreground), var(--foreground));\\n}\\n\\n.form-range:focus-visible::-webkit-slider-thumb {\\n border-color: var(--ring);\\n box-shadow: inset 0 0 0 1px var(--ring);\\n}\\n\\n.form-range::-moz-range-track {\\n height: 28px;\\n background: transparent;\\n}\\n\\n.form-range::-moz-range-thumb {\\n width: 20px;\\n height: 20px;\\n border: 1px solid var(--border);\\n border-radius: var(--radius-full);\\n background: light-dark(var(--primary-foreground), var(--foreground));\\n}\\n\\n.form-range:focus-visible::-moz-range-thumb {\\n border-color: var(--ring);\\n box-shadow: inset 0 0 0 1px var(--ring);\\n}\\n\\n.form-range:disabled {\\n cursor: not-allowed;\\n opacity: 0.4;\\n}\\n\\n.btn:not(.btn-primary, .viz-tile):is(\\n [aria-pressed=\\\"true\\\"],\\n [aria-selected=\\\"true\\\"],\\n .is-selected\\n) {\\n border-color: var(--primary);\\n color: var(--primary-foreground);\\n background: var(--primary);\\n}\\n\\n.btn.viz-tile:is([aria-pressed=\\\"true\\\"], [aria-selected=\\\"true\\\"], .is-selected) {\\n border-color: var(--primary);\\n box-shadow: inset 0 0 0 1px var(--primary);\\n}\\n\\n.btn:focus-visible,\\n.nav-link:focus-visible {\\n outline: 2px solid var(--ring);\\n outline-offset: 2px;\\n}\\n\\n@media (pointer: coarse) {\\n .btn,\\n .nav-link,\\n .form-control,\\n .form-select {\\n min-width: 44px;\\n min-height: 44px;\\n }\\n\\n /* Keep small-screen WebKit from zooming when a text field receives focus. */\\n .form-control,\\n .form-select {\\n font-size: max(16px, var(--font-size-normal));\\n }\\n\\n .form-control[type=\\\"file\\\"]::file-selector-button {\\n min-width: 44px;\\n min-height: 44px;\\n }\\n\\n .form-control-color[type=\\\"color\\\"] {\\n width: 44px;\\n height: 44px;\\n }\\n\\n .form-control:is(\\n [type=\\\"date\\\"],\\n [type=\\\"datetime-local\\\"],\\n [type=\\\"month\\\"],\\n [type=\\\"time\\\"],\\n [type=\\\"week\\\"]\\n ) {\\n min-width: 0;\\n max-width: 100%;\\n padding-block: 8px;\\n }\\n\\n .form-check {\\n min-height: 44px;\\n padding-inline: 15px;\\n }\\n\\n .form-check-input {\\n position: relative;\\n }\\n\\n .form-check-input::after {\\n position: absolute;\\n top: 50%;\\n left: 50%;\\n width: 44px;\\n height: 44px;\\n content: \\\"\\\";\\n transform: translate(-50%, -50%);\\n }\\n\\n .form-check-label {\\n display: inline-flex;\\n min-width: 44px;\\n min-height: 44px;\\n align-items: center;\\n }\\n\\n .form-range {\\n height: 44px;\\n touch-action: pan-y;\\n }\\n\\n .form-range::-webkit-slider-runnable-track {\\n height: 44px;\\n }\\n\\n .form-range::-moz-range-track {\\n height: 44px;\\n }\\n\\n .form-range::-webkit-slider-thumb {\\n margin-top: 12px;\\n }\\n}\\n\\nsvg {\\n display: block;\\n max-width: 100%;\\n height: auto;\\n}\\n\\n#widget > svg {\\n width: 100%;\\n}\\n\\n/* Model-authored chart rules can otherwise stretch icons after these styles load. */\\nsvg.lucide {\\n display: block;\\n width: var(--icon-size) !important;\\n height: var(--icon-size) !important;\\n flex: none;\\n margin: 0 !important;\\n stroke-width: 1.6;\\n}\\n\\n.text-warning,\\n.text-destructive {\\n color: var(--destructive);\\n}\\n\";\nexport const VISUALIZATION_HELPERS = \"\\n<script src=\\\"https://unpkg.com/@floating-ui/core@1.7.3/dist/floating-ui.core.umd.min.js\\\"></script>\\n<script src=\\\"https://unpkg.com/@floating-ui/dom@1.7.4/dist/floating-ui.dom.umd.min.js\\\"></script>\\n<script>\\n (() => {\\n if (window.FloatingUIDOM == null) {\\n return;\\n }\\n const { autoUpdate, computePosition, flip, offset, shift, size } = window.FloatingUIDOM;\\n const tooltipPlacements = new Set([\\\"top\\\", \\\"right\\\", \\\"bottom\\\", \\\"left\\\"]);\\n const tooltipId = `codex-visualization-tooltip-${\\n window.crypto?.randomUUID?.() ?? Date.now().toString(36)\\n }`;\\n const tooltipGap = 5;\\n const hoverDelay = 700;\\n const skipDelay = 300;\\n let activeTrigger = null;\\n let pendingTrigger = null;\\n let tooltip = null;\\n let openTimeout = null;\\n let autoUpdateCleanup = null;\\n let positionRequest = 0;\\n let skipDelayUntil = 0;\\n let lastPointerWasTouch = false;\\n let pinnedByTouch = false;\\n\\n const getTrigger = (target) =>\\n target?.nodeType === Node.ELEMENT_NODE ? target.closest(\\\"[data-tooltip]\\\") : null;\\n const containsTarget = (trigger, target) =>\\n target?.nodeType != null && trigger.contains(target);\\n const getContent = (trigger) => trigger.getAttribute(\\\"data-tooltip\\\")?.trim() ?? \\\"\\\";\\n const getPlacement = (trigger) => {\\n const placement = trigger.getAttribute(\\\"data-tooltip-placement\\\");\\n return tooltipPlacements.has(placement) ? placement : \\\"top\\\";\\n };\\n const getTooltip = () => {\\n if (tooltip == null) {\\n tooltip = document.createElement(\\\"div\\\");\\n tooltip.id = tooltipId;\\n tooltip.className = \\\"tooltip\\\";\\n tooltip.setAttribute(\\\"role\\\", \\\"tooltip\\\");\\n }\\n return tooltip;\\n };\\n const setDescribedBy = (trigger, described) => {\\n const ids = new Set(\\n (trigger.getAttribute(\\\"aria-describedby\\\") ?? \\\"\\\").split(/\\\\s+/).filter(Boolean),\\n );\\n if (described) {\\n ids.add(tooltipId);\\n } else {\\n ids.delete(tooltipId);\\n }\\n if (ids.size === 0) {\\n trigger.removeAttribute(\\\"aria-describedby\\\");\\n } else {\\n trigger.setAttribute(\\\"aria-describedby\\\", [...ids].join(\\\" \\\"));\\n }\\n };\\n const clearOpenTimeout = () => {\\n if (openTimeout != null) {\\n window.clearTimeout(openTimeout);\\n openTimeout = null;\\n }\\n pendingTrigger = null;\\n };\\n const closeTooltip = (activateSkipDelay = true) => {\\n clearOpenTimeout();\\n pinnedByTouch = false;\\n positionRequest += 1;\\n autoUpdateCleanup?.();\\n autoUpdateCleanup = null;\\n if (activeTrigger == null) {\\n return;\\n }\\n setDescribedBy(activeTrigger, false);\\n activeTrigger = null;\\n tooltip?.remove();\\n if (activateSkipDelay) {\\n skipDelayUntil = Date.now() + skipDelay;\\n }\\n };\\n const updatePosition = (trigger, floating) => {\\n const request = ++positionRequest;\\n void computePosition(trigger, floating, {\\n middleware: [\\n offset(tooltipGap),\\n flip({ padding: tooltipGap }),\\n shift({ padding: tooltipGap }),\\n size({\\n padding: tooltipGap,\\n apply({ availableHeight, availableWidth, elements }) {\\n elements.floating.style.setProperty(\\n \\\"--tooltip-available-width\\\",\\n `${Math.max(0, availableWidth)}px`,\\n );\\n elements.floating.style.setProperty(\\n \\\"--tooltip-available-height\\\",\\n `${Math.max(0, availableHeight)}px`,\\n );\\n },\\n }),\\n ],\\n placement: getPlacement(trigger),\\n strategy: \\\"fixed\\\",\\n })\\n .then(({ x, y }) => {\\n if (activeTrigger !== trigger || request !== positionRequest) {\\n return;\\n }\\n const scale = window.devicePixelRatio || 1;\\n floating.style.transform = `translate(${Math.round(x * scale) / scale}px, ${Math.round(y * scale) / scale}px)`;\\n floating.style.visibility = \\\"visible\\\";\\n })\\n .catch(() => {\\n if (activeTrigger === trigger && request === positionRequest) {\\n closeTooltip(false);\\n }\\n });\\n };\\n const openTooltip = (trigger) => {\\n const content = getContent(trigger);\\n if (!trigger.isConnected || content.length === 0) {\\n return;\\n }\\n clearOpenTimeout();\\n if (activeTrigger === trigger) {\\n return;\\n }\\n closeTooltip();\\n const floating = getTooltip();\\n floating.textContent = content;\\n floating.style.visibility = \\\"hidden\\\";\\n floating.style.transform = \\\"translate(0, 0)\\\";\\n document.body.appendChild(floating);\\n activeTrigger = trigger;\\n setDescribedBy(trigger, true);\\n autoUpdateCleanup = autoUpdate(trigger, floating, () => {\\n updatePosition(trigger, floating);\\n });\\n };\\n const requestOpen = (trigger, immediate = false) => {\\n if (\\n getContent(trigger).length === 0 ||\\n activeTrigger === trigger ||\\n pendingTrigger === trigger\\n ) {\\n return;\\n }\\n clearOpenTimeout();\\n pendingTrigger = trigger;\\n const delay =\\n immediate || activeTrigger != null || Date.now() < skipDelayUntil ? 0 : hoverDelay;\\n if (delay === 0) {\\n openTooltip(trigger);\\n return;\\n }\\n openTimeout = window.setTimeout(() => {\\n openTimeout = null;\\n pendingTrigger = null;\\n openTooltip(trigger);\\n }, delay);\\n };\\n const handlePointerOpen = (event) => {\\n if (event.pointerType === \\\"touch\\\") {\\n return;\\n }\\n const trigger = getTrigger(event.target);\\n if (trigger == null || containsTarget(trigger, event.relatedTarget)) {\\n return;\\n }\\n requestOpen(trigger);\\n };\\n const handlePointer = (event) => {\\n lastPointerWasTouch = event.type === \\\"pointerdown\\\" && event.pointerType === \\\"touch\\\";\\n };\\n const handleTouchClick = (event) => {\\n const isTouch = event.pointerType === \\\"touch\\\" || lastPointerWasTouch;\\n lastPointerWasTouch = false;\\n if (!isTouch || event.detail === 0) {\\n return;\\n }\\n const trigger = getTrigger(event.target);\\n if (\\n trigger == null ||\\n !trigger.isConnected ||\\n getContent(trigger).length === 0 ||\\n (pinnedByTouch && activeTrigger === trigger)\\n ) {\\n if (pinnedByTouch) {\\n closeTooltip();\\n }\\n return;\\n }\\n openTooltip(trigger);\\n pinnedByTouch = activeTrigger === trigger;\\n window.setTimeout(() => {\\n if (activeTrigger === trigger && !trigger.isConnected) {\\n closeTooltip(false);\\n }\\n }, 0);\\n };\\n const handleLeave = (event) => {\\n if (pinnedByTouch) {\\n return;\\n }\\n const trigger = getTrigger(event.target);\\n if (trigger == null || containsTarget(trigger, event.relatedTarget)) {\\n return;\\n }\\n if (activeTrigger === trigger || pendingTrigger === trigger) {\\n closeTooltip();\\n }\\n };\\n const handleFocusIn = (event) => {\\n const trigger = getTrigger(event.target);\\n if (trigger?.matches(\\\":focus-visible\\\")) {\\n requestOpen(trigger, true);\\n }\\n };\\n const handleKeyDown = (event) => {\\n if (event.key === \\\"Escape\\\") {\\n closeTooltip();\\n }\\n };\\n const handleContextMenu = (event) => {\\n lastPointerWasTouch = false;\\n const trigger = getTrigger(event.target);\\n if (activeTrigger === trigger || pendingTrigger === trigger) {\\n closeTooltip();\\n }\\n };\\n const destroy = () => {\\n closeTooltip(false);\\n lastPointerWasTouch = false;\\n document.removeEventListener(\\\"pointerover\\\", handlePointerOpen);\\n document.removeEventListener(\\\"pointerdown\\\", handlePointer);\\n document.removeEventListener(\\\"pointercancel\\\", handlePointer);\\n document.removeEventListener(\\\"click\\\", handleTouchClick);\\n document.removeEventListener(\\\"pointerout\\\", handleLeave);\\n document.removeEventListener(\\\"focusin\\\", handleFocusIn);\\n document.removeEventListener(\\\"focusout\\\", handleLeave);\\n document.removeEventListener(\\\"keydown\\\", handleKeyDown);\\n document.removeEventListener(\\\"contextmenu\\\", handleContextMenu);\\n tooltip = null;\\n };\\n\\n document.addEventListener(\\\"pointerover\\\", handlePointerOpen);\\n document.addEventListener(\\\"pointerdown\\\", handlePointer);\\n document.addEventListener(\\\"pointercancel\\\", handlePointer);\\n document.addEventListener(\\\"click\\\", handleTouchClick);\\n document.addEventListener(\\\"pointerout\\\", handleLeave);\\n document.addEventListener(\\\"focusin\\\", handleFocusIn);\\n document.addEventListener(\\\"focusout\\\", handleLeave);\\n document.addEventListener(\\\"keydown\\\", handleKeyDown);\\n document.addEventListener(\\\"contextmenu\\\", handleContextMenu);\\n window.addEventListener(\\\"pagehide\\\", destroy, { once: true });\\n })();\\n</script>\\n<script id=\\\"codex-visualization-tabs\\\">\\n (() => {\\n const selector = '.nav[role=\\\"tablist\\\"] [role=\\\"tab\\\"]';\\n const disabled = ':disabled,[aria-disabled=\\\"true\\\"]';\\n const selectTab = (selected) => {\\n const panelId = selected.getAttribute(\\\"aria-controls\\\");\\n for (const tab of selected.closest('[role=\\\"tablist\\\"]').querySelectorAll('[role=\\\"tab\\\"]')) {\\n const active = tab === selected;\\n tab.classList.toggle(\\\"active\\\", active);\\n tab.setAttribute(\\\"aria-selected\\\", String(active));\\n const id = tab.getAttribute(\\\"aria-controls\\\");\\n const panel = id && document.getElementById(id);\\n if (panel != null) {\\n panel.hidden = id !== panelId;\\n if (!panel.hidden && selected.id) {\\n panel.setAttribute(\\\"aria-labelledby\\\", selected.id);\\n }\\n }\\n }\\n };\\n const interact = (event) => {\\n const tab = event.target?.closest?.(selector);\\n if (event.defaultPrevented || tab == null || tab.matches(disabled)) {\\n return;\\n }\\n if (event.type === \\\"click\\\") {\\n selectTab(tab);\\n return;\\n }\\n const tabs = Array.from(\\n tab.closest('[role=\\\"tablist\\\"]').querySelectorAll('[role=\\\"tab\\\"]'),\\n ).filter((candidate) => !candidate.matches(disabled));\\n const current = tabs.indexOf(tab);\\n let next;\\n if (event.key === \\\"ArrowRight\\\" || event.key === \\\"ArrowDown\\\") {\\n next = (current + 1) % tabs.length;\\n } else if (event.key === \\\"ArrowLeft\\\" || event.key === \\\"ArrowUp\\\") {\\n next = (current + tabs.length - 1) % tabs.length;\\n } else if (event.key === \\\"Home\\\") {\\n next = 0;\\n } else if (event.key === \\\"End\\\") {\\n next = tabs.length - 1;\\n } else {\\n return;\\n }\\n event.preventDefault();\\n tabs[next].focus();\\n selectTab(tabs[next]);\\n };\\n\\n for (const list of document.querySelectorAll('.nav[role=\\\"tablist\\\"]')) {\\n const selected =\\n list.querySelector('[role=\\\"tab\\\"][aria-selected=\\\"true\\\"]') ??\\n list.querySelector('[role=\\\"tab\\\"].active') ??\\n list.querySelector('[role=\\\"tab\\\"]');\\n if (selected != null) {\\n selectTab(selected);\\n }\\n }\\n document.addEventListener(\\\"click\\\", interact);\\n document.addEventListener(\\\"keydown\\\", interact);\\n window.addEventListener(\\n \\\"pagehide\\\",\\n () => {\\n document.removeEventListener(\\\"click\\\", interact);\\n document.removeEventListener(\\\"keydown\\\", interact);\\n },\\n { once: true },\\n );\\n })();\\n</script>\\n<script\\n id=\\\"codex-visualization-lucide\\\"\\n async\\n src=\\\"https://unpkg.com/lucide@1.17.0/dist/umd/lucide.js\\\"\\n></script>\\n<script>\\n (() => {\\n const initialize = () => {\\n globalThis.lucide?.createIcons({ attrs: { width: 16, height: 16 } });\\n };\\n if (globalThis.lucide != null) {\\n initialize();\\n return;\\n }\\n document\\n .getElementById(\\\"codex-visualization-lucide\\\")\\n ?.addEventListener(\\\"load\\\", initialize, { once: true });\\n })();\\n</script>\\n\";\n","import { VISUALIZATION_CSS, VISUALIZATION_HELPERS } from \"./visualization-assets.gen\";\n\n/** Conversation styling/helpers only. Rendering and tool transport remain in the Site frame. */\nexport function inlineHtmlDocument(fragment: string): string {\n return (\n '<!doctype html><html><head><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\"><style>' +\n VISUALIZATION_CSS +\n \"</style><style>html,body{margin:0;min-height:0}body{padding:16px;box-sizing:border-box}</style></head><body>\" +\n fragment +\n VISUALIZATION_HELPERS +\n `<script>\n(()=>{\n window.addEventListener('message',event=>{\n if(event.source!==parent||event.data?.type!=='opengeni.preview.theme')return;\n if(event.data.theme==='light'||event.data.theme==='dark')document.documentElement.style.colorScheme=event.data.theme;\n previous=0;resize();\n });\n let previous=0;\n const resize=()=>{const height=Math.ceil(document.body.getBoundingClientRect().height);if(height!==previous){previous=height;parent.postMessage({type:'opengeni.preview.height',height},'*')}};\n new ResizeObserver(resize).observe(document.body);resize();\n})();\n</script></body></html>`\n );\n}\n","import {\n createBrowserEditableArtifactSession,\n type CreateBrowserEditableArtifactSessionOptions,\n type EditableArtifactBrowserRuntime,\n type EditableArtifactSession,\n} from \"@opengeni/sdk/editable-artifacts\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { EditableArtifactMessage } from \"./editable-artifact-ui\";\nimport {\n EditableDocumentArtifactSurface,\n type EditableDocumentArtifactSurfaceProps,\n} from \"./editable-document\";\nimport {\n EditablePresentationArtifactSurface,\n type EditablePresentationArtifactSurfaceProps,\n} from \"./editable-presentation\";\nimport {\n EditableSpreadsheetArtifactSurface,\n type EditableSpreadsheetArtifactSurfaceProps,\n} from \"./editable-spreadsheet\";\n\nexport type EditableArtifactWorkbenchProps = Readonly<{\n session: EditableArtifactSession;\n document?: Omit<EditableDocumentArtifactSurfaceProps, \"session\">;\n spreadsheet?: Omit<EditableSpreadsheetArtifactSurfaceProps, \"session\">;\n presentation?: Omit<EditablePresentationArtifactSurfaceProps, \"session\">;\n}>;\n\nexport type EditableArtifactWorkbenchHostProps = Omit<EditableArtifactWorkbenchProps, \"session\"> &\n Readonly<{\n /**\n * Complete identity of the browser session authority. Change this when the\n * artifact, deployment, principal, or authorization epoch changes.\n */\n sessionKey: string;\n /** Called for the active keyed lifecycle and again only after replacement or retry. */\n createSession: () => EditableArtifactSession;\n }>;\n\ntype DefaultBrowserArtifactTransport = Omit<\n NonNullable<CreateBrowserEditableArtifactSessionOptions[\"transport\"]>,\n \"apiKey\" | \"fetch\" | \"headers\" | \"webSocketFactory\"\n> &\n Readonly<{\n /** Static deployment auth headers; rotate authorizationEpoch when they change. */\n headers?: Readonly<Record<string, string>>;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchOptions = Omit<\n CreateBrowserEditableArtifactSessionOptions,\n \"runtime\" | \"storage\" | \"transport\"\n> &\n Readonly<{\n /** Default module Worker only; custom Worker hosts use EditableArtifactWorkbenchHost. */\n runtime: Omit<EditableArtifactBrowserRuntime, \"workerFactory\">;\n /** Default fetch/WebSocket only; static deployment auth headers are supported. */\n transport?: DefaultBrowserArtifactTransport;\n }>;\n\nexport type BrowserEditableArtifactWorkbenchProps = Omit<\n EditableArtifactWorkbenchProps,\n \"session\"\n> &\n Readonly<{ options: BrowserEditableArtifactWorkbenchOptions }>;\n\n/**\n * One modality-neutral SDK workbench. Embedding hosts keep one route/component;\n * each artifact still renders through its complete first-party editor surface.\n */\nexport function EditableArtifactWorkbench({\n session,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchProps) {\n switch (session.modality) {\n case \"document\":\n return (\n <EditableDocumentArtifactSurface\n {...document}\n session={session}\n title={document?.title ?? \"Document\"}\n />\n );\n case \"spreadsheet\":\n return <EditableSpreadsheetArtifactSurface {...spreadsheet} session={session} />;\n case \"presentation\":\n return <EditablePresentationArtifactSurface {...presentation} session={session} />;\n }\n}\n\n/**\n * Route/embed composition that owns exactly one SDK session. The host supplies\n * the authenticated SDK factory; React guarantees replacement and teardown.\n */\nexport function EditableArtifactWorkbenchHost({\n sessionKey,\n createSession,\n document,\n spreadsheet,\n presentation,\n}: EditableArtifactWorkbenchHostProps) {\n const createSessionRef = useRef(createSession);\n const [retryEpoch, setRetryEpoch] = useState(0);\n const [state, setState] = useState<\n | Readonly<{ key: string; session: EditableArtifactSession; error: null }>\n | Readonly<{ key: string | null; session: null; error: Error | null }>\n >({ key: null, session: null, error: null });\n\n useEffect(() => {\n createSessionRef.current = createSession;\n }, [createSession]);\n\n useEffect(() => {\n let owned: EditableArtifactSession | null = null;\n setState({ key: sessionKey, session: null, error: null });\n try {\n owned = createSessionRef.current();\n setState({ key: sessionKey, session: owned, error: null });\n } catch (cause) {\n setState({\n key: sessionKey,\n session: null,\n error: cause instanceof Error ? cause : new Error(\"Could not create artifact session\"),\n });\n }\n return () => {\n const closing = owned;\n owned = null;\n if (closing) void closing.close().catch(() => undefined);\n };\n }, [retryEpoch, sessionKey]);\n\n const retry = useCallback(() => setRetryEpoch((value) => value + 1), []);\n const currentError = state.key === sessionKey ? state.error : null;\n if (state.key === sessionKey && state.session) {\n return (\n <EditableArtifactWorkbench\n session={state.session}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n }\n return (\n <EditableArtifactMessage\n title={currentError ? \"Could not open this artifact\" : \"Opening artifact\"}\n detail={currentError?.message ?? \"Starting the secure editing session…\"}\n retry={currentError ? retry : undefined}\n />\n );\n}\n\n/**\n * Complete default-browser composition for embedders: verified WASM Worker,\n * durable IndexedDB state, authenticated live sync, teardown, and the matching\n * first-party editor. Advanced/custom transports compose the lower-level host.\n */\nexport function BrowserEditableArtifactWorkbench({\n options,\n document,\n spreadsheet,\n presentation,\n}: BrowserEditableArtifactWorkbenchProps) {\n const sessionKey = browserSessionKey(options);\n const createSession = useCallback(() => createBrowserEditableArtifactSession(options), [options]);\n return (\n <EditableArtifactWorkbenchHost\n sessionKey={sessionKey}\n createSession={createSession}\n {...(document ? { document } : {})}\n {...(spreadsheet ? { spreadsheet } : {})}\n {...(presentation ? { presentation } : {})}\n />\n );\n}\n\nfunction browserSessionKey(options: BrowserEditableArtifactWorkbenchOptions): string {\n const transport = options.transport\n ? {\n ...options.transport,\n // Credentials must not be copied into React lifecycle keys. The\n // authorization epoch is the explicit credential/grant rotation fence.\n headers: options.transport.headers\n ? Object.keys(options.transport.headers).sort()\n : undefined,\n }\n : null;\n return JSON.stringify(\n {\n baseUrl: options.baseUrl,\n workspaceId: options.workspaceId,\n artifact: { id: options.artifact.id, modality: options.artifact.modality },\n storageAuthority: options.storageAuthority,\n runtime: options.runtime,\n replicaId: options.replicaId ?? null,\n transport,\n },\n (_key, value: unknown) => (value instanceof URL ? value.href : value),\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACO,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAC1B,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","names":[]}
@@ -0,0 +1,73 @@
1
+ // src/timeline/retained-image.ts
2
+ import { useEffect, useRef, useState } from "react";
3
+ function useRetainedImageObjectUrl(artifact, load) {
4
+ const [state, setState] = useState({ kind: "loading" });
5
+ const artifactValue = retainedArtifactValue(artifact);
6
+ const stableArtifactRef = useRef({ value: artifactValue, artifact });
7
+ if (stableArtifactRef.current.value !== artifactValue) {
8
+ stableArtifactRef.current = { value: artifactValue, artifact };
9
+ }
10
+ const stableArtifact = stableArtifactRef.current.artifact;
11
+ useEffect(() => {
12
+ if (!load) {
13
+ setState({ kind: "unavailable", label: "retrieval is not configured" });
14
+ return;
15
+ }
16
+ const controller = new AbortController();
17
+ let objectUrl = null;
18
+ setState({ kind: "loading" });
19
+ void load(stableArtifact, controller.signal).then((source) => {
20
+ if (controller.signal.aborted) return;
21
+ if (!source) {
22
+ setState({ kind: "unavailable", label: "bytes are unavailable" });
23
+ return;
24
+ }
25
+ if (!(source instanceof Uint8Array)) {
26
+ if (!source.url.trim()) {
27
+ setState({ kind: "unavailable", label: "URL is unavailable" });
28
+ return;
29
+ }
30
+ setState({ kind: "ready", url: source.url });
31
+ return;
32
+ }
33
+ objectUrl = URL.createObjectURL(
34
+ new Blob([source], { type: stableArtifact.contentType })
35
+ );
36
+ setState({ kind: "ready", url: objectUrl });
37
+ }).catch((error) => {
38
+ if (controller.signal.aborted) return;
39
+ const status = error && typeof error === "object" && "status" in error ? Number(error.status) : null;
40
+ setState(
41
+ status === 404 ? { kind: "unavailable", label: "deleted" } : status === 410 ? { kind: "unavailable", label: "expired or unavailable" } : { kind: "error", message: "retrieval failed" }
42
+ );
43
+ });
44
+ return () => {
45
+ controller.abort();
46
+ if (objectUrl) URL.revokeObjectURL(objectUrl);
47
+ };
48
+ }, [stableArtifact, load]);
49
+ return state;
50
+ }
51
+ function retainedArtifactValue(artifact) {
52
+ return [
53
+ artifact.artifactId,
54
+ artifact.kind,
55
+ artifact.contentType,
56
+ artifact.originalBytes,
57
+ artifact.sha256,
58
+ artifact.retainedAt,
59
+ artifact.dimensions?.width ?? "",
60
+ artifact.dimensions?.height ?? "",
61
+ artifact.retention.policy,
62
+ artifact.retention.expiresAt ?? "",
63
+ artifact.retrieval.method,
64
+ artifact.retrieval.path,
65
+ artifact.retrieval.acceptRanges,
66
+ artifact.retrieval.maxRangeBytes
67
+ ].join("\0");
68
+ }
69
+
70
+ export {
71
+ useRetainedImageObjectUrl
72
+ };
73
+ //# sourceMappingURL=chunk-2TKI3WEG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/timeline/retained-image.ts"],"sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type { RetainedArtifactReference } from \"@opengeni/sdk\";\nimport type { ToolRendererProps } from \"./registry\";\ntype RetainedImageState =\n | { kind: \"loading\" }\n | { kind: \"ready\"; url: string }\n | { kind: \"unavailable\"; label: string }\n | { kind: \"error\"; message: string };\n\nexport function useRetainedImageObjectUrl(\n artifact: RetainedArtifactReference,\n load: ToolRendererProps[\"loadRetainedArtifact\"],\n): RetainedImageState {\n const [state, setState] = useState<RetainedImageState>({ kind: \"loading\" });\n // Function outputs are commonly serialized JSON. Parsing them creates a new\n // object on every render, so depend on the immutable wire value rather than\n // object identity; otherwise the loader can refetch after its own setState.\n const artifactValue = retainedArtifactValue(artifact);\n const stableArtifactRef = useRef({ value: artifactValue, artifact });\n if (stableArtifactRef.current.value !== artifactValue) {\n stableArtifactRef.current = { value: artifactValue, artifact };\n }\n const stableArtifact = stableArtifactRef.current.artifact;\n useEffect(() => {\n if (!load) {\n setState({ kind: \"unavailable\", label: \"retrieval is not configured\" });\n return;\n }\n const controller = new AbortController();\n let objectUrl: string | null = null;\n setState({ kind: \"loading\" });\n void load(stableArtifact, controller.signal)\n .then((source) => {\n if (controller.signal.aborted) return;\n if (!source) {\n setState({ kind: \"unavailable\", label: \"bytes are unavailable\" });\n return;\n }\n if (!(source instanceof Uint8Array)) {\n if (!source.url.trim()) {\n setState({ kind: \"unavailable\", label: \"URL is unavailable\" });\n return;\n }\n setState({ kind: \"ready\", url: source.url });\n return;\n }\n objectUrl = URL.createObjectURL(\n new Blob([source as unknown as BlobPart], { type: stableArtifact.contentType }),\n );\n setState({ kind: \"ready\", url: objectUrl });\n })\n .catch((error: unknown) => {\n if (controller.signal.aborted) return;\n const status =\n error && typeof error === \"object\" && \"status\" in error\n ? Number((error as { status?: unknown }).status)\n : null;\n setState(\n status === 404\n ? { kind: \"unavailable\", label: \"deleted\" }\n : status === 410\n ? { kind: \"unavailable\", label: \"expired or unavailable\" }\n : { kind: \"error\", message: \"retrieval failed\" },\n );\n });\n return () => {\n controller.abort();\n if (objectUrl) URL.revokeObjectURL(objectUrl);\n };\n }, [stableArtifact, load]);\n return state;\n}\n\nfunction retainedArtifactValue(artifact: RetainedArtifactReference): string {\n return [\n artifact.artifactId,\n artifact.kind,\n artifact.contentType,\n artifact.originalBytes,\n artifact.sha256,\n artifact.retainedAt,\n artifact.dimensions?.width ?? \"\",\n artifact.dimensions?.height ?? \"\",\n artifact.retention.policy,\n artifact.retention.expiresAt ?? \"\",\n artifact.retrieval.method,\n artifact.retrieval.path,\n artifact.retrieval.acceptRanges,\n artifact.retrieval.maxRangeBytes,\n ].join(\"\\0\");\n}\n"],"mappings":";AAAA,SAAS,WAAW,QAAQ,gBAAgB;AASrC,SAAS,0BACd,UACA,MACoB;AACpB,QAAM,CAAC,OAAO,QAAQ,IAAI,SAA6B,EAAE,MAAM,UAAU,CAAC;AAI1E,QAAM,gBAAgB,sBAAsB,QAAQ;AACpD,QAAM,oBAAoB,OAAO,EAAE,OAAO,eAAe,SAAS,CAAC;AACnE,MAAI,kBAAkB,QAAQ,UAAU,eAAe;AACrD,sBAAkB,UAAU,EAAE,OAAO,eAAe,SAAS;AAAA,EAC/D;AACA,QAAM,iBAAiB,kBAAkB,QAAQ;AACjD,YAAU,MAAM;AACd,QAAI,CAAC,MAAM;AACT,eAAS,EAAE,MAAM,eAAe,OAAO,8BAA8B,CAAC;AACtE;AAAA,IACF;AACA,UAAM,aAAa,IAAI,gBAAgB;AACvC,QAAI,YAA2B;AAC/B,aAAS,EAAE,MAAM,UAAU,CAAC;AAC5B,SAAK,KAAK,gBAAgB,WAAW,MAAM,EACxC,KAAK,CAAC,WAAW;AAChB,UAAI,WAAW,OAAO,QAAS;AAC/B,UAAI,CAAC,QAAQ;AACX,iBAAS,EAAE,MAAM,eAAe,OAAO,wBAAwB,CAAC;AAChE;AAAA,MACF;AACA,UAAI,EAAE,kBAAkB,aAAa;AACnC,YAAI,CAAC,OAAO,IAAI,KAAK,GAAG;AACtB,mBAAS,EAAE,MAAM,eAAe,OAAO,qBAAqB,CAAC;AAC7D;AAAA,QACF;AACA,iBAAS,EAAE,MAAM,SAAS,KAAK,OAAO,IAAI,CAAC;AAC3C;AAAA,MACF;AACA,kBAAY,IAAI;AAAA,QACd,IAAI,KAAK,CAAC,MAA6B,GAAG,EAAE,MAAM,eAAe,YAAY,CAAC;AAAA,MAChF;AACA,eAAS,EAAE,MAAM,SAAS,KAAK,UAAU,CAAC;AAAA,IAC5C,CAAC,EACA,MAAM,CAAC,UAAmB;AACzB,UAAI,WAAW,OAAO,QAAS;AAC/B,YAAM,SACJ,SAAS,OAAO,UAAU,YAAY,YAAY,QAC9C,OAAQ,MAA+B,MAAM,IAC7C;AACN;AAAA,QACE,WAAW,MACP,EAAE,MAAM,eAAe,OAAO,UAAU,IACxC,WAAW,MACT,EAAE,MAAM,eAAe,OAAO,yBAAyB,IACvD,EAAE,MAAM,SAAS,SAAS,mBAAmB;AAAA,MACrD;AAAA,IACF,CAAC;AACH,WAAO,MAAM;AACX,iBAAW,MAAM;AACjB,UAAI,UAAW,KAAI,gBAAgB,SAAS;AAAA,IAC9C;AAAA,EACF,GAAG,CAAC,gBAAgB,IAAI,CAAC;AACzB,SAAO;AACT;AAEA,SAAS,sBAAsB,UAA6C;AAC1E,SAAO;AAAA,IACL,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS;AAAA,IACT,SAAS,YAAY,SAAS;AAAA,IAC9B,SAAS,YAAY,UAAU;AAAA,IAC/B,SAAS,UAAU;AAAA,IACnB,SAAS,UAAU,aAAa;AAAA,IAChC,SAAS,UAAU;AAAA,IACnB,SAAS,UAAU;AAAA,IACnB,SAAS,UAAU;AAAA,IACnB,SAAS,UAAU;AAAA,EACrB,EAAE,KAAK,IAAI;AACb;","names":[]}
@@ -11,7 +11,7 @@ import {
11
11
  import {
12
12
  shouldSteerOnKey,
13
13
  shouldSubmitOnKey
14
- } from "./chunk-6J56T3MG.js";
14
+ } from "./chunk-NYESIADM.js";
15
15
  import {
16
16
  composerSubmissionErrorMessage,
17
17
  formatBytes,
@@ -4836,4 +4836,4 @@ export {
4836
4836
  useVoiceInput,
4837
4837
  ComposerTranscriptionControl
4838
4838
  };
4839
- //# sourceMappingURL=chunk-V3WX3TQG.js.map
4839
+ //# sourceMappingURL=chunk-45XEUVTK.js.map
@@ -111,11 +111,19 @@ function CopyHoverFrame({
111
111
  {
112
112
  "data-og-annotation-chrome": "",
113
113
  className: cn(
114
- "mt-1 flex h-7 items-center gap-1.5",
114
+ "flex h-6 items-center gap-1.5 pointer-coarse:h-11",
115
115
  align === "end" ? "justify-end" : "justify-start"
116
116
  ),
117
117
  children: [
118
- /* @__PURE__ */ jsx(CopyButton, { text: copyText, label, reveal: "group-hover" }),
118
+ /* @__PURE__ */ jsx(
119
+ CopyButton,
120
+ {
121
+ text: copyText,
122
+ label,
123
+ reveal: "group-hover",
124
+ className: "size-6 pointer-coarse:size-11"
125
+ }
126
+ ),
119
127
  trailing
120
128
  ]
121
129
  }
@@ -126,6 +134,8 @@ function CopyHoverFrame({
126
134
  // src/components/markdown.tsx
127
135
  import {
128
136
  Children,
137
+ createContext,
138
+ useContext,
129
139
  isValidElement,
130
140
  memo,
131
141
  useEffect as useEffect2,
@@ -419,7 +429,8 @@ function rehypeStreamReveal(options) {
419
429
  }
420
430
 
421
431
  // src/components/markdown.tsx
422
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
432
+ import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
433
+ var InteractiveContext = createContext({ source: "" });
423
434
  var baseComponents = {
424
435
  h1: ({ children, ...props }) => /* @__PURE__ */ jsx2(
425
436
  "h1",
@@ -506,7 +517,7 @@ var baseComponents = {
506
517
  }
507
518
  ),
508
519
  // Fenced code — quiet mono block (no card / no nested vertical scroll).
509
- pre: ({ children }) => /* @__PURE__ */ jsx2(MarkdownCodeBlock, { children }),
520
+ pre: InteractiveCodeBlock,
510
521
  // Tables stay unboxed (hairline rules); hover reveals a TSV copy control.
511
522
  table: ({ children, ...props }) => /* @__PURE__ */ jsx2(MarkdownTable, { ...props, children }),
512
523
  thead: ({ children, ...props }) => /* @__PURE__ */ jsx2("thead", { ...props, children }),
@@ -526,15 +537,7 @@ var baseComponents = {
526
537
  children
527
538
  }
528
539
  ),
529
- img: ({ alt, src, ...props }) => src ? /* @__PURE__ */ jsx2(
530
- "img",
531
- {
532
- alt: alt ?? "",
533
- src,
534
- className: "my-3 max-w-full rounded-og-md border border-og-border",
535
- ...props
536
- }
537
- ) : alt ? /* @__PURE__ */ jsx2("span", { className: "text-og-fg-subtle", "aria-disabled": "true", children: alt }) : null
540
+ img: MarkdownImage
538
541
  };
539
542
  var MARKDOWN_LINK_CLASS = "break-words font-medium text-og-accent-strong underline-offset-2 hover:underline";
540
543
  function markdownComponents(onSandboxFile) {
@@ -644,7 +647,20 @@ function sandboxFileLocationFromHref(href) {
644
647
  function sandboxFilePathFromHref(href) {
645
648
  return sandboxFileLocationFromHref(href)?.path ?? null;
646
649
  }
647
- var markdownUrlTransform = (url, key, node) => key === "href" && node.tagName === "a" && isSandboxHref(url) ? url : defaultUrlTransform(url);
650
+ function retainedImageId(src) {
651
+ return /^artifact:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i.exec(src)?.[1]?.toLowerCase() ?? null;
652
+ }
653
+ function MarkdownImage({ src, alt }) {
654
+ const { renderImage } = useContext(InteractiveContext);
655
+ if (!src) return /* @__PURE__ */ jsx2("span", { children: alt ?? "Image unavailable" });
656
+ if (retainedImageId(src))
657
+ return renderImage ? /* @__PURE__ */ jsx2(Fragment, { children: renderImage({ src, alt: alt ?? "" }) }) : /* @__PURE__ */ jsxs2("span", { children: [
658
+ alt || "Image",
659
+ " (preview unavailable)"
660
+ ] });
661
+ return /* @__PURE__ */ jsx2("img", { src, alt: alt ?? "", loading: "lazy", className: "my-3 max-w-full rounded-og-md" });
662
+ }
663
+ var markdownUrlTransform = (url, key, node) => key === "href" && node.tagName === "a" && isSandboxHref(url) || key === "src" && node.tagName === "img" && retainedImageId(url) ? url : defaultUrlTransform(url);
648
664
  var REVEAL_LINGER_MS = 480 * MOTION_INSPECT_SCALE;
649
665
  var MARKDOWN_SETTLE_MS = 480 * MOTION_INSPECT_SCALE;
650
666
  function nodeText(node) {
@@ -675,6 +691,25 @@ function fenceLanguage(children) {
675
691
  });
676
692
  return found;
677
693
  }
694
+ function InteractiveCodeBlock({ children, node }) {
695
+ const { source, render } = useContext(InteractiveContext);
696
+ const language = fenceLanguage(children);
697
+ if (render && (language === "opengeni-html" || language === "opengeni-site")) {
698
+ const start = node?.position?.start.offset;
699
+ const end = node?.position?.end.offset;
700
+ const original = start !== void 0 && end !== void 0 && end <= source.length ? source.slice(start, end) : "";
701
+ const lines = original.trimEnd().split("\n");
702
+ const opening = lines[0]?.match(/^ {0,3}([\x60]{3,}|~{3,})/);
703
+ const closing = lines.at(-1)?.replace(/^\s*(?:>\s*)+/, "").trim();
704
+ const complete = opening && lines.length > 1 && closing && closing.length >= opening[1].length && [...closing].every((c) => c === opening[1][0]);
705
+ if (!complete) return /* @__PURE__ */ jsx2("p", { role: "status", children: "Preparing preview\u2026" });
706
+ return /* @__PURE__ */ jsx2(Fragment, { children: render({
707
+ kind: language === "opengeni-html" ? "html" : "site",
708
+ content: nodeText(children).replace(/\n$/, "")
709
+ }) });
710
+ }
711
+ return /* @__PURE__ */ jsx2(MarkdownCodeBlock, { children });
712
+ }
678
713
  function MarkdownCodeBlock({ children }) {
679
714
  const code = nodeText(children).replace(/\n$/, "");
680
715
  const language = fenceLanguage(children);
@@ -735,7 +770,14 @@ function MarkdownTable({ children, className, ...props }) {
735
770
  ) })
736
771
  ] });
737
772
  }
738
- function MarkdownImpl({ children, className, streaming = false, onSandboxFile }) {
773
+ function MarkdownImpl({
774
+ children,
775
+ className,
776
+ streaming = false,
777
+ onSandboxFile,
778
+ renderInteractiveBlock,
779
+ renderImage
780
+ }) {
739
781
  const revealRef = useRef2(null);
740
782
  const bodyRef = useRef2(null);
741
783
  const [, bump] = useReducer((n) => n + 1, 0);
@@ -799,7 +841,15 @@ function MarkdownImpl({ children, className, streaming = false, onSandboxFile })
799
841
  }, [streaming]);
800
842
  const parseText = streaming || revealActive ? softenStreamingMarkdown(children) : children;
801
843
  const components = useMemo(() => markdownComponents(onSandboxFile), [onSandboxFile]);
802
- return /* @__PURE__ */ jsx2(TooltipProvider, { delayDuration: 400, children: /* @__PURE__ */ jsx2(
844
+ const interactiveContext = useMemo(
845
+ () => ({
846
+ source: children,
847
+ ...renderInteractiveBlock ? { render: renderInteractiveBlock } : {},
848
+ ...renderImage ? { renderImage } : {}
849
+ }),
850
+ [children, renderInteractiveBlock, renderImage]
851
+ );
852
+ return /* @__PURE__ */ jsx2(InteractiveContext.Provider, { value: interactiveContext, children: /* @__PURE__ */ jsx2(TooltipProvider, { delayDuration: 400, children: /* @__PURE__ */ jsx2(
803
853
  "div",
804
854
  {
805
855
  ref: bodyRef,
@@ -819,7 +869,7 @@ function MarkdownImpl({ children, className, streaming = false, onSandboxFile })
819
869
  }
820
870
  )
821
871
  }
822
- ) });
872
+ ) }) });
823
873
  }
824
874
  var Markdown = memo(MarkdownImpl);
825
875
 
@@ -830,6 +880,7 @@ export {
830
880
  CopyHoverFrame,
831
881
  sandboxFileLocationFromHref,
832
882
  sandboxFilePathFromHref,
883
+ retainedImageId,
833
884
  Markdown
834
885
  };
835
- //# sourceMappingURL=chunk-M2HNWZYR.js.map
886
+ //# sourceMappingURL=chunk-IHQII5WO.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/components/copy-button.tsx","../src/components/markdown.tsx","../src/lib/motion.ts","../src/lib/motion-inspect.ts","../src/components/soften-streaming-markdown.ts","../src/components/stream-reveal.ts"],"sourcesContent":["import { CheckIcon, CopyIcon } from \"lucide-react\";\nimport { useEffect, useRef, useState, type MouseEvent, type ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { copyTextToClipboard } from \"../lib/clipboard\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"./tooltip\";\n\nconst COPIED_MS = 1600;\n\nexport type CopyButtonProps = {\n /** Plain text to copy, or a lazy getter (tables / late DOM). */\n text: string | (() => string);\n /** Accessible name + tooltip while idle. */\n label?: string | undefined;\n className?: string | undefined;\n /**\n * `always` — visible control.\n * `group-hover` — parent must use `group/copy`; fades in on hover/focus-visible.\n */\n reveal?: \"always\" | \"group-hover\" | undefined;\n};\n\n/**\n * Ghost icon copy control — no chrome box, no \"Copy code\" label.\n * Copy → check flash. Hover-reveal via `group/copy` on a parent.\n */\nexport function CopyButton({\n text,\n label = \"Copy\",\n className,\n reveal = \"group-hover\",\n}: CopyButtonProps) {\n const [copied, setCopied] = useState(false);\n const [tipOpen, setTipOpen] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n useEffect(() => {\n return () => {\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n };\n }, []);\n\n const onClick = async (event: MouseEvent<HTMLButtonElement>) => {\n event.preventDefault();\n event.stopPropagation();\n // Capture before any await: React nulls `currentTarget` after the\n // synchronous handler turn. Blurring via the stale target throws and used\n // to skip the copied-reset timer, leaving the tip stuck on \"Copied\".\n const button = event.currentTarget;\n const pointerActivated = event.detail > 0;\n const value = typeof text === \"function\" ? text() : text;\n const ok = await copyTextToClipboard(value);\n if (!ok) {\n return;\n }\n setCopied(true);\n setTipOpen(true);\n if (timerRef.current !== null) {\n clearTimeout(timerRef.current);\n }\n // Always arm the reset before blur — a throw here must not leave the\n // forced \"Copied\" tip open forever.\n timerRef.current = setTimeout(() => {\n timerRef.current = null;\n setCopied(false);\n setTipOpen(false);\n }, COPIED_MS);\n // Pointer activation focuses the button and leaves `group-focus-within`\n // stuck after the cursor leaves — chrome never \"unhovers\". Keyboard\n // activation (`detail === 0`) keeps focus for a11y.\n if (pointerActivated) {\n button.blur();\n }\n };\n\n const tip = copied ? \"Copied\" : label;\n\n return (\n <Tooltip\n open={copied ? true : tipOpen}\n onOpenChange={(next) => {\n if (!copied) {\n setTipOpen(next);\n }\n }}\n >\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n data-og-copy=\"\"\n data-state={copied ? \"copied\" : \"idle\"}\n aria-label={tip}\n onClick={onClick}\n className={cn(\n \"inline-flex size-7 shrink-0 items-center justify-center rounded-og-sm pointer-coarse:size-11\",\n \"text-og-fg-subtle transition-[opacity,color,background-color] duration-150\",\n \"hover:bg-og-surface-2/80 hover:text-og-fg\",\n \"focus-visible:opacity-100 focus-visible:outline-hidden focus-visible:ring-2 focus-visible:ring-og-accent/40\",\n reveal === \"group-hover\" &&\n \"opacity-0 group-hover/copy:opacity-100 group-focus-within/copy:opacity-100 pointer-coarse:opacity-70\",\n copied && \"opacity-100 text-og-accent\",\n className,\n )}\n >\n {copied ? (\n <CheckIcon className=\"size-3.5\" aria-hidden />\n ) : (\n <CopyIcon className=\"size-3.5\" aria-hidden />\n )}\n </button>\n </TooltipTrigger>\n <TooltipContent side=\"top\">{tip}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** Hover-reveal chrome around a message / turn so {@link CopyButton} can fade in. */\nexport function CopyHoverFrame({\n children,\n className,\n copyText,\n label,\n align = \"end\",\n trailing,\n}: {\n children: ReactNode;\n className?: string | undefined;\n copyText: string;\n label: string;\n align?: \"start\" | \"end\" | undefined;\n /** Optional footer meta (e.g. sent/finished clock) — immediately after the copy control. */\n trailing?: ReactNode | undefined;\n}) {\n if (copyText.trim().length === 0) {\n return <div className={className}>{children}</div>;\n }\n return (\n <div className={cn(\"group/copy\", className)}>\n {children}\n {/* Sit under the body — top-right overlay collided with the first line. */}\n <div\n data-og-annotation-chrome=\"\"\n className={cn(\n \"flex h-6 items-center gap-1.5 pointer-coarse:h-11\",\n align === \"end\" ? \"justify-end\" : \"justify-start\",\n )}\n >\n <CopyButton\n text={copyText}\n label={label}\n reveal=\"group-hover\"\n className=\"size-6 pointer-coarse:size-11\"\n />\n {trailing}\n </div>\n </div>\n );\n}\n","import {\n Children,\n createContext,\n useContext,\n isValidElement,\n memo,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n type ComponentPropsWithoutRef,\n type ReactNode,\n} from \"react\";\nimport ReactMarkdown, {\n defaultUrlTransform,\n type Components,\n type ExtraProps,\n type UrlTransform,\n} from \"react-markdown\";\nimport remarkGfm from \"remark-gfm\";\nimport { cn } from \"../lib/cn\";\nimport { tableElementToTsv } from \"../lib/clipboard\";\nimport { prefersReducedMotion } from \"../lib/motion\";\nimport { MOTION_INSPECT_SCALE } from \"../lib/motion-inspect\";\nimport { CopyButton } from \"./copy-button\";\nimport type { observeMarkdownTableLayout } from \"./markdown-table-layout\";\nimport { softenStreamingMarkdown } from \"./soften-streaming-markdown\";\nimport { createStreamReveal, rehypeStreamReveal, type StreamReveal } from \"./stream-reveal\";\nimport { TooltipProvider } from \"./tooltip\";\n\n/**\n * The default renderer for chat message bodies in {@link MessageTimeline}.\n *\n * Agent (and user) messages arrive as GitHub-flavored markdown. This turns the\n * raw text into styled HTML using `react-markdown` + `remark-gfm`, themed to the\n * package's `og-*` design tokens so it reads as one cohesive dark surface — no\n * stock Tailwind colors leak in.\n *\n * It re-parses on every render, which is exactly right for streaming: a body\n * that is still arriving (an unterminated `**`, a half-open code fence, a table\n * mid-row) renders as best-effort markdown and resolves cleanly as the rest of\n * the tokens land. Consumers who want a different renderer can still pass\n * `renderMessageText` to `MessageTimeline` to override this entirely.\n */\nexport type MarkdownInteractiveBlock = { kind: \"html\" | \"site\"; content: string };\nconst InteractiveContext = createContext<{\n source: string;\n render?: (block: MarkdownInteractiveBlock) => ReactNode;\n renderImage?: (image: { src: string; alt: string }) => ReactNode;\n}>({ source: \"\" });\n\nexport type MarkdownProps = {\n renderImage?: ((image: { src: string; alt: string }) => ReactNode) | undefined;\n /** Host opt-in for assistant-authored interactive fences. */\n renderInteractiveBlock?: ((block: MarkdownInteractiveBlock) => ReactNode) | undefined;\n children: string;\n className?: string | undefined;\n /**\n * While true, newly arrived source fades in through tip ink (`.og-stream-ink`):\n * an age window over each append batch — fast streams keep a large soft band,\n * slow streams a tight tip. Paint-only: the DOM always holds the full truthful\n * text. Once streaming ends and trailing ink settles, the body re-renders as\n * plain markdown with a short local settle breath (no page-wide view\n * transition — that blinked the whole document).\n */\n streaming?: boolean | undefined;\n /**\n * Open a session-local file link in the host's Files surface. The path is the\n * exact decoded `sandbox:` payload; `line`, when present, is 1-based.\n */\n onSandboxFile?: ((path: string, line?: number) => void | Promise<void>) | undefined;\n};\n\n/** Exact target path plus optional 1-based line from a markdown href. */\nexport type SandboxFileLocation = {\n path: string;\n line: number | null;\n};\n\n/* --- element renderers (themed to og-* tokens) ------------------------------ */\n\nconst baseComponents: Components = {\n h1: ({ children, ...props }) => (\n <h1\n className=\"mt-5 mb-2.5 text-xl font-semibold tracking-tight text-og-fg first:mt-0\"\n {...props}\n >\n {children}\n </h1>\n ),\n h2: ({ children, ...props }) => (\n <h2 className=\"mt-5 mb-2 text-lg font-semibold tracking-tight text-og-fg first:mt-0\" {...props}>\n {children}\n </h2>\n ),\n h3: ({ children, ...props }) => (\n <h3\n className=\"mt-4 mb-1.5 text-og-md font-semibold tracking-tight text-og-fg first:mt-0\"\n {...props}\n >\n {children}\n </h3>\n ),\n h4: ({ children, ...props }) => (\n <h4\n className=\"mt-4 mb-1.5 text-og-sm font-semibold uppercase tracking-[0.04em] text-og-fg-muted first:mt-0\"\n {...props}\n >\n {children}\n </h4>\n ),\n p: ({ children, ...props }) => (\n <p className=\"my-2.5 leading-7 first:mt-0 last:mb-0\" {...props}>\n {children}\n </p>\n ),\n strong: ({ children, ...props }) => (\n <strong className=\"font-semibold text-og-fg\" {...props}>\n {children}\n </strong>\n ),\n em: ({ children, ...props }) => (\n <em className=\"italic\" {...props}>\n {children}\n </em>\n ),\n ul: ({ children, ...props }) => (\n <ul\n className=\"my-2.5 ml-5 flex list-disc flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </ul>\n ),\n ol: ({ children, ...props }) => (\n <ol\n className=\"my-2.5 ml-5 flex list-decimal flex-col gap-1 marker:text-og-fg-subtle first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </ol>\n ),\n // GFM task-list items carry a leading checkbox <input>; `list-none` + a\n // negative margin pull the checkbox back to the bullet column so it aligns\n // with the text.\n li: ({ children, ...props }) => (\n <li\n className=\"leading-7 marker:text-og-fg-subtle [&>ul]:my-1 [&>ol]:my-1 [&:has(>input)]:list-none [&:has(>input)]:-ml-5\"\n {...props}\n >\n {children}\n </li>\n ),\n input: ({ type, ...props }) =>\n type === \"checkbox\" ? (\n <input\n {...props}\n type=\"checkbox\"\n disabled\n className=\"mr-2 size-3.5 translate-y-[2px] cursor-default accent-og-accent align-baseline\"\n />\n ) : (\n <input type={type} {...props} />\n ),\n blockquote: ({ children, ...props }) => (\n <blockquote\n className=\"my-3 border-l-2 border-og-border-strong pl-3.5 text-og-fg-muted [&>p]:my-1.5 first:mt-0 last:mb-0\"\n {...props}\n >\n {children}\n </blockquote>\n ),\n hr: (props) => <hr className=\"my-4 border-0 border-t border-og-border\" {...props} />,\n // Inline `code` vs fenced code blocks. react-markdown v10 no longer passes an\n // `inline` flag; a fenced block is a <code> whose parent is <pre> (styled by\n // the `pre` renderer), so a `code` reaching here is treated as inline.\n code: ({ children, className: _className, ...props }) => (\n <code\n className=\"rounded-og-xs bg-og-surface-1 px-1 py-0.5 font-og-mono text-og-sm text-og-fg\"\n {...props}\n >\n {children}\n </code>\n ),\n // Fenced code — quiet mono block (no card / no nested vertical scroll).\n pre: InteractiveCodeBlock,\n // Tables stay unboxed (hairline rules); hover reveals a TSV copy control.\n table: ({ children, ...props }) => <MarkdownTable {...props}>{children}</MarkdownTable>,\n thead: ({ children, ...props }) => <thead {...props}>{children}</thead>,\n th: ({ children, ...props }) => (\n <th\n className=\"border-b border-og-border px-0 py-1.5 pr-4 text-left font-medium text-og-fg first:pl-0\"\n {...props}\n >\n {children}\n </th>\n ),\n td: ({ children, ...props }) => (\n <td\n className=\"border-b border-og-border/70 px-0 py-1.5 pr-4 align-top text-og-fg-muted [tr:last-child>&]:border-b-0\"\n {...props}\n >\n {children}\n </td>\n ),\n img: MarkdownImage,\n};\n\nconst MARKDOWN_LINK_CLASS =\n \"break-words font-medium text-og-accent-strong underline-offset-2 hover:underline\";\n\nfunction markdownComponents(onSandboxFile: MarkdownProps[\"onSandboxFile\"]): Components {\n return {\n ...baseComponents,\n a: ({ children, href, ...props }) => {\n const location = sandboxFileLocationFromHref(href);\n if (location !== null) {\n return (\n <SandboxMarkdownLink location={location} onSandboxFile={onSandboxFile}>\n {children}\n </SandboxMarkdownLink>\n );\n }\n if (isSandboxHref(href) || !href) {\n return (\n <span\n className=\"break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2\"\n aria-disabled=\"true\"\n title={\n isSandboxHref(href)\n ? \"This sandbox file reference is invalid\"\n : \"This link is unavailable\"\n }\n >\n {children}\n </span>\n );\n }\n return (\n <a\n className={MARKDOWN_LINK_CLASS}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n href={href}\n {...props}\n >\n {children}\n </a>\n );\n },\n };\n}\n\nfunction SandboxMarkdownLink({\n location,\n onSandboxFile,\n children,\n}: {\n location: SandboxFileLocation;\n onSandboxFile: MarkdownProps[\"onSandboxFile\"];\n children: ReactNode;\n}) {\n const [state, setState] = useState<\"idle\" | \"loading\" | \"error\">(\"idle\");\n const { path, line } = location;\n if (!onSandboxFile) {\n return (\n <span\n className=\"break-words font-medium text-og-fg-subtle underline decoration-dotted underline-offset-2\"\n aria-disabled=\"true\"\n title=\"This sandbox file requires a session-aware handler\"\n >\n {children}\n </span>\n );\n }\n const idleTitle = line !== null ? `Open ${path} at line ${line}` : `Open ${path}`;\n return (\n <button\n type=\"button\"\n className={cn(\n MARKDOWN_LINK_CLASS,\n \"inline-flex min-h-7 cursor-pointer items-center disabled:cursor-wait disabled:opacity-70 pointer-coarse:min-h-11\",\n )}\n disabled={state === \"loading\"}\n aria-busy={state === \"loading\"}\n title={state === \"error\" ? \"Couldn't open this file. Select to retry.\" : idleTitle}\n onClick={() => {\n setState(\"loading\");\n void Promise.resolve(onSandboxFile(path, line ?? undefined)).then(\n () => setState(\"idle\"),\n () => setState(\"error\"),\n );\n }}\n >\n {children}\n {state === \"loading\" ? \" (opening…)\" : state === \"error\" ? \" (retry)\" : null}\n </button>\n );\n}\n\nconst SANDBOX_SCHEME = \"sandbox:\";\nconst LEGACY_WORKSPACE_PREFIX = \"/workspace/\";\nconst TRAILING_LINE = /:([0-9]+)$/u;\nconst TRAILING_INVALID_LINE = /:-(?:[0-9]+)$|:[0-9]+-[0-9]+$/u;\nconst CONTROL_CHARACTER = /[\\u0000-\\u001f\\u007f]/u;\n\nfunction isSandboxHref(href: string | undefined): boolean {\n return href?.startsWith(SANDBOX_SCHEME) ?? false;\n}\n\n/**\n * Parse an OpenGeni `sandbox:` application href (plus the historical bare\n * `/workspace/...` form). The decoded path is intentionally opaque here:\n * target selection, path policy, and filesystem authority belong to the\n * session-aware host and its FileSystem boundary.\n */\nexport function sandboxFileLocationFromHref(href: string | undefined): SandboxFileLocation | null {\n if (!href) return null;\n const encodedLocation = isSandboxHref(href)\n ? href.slice(SANDBOX_SCHEME.length)\n : href.startsWith(LEGACY_WORKSPACE_PREFIX)\n ? href\n : null;\n if (!encodedLocation || encodedLocation.includes(\"?\") || encodedLocation.includes(\"#\")) {\n return null;\n }\n if (TRAILING_INVALID_LINE.test(encodedLocation)) return null;\n const lineMatch = TRAILING_LINE.exec(encodedLocation);\n const encodedPath = lineMatch ? encodedLocation.slice(0, -lineMatch[0].length) : encodedLocation;\n const line = lineMatch?.[1] ? Number(lineMatch[1]) : null;\n if (line !== null && (!Number.isSafeInteger(line) || line < 1)) return null;\n if (!encodedPath) return null;\n try {\n const path = decodeURIComponent(encodedPath);\n return path && !CONTROL_CHARACTER.test(path) ? { path, line } : null;\n } catch {\n return null;\n }\n}\n\n/** Return the exact decoded path for a supported sandbox-link href. */\nexport function sandboxFilePathFromHref(href: string | undefined): string | null {\n return sandboxFileLocationFromHref(href)?.path ?? null;\n}\n\nexport function retainedImageId(src: string): string | null {\n return (\n /^artifact:([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i\n .exec(src)?.[1]\n ?.toLowerCase() ?? null\n );\n}\nfunction MarkdownImage({ src, alt }: ComponentPropsWithoutRef<\"img\">) {\n const { renderImage } = useContext(InteractiveContext);\n if (!src) return <span>{alt ?? \"Image unavailable\"}</span>;\n if (retainedImageId(src))\n return renderImage ? (\n <>{renderImage({ src, alt: alt ?? \"\" })}</>\n ) : (\n <span>{alt || \"Image\"} (preview unavailable)</span>\n );\n return <img src={src} alt={alt ?? \"\"} loading=\"lazy\" className=\"my-3 max-w-full rounded-og-md\" />;\n}\n\nconst markdownUrlTransform: UrlTransform = (url, key, node) =>\n (key === \"href\" && node.tagName === \"a\" && isSandboxHref(url)) ||\n (key === \"src\" && node.tagName === \"img\" && retainedImageId(url))\n ? url\n : defaultUrlTransform(url);\n\n/** How long after the stream ends the reveal pipeline stays for trailing animations. */\n/** Trailing ink window after stream end — keep ≥ {@link INK_FADE_MS}. */\nconst REVEAL_LINGER_MS = 480 * MOTION_INSPECT_SCALE;\n/** Keep in sync with `--og-duration-markdown-crystallize` / view-transition CSS. */\nconst MARKDOWN_SETTLE_MS = 480 * MOTION_INSPECT_SCALE;\n\nfunction nodeText(node: ReactNode): string {\n if (node == null || typeof node === \"boolean\") {\n return \"\";\n }\n if (typeof node === \"string\" || typeof node === \"number\") {\n return String(node);\n }\n if (Array.isArray(node)) {\n return node.map(nodeText).join(\"\");\n }\n if (isValidElement<{ children?: ReactNode }>(node)) {\n return nodeText(node.props.children);\n }\n return \"\";\n}\n\nfunction fenceLanguage(children: ReactNode): string | null {\n let found: string | null = null;\n Children.forEach(children, (child) => {\n if (found || !isValidElement<{ className?: string }>(child)) {\n return;\n }\n const match = /language-([a-zA-Z0-9_+-]+)/.exec(child.props.className ?? \"\");\n if (match?.[1]) {\n found = match[1];\n }\n });\n return found;\n}\n\nfunction InteractiveCodeBlock({ children, node }: ComponentPropsWithoutRef<\"pre\"> & ExtraProps) {\n const { source, render } = useContext(InteractiveContext);\n const language = fenceLanguage(children);\n if (render && (language === \"opengeni-html\" || language === \"opengeni-site\")) {\n const start = node?.position?.start.offset;\n const end = node?.position?.end.offset;\n const original =\n start !== undefined && end !== undefined && end <= source.length\n ? source.slice(start, end)\n : \"\";\n const lines = original.trimEnd().split(\"\\n\");\n const opening = lines[0]?.match(/^ {0,3}([\\x60]{3,}|~{3,})/);\n\n const closing = lines\n .at(-1)\n ?.replace(/^\\s*(?:>\\s*)+/, \"\")\n .trim();\n const complete =\n opening &&\n lines.length > 1 &&\n closing &&\n closing.length >= opening[1]!.length &&\n [...closing].every((c) => c === opening[1]![0]);\n if (!complete) return <p role=\"status\">Preparing preview…</p>;\n return (\n <>\n {render({\n kind: language === \"opengeni-html\" ? \"html\" : \"site\",\n content: nodeText(children).replace(/\\n$/, \"\"),\n })}\n </>\n );\n }\n return <MarkdownCodeBlock>{children}</MarkdownCodeBlock>;\n}\n\nfunction MarkdownCodeBlock({ children }: { children?: ReactNode }) {\n const code = nodeText(children).replace(/\\n$/, \"\");\n const language = fenceLanguage(children);\n // mt-only (no mb / last:mb-0): next sibling streaming in used to flip a\n // previous block's bottom margin on and yank tip-follow. Copy is overlay-only.\n // Fixed leading + overflow-x:auto with stable block chrome so wide ASCII lines\n // don't pop a scrollbar gutters mid-stream (another tip bob).\n return (\n <div className=\"group/copy relative mt-3 first:mt-0\">\n <div className=\"pointer-events-none absolute top-1.5 right-1.5 z-10 flex items-center gap-1\">\n {language ? (\n <span className=\"rounded px-1 py-0.5 font-og-mono text-[10px] uppercase tracking-wide text-og-fg-subtle/80 opacity-0 transition-opacity group-hover/copy:opacity-100 pointer-coarse:opacity-70\">\n {language}\n </span>\n ) : null}\n <div className=\"pointer-events-auto\">\n <CopyButton text={code} label=\"Copy code\" reveal=\"group-hover\" />\n </div>\n </div>\n <pre\n tabIndex={0}\n className=\"overflow-x-auto overflow-y-hidden rounded-og-md bg-og-surface-1/70 px-3 py-2.5 font-og-mono text-og-sm leading-5 text-og-fg-muted [scrollbar-gutter:stable] [&>code]:block [&>code]:border-0 [&>code]:bg-transparent [&>code]:p-0 [&>code]:leading-5 [&>code]:text-inherit\"\n >\n {children}\n </pre>\n </div>\n );\n}\n\nfunction MarkdownTable({ children, className, ...props }: ComponentPropsWithoutRef<\"table\">) {\n const wrapperRef = useRef<HTMLDivElement>(null);\n const tableRef = useRef<HTMLTableElement>(null);\n const layoutRef = useRef<ReturnType<typeof observeMarkdownTableLayout>>(undefined);\n useEffect(() => {\n const wrapper = wrapperRef.current;\n const table = tableRef.current;\n if (!wrapper?.closest(\"[data-og-wide-table-message]\") || !table) return;\n let disposed = false;\n // Ordinary tables remain usable even if this optional layout chunk fails.\n void import(\"./markdown-table-layout\")\n .then(({ observeMarkdownTableLayout }) => {\n if (!disposed) layoutRef.current = observeMarkdownTableLayout(wrapper, table);\n })\n .catch(() => {});\n return () => {\n disposed = true;\n layoutRef.current?.disconnect();\n layoutRef.current = undefined;\n };\n }, []);\n // ReactMarkdown recreates table children even when only later prose changes.\n // Remeasure genuine content changes without collapsing the expanded wrapper\n // between cleanup and the asynchronous observer-module import on each update.\n useEffect(() => {\n layoutRef.current?.measure();\n }, [children]);\n return (\n <div ref={wrapperRef} className=\"group/copy relative mt-3 max-w-full first:mt-0\">\n <div className=\"pointer-events-none absolute top-0 right-0 z-10\">\n <div className=\"pointer-events-auto\">\n <CopyButton\n text={() => tableElementToTsv(tableRef.current)}\n label=\"Copy table\"\n reveal=\"group-hover\"\n />\n </div>\n </div>\n <div className=\"overflow-x-auto\" tabIndex={0}>\n <table\n ref={tableRef}\n className={cn(\"w-full min-w-0 border-collapse text-og-base\", className)}\n {...props}\n >\n {children}\n </table>\n </div>\n </div>\n );\n}\n\nfunction MarkdownImpl({\n children,\n className,\n streaming = false,\n onSandboxFile,\n renderInteractiveBlock,\n renderImage,\n}: MarkdownProps) {\n // Tip-ink engine for THIS body: created on the first streaming render, kept\n // through a short linger after the stream ends (so the last age window can\n // finish), then dropped so settled bodies pay zero cost. Observing during\n // render is idempotent per text length — StrictMode double-renders are safe.\n const revealRef = useRef<StreamReveal | null>(null);\n const bodyRef = useRef<HTMLDivElement | null>(null);\n const [, bump] = useReducer((n: number) => n + 1, 0);\n const [settling, setSettling] = useState(false);\n const hadRevealRef = useRef(false);\n const now = typeof performance !== \"undefined\" ? performance.now() : Date.now();\n\n // Local settle breath only — View Transitions with `::view-transition-*(*)`\n // were fading the document root and felt like a full-page blink / focus loss\n // right as a turn ended (just before the next user message in the seed loop).\n const crystallize = (mutate: () => void) => {\n mutate();\n setSettling(true);\n bump();\n return setTimeout(() => setSettling(false), MARKDOWN_SETTLE_MS);\n };\n if (streaming && revealRef.current === null && !prefersReducedMotion()) {\n revealRef.current = createStreamReveal();\n }\n const reveal = revealRef.current;\n if (reveal !== null && streaming) {\n reveal.observe(children, now);\n }\n if (reveal !== null) {\n hadRevealRef.current = true;\n }\n const revealActive = reveal !== null && (streaming || reveal.hasActive(now));\n // The plugin walks the standard hast tree; a structural local type keeps the\n // module dependency-free, at the cost of this narrowing cast at the seam.\n const rehypePlugins =\n revealActive && reveal !== null\n ? ([[rehypeStreamReveal, { reveal, now }]] as unknown as NonNullable<\n Parameters<typeof ReactMarkdown>[0][\"rehypePlugins\"]\n >)\n : undefined;\n\n // Drop tip ink after trailing age windows finish. Same commit crystallizes:\n // ink spans → final plain markdown (soften off) + a short local settle breath.\n useEffect(() => {\n if (streaming || revealRef.current === null) {\n return;\n }\n let clearSettle: ReturnType<typeof setTimeout> | undefined;\n const timer = setTimeout(() => {\n const shouldSettle = hadRevealRef.current && !prefersReducedMotion();\n if (shouldSettle) {\n hadRevealRef.current = false;\n }\n if (shouldSettle) {\n clearSettle = crystallize(() => {\n revealRef.current = null;\n });\n } else {\n revealRef.current = null;\n bump();\n }\n }, REVEAL_LINGER_MS);\n return () => {\n clearTimeout(timer);\n if (clearSettle !== undefined) {\n clearTimeout(clearSettle);\n }\n };\n }, [streaming]);\n\n // No-reveal path (stream ended before any ink batch): soften already dropped\n // with `streaming`; keep the same local settle breath.\n const wasStreamingRef = useRef(streaming);\n useEffect(() => {\n const ended = wasStreamingRef.current && !streaming;\n wasStreamingRef.current = streaming;\n if (!ended || revealRef.current !== null || prefersReducedMotion()) {\n return;\n }\n setSettling(true);\n const timer = setTimeout(() => setSettling(false), MARKDOWN_SETTLE_MS);\n return () => clearTimeout(timer);\n }, [streaming]);\n\n // Soften unfinished markers for DISPLAY while the reveal pipeline is alive\n // (stream + linger) — not only while `streaming` — so task lists / tables /\n // fences don't snap to final GFM one commit before the crystallize morph.\n // Reveal identity still tracks the true source (`children`).\n const parseText = streaming || revealActive ? softenStreamingMarkdown(children) : children;\n const components = useMemo(() => markdownComponents(onSandboxFile), [onSandboxFile]);\n\n const interactiveContext = useMemo(\n () => ({\n source: children,\n ...(renderInteractiveBlock ? { render: renderInteractiveBlock } : {}),\n ...(renderImage ? { renderImage } : {}),\n }),\n [children, renderInteractiveBlock, renderImage],\n );\n\n // `min-w-0` lets the prose shrink inside flex parents (message bubbles) so\n // long links and code blocks wrap/scroll instead of forcing overflow.\n return (\n <InteractiveContext.Provider value={interactiveContext}>\n <TooltipProvider delayDuration={400}>\n <div\n ref={bodyRef}\n className={cn(\n \"og-markdown-body min-w-0 break-words\",\n settling && \"og-markdown-settle\",\n className,\n )}\n >\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n rehypePlugins={rehypePlugins}\n components={components}\n urlTransform={markdownUrlTransform}\n >\n {parseText}\n </ReactMarkdown>\n </div>\n </TooltipProvider>\n </InteractiveContext.Provider>\n );\n}\n\n/** Memoized so streaming re-renders of the parent don't re-parse settled bodies. */\nexport const Markdown = memo(MarkdownImpl);\n","import { flushSync } from \"react-dom\";\n\n/**\n * Live `prefers-reduced-motion` check for JS-driven motion (scroll glides,\n * streaming word reveals). CSS animations are already neutralized globally in\n * styles/index.css; this lets the imperative paths skip their work entirely.\n */\nlet query: MediaQueryList | null | undefined;\n\nexport function prefersReducedMotion(): boolean {\n if (query === undefined) {\n query =\n typeof window !== \"undefined\" && typeof window.matchMedia === \"function\"\n ? window.matchMedia(\"(prefers-reduced-motion: reduce)\")\n : null;\n }\n return query?.matches ?? false;\n}\n\n/** Test seam: forget the cached MediaQueryList so a stubbed matchMedia applies. */\nexport function resetReducedMotionCache(): void {\n query = undefined;\n}\n\ntype ViewTransitionResult = { finished: Promise<void> };\ntype ViewTransitionCallback = () => void;\ntype ViewTransitionOptions = {\n update: ViewTransitionCallback;\n types?: string[];\n};\ntype ViewTransitionStarter = {\n (callback: ViewTransitionCallback): ViewTransitionResult;\n (options: ViewTransitionOptions): ViewTransitionResult;\n};\n\n/** Active VT type for markdown crystallize — scoped CSS, not a full-page blink. */\nexport const MARKDOWN_CRYSTALLIZE_VT_TYPE = \"og-md-crystallize\";\n\n/**\n * Run a DOM update inside the browser View Transition API when available.\n * Snapshots the before/after paint and cross-fades (or custom CSS morphs)\n * between them — the platform \"morph\" primitive React's experimental\n * `<ViewTransition>` wraps. Falls back to a synchronous update.\n */\nexport function runViewTransition(update: () => void, options?: { types?: string[] }): void {\n if (prefersReducedMotion()) {\n update();\n return;\n }\n const doc = typeof document !== \"undefined\" ? document : null;\n const start = doc\n ? ((doc as Document & { startViewTransition?: ViewTransitionStarter }).startViewTransition ??\n null)\n : null;\n if (typeof start !== \"function\") {\n update();\n return;\n }\n const types = options?.types;\n if (types && types.length > 0) {\n try {\n Reflect.apply(start, doc, [\n {\n update: () => {\n flushSync(update);\n },\n types,\n },\n ]);\n return;\n } catch {\n // Older engines only accept the callback form.\n }\n }\n Reflect.apply(start, doc, [\n () => {\n flushSync(update);\n },\n ]);\n}\n","/**\n * TEMP eyeball scale for vertical motion (tip-follow, settle fold, CSS).\n * Set back to `1` before landing — not a product knob.\n */\nexport const MOTION_INSPECT_SCALE = 1;\n","/**\n * Display-only softener for mid-stream markdown.\n *\n * While tokens are still arriving, incomplete markers (`**bold`, an open\n * fence, a half-finished link) would otherwise render as raw punctuation —\n * the hard \"breaking\" flash. This closes a small set of common unfinished\n * constructs so the parse looks settled; the SOURCE string is never mutated\n * (callers pass the softened copy only into the markdown parser).\n *\n * When the real closers land, the softened and true parses converge and the\n * crystallize breath covers the remount.\n */\n\nexport function softenStreamingMarkdown(source: string): string {\n if (source.length === 0) {\n return source;\n }\n let text = source;\n\n // Unclosed fenced code block: an odd count of ``` line-openers means the\n // trailing fence is still in flight. Always soft-close — including an empty\n // opener — so code chrome (padding/tint) appears once at ``` and lines only\n // grow the body. Stripping empty openers deferred chrome until the first\n // body line, which landed as one fat height spike (yank around fences).\n //\n // If the body already ends with `\\n`, append only ``` — a second `\\n``` would\n // invent a blank line that vanishes when the real closer lands (height shrink\n // → tip-follow compensate + mid soft-rise cancel = up/down flicker).\n if (countFences(text) % 2 === 1) {\n text += text.endsWith(\"\\n\") ? \"```\" : \"\\n```\";\n }\n\n // Work outside fenced blocks so we don't \"fix\" markers that are literal\n // code content.\n const segments = splitByFences(text);\n for (const segment of segments) {\n if (segment.kind === \"fence\") {\n continue;\n }\n segment.value = closeInlineMarkers(segment.value);\n }\n let result = segments.map((segment) => segment.value).join(\"\");\n // split(\"\\n\") drops a trailing newline into an empty final line; restore it\n // so balanced finished fences round-trip byte-identical.\n if (text.endsWith(\"\\n\") && !result.endsWith(\"\\n\")) {\n result += \"\\n\";\n }\n return result;\n}\n\nfunction countFences(text: string): number {\n let count = 0;\n for (const line of text.split(\"\\n\")) {\n if (/^ {0,3}```/.test(line)) {\n count += 1;\n }\n }\n return count;\n}\n\ntype Segment = { kind: \"prose\" | \"fence\"; value: string };\n\nfunction splitByFences(text: string): Segment[] {\n const segments: Segment[] = [];\n const lines = text.split(\"\\n\");\n let buf: string[] = [];\n let inFence = false;\n /**\n * `boundary`: prose → fence. `join` alone drops a blank line before ```\n * (`[\"a\",\"\"].join` → `\"a\\n\"`, need `\"a\\n\\n\"`), so append an extra `\\n`.\n * `end`: final segment. Trailing `\"\"` from `split(\"\\n\")` already encodes a\n * terminating newline — do NOT append another (that was inventing `\\n\\n`\n * on every streamed line and shrinking it away at crystallize).\n */\n const flush = (kind: Segment[\"kind\"], mode: \"boundary\" | \"end\") => {\n if (buf.length === 0) {\n return;\n }\n let value = buf.join(\"\\n\");\n if (mode === \"boundary\") {\n value += \"\\n\";\n }\n segments.push({ kind, value });\n buf = [];\n };\n for (const line of lines) {\n const isFence = /^ {0,3}```/.test(line);\n if (isFence) {\n if (inFence) {\n buf.push(line);\n flush(\"fence\", \"end\");\n inFence = false;\n } else {\n flush(\"prose\", \"boundary\");\n buf.push(line);\n inFence = true;\n }\n continue;\n }\n buf.push(line);\n }\n flush(inFence ? \"fence\" : \"prose\", \"end\");\n return segments;\n}\n\n/**\n * Close unmatched **, *, ~~, and ` in prose. Order matters: handle the\n * longer bold/strike markers before single `*` so we don't steal from `**`.\n */\nfunction closeInlineMarkers(prose: string): string {\n let text = prose;\n text = closeDelimiter(text, \"~~\");\n text = closeDelimiter(text, \"**\");\n text = closeDelimiter(text, \"__\");\n text = closeSingleBackticks(text);\n text = closeSingleAsterisks(text);\n text = closeUnfinishedLink(text);\n return text;\n}\n\nfunction closeDelimiter(text: string, delimiter: string): string {\n // Count occurrences that aren't escaped. Odd → append a closer.\n let count = 0;\n let i = 0;\n while (i < text.length) {\n if (text[i] === \"\\\\\" && i + 1 < text.length) {\n i += 2;\n continue;\n }\n if (text.startsWith(delimiter, i)) {\n count += 1;\n i += delimiter.length;\n continue;\n }\n i += 1;\n }\n return count % 2 === 1 ? insertBeforeTrailingNewlines(text, delimiter) : text;\n}\n\n/** Soft closers belong before trailing `\\n`s so restore/round-trip stay stable. */\nfunction insertBeforeTrailingNewlines(text: string, suffix: string): string {\n let end = text.length;\n while (end > 0 && text[end - 1] === \"\\n\") {\n end -= 1;\n }\n return text.slice(0, end) + suffix + text.slice(end);\n}\n\nfunction closeSingleBackticks(text: string): string {\n // Ignore ``` (fences already stripped) and even pairs. A trailing unmatched\n // ` is the common \"inline code still typing\" case.\n let count = 0;\n for (let i = 0; i < text.length; i += 1) {\n if (text[i] === \"\\\\\" && i + 1 < text.length) {\n i += 1;\n continue;\n }\n if (text[i] === \"`\") {\n // Skip triple backticks if any leaked into prose.\n if (text.startsWith(\"```\", i)) {\n i += 2;\n continue;\n }\n count += 1;\n }\n }\n return count % 2 === 1 ? insertBeforeTrailingNewlines(text, \"`\") : text;\n}\n\nfunction closeSingleAsterisks(text: string): string {\n // Count `*` that are NOT part of `**` (already handled). Odd → close italic.\n let count = 0;\n for (let i = 0; i < text.length; i += 1) {\n if (text[i] === \"\\\\\" && i + 1 < text.length) {\n i += 1;\n continue;\n }\n if (text[i] === \"*\" && text[i + 1] === \"*\") {\n i += 1;\n continue;\n }\n if (text[i] === \"*\") {\n count += 1;\n }\n }\n return count % 2 === 1 ? insertBeforeTrailingNewlines(text, \"*\") : text;\n}\n\nfunction closeUnfinishedLink(text: string): string {\n // `[label](url` without the trailing `)` — close it. Bare `[label` without\n // `](` is left alone (too ambiguous with footnotes / prose brackets).\n const open = text.lastIndexOf(\"](\");\n if (open === -1) {\n return text;\n }\n const after = text.slice(open + 2);\n if (after.includes(\")\")) {\n return text;\n }\n // Don't close if a later `[` started something else after.\n if (after.includes(\"[\")) {\n return text;\n }\n return insertBeforeTrailingNewlines(text, \")\");\n}\n","/* ----------------------------------------------------------------------------\n Streaming tip ink (age-window fade)\n\n Append-only markdown grows at the tip. Rather than staggering per-word\n onsets (glitter under fast models), each append batch is born at wall time\n and fades in over a fixed age window:\n\n opacity progress = clamp((now − birth) / INK_FADE_MS, 0, 1)\n\n Fast arrival → many recent characters still young → a large soft band.\n Slow arrival → only the tip is young → a tight tip wash.\n Same rule both ways; time does the work. No per-word stagger, no artificial\n content lag — layout always holds the truthful text; paint only.\n\n Identity is the character offset into the source. CSS animation-delay =\n birth − now (often negative) so mid-fade re-renders resume, never restart.\n Runs settle back to plain text once age ≥ INK_FADE_MS (zero span cost).\n -------------------------------------------------------------------------- */\n\nimport { MOTION_INSPECT_SCALE } from \"../lib/motion-inspect\";\n\n/** Keep in sync with `--og-duration-stream` / `.og-stream-ink` in styles. */\nexport const INK_FADE_MS = 420 * MOTION_INSPECT_SCALE;\n/** @deprecated Use {@link INK_FADE_MS}. */\nexport const WORD_ANIMATION_MS = INK_FADE_MS;\n\n/**\n * A first observation larger than this is pre-existing history (timeline\n * opened mid-stream), not live tip — it renders instantly.\n */\nconst INITIAL_ANIMATED_LIMIT = 400;\n\ntype InkBatch = {\n start: number;\n end: number;\n birth: number;\n};\n\nexport type StreamReveal = {\n /** Register the full current source text; new suffix becomes an ink batch. */\n observe(text: string, now: number): void;\n /**\n * CSS animation-delay (ms) for the run covering `offset`, or null when that\n * ink has settled and should render as plain text. Negative = resume mid-fade.\n */\n delayFor(offset: number, now: number): number | null;\n /** True while any batch is still inside its fade window. */\n hasActive(now: number): boolean;\n};\n\nexport function createStreamReveal(): StreamReveal {\n let batches: InkBatch[] = [];\n let revealedChars = -1;\n\n return {\n observe(text, now) {\n if (revealedChars === -1) {\n revealedChars = text.length > INITIAL_ANIMATED_LIMIT ? text.length : 0;\n }\n if (text.length <= revealedChars) {\n // Idempotent re-observation (StrictMode) or defensive no-op on shrink.\n revealedChars = Math.max(revealedChars, text.length);\n return;\n }\n batches.push({ start: revealedChars, end: text.length, birth: now });\n revealedChars = text.length;\n batches = batches.filter((batch) => batch.birth + INK_FADE_MS > now);\n },\n\n delayFor(offset, now) {\n const batch = findBatch(batches, offset);\n if (!batch) {\n return null;\n }\n const delay = batch.birth - now;\n return delay + INK_FADE_MS <= 0 ? null : delay;\n },\n\n hasActive(now) {\n const last = batches[batches.length - 1];\n return last !== undefined && last.birth + INK_FADE_MS > now;\n },\n };\n}\n\nfunction findBatch(batches: readonly InkBatch[], offset: number): InkBatch | null {\n let low = 0;\n let high = batches.length - 1;\n while (low <= high) {\n const mid = (low + high) >> 1;\n const batch = batches[mid]!;\n if (offset < batch.start) {\n high = mid - 1;\n } else if (offset >= batch.end) {\n low = mid + 1;\n } else {\n return batch;\n }\n }\n return null;\n}\n\n/* ----------------------------------------------------------------------------\n rehype: wrap still-fading source runs in `.og-stream-ink` spans.\n\n Contiguous offsets that share one birth (one append batch) become ONE span —\n a continuous ink surface, not per-word glitter. Code/pre stay plain. Nodes\n without source positions (syntax rewritten around them) render plain too.\n -------------------------------------------------------------------------- */\n\ntype HastText = {\n type: \"text\";\n value: string;\n position?: { start?: { offset?: number | undefined } | undefined } | undefined;\n};\n\ntype HastParent = {\n type: string;\n tagName?: string;\n value?: string;\n children?: HastChild[];\n};\n\ntype HastChild = (HastText | HastParent) & Record<string, unknown>;\n\nexport function rehypeStreamReveal(options: { reveal: StreamReveal; now: number }) {\n const { reveal, now } = options;\n return (tree: HastParent) => {\n walk(tree, false);\n };\n\n function walk(node: HastParent, insideVerbatim: boolean): void {\n if (!node.children) {\n return;\n }\n const verbatim = insideVerbatim || node.tagName === \"code\" || node.tagName === \"pre\";\n const next: HastChild[] = [];\n for (const child of node.children) {\n if (child.type === \"text\" && !verbatim) {\n next.push(...splitTextNode(child as HastText));\n continue;\n }\n walk(child as HastParent, verbatim);\n next.push(child);\n }\n node.children = next;\n }\n\n function splitTextNode(node: HastText): HastChild[] {\n const sourceOffset = node.position?.start?.offset;\n if (sourceOffset === undefined) {\n return [node as HastChild];\n }\n const value = node.value;\n const out: HastChild[] = [];\n let plain = \"\";\n const flushPlain = () => {\n if (plain.length > 0) {\n out.push({ type: \"text\", value: plain } as HastChild);\n plain = \"\";\n }\n };\n\n let i = 0;\n while (i < value.length) {\n const delay = reveal.delayFor(sourceOffset + i, now);\n let j = i + 1;\n while (j < value.length) {\n const nextDelay = reveal.delayFor(sourceOffset + j, now);\n if (nextDelay !== delay) {\n break;\n }\n j += 1;\n }\n const slice = value.slice(i, j);\n if (delay === null) {\n plain += slice;\n } else {\n flushPlain();\n out.push({\n type: \"element\",\n tagName: \"span\",\n properties: {\n className: [\"og-stream-ink\"],\n style: `animation-delay:${Math.round(delay)}ms`,\n },\n children: [{ type: \"text\", value: slice }],\n } as unknown as HastChild);\n }\n i = j;\n }\n flushPlain();\n return out.length > 0 ? out : [node as HastChild];\n }\n}\n"],"mappings":"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","names":["useEffect","useRef","useState","jsx","jsxs","useState","useRef","useEffect"]}