@mgamadeus/ddd-agents 0.1.0-alpha.22 → 0.1.0-alpha.24

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 (164) hide show
  1. package/README.md +3 -2
  2. package/dist/chat.js +87 -893
  3. package/dist/chat.js.map +1 -1
  4. package/dist/chunks/ConversationMessageInputComposerWidgets-BxyaFBA6.js +631 -0
  5. package/dist/chunks/ConversationMessageInputComposerWidgets-BxyaFBA6.js.map +1 -0
  6. package/dist/chunks/{WebSearchResultsConversationWidget-BvnLWHyi.js → WebSearchResultsConversationWidget-as3p5bHw.js} +147 -1125
  7. package/dist/chunks/WebSearchResultsConversationWidget-as3p5bHw.js.map +1 -0
  8. package/dist/chunks/{canvas-behaviours-BRFR1ALE.js → canvas-behaviours-AvzKSYyv.js} +4 -4
  9. package/dist/chunks/{canvas-behaviours-BRFR1ALE.js.map → canvas-behaviours-AvzKSYyv.js.map} +1 -1
  10. package/dist/chunks/canvas-reducers-Bfp_i7lc.js +88 -0
  11. package/dist/chunks/canvas-reducers-Bfp_i7lc.js.map +1 -0
  12. package/dist/chunks/{canvasBodies-9SuF6NAB.js → canvasBodies-Cvu3l38p.js} +12 -6
  13. package/dist/chunks/canvasBodies-Cvu3l38p.js.map +1 -0
  14. package/dist/chunks/canvasStorage-EvQsGdto.js +65 -0
  15. package/dist/chunks/canvasStorage-EvQsGdto.js.map +1 -0
  16. package/dist/chunks/contract-BxmMxYPF.js +96 -0
  17. package/dist/chunks/contract-BxmMxYPF.js.map +1 -0
  18. package/dist/chunks/conversation-BEF0aesf.js +31 -0
  19. package/dist/chunks/conversation-BEF0aesf.js.map +1 -0
  20. package/dist/chunks/entity-detail-name-3A82gDAp.js +15 -0
  21. package/dist/chunks/entity-detail-name-3A82gDAp.js.map +1 -0
  22. package/dist/chunks/icon-names-Di6c4zLo.js +86 -0
  23. package/dist/chunks/icon-names-Di6c4zLo.js.map +1 -0
  24. package/dist/chunks/index-7Qc_3GbG.js +1046 -0
  25. package/dist/chunks/index-7Qc_3GbG.js.map +1 -0
  26. package/dist/chunks/{ConversationMarkdown-W7NHglmL.js → widget-click-signal-sources-DulRkNvZ.js} +54 -7
  27. package/dist/chunks/widget-click-signal-sources-DulRkNvZ.js.map +1 -0
  28. package/dist/chunks/{widget-image-readiness-signal-DeOuL89j.js → widget-image-readiness-signal-D3ci53xr.js} +2 -2
  29. package/dist/chunks/{widget-image-readiness-signal-DeOuL89j.js.map → widget-image-readiness-signal-D3ci53xr.js.map} +1 -1
  30. package/dist/chunks/{widget-name-resolver-DyIY6Zu4.js → widget-name-resolver-BGN3HpoG.js} +80 -117
  31. package/dist/chunks/widget-name-resolver-BGN3HpoG.js.map +1 -0
  32. package/dist/chunks/{withPollingChangeSubscription-BLDAWF-o.js → withPollingChangeSubscription-B16htQGd.js} +2 -2
  33. package/dist/chunks/{withPollingChangeSubscription-BLDAWF-o.js.map → withPollingChangeSubscription-B16htQGd.js.map} +1 -1
  34. package/dist/client-testing.js +91 -2
  35. package/dist/client-testing.js.map +1 -1
  36. package/dist/client.js +1 -1
  37. package/dist/contract.js +8 -27
  38. package/dist/contract.js.map +1 -1
  39. package/dist/files/chat/Conversation.module.scss +268 -0
  40. package/dist/files/chat/ConversationViewBody/ConversationViewBody.module.scss +336 -0
  41. package/dist/files/chat/_conversation-tokens.scss +37 -0
  42. package/dist/files/image-render/WidgetImageRender.module.scss +22 -0
  43. package/dist/files/kit/ComposedViewConversationWidget.md +59 -0
  44. package/dist/files/kit/components/data/data.preview-fixtures.json +3298 -0
  45. package/dist/files/kit/components/embedding/widget.preview-fixtures.json +147 -0
  46. package/dist/files/kit/components/entity/entity-link.preview-fixtures.json +340 -0
  47. package/dist/files/kit/components/form/form.preview-fixtures.json +319 -0
  48. package/dist/files/kit/components/inputs/button.preview-fixtures.json +301 -0
  49. package/dist/files/kit/components/inputs/checkbox.preview-fixtures.json +35 -0
  50. package/dist/files/kit/components/inputs/date-picker.preview-fixtures.json +36 -0
  51. package/dist/files/kit/components/inputs/input.preview-fixtures.json +55 -0
  52. package/dist/files/kit/components/inputs/radio-group.preview-fixtures.json +76 -0
  53. package/dist/files/kit/components/inputs/select.preview-fixtures.json +314 -0
  54. package/dist/files/kit/components/inputs/slider.preview-fixtures.json +178 -0
  55. package/dist/files/kit/components/inputs/tabs.preview-fixtures.json +304 -0
  56. package/dist/files/kit/components/inputs/textarea.preview-fixtures.json +37 -0
  57. package/dist/files/kit/components/layout/layout.preview-fixtures.json +892 -0
  58. package/dist/files/kit/components/map/map.preview-fixtures.json +339 -0
  59. package/dist/files/kit/components/media/image-group.preview-fixtures.json +228 -0
  60. package/dist/files/kit/components/media/image.preview-fixtures.json +61 -0
  61. package/dist/files/kit/components/media/video-card/video-card.preview-fixtures.json +121 -0
  62. package/dist/files/kit/components/media/video.preview-fixtures.json +68 -0
  63. package/dist/files/kit/components/rich/code.preview-fixtures.json +105 -0
  64. package/dist/files/kit/components/rich/diagram.preview-fixtures.json +89 -0
  65. package/dist/files/kit/components/rich/math.preview-fixtures.json +152 -0
  66. package/dist/files/kit/components/rich/svg.preview-fixtures.json +243 -0
  67. package/dist/files/kit/components/text/badge.preview-fixtures.json +44 -0
  68. package/dist/files/kit/components/text/caption.preview-fixtures.json +31 -0
  69. package/dist/files/kit/components/text/favicon.preview-fixtures.json +69 -0
  70. package/dist/files/kit/components/text/label.preview-fixtures.json +48 -0
  71. package/dist/files/kit/components/text/link.preview-fixtures.json +103 -0
  72. package/dist/files/kit/components/text/markdown.preview-fixtures.json +29 -0
  73. package/dist/files/kit/components/text/source-ref.preview-fixtures.json +51 -0
  74. package/dist/files/kit/components/text/text.preview-fixtures.json +106 -0
  75. package/dist/files/kit/components/text/title.preview-fixtures.json +172 -0
  76. package/dist/files/kit/composed-view-widget-contract.json +88 -0
  77. package/dist/files/kit/composed-view.preview-fixtures.json +376 -0
  78. package/dist/files/renderer/conversation-widget-layout.module.scss +47 -0
  79. package/dist/files/renderer/widget-tree/composed-node-schema.json +3428 -0
  80. package/dist/files/styles/_conversation-widget-container.scss +6 -0
  81. package/dist/files/styles/_media.scss +50 -0
  82. package/dist/files/styles/_spacings.scss +23 -0
  83. package/dist/files/styles/_surfaces.scss +28 -0
  84. package/dist/files/widgets/ClockConversationWidget/ClockConversationWidget.md +53 -0
  85. package/dist/files/widgets/ClockConversationWidget/clock.preview-fixtures.json +76 -0
  86. package/dist/files/widgets/ConceptExplainerConversationWidget/ConceptExplainerConversationWidget.md +86 -0
  87. package/dist/files/widgets/ConceptExplainerConversationWidget/concept-explainer.preview-fixtures.json +23 -0
  88. package/dist/files/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsConversationWidget.md +59 -0
  89. package/dist/files/widgets/ConversationSearchResultsConversationWidget/conversation-search-results.preview-fixtures.json +85 -0
  90. package/dist/files/widgets/CurrencyConverterConversationWidget/CurrencyConverterConversationWidget.md +51 -0
  91. package/dist/files/widgets/CurrencyConverterConversationWidget/currency-converter.preview-fixtures.json +73 -0
  92. package/dist/files/widgets/CustomVisualizationConversationWidget/CustomVisualizationConversationWidget.md +83 -0
  93. package/dist/files/widgets/CustomVisualizationConversationWidget/custom-visualization.preview-fixtures.json +227 -0
  94. package/dist/files/widgets/CustomVisualizationConversationWidget/sandbox-frame/custom-visualization-frame.html +188 -0
  95. package/dist/files/widgets/EntityMentionConversationWidget/EntityMentionConversationWidget.md +55 -0
  96. package/dist/files/widgets/EntityMentionConversationWidget/entity-mention.preview-fixtures.json +55 -0
  97. package/dist/files/widgets/MultiChoiceConversationWidget/MultiChoiceConversationWidget.md +61 -0
  98. package/dist/files/widgets/MultiChoiceConversationWidget/multi-choice-widget-contract.json +43 -0
  99. package/dist/files/widgets/MultiChoiceConversationWidget/multi-choice.preview-fixtures.json +103 -0
  100. package/dist/files/widgets/QuickRepliesConversationWidget/QuickRepliesConversationWidget.md +65 -0
  101. package/dist/files/widgets/QuickRepliesConversationWidget/quick-replies-widget-contract.json +43 -0
  102. package/dist/files/widgets/QuickRepliesConversationWidget/quick-replies.preview-fixtures.json +45 -0
  103. package/dist/files/widgets/SuggestedActions/SuggestedActions.md +60 -0
  104. package/dist/files/widgets/SuggestedActions/suggested-actions.preview-fixtures.json +19 -0
  105. package/dist/files/widgets/ToolTraceConversationWidget/ToolTraceConversationWidget.md +48 -0
  106. package/dist/files/widgets/ToolTraceConversationWidget/tool-trace.preview-fixtures.json +32 -0
  107. package/dist/files/widgets/WebSearchResultsConversationWidget/WebSearchResultsConversationWidget.md +49 -0
  108. package/dist/files/widgets/WebSearchResultsConversationWidget/web-search-results.preview-fixtures.json +57 -0
  109. package/dist/files/widgets/WritingDraftConversationWidget/WritingDraftConversationWidget.md +66 -0
  110. package/dist/files/widgets/WritingDraftConversationWidget/writing-draft.preview-fixtures.json +129 -0
  111. package/dist/image-render.js +11 -10
  112. package/dist/image-render.js.map +1 -1
  113. package/dist/index.js +32 -27
  114. package/dist/index.js.map +1 -1
  115. package/dist/kit.js +11 -2
  116. package/dist/kit.js.map +1 -1
  117. package/dist/preview.js +47 -18
  118. package/dist/preview.js.map +1 -1
  119. package/dist/provider.js +71 -0
  120. package/dist/provider.js.map +1 -0
  121. package/dist/renderer.js +142 -62
  122. package/dist/renderer.js.map +1 -1
  123. package/dist/styles.css +86 -38
  124. package/dist/types/client/testing/test-conversation-widgets.d.ts +25 -0
  125. package/dist/types/client/testing/widget-hydration-stand-ins.d.ts +42 -0
  126. package/dist/types/entries/chat.d.ts +12 -0
  127. package/dist/types/entries/client-testing.d.ts +4 -0
  128. package/dist/types/entries/contract.d.ts +1 -0
  129. package/dist/types/entries/index.d.ts +4 -3
  130. package/dist/types/entries/kit.d.ts +7 -0
  131. package/dist/types/entries/preview.d.ts +2 -0
  132. package/dist/types/entries/provider.d.ts +1 -0
  133. package/dist/types/entries/renderer.d.ts +19 -1
  134. package/dist/types/entries/widgets.d.ts +13 -0
  135. package/dist/types/kit/components/data/apex-chart-component.d.ts +3 -0
  136. package/dist/types/kit/components/data/chart-model.d.ts +164 -0
  137. package/dist/types/kit/components/data/data-value-format.d.ts +44 -0
  138. package/dist/types/kit/components/data/use-chart-palette.d.ts +9 -0
  139. package/dist/types/kit/components/data/use-number-locale.d.ts +5 -0
  140. package/dist/types/kit/components/map/use-google-maps-auth-failure.d.ts +18 -0
  141. package/dist/types/kit/entity-detail/entity-detail-bodies.d.ts +2 -0
  142. package/dist/types/provider/index.d.ts +1 -0
  143. package/dist/types/renderer/_access/ConversationWidgetGateSkeleton.d.ts +6 -0
  144. package/dist/types/renderer/_agent-space/use-conversation-widget-agent-space-fallback.d.ts +16 -0
  145. package/dist/types/renderer/canvas/entity-detail-instance.d.ts +5 -3
  146. package/dist/types/renderer/canvas/use-anchor-widget-agent-space-key.d.ts +17 -0
  147. package/dist/types/renderer/conversationWidgetRegistry.d.ts +6 -0
  148. package/dist/types/renderer/read-conversation-widget-variant.d.ts +22 -0
  149. package/dist/types/renderer/widget-hydration/use-widget-hydration.d.ts +5 -0
  150. package/dist/types/widgets/EntityMentionConversationWidget/stories/EntityMentionAskFlowStory.d.ts +8 -0
  151. package/dist/types/widgets/_shared/CardFooter.d.ts +6 -0
  152. package/dist/types/widgets/_shared/WidgetLabel.d.ts +8 -0
  153. package/dist/types/widgets/_shared/entity-update-channel.d.ts +17 -0
  154. package/dist/types/widgets/_shared/use-element-visible.d.ts +6 -0
  155. package/dist/widgets.js +120 -27
  156. package/dist/widgets.js.map +1 -1
  157. package/package.json +74 -1
  158. package/public-api.json +779 -0
  159. package/dist/chunks/ConversationMarkdown-W7NHglmL.js.map +0 -1
  160. package/dist/chunks/WebSearchResultsConversationWidget-BvnLWHyi.js.map +0 -1
  161. package/dist/chunks/canvasBodies-9SuF6NAB.js.map +0 -1
  162. package/dist/chunks/decide-canvas-open-Ct-wnNEJ.js +0 -20
  163. package/dist/chunks/decide-canvas-open-Ct-wnNEJ.js.map +0 -1
  164. package/dist/chunks/widget-name-resolver-DyIY6Zu4.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"canvasBodies-9SuF6NAB.js","sources":["../../src/renderer/canvas/use-anchor-widget-payload.ts","../../src/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvas.tsx","../../src/widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvasBody.tsx","../../src/widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvas.tsx","../../src/widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvasBody.tsx","../../src/widgets/EntityMentionConversationWidget/shared/use-entity-mention-composer.ts","../../src/widgets/EntityMentionConversationWidget/EntityMentionAskButton/EntityMentionAskButton.tsx","../../src/kit/entity-detail/entity-detail-bodies.ts","../../src/kit/entity-detail/entity-detail-name.ts","../../src/kit/entity-detail/EntityDetailCanvasBody.tsx","../../src/kit/map-full-screen/MapFullScreenCanvasBody.tsx","../../src/renderer/canvas/canvasBodies.tsx"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { CanvasState } from \"./canvas-state\";\nimport { payloadHashOfInstanceId } from \"./canvas-state\";\nimport { findWidgetFenceByPayloadHash, findWidgetFencesInMarkdown } from \"./find-widget-fences-in-markdown\";\n\n/**\n * The payload string of the widget a message-anchored canvas was opened from: the fence of `widgetName` in the anchor\n * message whose payload hash the canvas instance id carries (`canvasInstanceIdForMessagePayload`); when the instance\n * id carries no hash (one canvas per message), the first fence of that name. Undefined for a page anchor, a missing\n * anchor message, or a message that no longer carries the fence — the body then renders nothing.\n */\nexport const useAnchorWidgetPayload = (\n canvas: CanvasState,\n anchorMessageMarkdown: string | null,\n widgetName: string,\n): string | undefined =>\n useMemo(() => {\n if (canvas.anchor.kind !== \"message\" || anchorMessageMarkdown === null) return undefined;\n const payloadHash = payloadHashOfInstanceId(canvas.instanceId);\n if (payloadHash !== undefined) {\n return findWidgetFenceByPayloadHash(anchorMessageMarkdown, widgetName, payloadHash)?.payload;\n }\n return findWidgetFencesInMarkdown(anchorMessageMarkdown).find((fence) => fence.name === widgetName)?.payload;\n }, [canvas.anchor, canvas.instanceId, anchorMessageMarkdown, widgetName]);\n","import { ConversationSearchResultsList, Text } from \"../../provider/components\";\nimport React from \"react\";\nimport { parseConversationSearchResultsPayload } from \"./shared/conversation-search-results-widget-payload\";\n\ntype ConversationSearchResultsCanvasProps = {\n query: string;\n groups: ReturnType<typeof parseConversationSearchResultsPayload>[\"groups\"];\n onOpenConversation: (conversationId: number, messageId?: number) => void;\n};\n\n// Canvas body styles — the same as every list canvas body, so the full-screen panel behaves the same:\n// a full-height flex column whose inner area SCROLLS (scrollStyle: flex 1 + overflowY auto — without it the content\n// overflows the panel with no scrollbar), plus a horizontal inset (contentStyle) because the results list is built\n// for the narrow inline chat column where the bubble provides the gutter — in the canvas there is no bubble, so it would\n// otherwise render edge-to-edge.\nconst canvasStyle: React.CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n background: \"var(--agents-bg)\",\n};\nconst scrollStyle: React.CSSProperties = {\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n};\nconst contentStyle: React.CSSProperties = {\n padding: \"16px 24px 24px\",\n};\n\n/** The canvas body — a titled wrapper around the same grouped results, scrollable + inset like the other canvas widgets. */\nexport const ConversationSearchResultsCanvas = (props: ConversationSearchResultsCanvasProps) => (\n <div style={canvasStyle} data-testid=\"conversation-search-results-widget-canvas\">\n <div style={scrollStyle}>\n <div style={contentStyle} data-testid=\"conversation-search-results-widget-canvas-results\">\n <Text\n role=\"title\"\n replacements={{ query: props.query }}\n testId=\"conversation-search-results-widget-canvas-title\"\n >\n {'Search results for \"%query%\"'}\n </Text>\n <ConversationSearchResultsList groups={props.groups} query={props.query} onOpenConversation={props.onOpenConversation} />\n </div>\n </div>\n </div>\n);\n","import React, { useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useConversationWidgetContext } from \"../../renderer/ConversationWidgetCallbacksContext\";\nimport { useAnchorWidgetPayload } from \"../../renderer/canvas/use-anchor-widget-payload\";\nimport { parseConversationSearchResultsPayload } from \"./shared/conversation-search-results-widget-payload\";\nimport { ConversationSearchResultsCanvas } from \"./ConversationSearchResultsCanvas\";\n\n/**\n * The `conversationSearchResults` CANVAS BODY (`canvasBodies.tsx`): re-reads the `ConversationSearchResults` fence of\n * the anchor message — the same payload the inline widget rendered from — and shows the grouped results. Nothing was\n * stored for it but the pointer. Renders nothing when the anchor message no longer carries the fence.\n */\nexport const ConversationSearchResultsCanvasBody = ({ canvas, anchorMessageMarkdown }: CanvasBodyProps) => {\n const { onOpenConversation } = useConversationWidgetContext();\n const payload = useAnchorWidgetPayload(canvas, anchorMessageMarkdown, \"ConversationSearchResults\");\n const parsed = useMemo(\n () => (payload === undefined ? null : parseConversationSearchResultsPayload(payload)),\n [payload],\n );\n if (parsed === null || parsed.groups.length === 0) return null;\n return (\n <ConversationSearchResultsCanvas\n query={parsed.query}\n groups={parsed.groups}\n onOpenConversation={(conversationId, messageId) => onOpenConversation?.(conversationId, messageId)}\n />\n );\n};\n","import { Text } from \"../../provider/components\";\nimport React from \"react\";\nimport { WebSearchResultSource } from \"./shared/web-search-results-widget-payload\";\nimport { WebSearchAnswer } from \"./WebSearchAnswer\";\nimport { WebSearchSourcesList } from \"./WebSearchSourcesList\";\n\ntype WebSearchResultsCanvasProps = {\n query: string;\n answer: string;\n sources: WebSearchResultSource[];\n provider?: string;\n};\n\n// Canvas body styles — mirror the ConversationSearchResults / listReviews drawer widgets: a full-height flex column\n// whose inner area SCROLLS (flex 1 + overflowY auto) with a horizontal inset (there is no chat bubble gutter in the canvas).\nconst canvasStyle: React.CSSProperties = {\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n minHeight: 0,\n background: \"var(--agents-bg)\",\n};\nconst scrollStyle: React.CSSProperties = { flex: 1, minHeight: 0, overflowY: \"auto\" };\nconst contentStyle: React.CSSProperties = { padding: \"16px 24px 24px\" };\n\n/** The canvas body — the full answer + sources, scrollable + inset like the other canvas widgets. */\nexport const WebSearchResultsCanvas = (props: WebSearchResultsCanvasProps) => (\n <div style={canvasStyle} data-testid=\"web-search-results-widget-canvas\">\n <div style={scrollStyle}>\n <div style={contentStyle}>\n {props.query ? (\n <Text\n role=\"title\"\n replacements={{ query: props.query }}\n testId=\"web-search-results-widget-canvas-title\"\n >\n {'\"%query%\"'}\n </Text>\n ) : (\n <Text role=\"title\" testId=\"web-search-results-widget-canvas-title\">\n Web search\n </Text>\n )}\n <div style={{ marginTop: 12 }}>\n <WebSearchAnswer answer={props.answer} />\n </div>\n <WebSearchSourcesList\n sources={props.sources}\n provider={props.provider}\n testId=\"web-search-results-widget-canvas\"\n />\n </div>\n </div>\n </div>\n);\n","import React, { useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useAnchorWidgetPayload } from \"../../renderer/canvas/use-anchor-widget-payload\";\nimport { parseWebSearchResultsPayload } from \"./shared/web-search-results-widget-payload\";\nimport { WebSearchResultsCanvas } from \"./WebSearchResultsCanvas\";\n\n/**\n * The `webSearchResults` CANVAS BODY (`canvasBodies.tsx`): re-reads the `WebSearchResults` fence of the anchor message\n * — the answer and its cited sources the inline widget rendered from — and shows them in the canvas. Renders nothing\n * when the anchor message no longer carries the fence.\n */\nexport const WebSearchResultsCanvasBody = ({ canvas, anchorMessageMarkdown }: CanvasBodyProps) => {\n const payload = useAnchorWidgetPayload(canvas, anchorMessageMarkdown, \"WebSearchResults\");\n const parsed = useMemo(() => (payload === undefined ? null : parseWebSearchResultsPayload(payload)), [payload]);\n if (parsed === null || (parsed.answer.trim() === \"\" && parsed.sources.length === 0)) return null;\n return (\n <WebSearchResultsCanvas\n query={parsed.query}\n answer={parsed.answer}\n sources={parsed.sources}\n provider={parsed.provider}\n />\n );\n};\n","import { useCallback } from \"react\";\nimport { useConversationWidgetContext } from \"../../../renderer/ConversationWidgetCallbacksContext\";\nimport {\n buildEntityMentionFields,\n ENTITY_MENTION_WIDGET_NAME,\n entityMentionKey,\n EntityMentionTarget,\n MAX_ENTITY_MENTIONS_PER_MESSAGE,\n normalizeEntityMentionFields,\n toEntityMentionWireFields,\n} from \"./entity-mention\";\n\nexport interface UseEntityMentionComposerResult {\n /** Whether this entity is already mentioned in the composer. */\n isMentioned: (target: EntityMentionTarget) => boolean;\n /**\n * Puts the entity into the composer as an `EntityMention` chip — once per entity (a second click is a no-op); past\n * {@link MAX_ENTITY_MENTIONS_PER_MESSAGE} the new entity takes the place of the oldest mention (one write: a remove\n * and an add in one event would both read the list before either). Sends nothing: the owner writes the question.\n * Returns false for a target that names no entity.\n */\n mentionEntity: (target: EntityMentionTarget) => boolean;\n}\n\n/**\n * The opener side of the `EntityMention` composer widget: what the detail panel's \"Ask about this\"\n * button calls. Reads and writes the composer widgets of the chat's widget context; the composer strip renders them.\n */\nexport const useEntityMentionComposer = (): UseEntityMentionComposerResult => {\n const { composerWidgets, addComposerWidget, replaceComposerWidgetFields } = useConversationWidgetContext();\n\n const findMentionWidgets = useCallback(\n () => composerWidgets.filter((composerWidget) => composerWidget.widgetName === ENTITY_MENTION_WIDGET_NAME),\n [composerWidgets],\n );\n\n const isMentioned = useCallback(\n (target: EntityMentionTarget) => {\n const mention = buildEntityMentionFields(target);\n if (mention === null) return false;\n return findMentionWidgets().some((composerWidget) => {\n const heldMention = normalizeEntityMentionFields(composerWidget.fields);\n return heldMention !== null && entityMentionKey(heldMention) === entityMentionKey(mention);\n });\n },\n [findMentionWidgets],\n );\n\n const mentionEntity = useCallback(\n (target: EntityMentionTarget) => {\n const mention = buildEntityMentionFields(target);\n if (mention === null) return false;\n if (isMentioned(target)) return true;\n const mentionWidgets = findMentionWidgets();\n if (mentionWidgets.length >= MAX_ENTITY_MENTIONS_PER_MESSAGE) {\n replaceComposerWidgetFields(mentionWidgets[0].composerWidgetId, toEntityMentionWireFields(mention));\n } else {\n addComposerWidget(ENTITY_MENTION_WIDGET_NAME, toEntityMentionWireFields(mention));\n }\n return true;\n },\n [isMentioned, findMentionWidgets, replaceComposerWidgetFields, addComposerWidget],\n );\n\n return { isMentioned, mentionEntity };\n};\n","import { useIsEmailWidgetRender } from \"../../../renderer/ConversationWidgetRenderContext\";\nimport { ConversationWidgetButton } from \"../../_shared/ConversationWidgetButton\";\nimport type { EntityMentionTarget } from \"../shared/entity-mention\";\nimport { useEntityMentionComposer } from \"../shared/use-entity-mention-composer\";\n\nexport interface EntityMentionAskButtonProps extends EntityMentionTarget {\n testId?: string;\n}\n\n/**\n * The detail panel's \"Ask about this\" button (ChatGPT's \"Anschlussfrage stellen\"):\n * puts the entity into the chat input as an `EntityMention` chip and sends NOTHING — the owner writes the question,\n * the chip rides in that message as a fence, and the backend reads which entity the question is about. Not a\n * next-step CTA: it posts no prompt. A second click on the same entity changes nothing; the\n * label turns into \"Added to your message\". Mounted by the `entityDetail` canvas (the shell or a domain body) with\n * the entity the panel shows; renders nothing in the e-mail capture or for a target that names no entity.\n */\nexport const EntityMentionAskButton = (props: EntityMentionAskButtonProps) => {\n const { entityType, entityId, label, agentSpaceKey, testId = \"entity-mention-ask\" } = props;\n const isEmailRender = useIsEmailWidgetRender();\n const { isMentioned, mentionEntity } = useEntityMentionComposer();\n const target = { entityType, entityId, label, agentSpaceKey };\n if (isEmailRender) return null;\n const isAlreadyMentioned = isMentioned(target);\n return (\n <ConversationWidgetButton\n variant=\"primary\"\n size=\"medium\"\n icon={isAlreadyMentioned ? \"check\" : \"message\"}\n disabled={isAlreadyMentioned}\n onClick={() => mentionEntity(target)}\n testId={testId}\n >\n {isAlreadyMentioned ? \"Added to your message\" : \"Ask about this\"}\n </ConversationWidgetButton>\n );\n};\n","import type React from \"react\";\nimport { createContext, useContext } from \"react\";\n\n/**\n * The bodies of the `entityDetail` canvas, one per entity type: every `*.entity-detail-body.tsx` below\n * `widgets/` that exports `entityDetailBody` registers itself by folder glob — an entity type is added with\n * the backend `<Type>EntityReferenceResolver` and this one file, and edits no list. A second body for one entity type\n * is a build error (thrown at module load).\n */\n\nexport interface EntityDetailBodyProps {\n entityType: string;\n /** The id as the backend resolved it (a row id or an external id). */\n entityId: string;\n /** The key of the agent space the chat is scoped to, for a body whose read endpoint is agent-space-scoped. */\n agentSpaceKey?: number;\n}\n\nexport interface EntityDetailBodyDefinition {\n /** The backend resolver's `ENTITY_TYPE`. */\n entityType: string;\n /** Self-hydrates the entity by id through its own read endpoint (the endpoint's entity rights apply). */\n component: React.ComponentType<EntityDetailBodyProps>;\n}\n\nconst bodyModules = import.meta.glob<{ entityDetailBody?: EntityDetailBodyDefinition }>(\n [\"../../widgets/**/*.entity-detail-body.tsx\", \"../**/*.entity-detail-body.tsx\"],\n { eager: true },\n);\n\nexport const buildEntityDetailBodyRegistry = (\n definitions: EntityDetailBodyDefinition[],\n): Readonly<Record<string, EntityDetailBodyDefinition>> => {\n const registry: Record<string, EntityDetailBodyDefinition> = {};\n for (const definition of definitions) {\n if (Object.prototype.hasOwnProperty.call(registry, definition.entityType)) {\n throw new Error(`Two entity detail bodies register the entity type \"${definition.entityType}\".`);\n }\n registry[definition.entityType] = definition;\n }\n return registry;\n};\n\n/** The body definitions a set of `*.entity-detail-body.tsx` modules export (the package's or an app's glob). */\nexport const readEntityDetailBodyDefinitions = (\n modules: Record<string, { entityDetailBody?: EntityDetailBodyDefinition }>,\n): EntityDetailBodyDefinition[] =>\n Object.values(modules)\n .map((bodyModule) => bodyModule.entityDetailBody)\n .filter((definition): definition is EntityDetailBodyDefinition => definition !== undefined);\n\n/** Entity type → body: the package's folder, then what an app registers (`registerEntityDetailBodies`). */\nexport const entityDetailBodies: Record<string, EntityDetailBodyDefinition> = {\n ...buildEntityDetailBodyRegistry(readEntityDetailBodyDefinitions(bodyModules)),\n};\n\n/** Adds an app's entity detail bodies. Runs outside React, before the first render; an entity type registers once. */\nexport const registerEntityDetailBodies = (definitions: readonly EntityDetailBodyDefinition[]): void => {\n Object.assign(\n entityDetailBodies,\n buildEntityDetailBodyRegistry([...Object.values(entityDetailBodies), ...definitions]),\n );\n};\n\n/** The registry the canvas body uses — the folder's by default; a spec or a story may provide stubs. */\nexport const EntityDetailBodiesContext =\n createContext<Readonly<Record<string, EntityDetailBodyDefinition>>>(entityDetailBodies);\n\nexport const useEntityDetailBodies = () => useContext(EntityDetailBodiesContext);\n","import { createContext, useContext, useEffect } from \"react\";\n\n/**\n * The name of the entity the `entityDetail` canvas shows: a detail body knows it only once it hydrated,\n * the shell needs it for the \"Ask about this\" chip — ChatGPT's follow-up chip names the business, a chip without it\n * says \"About this entry\". A body reports the name with {@link useReportEntityDetailName}; outside the shell (a story,\n * a spec of the body alone) the report goes nowhere.\n */\nexport const EntityDetailNameReportContext = createContext<(entityName: string | undefined) => void>(() => undefined);\n\n/** Reports the shown entity's name (the hydrated business, keyword or review title) to the `entityDetail` shell. */\nexport const useReportEntityDetailName = (entityName: string | undefined): void => {\n const reportEntityName = useContext(EntityDetailNameReportContext);\n const trimmedName = entityName?.trim() || undefined;\n useEffect(() => {\n reportEntityName(trimmedName);\n }, [reportEntityName, trimmedName]);\n};\n","import { Text } from \"../../provider/components\";\nimport { useCallback, useState } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { readEntityDetailInstanceId } from \"../../renderer/canvas/entity-detail-instance\";\nimport { EntityMentionAskButton } from \"../../widgets/EntityMentionConversationWidget/EntityMentionAskButton/EntityMentionAskButton\";\nimport { useEntityDetailBodies } from \"./entity-detail-bodies\";\nimport { EntityDetailNameReportContext } from \"./entity-detail-name\";\nimport styles from \"./EntityDetailCanvasBody.module.scss\";\n\n/**\n * The `entityDetail` CANVAS BODY (`canvasBodies.tsx`): the shell around one entity's detail. It reads\n * WHICH entity from the canvas instance id (`entityDetail:<entityType>:<id>`) and mounts the body registered for that\n * entity type; the body self-hydrates by id. An entity type without a body renders a short notice instead of nothing,\n * so a click never lands on an empty pane. \"Ask about this\" stays at the pane's foot while the detail scrolls and\n * names the entity in its chip once the body reported the name (`useReportEntityDetailName`).\n */\nexport const EntityDetailCanvasBody = ({ canvas, agentSpaceKey }: CanvasBodyProps) => {\n const bodies = useEntityDetailBodies();\n const [reportedEntity, setReportedEntity] = useState<{ instanceId: string; name: string | undefined }>();\n const reportEntityName = useCallback(\n (entityName: string | undefined) => setReportedEntity({ instanceId: canvas.instanceId, name: entityName }),\n [canvas.instanceId],\n );\n const target = readEntityDetailInstanceId(canvas.instanceId);\n if (target === undefined) return null;\n const definition = Object.prototype.hasOwnProperty.call(bodies, target.entityType)\n ? bodies[target.entityType]\n : undefined;\n if (!definition) {\n return (\n <div className={styles.entityDetail} data-testid=\"entity-detail-canvas\">\n <Text role=\"help\" color=\"var(--agents-fg-light)\" testId=\"entity-detail-canvas-unsupported\">\n {\"This detail cannot be shown here yet.\"}\n </Text>\n </div>\n );\n }\n const Body = definition.component;\n // A name reported for the previous entity never labels the next one's chip.\n const entityName = reportedEntity?.instanceId === canvas.instanceId ? reportedEntity.name : undefined;\n return (\n <div className={styles.entityDetail} data-testid=\"entity-detail-canvas\">\n <EntityDetailNameReportContext.Provider value={reportEntityName}>\n <Body entityType={target.entityType} entityId={target.entityId} agentSpaceKey={agentSpaceKey} />\n </EntityDetailNameReportContext.Provider>\n <div className={styles.entityDetailFooter}>\n <EntityMentionAskButton\n entityType={target.entityType}\n entityId={target.entityId}\n label={entityName}\n agentSpaceKey={agentSpaceKey}\n />\n </div>\n </div>\n );\n};\n","import { Text } from \"../../provider/components\";\nimport { useCallback, useMemo } from \"react\";\nimport type { CanvasBodyProps } from \"../../renderer/canvas/canvas-body-props\";\nimport { useConversationWidgetContext } from \"../../renderer/ConversationWidgetCallbacksContext\";\nimport {\n canvasInstanceIdForEntityDetail,\n readOpenEntityActionTarget,\n} from \"../../renderer/canvas/entity-detail-instance\";\nimport type {\n ComposedViewAction,\n ComposedViewTree,\n} from \"../../renderer/widget-tree/composed-view-tree\";\nimport type { ExpressionValue } from \"../../renderer/widget-tree/expression/evaluate-expression\";\nimport { ComposedViewRenderer } from \"../ComposedViewRenderer\";\nimport { findMapNodeInMarkdown, readMapNodeKeyOfInstanceId } from \"../components/map/map-full-screen-instance\";\nimport { MapPresentationContext } from \"../components/map/map-presentation-context\";\nimport mapStyles from \"../components/map/Map.module.scss\";\n\n/** The body reports nothing of its own: the inline block already reported this map to the model. */\nconst ignoreRenderReport = () => {};\n\n/**\n * The `mapFullScreen` CANVAS BODY (`canvasBodies.tsx`): one `Map` node of the anchor\n * message, full screen — the map filling the pane beside the list of its points. It finds the node through the\n * message's `ComposedView` fences and the node key its instance id carries (`map-full-screen-instance.ts`), then\n * renders it through the same `ComposedViewRenderer` with the node's own tree, so its bindings (`$data`, `$from`,\n * `$source`, `$computed`, `$state` at its initial value) and its actions resolve exactly as inline; the\n * `MapPresentationContext` switches the node to its full-screen layout. A point's `openEntity` action opens the\n * `entityDetail` canvas on the same anchor message (it replaces this canvas, as a click on an inline point would).\n */\nexport const MapFullScreenCanvasBody = (props: CanvasBodyProps) => {\n const { canvas, anchorMessageMarkdown, agentSpaceKey } = props;\n const { openCanvas } = useConversationWidgetContext();\n const mapNodeKey = readMapNodeKeyOfInstanceId(canvas.instanceId);\n\n const mapTree = useMemo<ComposedViewTree | undefined>(() => {\n if (anchorMessageMarkdown === null || mapNodeKey === undefined) return undefined;\n const mapNodeInComposedView = findMapNodeInMarkdown(anchorMessageMarkdown, mapNodeKey);\n if (!mapNodeInComposedView) return undefined;\n // The map alone, with its tree's state, data, computed values and actions; the tree's findings were the inline\n // block's to report.\n return { ...mapNodeInComposedView.tree, title: null, view: mapNodeInComposedView.mapNode, findings: [] };\n }, [anchorMessageMarkdown, mapNodeKey]);\n\n const anchor = canvas.anchor;\n const onOpenEntity = useCallback(\n (action: ComposedViewAction, currentRow?: ExpressionValue) => {\n const target = readOpenEntityActionTarget(action, currentRow);\n if (target === undefined || anchor.kind !== \"message\") return;\n openCanvas({\n canvasId: \"entityDetail\",\n instanceId: canvasInstanceIdForEntityDetail(target),\n anchor,\n origin: \"cardClick\",\n justDelivered: false,\n });\n },\n [openCanvas, anchor],\n );\n\n if (!mapTree) {\n return (\n <div\n className={mapStyles.fullScreenNotice}\n data-canvas-instance={canvas.instanceId}\n data-testid=\"map-full-screen-canvas-unavailable\"\n >\n <Text role=\"help\" color=\"var(--agents-fg-light)\">\n {\"This map is no longer available.\"}\n </Text>\n </div>\n );\n }\n return (\n <div\n className={mapStyles.fullScreenBody}\n data-canvas-instance={canvas.instanceId}\n data-testid=\"map-full-screen-canvas\"\n >\n <MapPresentationContext.Provider value=\"fullScreen\">\n <ComposedViewRenderer\n tree={mapTree}\n interactive\n isEmailRender={false}\n messageId={anchor.kind === \"message\" ? anchor.messageId : undefined}\n agentSpaceKey={agentSpaceKey}\n onReport={ignoreRenderReport}\n onOpenEntity={onOpenEntity}\n testId=\"map-full-screen-canvas-view\"\n />\n </MapPresentationContext.Provider>\n </div>\n );\n};\n","import type React from \"react\";\nimport type { CanvasId } from \"./canvas-behaviours\";\nimport type { CanvasBodyProps } from \"./canvas-body-props\";\nimport { ConversationSearchResultsCanvasBody } from \"../../widgets/ConversationSearchResultsConversationWidget/ConversationSearchResultsCanvasBody\";\nimport { WebSearchResultsCanvasBody } from \"../../widgets/WebSearchResultsConversationWidget/WebSearchResultsCanvasBody\";\nimport { EntityDetailCanvasBody } from \"../../kit/entity-detail/EntityDetailCanvasBody\";\nimport { MapFullScreenCanvasBody } from \"../../kit/map-full-screen/MapFullScreenCanvasBody\";\n\nexport type { CanvasBodyProps } from \"./canvas-body-props\";\nexport { canvasFeatureFlagOf } from \"./canvas-feature-flags\";\n\n/**\n * THE CANVAS BODIES — canvas id → the React component the shell mounts in the canvas pane. The one module that knows\n * both the canvas ids and React components, and it is imported ONLY by `CanvasPane` (the shell), never by\n * the slice, the behaviours or a widget — that is the import layering that keeps the store-init temporal-dead-zone\n * cycle away. The bodies themselves are small: a body that hosts a heavy page (an app's list page or editor)\n * lazy-loads that page, exactly as its widget did. Every canvas has a body; nothing\n * else hands the pane a rendered node.\n *\n * The package's own bodies are listed here; an app adds the bodies of its canvases with `registerCanvasBodies` before\n * the first render. The object is filled in place, so the shell reads every registration.\n */\nexport const canvasBodies = {\n conversationSearchResults: ConversationSearchResultsCanvasBody,\n webSearchResults: WebSearchResultsCanvasBody,\n entityDetail: EntityDetailCanvasBody,\n mapFullScreen: MapFullScreenCanvasBody,\n} as Record<CanvasId, React.ComponentType<CanvasBodyProps>>;\n\n/** Adds an app's canvas bodies (canvas id → body). Runs outside React, before the first render. */\nexport const registerCanvasBodies = (\n bodies: Readonly<Partial<Record<CanvasId, React.ComponentType<CanvasBodyProps>>>>,\n): void => {\n Object.assign(canvasBodies, bodies);\n};\n"],"names":["canvasStyle","scrollStyle","contentStyle","entityName"],"mappings":";;;;;AAWO,MAAM,yBAAyB,CACpC,QACA,uBACA,eAEA,QAAQ,MAAM;AACZ,MAAI,OAAO,OAAO,SAAS,aAAa,0BAA0B,KAAM,QAAO;AAC/E,QAAM,cAAc,wBAAwB,OAAO,UAAU;AAC7D,MAAI,gBAAgB,QAAW;AAC7B,WAAO,6BAA6B,uBAAuB,YAAY,WAAW,GAAG;AAAA,EACvF;AACA,SAAO,2BAA2B,qBAAqB,EAAE,KAAK,CAAC,UAAU,MAAM,SAAS,UAAU,GAAG;AACvG,GAAG,CAAC,OAAO,QAAQ,OAAO,YAAY,uBAAuB,UAAU,CAAC;ACR1E,MAAMA,gBAAmC;AAAA,EACvC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,eAAe;AAAA,EACf,WAAW;AAAA,EACX,YAAY;AACd;AACA,MAAMC,gBAAmC;AAAA,EACvC,MAAM;AAAA,EACN,WAAW;AAAA,EACX,WAAW;AACb;AACA,MAAMC,iBAAoC;AAAA,EACxC,SAAS;AACX;AAGO,MAAM,kCAAkC,CAAC,8BAC7C,OAAA,EAAI,OAAOF,eAAa,eAAY,6CACnC,UAAA,oBAAC,OAAA,EAAI,OAAOC,eACV,UAAA,qBAAC,SAAI,OAAOC,gBAAc,eAAY,qDACpC,UAAA;AAAA,EAAA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAc,EAAE,OAAO,MAAM,MAAA;AAAA,MAC7B,QAAO;AAAA,MAEN,UAAA;AAAA,IAAA;AAAA,EAAA;AAAA,EAEH,oBAAC,+BAAA,EAA8B,QAAQ,MAAM,QAAQ,OAAO,MAAM,OAAO,oBAAoB,MAAM,mBAAA,CAAoB;AAAA,EAAA,CACzH,GACF,GACF;ACnCK,MAAM,sCAAsC,CAAC,EAAE,QAAQ,4BAA6C;AACzG,QAAM,EAAE,mBAAA,IAAuB,6BAAA;AAC/B,QAAM,UAAU,uBAAuB,QAAQ,uBAAuB,2BAA2B;AACjG,QAAM,SAAS;AAAA,IACb,MAAO,YAAY,SAAY,OAAO,sCAAsC,OAAO;AAAA,IACnF,CAAC,OAAO;AAAA,EAAA;AAEV,MAAI,WAAW,QAAQ,OAAO,OAAO,WAAW,EAAG,QAAO;AAC1D,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,oBAAoB,CAAC,gBAAgB,cAAc,qBAAqB,gBAAgB,SAAS;AAAA,IAAA;AAAA,EAAA;AAGvG;ACZA,MAAM,cAAmC;AAAA,EACvC,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,eAAe;AAAA,EACf,WAAW;AAAA,EACX,YAAY;AACd;AACA,MAAM,cAAmC,EAAE,MAAM,GAAG,WAAW,GAAG,WAAW,OAAA;AAC7E,MAAM,eAAoC,EAAE,SAAS,iBAAA;AAG9C,MAAM,yBAAyB,CAAC,UACrC,oBAAC,OAAA,EAAI,OAAO,aAAa,eAAY,oCACnC,UAAA,oBAAC,SAAI,OAAO,aACV,UAAA,qBAAC,OAAA,EAAI,OAAO,cACT,UAAA;AAAA,EAAA,MAAM,QACL;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAc,EAAE,OAAO,MAAM,MAAA;AAAA,MAC7B,QAAO;AAAA,MAEN,UAAA;AAAA,IAAA;AAAA,EAAA,IAGH,oBAAC,MAAA,EAAK,MAAK,SAAQ,QAAO,0CAAyC,UAAA,cAEnE;AAAA,EAEF,oBAAC,OAAA,EAAI,OAAO,EAAE,WAAW,GAAA,GACvB,UAAA,oBAAC,iBAAA,EAAgB,QAAQ,MAAM,OAAA,CAAQ,EAAA,CACzC;AAAA,EACA;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAS,MAAM;AAAA,MACf,UAAU,MAAM;AAAA,MAChB,QAAO;AAAA,IAAA;AAAA,EAAA;AACT,EAAA,CACF,GACF,GACF;AC3CK,MAAM,6BAA6B,CAAC,EAAE,QAAQ,4BAA6C;AAChG,QAAM,UAAU,uBAAuB,QAAQ,uBAAuB,kBAAkB;AACxF,QAAM,SAAS,QAAQ,MAAO,YAAY,SAAY,OAAO,6BAA6B,OAAO,GAAI,CAAC,OAAO,CAAC;AAC9G,MAAI,WAAW,QAAS,OAAO,OAAO,KAAA,MAAW,MAAM,OAAO,QAAQ,WAAW,EAAI,QAAO;AAC5F,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,MACf,SAAS,OAAO;AAAA,MAChB,UAAU,OAAO;AAAA,IAAA;AAAA,EAAA;AAGvB;ACKO,MAAM,2BAA2B,MAAsC;AAC5E,QAAM,EAAE,iBAAiB,mBAAmB,4BAAA,IAAgC,6BAAA;AAE5E,QAAM,qBAAqB;AAAA,IACzB,MAAM,gBAAgB,OAAO,CAAC,mBAAmB,eAAe,eAAe,0BAA0B;AAAA,IACzG,CAAC,eAAe;AAAA,EAAA;AAGlB,QAAM,cAAc;AAAA,IAClB,CAAC,WAAgC;AAC/B,YAAM,UAAU,yBAAyB,MAAM;AAC/C,UAAI,YAAY,KAAM,QAAO;AAC7B,aAAO,mBAAA,EAAqB,KAAK,CAAC,mBAAmB;AACnD,cAAM,cAAc,6BAA6B,eAAe,MAAM;AACtE,eAAO,gBAAgB,QAAQ,iBAAiB,WAAW,MAAM,iBAAiB,OAAO;AAAA,MAC3F,CAAC;AAAA,IACH;AAAA,IACA,CAAC,kBAAkB;AAAA,EAAA;AAGrB,QAAM,gBAAgB;AAAA,IACpB,CAAC,WAAgC;AAC/B,YAAM,UAAU,yBAAyB,MAAM;AAC/C,UAAI,YAAY,KAAM,QAAO;AAC7B,UAAI,YAAY,MAAM,EAAG,QAAO;AAChC,YAAM,iBAAiB,mBAAA;AACvB,UAAI,eAAe,UAAU,iCAAiC;AAC5D,oCAA4B,eAAe,CAAC,EAAE,kBAAkB,0BAA0B,OAAO,CAAC;AAAA,MACpG,OAAO;AACL,0BAAkB,4BAA4B,0BAA0B,OAAO,CAAC;AAAA,MAClF;AACA,aAAO;AAAA,IACT;AAAA,IACA,CAAC,aAAa,oBAAoB,6BAA6B,iBAAiB;AAAA,EAAA;AAGlF,SAAO,EAAE,aAAa,cAAA;AACxB;AChDO,MAAM,yBAAyB,CAAC,UAAuC;AAC5E,QAAM,EAAE,YAAY,UAAU,OAAO,eAAe,SAAS,yBAAyB;AACtF,QAAM,gBAAgB,uBAAA;AACtB,QAAM,EAAE,aAAa,cAAA,IAAkB,yBAAA;AACvC,QAAM,SAAS,EAAE,YAAY,UAAU,OAAO,cAAA;AAC9C,MAAI,cAAe,QAAO;AAC1B,QAAM,qBAAqB,YAAY,MAAM;AAC7C,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,MAAM,qBAAqB,UAAU;AAAA,MACrC,UAAU;AAAA,MACV,SAAS,MAAM,cAAc,MAAM;AAAA,MACnC;AAAA,MAEC,+BAAqB,0BAA0B;AAAA,IAAA;AAAA,EAAA;AAGtD;ACXA,MAAM,cAAc,uBAAA,OAAA,CAAA,CAAA;AAKb,MAAM,gCAAgC,CAC3C,gBACyD;AACzD,QAAM,WAAuD,CAAA;AAC7D,aAAW,cAAc,aAAa;AACpC,QAAI,OAAO,UAAU,eAAe,KAAK,UAAU,WAAW,UAAU,GAAG;AACzE,YAAM,IAAI,MAAM,sDAAsD,WAAW,UAAU,IAAI;AAAA,IACjG;AACA,aAAS,WAAW,UAAU,IAAI;AAAA,EACpC;AACA,SAAO;AACT;AAGO,MAAM,kCAAkC,CAC7C,YAEA,OAAO,OAAO,OAAO,EAClB,IAAI,CAAC,eAAe,WAAW,gBAAgB,EAC/C,OAAO,CAAC,eAAyD,eAAe,MAAS;AAGvF,MAAM,qBAAiE;AAAA,EAC5E,GAAG,8BAA8B,gCAAgC,WAAW,CAAC;AAC/E;AAGO,MAAM,6BAA6B,CAAC,gBAA6D;AACtG,SAAO;AAAA,IACL;AAAA,IACA,8BAA8B,CAAC,GAAG,OAAO,OAAO,kBAAkB,GAAG,GAAG,WAAW,CAAC;AAAA,EAAA;AAExF;AAGO,MAAM,4BACX,cAAoE,kBAAkB;AAEjF,MAAM,wBAAwB,MAAM,WAAW,yBAAyB;AC5DxE,MAAM,gCAAgC,cAAwD,MAAM,MAAS;;;;;;;ACQ7G,MAAM,yBAAyB,CAAC,EAAE,QAAQ,oBAAqC;AACpF,QAAM,SAAS,sBAAA;AACf,QAAM,CAAC,gBAAgB,iBAAiB,IAAI,SAAA;AAC5C,QAAM,mBAAmB;AAAA,IACvB,CAACC,gBAAmC,kBAAkB,EAAE,YAAY,OAAO,YAAY,MAAMA,aAAY;AAAA,IACzG,CAAC,OAAO,UAAU;AAAA,EAAA;AAEpB,QAAM,SAAS,2BAA2B,OAAO,UAAU;AAC3D,MAAI,WAAW,OAAW,QAAO;AACjC,QAAM,aAAa,OAAO,UAAU,eAAe,KAAK,QAAQ,OAAO,UAAU,IAC7E,OAAO,OAAO,UAAU,IACxB;AACJ,MAAI,CAAC,YAAY;AACf,+BACG,OAAA,EAAI,WAAW,OAAO,cAAc,eAAY,wBAC/C,UAAA,oBAAC,MAAA,EAAK,MAAK,QAAO,OAAM,0BAAyB,QAAO,oCACrD,mDACH,GACF;AAAA,EAEJ;AACA,QAAM,OAAO,WAAW;AAExB,QAAM,aAAa,gBAAgB,eAAe,OAAO,aAAa,eAAe,OAAO;AAC5F,8BACG,OAAA,EAAI,WAAW,OAAO,cAAc,eAAY,wBAC/C,UAAA;AAAA,IAAA,oBAAC,8BAA8B,UAA9B,EAAuC,OAAO,kBAC7C,UAAA,oBAAC,MAAA,EAAK,YAAY,OAAO,YAAY,UAAU,OAAO,UAAU,eAA8B,GAChG;AAAA,IACA,oBAAC,OAAA,EAAI,WAAW,OAAO,oBACrB,UAAA;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,YAAY,OAAO;AAAA,QACnB,UAAU,OAAO;AAAA,QACjB,OAAO;AAAA,QACP;AAAA,MAAA;AAAA,IAAA,EACF,CACF;AAAA,EAAA,GACF;AAEJ;ACpCA,MAAM,qBAAqB,MAAM;AAAC;AAW3B,MAAM,0BAA0B,CAAC,UAA2B;AACjE,QAAM,EAAE,QAAQ,uBAAuB,cAAA,IAAkB;AACzD,QAAM,EAAE,WAAA,IAAe,6BAAA;AACvB,QAAM,aAAa,2BAA2B,OAAO,UAAU;AAE/D,QAAM,UAAU,QAAsC,MAAM;AAC1D,QAAI,0BAA0B,QAAQ,eAAe,OAAW,QAAO;AACvE,UAAM,wBAAwB,sBAAsB,uBAAuB,UAAU;AACrF,QAAI,CAAC,sBAAuB,QAAO;AAGnC,WAAO,EAAE,GAAG,sBAAsB,MAAM,OAAO,MAAM,MAAM,sBAAsB,SAAS,UAAU,GAAC;AAAA,EACvG,GAAG,CAAC,uBAAuB,UAAU,CAAC;AAEtC,QAAM,SAAS,OAAO;AACtB,QAAM,eAAe;AAAA,IACnB,CAAC,QAA4B,eAAiC;AAC5D,YAAM,SAAS,2BAA2B,QAAQ,UAAU;AAC5D,UAAI,WAAW,UAAa,OAAO,SAAS,UAAW;AACvD,iBAAW;AAAA,QACT,UAAU;AAAA,QACV,YAAY,gCAAgC,MAAM;AAAA,QAClD;AAAA,QACA,QAAQ;AAAA,QACR,eAAe;AAAA,MAAA,CAChB;AAAA,IACH;AAAA,IACA,CAAC,YAAY,MAAM;AAAA,EAAA;AAGrB,MAAI,CAAC,SAAS;AACZ,WACE;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,WAAW,UAAU;AAAA,QACrB,wBAAsB,OAAO;AAAA,QAC7B,eAAY;AAAA,QAEZ,8BAAC,MAAA,EAAK,MAAK,QAAO,OAAM,0BACrB,UAAA,mCAAA,CACH;AAAA,MAAA;AAAA,IAAA;AAAA,EAGN;AACA,SACE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW,UAAU;AAAA,MACrB,wBAAsB,OAAO;AAAA,MAC7B,eAAY;AAAA,MAEZ,UAAA,oBAAC,uBAAuB,UAAvB,EAAgC,OAAM,cACrC,UAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,MAAM;AAAA,UACN,aAAW;AAAA,UACX,eAAe;AAAA,UACf,WAAW,OAAO,SAAS,YAAY,OAAO,YAAY;AAAA,UAC1D;AAAA,UACA,UAAU;AAAA,UACV;AAAA,UACA,QAAO;AAAA,QAAA;AAAA,MAAA,EACT,CACF;AAAA,IAAA;AAAA,EAAA;AAGN;ACvEO,MAAM,eAAe;AAAA,EAC1B,2BAA2B;AAAA,EAC3B,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,eAAe;AACjB;AAGO,MAAM,uBAAuB,CAClC,WACS;AACT,SAAO,OAAO,cAAc,MAAM;AACpC;"}
@@ -1,20 +0,0 @@
1
- "use client";
2
- import { ab as sameCanvasIdentity } from "./WebSearchResultsConversationWidget-BvnLWHyi.js";
3
- const ACCEPT = { kind: "accept" };
4
- const ignore = (reason) => ({ kind: "ignore", reason });
5
- const decideCanvasOpen = (behaviour, openCanvas, lastClosedCanvas, request) => {
6
- if (behaviour === void 0) return ignore("unknownCanvas");
7
- if (!request.hostHasCanvasSurface) return ignore("noSurface");
8
- if (request.origin !== "deliveredInMessage") return ACCEPT;
9
- if (!request.justDelivered) return ignore("replay");
10
- if (openCanvas !== null && sameCanvasIdentity(openCanvas, request)) return ignore("alreadyOpen");
11
- if (lastClosedCanvas !== null && lastClosedCanvas.closedByCustomer && sameCanvasIdentity(lastClosedCanvas, request)) {
12
- return ignore("customerClosedIt");
13
- }
14
- if (!request.viewportViable && behaviour.narrowViewport === "none") return ignore("noTakeoverOnNarrowViewport");
15
- return ACCEPT;
16
- };
17
- export {
18
- decideCanvasOpen as d
19
- };
20
- //# sourceMappingURL=decide-canvas-open-Ct-wnNEJ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decide-canvas-open-Ct-wnNEJ.js","sources":["../../src/renderer/canvas/decide-canvas-open.ts"],"sourcesContent":["import type { CanvasBehaviour } from \"./canvas-behaviours\";\nimport { CanvasOpenRequest, CanvasState, LastClosedCanvas, sameCanvasIdentity } from \"./canvas-state\";\n\n/**\n * Why an open request is ignored. Every reason is a sentence the shell could log:\n * - `unknownCanvas` no behaviour is declared for the id (a stale stored pointer, a typo)\n * - `noSurface` the host renders no split (`disableSplitView`), so there is nowhere to open\n * - `replay` a delivery-origin request for a message that was NOT just delivered — history\n * replay, a reload, scroll-back; rejected BEFORE anything is read or written\n * - `alreadyOpen` a delivery-origin request for the identity that is already open (the agent re-emits\n * an editor widget after a rebuild) — the open canvas is kept, never remounted\n * - `customerClosedIt` the customer closed exactly this identity and nothing has cleared the veto yet\n * - `noTakeoverOnNarrowViewport` a live delivery on a narrow viewport of a canvas that declares no overlay — the\n * card stays, the customer taps it\n */\nexport type CanvasOpenIgnoreReason =\n | \"unknownCanvas\"\n | \"noSurface\"\n | \"replay\"\n | \"alreadyOpen\"\n | \"customerClosedIt\"\n | \"noTakeoverOnNarrowViewport\";\n\nexport type CanvasOpenDecision =\n | { readonly kind: \"accept\" }\n | { readonly kind: \"ignore\"; readonly reason: CanvasOpenIgnoreReason };\n\nconst ACCEPT: CanvasOpenDecision = { kind: \"accept\" };\n\nconst ignore = (reason: CanvasOpenIgnoreReason): CanvasOpenDecision => ({ kind: \"ignore\", reason });\n\n/**\n * THE opening rule — the one place that answers \"may this canvas open now?\". Pure: it reads the behaviour, the open\n * canvas, the last closed one and the request, and returns Accept or Ignore. It never mutates; the reducer\n * (`canvas-reducers.ts`) applies an Accept. There is no merge rung: the same identity opened again from a card click\n * is a fresh Accept (remount), and the refresh contract of a pinned work surface is a value the body derives from the\n * message list, not a reducer merge.\n *\n * A `cardClick`, an `openedByPage` and a `restoredAfterReload` request always open (the customer, the page or the\n * stored pointer decided); only `deliveredInMessage` is judged.\n */\nexport const decideCanvasOpen = (\n behaviour: CanvasBehaviour | undefined,\n openCanvas: CanvasState | null,\n lastClosedCanvas: LastClosedCanvas | null,\n request: CanvasOpenRequest,\n): CanvasOpenDecision => {\n if (behaviour === undefined) return ignore(\"unknownCanvas\");\n if (!request.hostHasCanvasSurface) return ignore(\"noSurface\");\n if (request.origin !== \"deliveredInMessage\") return ACCEPT;\n\n // Replay is rejected first: a replayed message must not touch the open canvas in any way.\n if (!request.justDelivered) return ignore(\"replay\");\n if (openCanvas !== null && sameCanvasIdentity(openCanvas, request)) return ignore(\"alreadyOpen\");\n if (lastClosedCanvas !== null && lastClosedCanvas.closedByCustomer && sameCanvasIdentity(lastClosedCanvas, request)) {\n return ignore(\"customerClosedIt\");\n }\n if (!request.viewportViable && behaviour.narrowViewport === \"none\") return ignore(\"noTakeoverOnNarrowViewport\");\n return ACCEPT;\n};\n"],"names":[],"mappings":";;AA2BA,MAAM,SAA6B,EAAE,MAAM,SAAA;AAE3C,MAAM,SAAS,CAAC,YAAwD,EAAE,MAAM,UAAU,OAAA;AAYnF,MAAM,mBAAmB,CAC9B,WACA,YACA,kBACA,YACuB;AACvB,MAAI,cAAc,OAAW,QAAO,OAAO,eAAe;AAC1D,MAAI,CAAC,QAAQ,qBAAsB,QAAO,OAAO,WAAW;AAC5D,MAAI,QAAQ,WAAW,qBAAsB,QAAO;AAGpD,MAAI,CAAC,QAAQ,cAAe,QAAO,OAAO,QAAQ;AAClD,MAAI,eAAe,QAAQ,mBAAmB,YAAY,OAAO,EAAG,QAAO,OAAO,aAAa;AAC/F,MAAI,qBAAqB,QAAQ,iBAAiB,oBAAoB,mBAAmB,kBAAkB,OAAO,GAAG;AACnH,WAAO,OAAO,kBAAkB;AAAA,EAClC;AACA,MAAI,CAAC,QAAQ,kBAAkB,UAAU,mBAAmB,OAAQ,QAAO,OAAO,4BAA4B;AAC9G,SAAO;AACT;"}