@ahggg/dsh-side-chat 0.4.2 → 0.5.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 (40) hide show
  1. package/lib/client/index.d.ts +1 -1
  2. package/lib/client/index.d.ts.map +1 -1
  3. package/lib/client/index.js +1 -1
  4. package/lib/client/index.js.map +1 -1
  5. package/lib/client/panel/SelectionQuote.d.ts.map +1 -1
  6. package/lib/client/panel/SelectionQuote.js +26 -1
  7. package/lib/client/panel/SelectionQuote.js.map +1 -1
  8. package/lib/client/parent-composer/ParentConversationAnnotations.d.ts.map +1 -1
  9. package/lib/client/parent-composer/ParentConversationAnnotations.js +4 -2
  10. package/lib/client/parent-composer/ParentConversationAnnotations.js.map +1 -1
  11. package/lib/client/parent-composer/add-to-conversation.d.ts +16 -0
  12. package/lib/client/parent-composer/add-to-conversation.d.ts.map +1 -1
  13. package/lib/client/parent-composer/add-to-conversation.js +143 -17
  14. package/lib/client/parent-composer/add-to-conversation.js.map +1 -1
  15. package/lib/client/parent-composer/annotation-persistence.d.ts +19 -0
  16. package/lib/client/parent-composer/annotation-persistence.d.ts.map +1 -0
  17. package/lib/client/parent-composer/annotation-persistence.js +97 -0
  18. package/lib/client/parent-composer/annotation-persistence.js.map +1 -0
  19. package/lib/client/rc6/Rc6SideChatOverlay.d.ts.map +1 -1
  20. package/lib/client/rc6/Rc6SideChatOverlay.js +51 -3
  21. package/lib/client/rc6/Rc6SideChatOverlay.js.map +1 -1
  22. package/lib/client/rc6/sessions-adapter.d.ts +10 -0
  23. package/lib/client/rc6/sessions-adapter.d.ts.map +1 -1
  24. package/lib/client/rc6/sessions-adapter.js +64 -16
  25. package/lib/client/rc6/sessions-adapter.js.map +1 -1
  26. package/lib/client/selection/ConversationAnnotationMarkers.d.ts +9 -0
  27. package/lib/client/selection/ConversationAnnotationMarkers.d.ts.map +1 -0
  28. package/lib/client/selection/ConversationAnnotationMarkers.js +241 -0
  29. package/lib/client/selection/ConversationAnnotationMarkers.js.map +1 -0
  30. package/lib/client/selection/SelectionActions.d.ts +6 -1
  31. package/lib/client/selection/SelectionActions.d.ts.map +1 -1
  32. package/lib/client/selection/SelectionActions.js +9 -8
  33. package/lib/client/selection/SelectionActions.js.map +1 -1
  34. package/lib/client/selection/selection-controller.d.ts +11 -0
  35. package/lib/client/selection/selection-controller.d.ts.map +1 -1
  36. package/lib/client/selection/selection-controller.js +54 -0
  37. package/lib/client/selection/selection-controller.js.map +1 -1
  38. package/lib/client.js +689 -102
  39. package/lib/client.js.map +1 -1
  40. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -8,7 +8,7 @@ window.__ModuleLoader__.load({
8
8
  let react_jsx_runtime = require("react/jsx-runtime");
9
9
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
10
10
  //#region \0dsh-side-chat-css:L2hvbWUvcnVubmVyL3dvcmsvZHNoLXNpZGUtY2hhdC9kc2gtc2lkZS1jaGF0L3NyYy9jbGllbnQvcGFuZWwvc2lkZS1jaGF0LmNzcw
11
- var _dsh_side_chat_css_L2hvbWUvcnVubmVyL3dvcmsvZHNoLXNpZGUtY2hhdC9kc2gtc2lkZS1jaGF0L3NyYy9jbGllbnQvcGFuZWwvc2lkZS1jaGF0LmNzcw_default = ".dsh-side-chat-overlay {\n pointer-events: none;\n}\n\n.dsh-side-chat-overlay > * {\n pointer-events: auto;\n}\n\n.dsh-side-chat-panel {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n position: fixed;\n z-index: 70;\n right: clamp(12px, 2vw, 20px);\n bottom: clamp(12px, 2vw, 20px);\n display: flex;\n width: min(840px, calc(100vw - 32px));\n height: clamp(460px, 62dvh, 980px);\n max-height: calc(100dvh - 32px);\n min-width: 0;\n min-height: 0;\n box-sizing: border-box;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--side-chat-border);\n border-radius: 28px;\n background: var(--side-chat-bg);\n color: var(--dsw-text, #19191d);\n box-shadow: 0 12px 36px rgb(0 0 0 / 11%), 0 2px 8px rgb(0 0 0 / 6%);\n}\n\n.dsh-side-chat-conversation {\n display: flex;\n height: 100%;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n}\n\n.dsh-side-chat-transcript {\n display: flex;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 12px;\n overflow-x: hidden;\n overflow-y: auto;\n padding: 18px 20px 24px;\n scrollbar-color: color-mix(in srgb, var(--side-chat-muted) 34%, transparent) transparent;\n scrollbar-width: thin;\n}\n\n.dsh-side-chat-message {\n max-width: 92%;\n padding: 10px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 12px;\n background: var(--dsw-surface-subtle, #f7f7f9);\n}\n\n.dsh-side-chat-message[data-role=\"user\"] {\n align-self: end;\n background: var(--dsw-accent-soft, #eef4ff);\n}\n\n.dsh-side-chat-message[data-role=\"assistant\"] {\n align-self: start;\n min-width: 0;\n max-width: 100%;\n border-color: transparent;\n background: transparent;\n overflow-wrap: anywhere;\n}\n.dsh-side-chat-message-role,\n.dsh-side-chat-message-note { display: block; margin-bottom: 5px; color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-message-text { white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-message pre,\n.dsh-side-chat-turn-notice pre { overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-message[data-role=\"assistant\"] :where(table) {\n display: block;\n max-width: 100%;\n overflow-x: auto;\n}\n.dsh-side-chat-tool-branch {\n min-width: 0;\n max-width: 100%;\n flex: 0 0 auto;\n}\n.dsh-side-chat-tool {\n display: flex;\n min-width: 0;\n max-width: 100%;\n flex: 0 0 auto;\n flex-direction: column;\n border-radius: 6px;\n}\n.dsh-side-chat-tool-row {\n position: relative;\n overflow: hidden;\n}\n.dsh-side-chat-tool[data-state=\"running\"] .dsh-side-chat-tool-row::after,\n.dsh-side-chat-tool[data-state=\"pending\"] .dsh-side-chat-tool-row::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 300px;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 60%, transparent) 55%,\n transparent 100%\n );\n content: '';\n pointer-events: none;\n animation: dsh-side-chat-tool-sweep 2.6s ease-out infinite;\n}\n@keyframes dsh-side-chat-tool-sweep {\n 0% { left: -300px; }\n 90%, 100% { left: 100%; }\n}\n.dsh-side-chat-tool-row:focus-visible {\n border-radius: 4px;\n outline: 2px solid color-mix(in srgb, var(--dsw-alias-button-info, #1473e6) 42%, transparent);\n outline-offset: 1px;\n}\n.dsh-side-chat-tool-leading { flex-shrink: 0; }\n.dsh-side-chat-tool-chevron { color: var(--dsw-alias-label-secondary, var(--side-chat-muted)); }\n.dsh-side-chat-tool-title { font-weight: 400; }\n.dsh-side-chat-tool-separator {\n width: 2px;\n height: 2px;\n flex: none;\n margin: 0 8px;\n border-radius: 1px;\n background: var(--dsw-alias-label-caption, #a1a1aa);\n}\n.dsh-side-chat-tool-summary {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n color: var(--dsw-alias-label-tertiary, var(--side-chat-muted));\n font-size: 14px;\n line-height: 24px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-side-chat-tool-error-summary { color: var(--dsw-alias-state-error-primary, var(--dsw-danger, #b42318)); }\n.dsh-side-chat-tool-body-wrap {\n display: flex;\n min-width: 0;\n flex-direction: column;\n}\n.dsh-side-chat-tool-code,\n.dsh-side-chat-tool-diff,\n.dsh-side-chat-tool-read,\n.dsh-side-chat-tool-search,\n.dsh-side-chat-tool-terminal,\n.dsh-side-chat-tool-web {\n margin: 4px 0 4px 4px;\n}\n.dsh-side-chat-tool-code { --dsl-code-block-content-font: var(--dsw-font-markdown-code-block-small); }\n.dsh-side-chat-tool-terminal {\n --dsl-terminal-font: var(--dsw-font-markdown-code-block-small);\n --dsl-terminal-line-height: 18px;\n --dsl-terminal-output-max-height: 224px;\n border: 1px solid var(--dsw-alias-border-l1, var(--side-chat-border));\n}\n.dsh-side-chat-tool-io-card {\n display: flex;\n flex-direction: column;\n margin: 4px 0 4px 4px;\n border: 1px solid var(--dsw-alias-border-l1, var(--side-chat-border));\n border-radius: 12px;\n background: var(--dsw-alias-markdown-code-block, #f6f6f7);\n font: var(--dsw-font-markdown-code-block-small, 12px/18px ui-monospace, SFMono-Regular, Consolas, monospace);\n}\n.dsh-side-chat-tool-io-section {\n display: grid;\n max-height: 150px;\n grid-template-columns: max-content minmax(0, 1fr);\n column-gap: 14px;\n align-items: baseline;\n overflow-y: auto;\n padding: 12px 16px;\n}\n.dsh-side-chat-tool-io-divider {\n height: 1px;\n flex: none;\n background: var(--dsw-alias-border-l2, var(--side-chat-border));\n}\n.dsh-side-chat-tool-io-label {\n position: sticky;\n top: 0;\n align-self: start;\n color: var(--dsw-alias-label-caption, #8d8d95);\n}\n.dsh-side-chat-tool-io-text {\n min-width: 0;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--dsw-alias-label-secondary, #4b4b52);\n}\n.dsh-side-chat-tool-io-text[data-error] { color: var(--dsw-alias-state-error-primary, var(--dsw-danger, #b42318)); }\n.dsh-side-chat-tool-subcalls {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 4px 0 2px 22px;\n padding-left: 8px;\n border-left: 1px solid var(--dsw-alias-border-l2, var(--side-chat-border));\n}\n.dsh-side-chat-tool-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n}\n.dsh-side-chat-turn-notice,\n.dsh-side-chat-interaction,\n.dsh-side-chat-queue { padding: 10px; border: 1px solid var(--side-chat-border); border-radius: 10px; }\n.dsh-side-chat-interaction fieldset { margin: 8px 0; border: 1px solid var(--side-chat-border); border-radius: 8px; }\n.dsh-side-chat-question-option { display: flex; gap: 8px; margin: 8px 0; }\n.dsh-side-chat-interaction textarea { width: 100%; box-sizing: border-box; resize: vertical; }\n.dsh-side-chat-interaction-actions,\n.dsh-side-chat-composer > div,\n.dsh-side-chat-queue > div { display: flex; justify-content: end; gap: 8px; }\n.dsh-side-chat-interaction button,\n.dsh-side-chat-composer button,\n.dsh-side-chat-queue button { min-height: 32px; border: 1px solid var(--side-chat-border); border-radius: 7px; background: var(--dsw-control, #f7f7f9); color: inherit; cursor: pointer; }\n.dsh-side-chat-composer {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px;\n align-items: end;\n margin: 0 12px 12px;\n padding: 8px 8px 8px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-composer textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-composer button { align-self: end; }\n.dsh-side-chat-loading { display: grid; height: 100%; place-items: center; color: var(--side-chat-muted); }\n\n.dsh-side-chat-header {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px 12px;\n align-items: center;\n flex: 0 0 auto;\n min-height: 46px;\n box-sizing: border-box;\n padding: 5px 10px 5px 16px;\n border-bottom: 1px solid var(--side-chat-border);\n background: var(--side-chat-bg);\n}\n\n.dsh-side-chat-heading { display: flex; min-width: 0; flex-direction: column; }\n.dsh-side-chat-heading strong { font-size: 14px; font-weight: 600; }\n.dsh-side-chat-footer { color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-header button,\n.dsh-side-chat-inline-actions button,\n.dsh-side-chat-draft button,\n.dsh-side-chat-error button,\n.dsh-side-chat-selection-actions button {\n min-height: 32px;\n border: 1px solid var(--side-chat-border);\n border-radius: 7px;\n background: var(--dsw-control, #f7f7f9);\n color: inherit;\n cursor: pointer;\n}\n.dsh-side-chat-header button:disabled { cursor: not-allowed; opacity: .55; }\n.dsh-side-chat-header .dsh-side-chat-heading {\n align-items: flex-start;\n min-height: 0;\n padding: 4px 0;\n border: 0;\n background: transparent;\n text-align: left;\n}\n.dsh-side-chat-header > button:last-child {\n width: 32px;\n min-height: 32px;\n padding: 0;\n border: 0;\n border-radius: 999px;\n background: transparent;\n font-size: 20px;\n line-height: 1;\n}\n.dsh-side-chat-header > button:last-child:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n\n.dsh-side-chat-quote { position: relative; max-width: 100%; align-self: flex-start; }\n.dsh-side-chat-quote-chip {\n display: inline-flex;\n min-height: 36px;\n align-items: center;\n overflow: hidden;\n padding: 0;\n border: 1px solid var(--side-chat-border);\n border-radius: 999px;\n background: var(--side-chat-bg);\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-chip { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-trigger {\n display: inline-flex;\n min-height: 34px;\n align-items: center;\n gap: 8px;\n padding: 0 11px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-quote-trigger strong { font-size: 13px; font-weight: 500; line-height: 1; }\n.dsh-side-chat-quote-icon {\n width: 16px;\n height: 16px;\n flex: 0 0 auto;\n color: var(--side-chat-muted);\n fill: none;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 1.7;\n}\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-remove {\n display: grid;\n width: 0;\n height: 34px;\n min-height: 34px;\n box-sizing: border-box;\n flex: 0 0 auto;\n place-items: center;\n overflow: hidden;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--side-chat-muted);\n cursor: pointer;\n font: inherit;\n font-size: 18px;\n line-height: 1;\n opacity: 0;\n pointer-events: none;\n transition: width 120ms ease, margin-left 120ms ease, opacity 100ms ease, background-color 100ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-remove,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-remove {\n width: 30px;\n opacity: 1;\n pointer-events: auto;\n}\n.dsh-side-chat-quote-remove:hover { background: rgb(0 0 0 / 6%); color: inherit; }\n.dsh-side-chat-quote-details {\n position: absolute;\n z-index: 10;\n bottom: calc(100% + 8px);\n left: 0;\n width: min(520px, calc(100vw - 64px));\n max-width: calc(100vw - 48px);\n box-sizing: border-box;\n padding: 14px 16px;\n border: 1px solid var(--side-chat-border);\n border-radius: 16px;\n background: var(--side-chat-bg);\n box-shadow: 0 4px 14px rgb(0 0 0 / 8%);\n font-size: 14px;\n line-height: 1.45;\n opacity: 0;\n pointer-events: none;\n transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 4px);\n visibility: hidden;\n transition: opacity 100ms ease, transform 120ms ease, visibility 100ms ease;\n}\n.dsh-side-chat-quote-details::before {\n content: '';\n position: absolute;\n right: 0;\n bottom: -8px;\n left: 0;\n height: 8px;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-details,\n.dsh-side-chat-quote[data-hovered] .dsh-side-chat-quote-details,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-details,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-details {\n opacity: 1;\n pointer-events: auto;\n transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 0);\n visibility: visible;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details {\n top: calc(100% + 8px);\n right: 0;\n bottom: auto;\n left: auto;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details::before {\n top: -8px;\n bottom: auto;\n}\n.dsh-side-chat-quote-details-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\n.dsh-side-chat-quote-details-header strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-detail + .dsh-side-chat-quote-detail {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--side-chat-border);\n}\n.dsh-side-chat-quote pre {\n max-height: 180px;\n margin: 4px 0 0;\n overflow: auto;\n white-space: pre-wrap;\n font: inherit;\n}\n.dsh-side-chat-quote-comment {\n margin-top: 9px;\n}\n.dsh-side-chat-quote-comment > strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-comment > pre { margin-top: 4px; }\n.dsh-side-chat-error { margin: 10px 16px 0; padding: 10px 12px; border: 1px solid var(--side-chat-border); border-radius: 14px; background: var(--dsw-surface-subtle, #f7f7f9); }\n.dsh-side-chat-error { border-color: var(--dsw-danger, #b42318); }\n.dsh-side-chat-body { min-height: 0; flex: 1; overflow: hidden; }\n.dsh-side-chat-annotated-user-message {\n display: flex;\n max-width: 92%;\n align-self: end;\n align-items: flex-start;\n flex-direction: column;\n gap: 8px;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-message { max-width: 100%; align-self: stretch; }\n\n/* The DSH occurrence remains the durable serialization carrier, while this\n plugin-owned capsule supplies the visible and interactive projection. */\n[data-composer-seat] [data-decoration=\"chip\"][title=\"__dsh_side_chat_annotations__\"] {\n visibility: hidden;\n}\n.dsh-side-chat-parent-annotation-dock,\n.dsh-side-chat-parent-user-message {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n color: var(--dsw-text, #19191d);\n}\n.dsh-side-chat-parent-annotation-dock {\n position: relative;\n z-index: 20;\n width: calc(100% - 32px);\n max-width: var(--dsh-composer-card-max-width, 780px);\n height: 0;\n margin: 0 auto;\n pointer-events: none;\n}\n.dsh-side-chat-parent-annotation-dock > .dsh-side-chat-quote {\n position: absolute;\n top: 16px;\n left: 16px;\n pointer-events: auto;\n}\n.dsh-side-chat-parent-user-message {\n display: flex;\n width: 100%;\n flex-direction: column;\n align-items: flex-end;\n gap: 8px;\n}\n.dsh-side-chat-parent-user-message > .dsh-side-chat-quote { align-self: flex-end; }\n.dsh-side-chat-parent-user-message > .dsh-side-chat-quote .dsh-side-chat-quote-details {\n right: 0;\n left: auto;\n}\n.dsh-side-chat-draft {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n min-height: 0;\n flex: 0 0 auto;\n gap: 8px;\n align-items: end;\n margin: auto 12px 12px;\n padding: 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-draft > .dsh-side-chat-quote { grid-column: 1 / -1; }\n.dsh-side-chat-draft label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n}\n.dsh-side-chat-draft textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px 2px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-draft > button { align-self: end; }\n.dsh-side-chat-panel .dsh-side-chat-send-button,\n.dsh-side-chat-panel .dsh-side-chat-stop-button {\n display: grid;\n width: 34px;\n height: 34px;\n min-height: 34px;\n flex: none;\n place-items: center;\n padding: 1px 6px;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-button-info-fill, #4176e6);\n color: #fff;\n cursor: pointer;\n line-height: 1;\n transform: translateY(-2px);\n transition: background-color 100ms ease;\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:hover:not(:disabled),\n.dsh-side-chat-panel .dsh-side-chat-stop-button:hover:not(:disabled) {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:disabled,\n.dsh-side-chat-panel .dsh-side-chat-stop-button:disabled { cursor: default; opacity: .4; }\n.dsh-side-chat-footer { display: none; }\n.dsh-side-chat-announcer { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }\n\n.dsh-side-chat-selection-actions {\n position: fixed;\n z-index: 90;\n display: flex;\n max-width: calc(100vw - 16px);\n flex-wrap: wrap;\n gap: 0;\n padding: 0;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 4px 14px rgb(0 0 0 / 12%);\n overflow: hidden;\n}\n.dsh-side-chat-selection-actions button {\n min-height: 36px;\n padding: 0 14px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-selection-actions button:hover:not(:disabled),\n.dsh-side-chat-selection-actions button:focus-visible {\n background: var(--dsw-surface-subtle, #f3f3f5);\n}\n.dsh-side-chat-selection-actions button + button {\n border-left: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 0;\n}\n\n.dsh-side-chat-selection-marker {\n position: fixed;\n z-index: 91;\n display: grid;\n width: 28px;\n height: 28px;\n place-items: center;\n border: 2px solid var(--dsw-surface, #fff);\n border-radius: 999px;\n background: var(--dsw-alias-button-info, #1473e6);\n box-shadow: 0 2px 6px rgb(0 0 0 / 12%);\n color: #fff;\n font-size: 13px;\n font-weight: 600;\n line-height: 1;\n pointer-events: none;\n}\n\n.dsh-side-chat-selection-comment {\n position: fixed;\n z-index: 92;\n display: grid;\n max-width: calc(100vw - 16px);\n box-sizing: border-box;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 20px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 5px 18px rgb(0 0 0 / 9%);\n color: var(--dsw-text, #19191d);\n}\n.dsh-side-chat-selection-comment textarea {\n width: 100%;\n min-height: 48px;\n max-height: 128px;\n box-sizing: border-box;\n resize: none;\n padding: 6px 8px;\n overflow-y: auto;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.45;\n}\n.dsh-side-chat-selection-comment-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.dsh-side-chat-selection-comment-actions button {\n min-height: 32px;\n padding: 0 14px;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-selection-comment-actions button:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-selection-comment-actions .dsh-side-chat-selection-comment-save {\n border-color: transparent;\n background: var(--dsw-alias-button-info, #1473e6);\n color: #fff;\n}\n.dsh-side-chat-selection-comment-actions .dsh-side-chat-selection-comment-save:hover {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n\n@media (max-width: 900px) {\n .dsh-side-chat-panel {\n right: 12px;\n bottom: 12px;\n width: calc(100vw - 24px);\n max-height: calc(100dvh - 24px);\n border-radius: 24px;\n }\n}\n\n@media (max-width: 720px) {\n .dsh-side-chat-panel {\n right: 8px;\n bottom: 8px;\n width: calc(100vw - 16px);\n height: min(78dvh, 760px);\n max-height: calc(100dvh - 16px);\n border-radius: 22px;\n }\n .dsh-side-chat-transcript { padding: 14px 14px 20px; }\n .dsh-side-chat-header { padding-left: 14px; }\n .dsh-side-chat-error { margin-inline: 12px; }\n}\n\n@media (max-height: 620px) {\n .dsh-side-chat-panel {\n bottom: 8px;\n height: calc(100dvh - 16px);\n max-height: calc(100dvh - 16px);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .dsh-side-chat-panel { animation: dsh-side-chat-enter 160ms ease-out; }\n @keyframes dsh-side-chat-enter { from { transform: translateY(18px) scale(.985); opacity: .7; } }\n}\n\n@media (forced-colors: active) {\n.dsh-side-chat-panel,\n.dsh-side-chat-selection-actions,\n.dsh-side-chat-selection-comment { border: 1px solid CanvasText; }\n}\n";
11
+ var _dsh_side_chat_css_L2hvbWUvcnVubmVyL3dvcmsvZHNoLXNpZGUtY2hhdC9kc2gtc2lkZS1jaGF0L3NyYy9jbGllbnQvcGFuZWwvc2lkZS1jaGF0LmNzcw_default = ".dsh-side-chat-overlay {\n pointer-events: none;\n}\n\n.dsh-side-chat-overlay > * {\n pointer-events: auto;\n}\n\n.dsh-side-chat-panel {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n position: fixed;\n z-index: 70;\n right: clamp(12px, 2vw, 20px);\n bottom: clamp(12px, 2vw, 20px);\n display: flex;\n width: min(840px, calc(100vw - 32px));\n height: clamp(460px, 62dvh, 980px);\n max-height: calc(100dvh - 32px);\n min-width: 0;\n min-height: 0;\n box-sizing: border-box;\n flex-direction: column;\n overflow: hidden;\n border: 1px solid var(--side-chat-border);\n border-radius: 28px;\n background: var(--side-chat-bg);\n color: var(--dsw-text, #19191d);\n box-shadow: 0 12px 36px rgb(0 0 0 / 11%), 0 2px 8px rgb(0 0 0 / 6%);\n}\n\n.dsh-side-chat-conversation {\n display: flex;\n height: 100%;\n min-height: 0;\n flex-direction: column;\n overflow: hidden;\n}\n\n.dsh-side-chat-transcript {\n display: flex;\n min-height: 0;\n flex: 1;\n flex-direction: column;\n gap: 12px;\n overflow-x: hidden;\n overflow-y: auto;\n padding: 18px 20px 24px;\n scrollbar-color: color-mix(in srgb, var(--side-chat-muted) 34%, transparent) transparent;\n scrollbar-width: thin;\n}\n\n.dsh-side-chat-message {\n max-width: 92%;\n padding: 10px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 12px;\n background: var(--dsw-surface-subtle, #f7f7f9);\n}\n\n.dsh-side-chat-message[data-role=\"user\"] {\n align-self: end;\n background: var(--dsw-accent-soft, #eef4ff);\n}\n\n.dsh-side-chat-message[data-role=\"assistant\"] {\n align-self: start;\n min-width: 0;\n max-width: 100%;\n border-color: transparent;\n background: transparent;\n overflow-wrap: anywhere;\n}\n.dsh-side-chat-message-role,\n.dsh-side-chat-message-note { display: block; margin-bottom: 5px; color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-message-text { white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-message pre,\n.dsh-side-chat-turn-notice pre { overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; }\n.dsh-side-chat-message[data-role=\"assistant\"] :where(table) {\n display: block;\n max-width: 100%;\n overflow-x: auto;\n}\n.dsh-side-chat-tool-branch {\n min-width: 0;\n max-width: 100%;\n flex: 0 0 auto;\n}\n.dsh-side-chat-tool {\n display: flex;\n min-width: 0;\n max-width: 100%;\n flex: 0 0 auto;\n flex-direction: column;\n border-radius: 6px;\n}\n.dsh-side-chat-tool-row {\n position: relative;\n overflow: hidden;\n}\n.dsh-side-chat-tool[data-state=\"running\"] .dsh-side-chat-tool-row::after,\n.dsh-side-chat-tool[data-state=\"pending\"] .dsh-side-chat-tool-row::after {\n position: absolute;\n top: 0;\n bottom: 0;\n left: 0;\n width: 300px;\n background: linear-gradient(\n 90deg,\n transparent 0%,\n color-mix(in srgb, var(--dsw-alias-bg-base, #fff) 60%, transparent) 55%,\n transparent 100%\n );\n content: '';\n pointer-events: none;\n animation: dsh-side-chat-tool-sweep 2.6s ease-out infinite;\n}\n@keyframes dsh-side-chat-tool-sweep {\n 0% { left: -300px; }\n 90%, 100% { left: 100%; }\n}\n.dsh-side-chat-tool-row:focus-visible {\n border-radius: 4px;\n outline: 2px solid color-mix(in srgb, var(--dsw-alias-button-info, #1473e6) 42%, transparent);\n outline-offset: 1px;\n}\n.dsh-side-chat-tool-leading { flex-shrink: 0; }\n.dsh-side-chat-tool-chevron { color: var(--dsw-alias-label-secondary, var(--side-chat-muted)); }\n.dsh-side-chat-tool-title { font-weight: 400; }\n.dsh-side-chat-tool-separator {\n width: 2px;\n height: 2px;\n flex: none;\n margin: 0 8px;\n border-radius: 1px;\n background: var(--dsw-alias-label-caption, #a1a1aa);\n}\n.dsh-side-chat-tool-summary {\n flex: 1 1 auto;\n min-width: 0;\n overflow: hidden;\n color: var(--dsw-alias-label-tertiary, var(--side-chat-muted));\n font-size: 14px;\n line-height: 24px;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.dsh-side-chat-tool-error-summary { color: var(--dsw-alias-state-error-primary, var(--dsw-danger, #b42318)); }\n.dsh-side-chat-tool-body-wrap {\n display: flex;\n min-width: 0;\n flex-direction: column;\n}\n.dsh-side-chat-tool-code,\n.dsh-side-chat-tool-diff,\n.dsh-side-chat-tool-read,\n.dsh-side-chat-tool-search,\n.dsh-side-chat-tool-terminal,\n.dsh-side-chat-tool-web {\n margin: 4px 0 4px 4px;\n}\n.dsh-side-chat-tool-code { --dsl-code-block-content-font: var(--dsw-font-markdown-code-block-small); }\n.dsh-side-chat-tool-terminal {\n --dsl-terminal-font: var(--dsw-font-markdown-code-block-small);\n --dsl-terminal-line-height: 18px;\n --dsl-terminal-output-max-height: 224px;\n border: 1px solid var(--dsw-alias-border-l1, var(--side-chat-border));\n}\n.dsh-side-chat-tool-io-card {\n display: flex;\n flex-direction: column;\n margin: 4px 0 4px 4px;\n border: 1px solid var(--dsw-alias-border-l1, var(--side-chat-border));\n border-radius: 12px;\n background: var(--dsw-alias-markdown-code-block, #f6f6f7);\n font: var(--dsw-font-markdown-code-block-small, 12px/18px ui-monospace, SFMono-Regular, Consolas, monospace);\n}\n.dsh-side-chat-tool-io-section {\n display: grid;\n max-height: 150px;\n grid-template-columns: max-content minmax(0, 1fr);\n column-gap: 14px;\n align-items: baseline;\n overflow-y: auto;\n padding: 12px 16px;\n}\n.dsh-side-chat-tool-io-divider {\n height: 1px;\n flex: none;\n background: var(--dsw-alias-border-l2, var(--side-chat-border));\n}\n.dsh-side-chat-tool-io-label {\n position: sticky;\n top: 0;\n align-self: start;\n color: var(--dsw-alias-label-caption, #8d8d95);\n}\n.dsh-side-chat-tool-io-text {\n min-width: 0;\n white-space: pre-wrap;\n word-break: break-word;\n color: var(--dsw-alias-label-secondary, #4b4b52);\n}\n.dsh-side-chat-tool-io-text[data-error] { color: var(--dsw-alias-state-error-primary, var(--dsw-danger, #b42318)); }\n.dsh-side-chat-tool-subcalls {\n display: flex;\n flex-direction: column;\n gap: 4px;\n margin: 4px 0 2px 22px;\n padding-left: 8px;\n border-left: 1px solid var(--dsw-alias-border-l2, var(--side-chat-border));\n}\n.dsh-side-chat-tool-visually-hidden {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip: rect(0 0 0 0);\n white-space: nowrap;\n}\n.dsh-side-chat-turn-notice,\n.dsh-side-chat-interaction,\n.dsh-side-chat-queue { padding: 10px; border: 1px solid var(--side-chat-border); border-radius: 10px; }\n.dsh-side-chat-interaction fieldset { margin: 8px 0; border: 1px solid var(--side-chat-border); border-radius: 8px; }\n.dsh-side-chat-question-option { display: flex; gap: 8px; margin: 8px 0; }\n.dsh-side-chat-interaction textarea { width: 100%; box-sizing: border-box; resize: vertical; }\n.dsh-side-chat-interaction-actions,\n.dsh-side-chat-composer > div,\n.dsh-side-chat-queue > div { display: flex; justify-content: end; gap: 8px; }\n.dsh-side-chat-interaction button,\n.dsh-side-chat-composer button,\n.dsh-side-chat-queue button { min-height: 32px; border: 1px solid var(--side-chat-border); border-radius: 7px; background: var(--dsw-control, #f7f7f9); color: inherit; cursor: pointer; }\n.dsh-side-chat-composer {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px;\n align-items: end;\n margin: 0 12px 12px;\n padding: 8px 8px 8px 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-composer textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-composer button { align-self: end; }\n.dsh-side-chat-loading { display: grid; height: 100%; place-items: center; color: var(--side-chat-muted); }\n\n.dsh-side-chat-header {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n gap: 8px 12px;\n align-items: center;\n flex: 0 0 auto;\n min-height: 46px;\n box-sizing: border-box;\n padding: 5px 10px 5px 16px;\n border-bottom: 1px solid var(--side-chat-border);\n background: var(--side-chat-bg);\n}\n\n.dsh-side-chat-heading { display: flex; min-width: 0; flex-direction: column; }\n.dsh-side-chat-heading strong { font-size: 14px; font-weight: 600; }\n.dsh-side-chat-footer { color: var(--side-chat-muted); font-size: 12px; }\n.dsh-side-chat-header button,\n.dsh-side-chat-inline-actions button,\n.dsh-side-chat-draft button,\n.dsh-side-chat-error button,\n.dsh-side-chat-selection-actions button {\n min-height: 32px;\n border: 1px solid var(--side-chat-border);\n border-radius: 7px;\n background: var(--dsw-control, #f7f7f9);\n color: inherit;\n cursor: pointer;\n}\n.dsh-side-chat-header button:disabled { cursor: not-allowed; opacity: .55; }\n.dsh-side-chat-header .dsh-side-chat-heading {\n align-items: flex-start;\n min-height: 0;\n padding: 4px 0;\n border: 0;\n background: transparent;\n text-align: left;\n}\n.dsh-side-chat-header > button:last-child {\n width: 32px;\n min-height: 32px;\n padding: 0;\n border: 0;\n border-radius: 999px;\n background: transparent;\n font-size: 20px;\n line-height: 1;\n}\n.dsh-side-chat-header > button:last-child:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n\n.dsh-side-chat-quote { position: relative; max-width: 100%; align-self: flex-start; }\n.dsh-side-chat-quote-chip {\n display: inline-flex;\n min-height: 36px;\n align-items: center;\n overflow: hidden;\n padding: 0;\n border: 1px solid var(--side-chat-border);\n border-radius: 999px;\n background: var(--side-chat-bg);\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-chip,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-chip { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-trigger {\n display: inline-flex;\n min-height: 34px;\n align-items: center;\n gap: 8px;\n padding: 0 11px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-quote-trigger strong { font-size: 13px; font-weight: 500; line-height: 1; }\n.dsh-side-chat-quote-icon {\n width: 16px;\n height: 16px;\n flex: 0 0 auto;\n color: var(--side-chat-muted);\n fill: none;\n stroke: currentColor;\n stroke-linecap: round;\n stroke-linejoin: round;\n stroke-width: 1.7;\n}\n.dsh-side-chat-quote-chip .dsh-side-chat-quote-remove {\n display: grid;\n width: 0;\n height: 34px;\n min-height: 34px;\n box-sizing: border-box;\n flex: 0 0 auto;\n place-items: center;\n overflow: hidden;\n padding: 0;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: var(--side-chat-muted);\n cursor: pointer;\n font: inherit;\n font-size: 18px;\n line-height: 1;\n opacity: 0;\n pointer-events: none;\n transition: width 120ms ease, margin-left 120ms ease, opacity 100ms ease, background-color 100ms ease;\n}\n.dsh-side-chat-quote:hover .dsh-side-chat-quote-remove,\n.dsh-side-chat-quote:focus-within .dsh-side-chat-quote-remove {\n width: 30px;\n opacity: 1;\n pointer-events: auto;\n}\n.dsh-side-chat-quote-remove:hover { background: rgb(0 0 0 / 6%); color: inherit; }\n.dsh-side-chat-quote-details {\n position: absolute;\n z-index: 10;\n bottom: calc(100% + 8px);\n left: 0;\n width: min(520px, calc(100vw - 64px));\n max-width: calc(100vw - 48px);\n box-sizing: border-box;\n padding: 14px 16px;\n border: 1px solid var(--side-chat-border);\n border-radius: 16px;\n background: var(--side-chat-bg);\n box-shadow: 0 4px 14px rgb(0 0 0 / 8%);\n font-size: 14px;\n line-height: 1.45;\n opacity: 0;\n pointer-events: none;\n transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 4px);\n visibility: hidden;\n transition: opacity 100ms ease, transform 120ms ease, visibility 100ms ease;\n}\n.dsh-side-chat-quote-details::before {\n content: '';\n position: absolute;\n right: 0;\n bottom: -8px;\n left: 0;\n height: 8px;\n}\n.dsh-side-chat-quote[data-hovered] .dsh-side-chat-quote-details,\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-details {\n opacity: 1;\n pointer-events: auto;\n transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 0);\n visibility: visible;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details {\n top: calc(100% + 8px);\n right: 0;\n bottom: auto;\n left: auto;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-quote-details::before {\n top: -8px;\n bottom: auto;\n}\n.dsh-side-chat-quote-details-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; }\n.dsh-side-chat-quote-details-header strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-detail + .dsh-side-chat-quote-detail {\n margin-top: 12px;\n padding-top: 12px;\n border-top: 1px solid var(--side-chat-border);\n}\n.dsh-side-chat-quote pre {\n max-height: 180px;\n margin: 4px 0 0;\n overflow: auto;\n white-space: pre-wrap;\n font: inherit;\n}\n.dsh-side-chat-quote-comment {\n margin-top: 9px;\n}\n.dsh-side-chat-quote-comment > strong { color: var(--side-chat-muted); font-size: 13px; font-weight: 500; }\n.dsh-side-chat-quote-comment > pre { margin-top: 4px; }\n.dsh-side-chat-error { margin: 10px 16px 0; padding: 10px 12px; border: 1px solid var(--side-chat-border); border-radius: 14px; background: var(--dsw-surface-subtle, #f7f7f9); }\n.dsh-side-chat-error { border-color: var(--dsw-danger, #b42318); }\n.dsh-side-chat-body { min-height: 0; flex: 1; overflow: hidden; }\n.dsh-side-chat-annotated-user-message {\n display: flex;\n max-width: 92%;\n align-self: end;\n align-items: flex-start;\n flex-direction: column;\n gap: 8px;\n}\n.dsh-side-chat-annotated-user-message .dsh-side-chat-message { max-width: 100%; align-self: stretch; }\n\n/* The DSH occurrence remains the durable serialization carrier, while this\n plugin-owned capsule supplies the visible and interactive projection. */\n[data-composer-seat] [data-decoration=\"chip\"][title=\"__dsh_side_chat_annotations__\"] {\n visibility: hidden;\n}\n.dsh-side-chat-parent-annotation-dock,\n.dsh-side-chat-parent-user-message {\n --side-chat-border: var(--dsw-border, #d8d8de);\n --side-chat-bg: var(--dsw-surface, #ffffff);\n --side-chat-muted: var(--dsw-text-muted, #62636a);\n color: var(--dsw-text, #19191d);\n}\n.dsh-side-chat-parent-annotation-dock {\n position: relative;\n z-index: 20;\n width: calc(100% - 32px);\n max-width: var(--dsh-composer-card-max-width, 780px);\n height: 0;\n /* The terminal zero-height dock would otherwise add a second gap between\n Todo/Goal/Queue and the input card. Its child still lands 10px inside the\n following card: -gap + top:16px against the card's own 6px gap. */\n margin: calc(0px - var(--dsh-composer-stack-gap, 6px)) auto 0;\n pointer-events: none;\n}\n.dsh-side-chat-parent-annotation-dock > .dsh-side-chat-quote {\n position: absolute;\n top: 16px;\n left: 16px;\n pointer-events: auto;\n}\n.dsh-side-chat-parent-user-message {\n display: flex;\n width: 100%;\n min-width: 0;\n flex-direction: column;\n align-items: stretch;\n gap: 8px;\n}\n.dsh-side-chat-parent-user-message > .dsh-side-chat-quote { align-self: flex-end; }\n/* rc.6 caps its inner user stack at 82%; give that percentage the full chat\n column as its containing width instead of the annotation chip's shrink width. */\n.dsh-side-chat-parent-user-message-body { width: 100%; min-width: 0; }\n.dsh-side-chat-parent-user-message > .dsh-side-chat-quote .dsh-side-chat-quote-details {\n right: 0;\n left: auto;\n}\n.dsh-side-chat-draft {\n display: grid;\n grid-template-columns: minmax(0, 1fr) auto;\n min-height: 0;\n flex: 0 0 auto;\n gap: 8px;\n align-items: end;\n margin: auto 12px 12px;\n padding: 12px;\n border: 1px solid var(--side-chat-border);\n border-radius: 24px;\n background: var(--side-chat-bg);\n box-shadow: 0 2px 8px rgb(0 0 0 / 5%);\n}\n.dsh-side-chat-draft > .dsh-side-chat-quote { grid-column: 1 / -1; }\n.dsh-side-chat-draft label {\n position: absolute;\n width: 1px;\n height: 1px;\n overflow: hidden;\n clip-path: inset(50%);\n}\n.dsh-side-chat-draft textarea {\n width: 100%;\n height: auto;\n min-height: 24px;\n max-height: 160px;\n box-sizing: border-box;\n resize: none;\n overflow-y: hidden;\n padding: 6px 2px;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.5;\n}\n.dsh-side-chat-draft > button { align-self: end; }\n.dsh-side-chat-panel .dsh-side-chat-send-button,\n.dsh-side-chat-panel .dsh-side-chat-stop-button {\n display: grid;\n width: 34px;\n height: 34px;\n min-height: 34px;\n flex: none;\n place-items: center;\n padding: 1px 6px;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-button-info-fill, #4176e6);\n color: #fff;\n cursor: pointer;\n line-height: 1;\n transform: translateY(-2px);\n transition: background-color 100ms ease;\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:hover:not(:disabled),\n.dsh-side-chat-panel .dsh-side-chat-stop-button:hover:not(:disabled) {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n.dsh-side-chat-panel .dsh-side-chat-send-button:disabled,\n.dsh-side-chat-panel .dsh-side-chat-stop-button:disabled { cursor: default; opacity: .4; }\n.dsh-side-chat-footer { display: none; }\n.dsh-side-chat-announcer { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); }\n\n.dsh-side-chat-selection-actions {\n position: fixed;\n z-index: 90;\n display: flex;\n max-width: calc(100vw - 16px);\n flex-wrap: wrap;\n gap: 0;\n padding: 0;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 4px 14px rgb(0 0 0 / 12%);\n overflow: hidden;\n}\n.dsh-side-chat-selection-actions button {\n min-height: 36px;\n padding: 0 14px;\n border: 0;\n border-radius: 0;\n background: transparent;\n color: inherit;\n transition: background-color 120ms ease;\n}\n.dsh-side-chat-selection-actions button:hover:not(:disabled),\n.dsh-side-chat-selection-actions button:focus-visible {\n background: var(--dsw-surface-subtle, #f3f3f5);\n}\n.dsh-side-chat-selection-actions button + button {\n border-left: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 0;\n}\n\n::highlight(dsh-side-chat-annotations) {\n background: color-mix(in srgb, var(--dsw-alias-button-info, #1473e6) 18%, transparent);\n}\n::highlight(dsh-side-chat-active-annotation) {\n background: color-mix(in srgb, var(--dsw-alias-button-info, #1473e6) 32%, transparent);\n text-decoration: underline;\n text-decoration-color: color-mix(in srgb, var(--dsw-alias-button-info, #1473e6) 70%, transparent);\n text-decoration-thickness: 1px;\n}\n\n.dsh-side-chat-annotation-marker,\n.dsh-side-chat-selection-marker {\n position: fixed;\n z-index: 91;\n display: grid;\n width: 22px;\n height: 22px;\n min-height: 22px;\n box-sizing: border-box;\n place-items: center;\n padding: 0;\n border: 0;\n border-radius: 999px;\n background: var(--dsw-alias-button-info, #1473e6);\n box-shadow: 0 2px 6px rgb(0 0 0 / 14%);\n color: #fff;\n font: inherit;\n font-size: 11px;\n font-weight: 600;\n line-height: 1;\n}\n.dsh-side-chat-annotation-marker { cursor: pointer; }\n.dsh-side-chat-selection-marker { pointer-events: none; }\n.dsh-side-chat-annotation-marker[data-large],\n.dsh-side-chat-selection-marker[data-large] { font-size: 9px; }\n.dsh-side-chat-annotation-marker[data-active] {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n.dsh-side-chat-annotation-marker:focus-visible {\n outline: 2px solid color-mix(in srgb, var(--dsw-alias-button-info, #1473e6) 32%, transparent);\n outline-offset: 1px;\n}\n\n.dsh-side-chat-selection-comment {\n position: fixed;\n z-index: 92;\n display: grid;\n max-width: calc(100vw - 16px);\n box-sizing: border-box;\n gap: 10px;\n padding: 12px;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 20px;\n background: var(--dsw-surface, #fff);\n box-shadow: 0 5px 18px rgb(0 0 0 / 9%);\n color: var(--dsw-text, #19191d);\n}\n.dsh-side-chat-selection-comment textarea {\n width: 100%;\n min-height: 48px;\n max-height: 128px;\n box-sizing: border-box;\n resize: none;\n padding: 6px 8px;\n overflow-y: auto;\n border: 0;\n outline: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n line-height: 1.45;\n}\n.dsh-side-chat-selection-comment-actions {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n}\n.dsh-side-chat-selection-comment-actions button {\n min-height: 32px;\n padding: 0 14px;\n border: 1px solid var(--dsw-border, #d8d8de);\n border-radius: 999px;\n background: var(--dsw-surface, #fff);\n color: inherit;\n cursor: pointer;\n font: inherit;\n}\n.dsh-side-chat-selection-comment-actions button:hover { background: var(--dsw-surface-subtle, #f3f3f5); }\n.dsh-side-chat-selection-comment-actions .dsh-side-chat-selection-comment-save {\n border-color: transparent;\n background: var(--dsw-alias-button-info, #1473e6);\n color: #fff;\n}\n.dsh-side-chat-selection-comment-actions .dsh-side-chat-selection-comment-save:hover {\n background: var(--dsw-alias-button-info-hover, #3467d6);\n}\n\n@media (max-width: 900px) {\n .dsh-side-chat-panel {\n right: 12px;\n bottom: 12px;\n width: calc(100vw - 24px);\n max-height: calc(100dvh - 24px);\n border-radius: 24px;\n }\n}\n\n@media (max-width: 720px) {\n .dsh-side-chat-panel {\n right: 8px;\n bottom: 8px;\n width: calc(100vw - 16px);\n height: min(78dvh, 760px);\n max-height: calc(100dvh - 16px);\n border-radius: 22px;\n }\n .dsh-side-chat-transcript { padding: 14px 14px 20px; }\n .dsh-side-chat-header { padding-left: 14px; }\n .dsh-side-chat-error { margin-inline: 12px; }\n}\n\n@media (max-height: 620px) {\n .dsh-side-chat-panel {\n bottom: 8px;\n height: calc(100dvh - 16px);\n max-height: calc(100dvh - 16px);\n }\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .dsh-side-chat-panel { animation: dsh-side-chat-enter 160ms ease-out; }\n @keyframes dsh-side-chat-enter { from { transform: translateY(18px) scale(.985); opacity: .7; } }\n}\n\n@media (forced-colors: active) {\n.dsh-side-chat-panel,\n.dsh-side-chat-selection-actions,\n.dsh-side-chat-selection-comment,\n.dsh-side-chat-annotation-marker { border: 1px solid CanvasText; }\n}\n";
12
12
  //#endregion
13
13
  //#region src/client/parent-composer/add-to-conversation.ts
14
14
  const SELECTION_REFERENCE_SOURCE = "dsh-side-chat-selection";
@@ -20,25 +20,61 @@ window.__ModuleLoader__.load({
20
20
  const trimmedComment = comment?.trim();
21
21
  return {
22
22
  text: selection.text,
23
+ selection,
23
24
  ...trimmedComment === void 0 || trimmedComment.length === 0 ? {} : { comment: trimmedComment }
24
25
  };
25
26
  }
26
27
  function encodeSelectionReference(annotations) {
27
28
  return JSON.stringify({
28
- version: 1,
29
+ version: 2,
29
30
  annotations
30
31
  });
31
32
  }
32
- function isAnnotation(value) {
33
+ function isSelection(value) {
34
+ if (typeof value !== "object" || value === null) return false;
35
+ const selection = value;
36
+ if (typeof selection.parentSessionId !== "string" || typeof selection.text !== "string" || !Number.isSafeInteger(selection.atSeq) || !Array.isArray(selection.fragments) || typeof selection.rect !== "object" || selection.rect === null) return false;
37
+ const rect = selection.rect;
38
+ if (![
39
+ rect.x,
40
+ rect.y,
41
+ rect.width,
42
+ rect.height,
43
+ rect.viewportWidth,
44
+ rect.viewportHeight
45
+ ].every((number) => typeof number === "number" && Number.isFinite(number))) return false;
46
+ return selection.fragments.every((candidate) => {
47
+ if (typeof candidate !== "object" || candidate === null) return false;
48
+ const fragment = candidate;
49
+ return typeof fragment.nodeKey === "string" && typeof fragment.nodeKind === "string" && typeof fragment.turnKey === "string" && Number.isSafeInteger(fragment.seq) && Number.isSafeInteger(fragment.startOffset) && Number.isSafeInteger(fragment.endOffset) && typeof fragment.text === "string" && [
50
+ "user",
51
+ "assistant",
52
+ "context",
53
+ "code"
54
+ ].includes(fragment.source ?? "") && typeof fragment.modelVisible === "boolean" && typeof fragment.settled === "boolean";
55
+ });
56
+ }
57
+ function isStoredAnnotation(value) {
33
58
  if (typeof value !== "object" || value === null) return false;
34
59
  const annotation = value;
35
- return typeof annotation.text === "string" && (annotation.comment === void 0 || typeof annotation.comment === "string");
60
+ return typeof annotation.text === "string" && (annotation.comment === void 0 || typeof annotation.comment === "string") && (annotation.selection === void 0 || isSelection(annotation.selection));
36
61
  }
37
- function decodeSelectionReference(ref) {
62
+ function visibleAnnotation(annotation) {
63
+ return {
64
+ text: annotation.text,
65
+ ...annotation.comment === void 0 ? {} : { comment: annotation.comment }
66
+ };
67
+ }
68
+ function decodeStoredSelectionReference(ref) {
38
69
  const value = JSON.parse(ref);
39
- if (isAnnotation(value)) return [value];
40
- if (value.version !== 1 || !Array.isArray(value.annotations) || value.annotations.length === 0 || !value.annotations.every(isAnnotation)) throw new Error("The selected conversation annotation is no longer valid.");
41
- return value.annotations;
70
+ if (isStoredAnnotation(value)) return [value];
71
+ if (typeof value !== "object" || value === null) throw new Error("The selected conversation annotation is no longer valid.");
72
+ const payload = value;
73
+ if (payload.version !== 1 && payload.version !== 2 || !Array.isArray(payload.annotations) || payload.annotations.length === 0 || !payload.annotations.every(isStoredAnnotation)) throw new Error("The selected conversation annotation is no longer valid.");
74
+ return payload.annotations;
75
+ }
76
+ function decodeSelectionReference(ref) {
77
+ return decodeStoredSelectionReference(ref).map(visibleAnnotation);
42
78
  }
43
79
  function selectedContext(annotations) {
44
80
  return [
@@ -63,16 +99,32 @@ window.__ModuleLoader__.load({
63
99
  function selectionOccurrences(snapshot) {
64
100
  return snapshot.occurrences.filter((occurrence) => occurrence.source === SELECTION_REFERENCE_SOURCE);
65
101
  }
66
- /** Read all plugin annotations represented by the current DSH input occurrence. */
67
- function conversationAnnotations(snapshot) {
102
+ function storedConversationAnnotations(snapshot) {
68
103
  return selectionOccurrences(snapshot).flatMap((occurrence) => {
69
104
  try {
70
- return [...decodeSelectionReference(occurrence.ref)];
105
+ return [...decodeStoredSelectionReference(occurrence.ref)];
71
106
  } catch {
72
107
  return [];
73
108
  }
74
109
  });
75
110
  }
111
+ /** Read all plugin annotations represented by the current DSH input occurrence. */
112
+ function conversationAnnotations(snapshot) {
113
+ return storedConversationAnnotations(snapshot).map(visibleAnnotation);
114
+ }
115
+ /** Read annotations that retain an exact source-selection anchor. */
116
+ function conversationSelectionAnnotations(snapshot) {
117
+ const anchored = [];
118
+ storedConversationAnnotations(snapshot).forEach((annotation, annotationIndex) => {
119
+ if (annotation.selection === void 0) return;
120
+ anchored.push({
121
+ ...visibleAnnotation(annotation),
122
+ annotationIndex,
123
+ selection: annotation.selection
124
+ });
125
+ });
126
+ return anchored;
127
+ }
76
128
  function draftWithoutSelectionOccurrences(snapshot) {
77
129
  const occurrences = [...selectionOccurrences(snapshot)].sort((a, b) => b.offset - a.offset);
78
130
  let draft = snapshot.draft;
@@ -105,10 +157,7 @@ window.__ModuleLoader__.load({
105
157
  }
106
158
  }
107
159
  };
108
- /** Add one passage to the parent composer's aggregated annotation occurrence. */
109
- function addSelectionToConversation(input, selection, comment) {
110
- const before = input.state.getSnapshot();
111
- const annotations = [...conversationAnnotations(before), annotationFromSelection(selection, comment)];
160
+ function writeConversationAnnotations(input, before, annotations) {
112
161
  const draft = draftWithoutSelectionOccurrences(before);
113
162
  if (selectionOccurrences(before).length > 0) input.setDraft(draft);
114
163
  const insertionState = input.state.getSnapshot();
@@ -125,6 +174,61 @@ window.__ModuleLoader__.load({
125
174
  input.setDraft(`${OBJECT_REPLACEMENT_CHARACTER}\n\n${draft}`);
126
175
  return true;
127
176
  }
177
+ /** Add one passage to the parent composer's aggregated annotation occurrence. */
178
+ function addSelectionToConversation(input, selection, comment) {
179
+ const before = input.state.getSnapshot();
180
+ return writeConversationAnnotations(input, before, [...storedConversationAnnotations(before), annotationFromSelection(selection, comment)]);
181
+ }
182
+ /** Replace the optional comment on one unsent selected-passage annotation. */
183
+ function updateConversationAnnotation(input, annotationIndex, comment) {
184
+ const before = input.state.getSnapshot();
185
+ const annotations = [...storedConversationAnnotations(before)];
186
+ const current = annotations[annotationIndex];
187
+ if (!Number.isSafeInteger(annotationIndex) || current === void 0) return false;
188
+ const trimmedComment = comment?.trim();
189
+ annotations[annotationIndex] = {
190
+ text: current.text,
191
+ ...current.selection === void 0 ? {} : { selection: current.selection },
192
+ ...trimmedComment === void 0 || trimmedComment.length === 0 ? {} : { comment: trimmedComment }
193
+ };
194
+ return writeConversationAnnotations(input, before, annotations);
195
+ }
196
+ /** Return the valid aggregated reference currently occupying the leading draft slot. */
197
+ function conversationAnnotationReference(snapshot) {
198
+ const occurrence = selectionOccurrences(snapshot).find((candidate) => candidate.offset === 0);
199
+ if (occurrence === void 0 || !snapshot.draft.startsWith(OBJECT_REPLACEMENT_CHARACTER)) return;
200
+ try {
201
+ decodeStoredSelectionReference(occurrence.ref);
202
+ return occurrence.ref;
203
+ } catch {
204
+ return;
205
+ }
206
+ }
207
+ function draftWithoutOrphanedAnnotationPrefix(snapshot) {
208
+ const prefix = `${OBJECT_REPLACEMENT_CHARACTER}\n\n`;
209
+ if (!snapshot.draft.startsWith(prefix) || snapshot.occurrences.some((occurrence) => occurrence.offset === 0)) return;
210
+ return snapshot.draft.slice(prefix.length);
211
+ }
212
+ /** Remove the plugin-owned prefix when rc.6 restored its draft without occurrences. */
213
+ function removeOrphanedConversationAnnotationPlaceholder(input) {
214
+ const draft = draftWithoutOrphanedAnnotationPrefix(input.state.getSnapshot());
215
+ if (draft === void 0) return false;
216
+ input.setDraft(draft);
217
+ return true;
218
+ }
219
+ /** Rehydrate a lost rc.6 occurrence only over the exact plugin-owned orphan prefix. */
220
+ function restoreConversationAnnotationReference(input, ref) {
221
+ let annotations;
222
+ try {
223
+ annotations = decodeStoredSelectionReference(ref);
224
+ } catch {
225
+ return false;
226
+ }
227
+ const draft = draftWithoutOrphanedAnnotationPrefix(input.state.getSnapshot());
228
+ if (draft === void 0) return false;
229
+ input.setDraft(draft);
230
+ return writeConversationAnnotations(input, input.state.getSnapshot(), annotations);
231
+ }
128
232
  function unescapeXmlText(value) {
129
233
  return value.replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&amp;", "&");
130
234
  }
@@ -248,6 +352,22 @@ window.__ModuleLoader__.load({
248
352
  (0, react.useEffect)(() => () => {
249
353
  if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
250
354
  }, []);
355
+ (0, react.useEffect)(() => {
356
+ if (!expanded) return;
357
+ const dismissOutside = (event) => {
358
+ const quote = quoteRef.current;
359
+ const target = event.target;
360
+ if (quote !== null && target instanceof Node && quote.contains(target)) return;
361
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
362
+ leaveTimerRef.current = void 0;
363
+ setHovered(false);
364
+ setExpanded(false);
365
+ };
366
+ document.addEventListener("mousedown", dismissOutside, true);
367
+ return () => {
368
+ document.removeEventListener("mousedown", dismissOutside, true);
369
+ };
370
+ }, [expanded]);
251
371
  const constrainDetailsToBoundary = () => {
252
372
  const details = detailsRef.current;
253
373
  const boundary = quoteRef.current?.closest(".dsh-side-chat-panel, [data-composer-seat], [data-chat-flow-kind]");
@@ -280,6 +400,11 @@ window.__ModuleLoader__.load({
280
400
  "aria-expanded": expanded,
281
401
  "aria-label": `${expanded ? messages.collapse : messages.expand}: ${messages.selectedPassage}`,
282
402
  onClick: () => {
403
+ if (expanded) {
404
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
405
+ leaveTimerRef.current = void 0;
406
+ setHovered(false);
407
+ }
283
408
  setExpanded((value) => !value);
284
409
  },
285
410
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
@@ -384,9 +509,12 @@ window.__ModuleLoader__.load({
384
509
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
385
510
  selections: parsed.annotations,
386
511
  messages: SIDE_CHAT_MESSAGES[currentLocale()]
387
- }), (0, react.createElement)(Original, {
388
- ...props,
389
- node
512
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
513
+ className: "dsh-side-chat-parent-user-message-body",
514
+ children: (0, react.createElement)(Original, {
515
+ ...props,
516
+ node
517
+ })
390
518
  })]
391
519
  });
392
520
  };
@@ -397,7 +525,7 @@ window.__ModuleLoader__.load({
397
525
  const removeDock = slots.inject("conversation.input.dock", () => slots.register({
398
526
  name: "conversation.input.dock",
399
527
  id: "dsh-side-chat-annotations",
400
- order: -100
528
+ order: 30
401
529
  }, ({ input }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ParentComposerAnnotations, {
402
530
  input,
403
531
  onRemove: removeAnnotations
@@ -5445,14 +5573,280 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5445
5573
  }
5446
5574
  });
5447
5575
  }
5576
+ function anchorByKey(root, nodeKey) {
5577
+ return [...root.querySelectorAll("[data-chat-anchor-key]")].find((anchor) => anchor.dataset["chatAnchorKey"] === nodeKey);
5578
+ }
5579
+ function restoreFragmentRanges(root, fragment) {
5580
+ const anchor = anchorByKey(root, fragment.nodeKey);
5581
+ if (anchor === void 0) return;
5582
+ const nodes = acceptedTextNodes(anchor, root);
5583
+ const visibleText = nodes.map((node) => node.data).join("");
5584
+ if (!Number.isSafeInteger(fragment.startOffset) || !Number.isSafeInteger(fragment.endOffset) || fragment.startOffset < 0 || fragment.endOffset <= fragment.startOffset || fragment.endOffset > visibleText.length || visibleText.slice(fragment.startOffset, fragment.endOffset) !== fragment.text) return;
5585
+ const ranges = [];
5586
+ let visibleOffset = 0;
5587
+ for (const node of nodes) {
5588
+ const nodeEnd = visibleOffset + node.data.length;
5589
+ const start = Math.max(fragment.startOffset, visibleOffset) - visibleOffset;
5590
+ const end = Math.min(fragment.endOffset, nodeEnd) - visibleOffset;
5591
+ if (end > start) {
5592
+ const range = document.createRange();
5593
+ range.setStart(node, start);
5594
+ range.setEnd(node, end);
5595
+ ranges.push(range);
5596
+ }
5597
+ visibleOffset = nodeEnd;
5598
+ if (visibleOffset >= fragment.endOffset) break;
5599
+ }
5600
+ return ranges.length === 0 ? void 0 : ranges;
5601
+ }
5602
+ /** Rebuild a saved selection only when its anchored visible text still matches. */
5603
+ function restoreDomConversationSelection(input) {
5604
+ const ranges = [];
5605
+ for (const fragment of input.selection.fragments) {
5606
+ const restored = restoreFragmentRanges(input.conversationRoot, fragment);
5607
+ if (restored === void 0) return;
5608
+ ranges.push(...restored);
5609
+ }
5610
+ const first = ranges[0];
5611
+ const last = ranges.at(-1);
5612
+ if (first === void 0 || last === void 0) return;
5613
+ const browserRange = document.createRange();
5614
+ browserRange.setStart(first.startContainer, first.startOffset);
5615
+ browserRange.setEnd(last.endContainer, last.endOffset);
5616
+ return {
5617
+ ranges,
5618
+ browserRange
5619
+ };
5620
+ }
5621
+ //#endregion
5622
+ //#region src/client/selection/ConversationAnnotationMarkers.tsx
5623
+ const ANNOTATION_HIGHLIGHT = "dsh-side-chat-annotations";
5624
+ const ACTIVE_ANNOTATION_HIGHLIGHT = "dsh-side-chat-active-annotation";
5625
+ function clamp$1(value, minimum, maximum) {
5626
+ return Math.min(Math.max(minimum, value), Math.max(minimum, maximum));
5627
+ }
5628
+ function boundsOf(rect) {
5629
+ const left = Number.isFinite(rect.left) ? rect.left : rect.x;
5630
+ const top = Number.isFinite(rect.top) ? rect.top : rect.y;
5631
+ const right = Number.isFinite(rect.right) ? rect.right : left + rect.width;
5632
+ const bottom = Number.isFinite(rect.bottom) ? rect.bottom : top + rect.height;
5633
+ return [
5634
+ left,
5635
+ top,
5636
+ right,
5637
+ bottom
5638
+ ].every(Number.isFinite) ? {
5639
+ left,
5640
+ top,
5641
+ right,
5642
+ bottom
5643
+ } : void 0;
5644
+ }
5645
+ function rangeBounds(ranges) {
5646
+ const boxes = [];
5647
+ for (const range of ranges) {
5648
+ const clientRects = typeof range.getClientRects === "function" ? [...range.getClientRects()] : [];
5649
+ const rects = clientRects.length > 0 ? clientRects : typeof range.getBoundingClientRect === "function" ? [range.getBoundingClientRect()] : [];
5650
+ for (const rect of rects) {
5651
+ const bounds = boundsOf(rect);
5652
+ if (bounds !== void 0 && (bounds.right > bounds.left || bounds.bottom > bounds.top)) boxes.push(bounds);
5653
+ }
5654
+ }
5655
+ if (boxes.length === 0) return;
5656
+ return {
5657
+ left: Math.min(...boxes.map((box) => box.left)),
5658
+ top: Math.min(...boxes.map((box) => box.top)),
5659
+ right: Math.max(...boxes.map((box) => box.right)),
5660
+ bottom: Math.max(...boxes.map((box) => box.bottom))
5661
+ };
5662
+ }
5663
+ function selectionRect(bounds) {
5664
+ return {
5665
+ x: bounds.left,
5666
+ y: bounds.top,
5667
+ width: bounds.right - bounds.left,
5668
+ height: bounds.bottom - bounds.top,
5669
+ viewportWidth: window.innerWidth,
5670
+ viewportHeight: window.innerHeight
5671
+ };
5672
+ }
5673
+ function visibleViewport(range) {
5674
+ let viewport = {
5675
+ left: 0,
5676
+ top: 0,
5677
+ right: window.innerWidth,
5678
+ bottom: window.innerHeight
5679
+ };
5680
+ const start = range.startContainer;
5681
+ const scrollport = (start.nodeType === Node.ELEMENT_NODE ? start : start.parentElement)?.closest("[data-conversation-scroll]");
5682
+ if (scrollport === null || scrollport === void 0) return viewport;
5683
+ const scrollBounds = boundsOf(scrollport.getBoundingClientRect());
5684
+ if (scrollBounds !== void 0 && scrollBounds.right > scrollBounds.left && scrollBounds.bottom > scrollBounds.top) viewport = {
5685
+ left: Math.max(viewport.left, scrollBounds.left),
5686
+ top: Math.max(viewport.top, scrollBounds.top),
5687
+ right: Math.min(viewport.right, scrollBounds.right),
5688
+ bottom: Math.min(viewport.bottom, scrollBounds.bottom)
5689
+ };
5690
+ const composer = scrollport.querySelector("[data-composer-seat]");
5691
+ const composerBounds = composer === null ? void 0 : boundsOf(composer.getBoundingClientRect());
5692
+ if (composerBounds !== void 0 && composerBounds.right > composerBounds.left && composerBounds.bottom > composerBounds.top && composerBounds.bottom > viewport.top && composerBounds.top < viewport.bottom) viewport = {
5693
+ ...viewport,
5694
+ bottom: Math.min(viewport.bottom, composerBounds.top)
5695
+ };
5696
+ return viewport;
5697
+ }
5698
+ function intersects(bounds, viewport) {
5699
+ return bounds.right > viewport.left && bounds.bottom > viewport.top && bounds.left < viewport.right && bounds.top < viewport.bottom;
5700
+ }
5701
+ function markerPositionsEqual(previous, next) {
5702
+ return previous.length === next.length && previous.every((position, index) => {
5703
+ const candidate = next[index];
5704
+ return candidate !== void 0 && candidate.annotationIndex === position.annotationIndex && candidate.left === position.left && candidate.top === position.top;
5705
+ });
5706
+ }
5707
+ function clearHighlights() {
5708
+ if (typeof CSS === "undefined" || CSS.highlights === void 0) return;
5709
+ CSS.highlights.delete(ANNOTATION_HIGHLIGHT);
5710
+ CSS.highlights.delete(ACTIVE_ANNOTATION_HIGHLIGHT);
5711
+ }
5712
+ function publishHighlights(ranges, activeRanges) {
5713
+ if (typeof CSS === "undefined" || CSS.highlights === void 0 || typeof Highlight === "undefined") return;
5714
+ CSS.highlights.set(ANNOTATION_HIGHLIGHT, new Highlight(...ranges));
5715
+ if (activeRanges.length === 0) {
5716
+ CSS.highlights.delete(ACTIVE_ANNOTATION_HIGHLIGHT);
5717
+ return;
5718
+ }
5719
+ const active = new Highlight(...activeRanges);
5720
+ active.priority = 1;
5721
+ CSS.highlights.set(ACTIVE_ANNOTATION_HIGHLIGHT, active);
5722
+ }
5723
+ function restoreBrowserSelection(range) {
5724
+ const browserSelection = window.getSelection();
5725
+ if (browserSelection === null) return;
5726
+ browserSelection.removeAllRanges();
5727
+ browserSelection.addRange(range);
5728
+ }
5729
+ /** Persistent source markers for unsent parent-composer annotations. */
5730
+ function ConversationAnnotationMarkers({ annotations, activeAnnotationIndex, onEdit }) {
5731
+ const resolvedRef = (0, react.useRef)(/* @__PURE__ */ new Map());
5732
+ const [positions, setPositions] = (0, react.useState)([]);
5733
+ (0, react.useEffect)(() => {
5734
+ if (annotations.length === 0) {
5735
+ resolvedRef.current.clear();
5736
+ setPositions((previous) => previous.length === 0 ? previous : []);
5737
+ clearHighlights();
5738
+ return;
5739
+ }
5740
+ let animationFrame;
5741
+ let observedConversationRoot = null;
5742
+ let resizeObserver;
5743
+ const refresh = () => {
5744
+ animationFrame = void 0;
5745
+ const conversationRoot = document.querySelector("[data-chat-flow]");
5746
+ if (conversationRoot !== observedConversationRoot) {
5747
+ resizeObserver?.disconnect();
5748
+ observedConversationRoot = conversationRoot;
5749
+ if (conversationRoot !== null) resizeObserver?.observe(conversationRoot);
5750
+ }
5751
+ const resolved = /* @__PURE__ */ new Map();
5752
+ const nextPositions = [];
5753
+ const highlightRanges = [];
5754
+ const activeRanges = [];
5755
+ if (conversationRoot !== null) for (const annotation of annotations) {
5756
+ const restored = restoreDomConversationSelection({
5757
+ selection: annotation.selection,
5758
+ conversationRoot
5759
+ });
5760
+ if (restored === void 0) continue;
5761
+ highlightRanges.push(...restored.ranges);
5762
+ if (annotation.annotationIndex === activeAnnotationIndex) activeRanges.push(...restored.ranges);
5763
+ const bounds = rangeBounds(restored.ranges);
5764
+ const viewport = visibleViewport(restored.browserRange);
5765
+ if (bounds === void 0 || !intersects(bounds, viewport)) continue;
5766
+ const rect = selectionRect(bounds);
5767
+ resolved.set(annotation.annotationIndex, {
5768
+ browserRange: restored.browserRange,
5769
+ rect
5770
+ });
5771
+ nextPositions.push({
5772
+ annotationIndex: annotation.annotationIndex,
5773
+ left: clamp$1(bounds.right + 3, viewport.left + 4, viewport.right - 26),
5774
+ top: clamp$1(bounds.top - 12, viewport.top + 4, viewport.bottom - 26)
5775
+ });
5776
+ }
5777
+ resolvedRef.current = resolved;
5778
+ setPositions((previous) => markerPositionsEqual(previous, nextPositions) ? previous : nextPositions);
5779
+ publishHighlights(highlightRanges, activeRanges);
5780
+ };
5781
+ const scheduleRefresh = () => {
5782
+ if (animationFrame !== void 0) return;
5783
+ animationFrame = window.requestAnimationFrame(refresh);
5784
+ };
5785
+ resizeObserver = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(scheduleRefresh);
5786
+ refresh();
5787
+ const mutationObserver = new MutationObserver(scheduleRefresh);
5788
+ mutationObserver.observe(document.body, {
5789
+ childList: true,
5790
+ characterData: true,
5791
+ subtree: true
5792
+ });
5793
+ document.addEventListener("scroll", scheduleRefresh, true);
5794
+ window.addEventListener("resize", scheduleRefresh);
5795
+ return () => {
5796
+ if (animationFrame !== void 0) window.cancelAnimationFrame(animationFrame);
5797
+ mutationObserver?.disconnect();
5798
+ resizeObserver?.disconnect();
5799
+ document.removeEventListener("scroll", scheduleRefresh, true);
5800
+ window.removeEventListener("resize", scheduleRefresh);
5801
+ clearHighlights();
5802
+ };
5803
+ }, [activeAnnotationIndex, annotations]);
5804
+ return positions.map((position) => {
5805
+ const annotation = annotations.find((candidate) => candidate.annotationIndex === position.annotationIndex);
5806
+ if (annotation === void 0) return null;
5807
+ const style = {
5808
+ left: position.left,
5809
+ top: position.top
5810
+ };
5811
+ const number = annotation.annotationIndex + 1;
5812
+ const badge = number > 99 ? "99+" : String(number);
5813
+ const activate = () => {
5814
+ const resolved = resolvedRef.current.get(annotation.annotationIndex);
5815
+ if (resolved === void 0) return;
5816
+ restoreBrowserSelection(resolved.browserRange);
5817
+ onEdit(annotation, {
5818
+ ...annotation.selection,
5819
+ rect: resolved.rect
5820
+ });
5821
+ window.requestAnimationFrame(() => {
5822
+ restoreBrowserSelection(resolved.browserRange);
5823
+ });
5824
+ };
5825
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5826
+ type: "button",
5827
+ className: "dsh-side-chat-annotation-marker",
5828
+ style,
5829
+ "data-active": annotation.annotationIndex === activeAnnotationIndex || void 0,
5830
+ "data-large": number > 99 || void 0,
5831
+ "aria-label": `Edit annotation ${String(number)}`,
5832
+ title: `Edit annotation ${String(number)}`,
5833
+ onMouseDown: (event) => {
5834
+ event.preventDefault();
5835
+ event.stopPropagation();
5836
+ },
5837
+ onClick: activate,
5838
+ children: badge
5839
+ }, `${annotation.selection.parentSessionId}:${annotation.selection.fragments[0]?.nodeKey ?? ""}:${String(annotation.annotationIndex)}`);
5840
+ });
5841
+ }
5448
5842
  //#endregion
5449
5843
  //#region src/client/selection/SelectionActions.tsx
5450
5844
  function clamp(value, minimum, maximum) {
5451
5845
  return Math.min(Math.max(minimum, value), Math.max(minimum, maximum));
5452
5846
  }
5453
- function SelectionActions({ selection, askDisabledReason, annotationNumber = 1, onAddToChat, onMoreDetails, onAskInSideChat, onAnnotationEditorChange, onDismiss }) {
5454
- const [editingAnnotation, setEditingAnnotation] = (0, react.useState)(false);
5455
- const [comment, setComment] = (0, react.useState)("");
5847
+ function SelectionActions({ selection, askDisabledReason, annotationNumber = 1, annotationEditor, onAddToChat, onMoreDetails, onAskInSideChat, onAnnotationEditorChange, onDismiss }) {
5848
+ const [editingAnnotation, setEditingAnnotation] = (0, react.useState)(annotationEditor !== void 0);
5849
+ const [comment, setComment] = (0, react.useState)(annotationEditor?.initialComment ?? "");
5456
5850
  const commentRef = (0, react.useRef)(null);
5457
5851
  const center = selection.rect.x + selection.rect.width / 2;
5458
5852
  const style = {
@@ -5468,9 +5862,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5468
5862
  width: editorWidth
5469
5863
  };
5470
5864
  const markerStyle = {
5471
- left: clamp(selection.rect.x + selection.rect.width - 10, 8, selection.rect.viewportWidth - 36),
5472
- top: selection.rect.y >= 38 ? selection.rect.y - 34 : selection.rect.y + selection.rect.height + 6
5865
+ left: clamp(selection.rect.x + selection.rect.width + 3, 4, selection.rect.viewportWidth - 26),
5866
+ top: clamp(selection.rect.y - 12, 4, selection.rect.viewportHeight - 26)
5473
5867
  };
5868
+ const markerNumber = annotationNumber > 99 ? "99+" : String(annotationNumber);
5474
5869
  const keepSelection = (event) => {
5475
5870
  event.preventDefault();
5476
5871
  };
@@ -5481,6 +5876,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5481
5876
  setEditingAnnotation(false);
5482
5877
  setComment("");
5483
5878
  onAnnotationEditorChange?.(false);
5879
+ if (annotationEditor !== void 0) onDismiss();
5484
5880
  };
5485
5881
  const saveAnnotation = () => {
5486
5882
  const trimmed = comment.trim();
@@ -5504,15 +5900,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5504
5900
  saveAnnotation();
5505
5901
  }
5506
5902
  };
5507
- if (editingAnnotation) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5903
+ if (editingAnnotation) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [annotationEditor === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5508
5904
  className: "dsh-side-chat-selection-marker",
5509
5905
  "aria-hidden": "true",
5906
+ "data-large": annotationNumber > 99 || void 0,
5510
5907
  style: markerStyle,
5511
- children: String(annotationNumber)
5908
+ children: markerNumber
5512
5909
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
5513
5910
  className: "dsh-side-chat-selection-comment",
5514
5911
  role: "dialog",
5515
- "aria-label": "Add annotation comment",
5912
+ "aria-label": annotationEditor?.dialogLabel ?? "Add annotation comment",
5516
5913
  style: editorStyle,
5517
5914
  onSubmit: submitAnnotation,
5518
5915
  onMouseDown: (event) => {
@@ -6487,6 +6884,89 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6487
6884
  return value;
6488
6885
  }
6489
6886
  //#endregion
6887
+ //#region src/client/parent-composer/annotation-persistence.ts
6888
+ const STORAGE_PREFIX = "dsh-side-chat:composer-annotations:";
6889
+ function browserSessionStorage() {
6890
+ if (typeof window === "undefined") return;
6891
+ try {
6892
+ return window.sessionStorage;
6893
+ } catch {
6894
+ return;
6895
+ }
6896
+ }
6897
+ function storageKey(sessionId) {
6898
+ return `${STORAGE_PREFIX}${encodeURIComponent(sessionId)}`;
6899
+ }
6900
+ function recordOf(snapshot) {
6901
+ const ref = conversationAnnotationReference(snapshot);
6902
+ return ref === void 0 ? void 0 : {
6903
+ version: 1,
6904
+ draft: snapshot.draft,
6905
+ ref
6906
+ };
6907
+ }
6908
+ /** Tab-scoped recovery for rc.6 drafts that persist U+FFFC without occurrences. */
6909
+ var ConversationAnnotationPersistence = class {
6910
+ storage;
6911
+ observedSessions = /* @__PURE__ */ new Set();
6912
+ constructor(storage = browserSessionStorage()) {
6913
+ this.storage = storage;
6914
+ }
6915
+ reconcile(sessionId, input) {
6916
+ const key = storageKey(sessionId);
6917
+ const snapshot = input.state.getSnapshot();
6918
+ const current = recordOf(snapshot);
6919
+ if (current !== void 0) {
6920
+ this.observedSessions.add(key);
6921
+ this.write(key, current);
6922
+ return;
6923
+ }
6924
+ const stored = this.read(key);
6925
+ if (stored !== void 0 && snapshot.draft === stored.draft) {
6926
+ this.observedSessions.add(key);
6927
+ if (restoreConversationAnnotationReference(input, stored.ref)) return;
6928
+ this.remove(key);
6929
+ removeOrphanedConversationAnnotationPlaceholder(input);
6930
+ return;
6931
+ }
6932
+ if (this.observedSessions.has(key)) {
6933
+ this.remove(key);
6934
+ removeOrphanedConversationAnnotationPlaceholder(input);
6935
+ return;
6936
+ }
6937
+ if (stored !== void 0 && snapshot.draft === "") return;
6938
+ if (stored !== void 0) this.remove(key);
6939
+ removeOrphanedConversationAnnotationPlaceholder(input);
6940
+ }
6941
+ read(key) {
6942
+ if (this.storage === void 0) return;
6943
+ try {
6944
+ const raw = this.storage.getItem(key);
6945
+ if (raw === null) return;
6946
+ const value = JSON.parse(raw);
6947
+ return value.version === 1 && typeof value.draft === "string" && typeof value.ref === "string" ? {
6948
+ version: 1,
6949
+ draft: value.draft,
6950
+ ref: value.ref
6951
+ } : void 0;
6952
+ } catch {
6953
+ return;
6954
+ }
6955
+ }
6956
+ write(key, record) {
6957
+ if (this.storage === void 0) return;
6958
+ try {
6959
+ this.storage.setItem(key, JSON.stringify(record));
6960
+ } catch {}
6961
+ }
6962
+ remove(key) {
6963
+ if (this.storage === void 0) return;
6964
+ try {
6965
+ this.storage.removeItem(key);
6966
+ } catch {}
6967
+ }
6968
+ };
6969
+ //#endregion
6490
6970
  //#region src/client/rc6/sessions-adapter.ts
6491
6971
  const BINDING_WAIT_MS = 8e3;
6492
6972
  function sideChatError(error, fallback) {
@@ -6628,11 +7108,34 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6628
7108
  var Rc6SideChatSessions = class {
6629
7109
  ctx;
6630
7110
  renamed = /* @__PURE__ */ new Set();
7111
+ annotationPersistence = new ConversationAnnotationPersistence();
6631
7112
  constructor(ctx) {
6632
7113
  this.ctx = ctx;
6633
7114
  }
6634
7115
  /** Observable rc.6 Session-list surface used to follow main-session switches. */
6635
7116
  subscribeList = (listener) => this.ctx.sessions.list.subscribe(listener);
7117
+ /** Follow both current-session switches and that session's composer state. */
7118
+ subscribeConversationInput = (listener) => {
7119
+ let input;
7120
+ let removeInputListener = () => {};
7121
+ const bindInput = () => {
7122
+ const next = this.currentParentInput();
7123
+ if (next === input) return;
7124
+ removeInputListener();
7125
+ input = next;
7126
+ removeInputListener = input?.state.subscribe?.(listener) ?? (() => {});
7127
+ };
7128
+ bindInput();
7129
+ const removeListListener = this.ctx.sessions.list.subscribe(() => {
7130
+ bindInput();
7131
+ listener();
7132
+ });
7133
+ return () => {
7134
+ removeListListener();
7135
+ removeInputListener();
7136
+ };
7137
+ };
7138
+ currentConversationInputSnapshot = () => this.currentParentInput()?.state.getSnapshot();
6636
7139
  currentSessionId() {
6637
7140
  const current = this.ctx.sessions.list.getSnapshot().current;
6638
7141
  return current === void 0 ? void 0 : SessionId(current);
@@ -6653,25 +7156,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6653
7156
  /** Add one selected passage to the native composer of its parent Session. */
6654
7157
  addSelectionToConversation(selection, comment) {
6655
7158
  if (this.currentSessionId() !== selection.parentSessionId) return false;
6656
- const scope = this.ctx.sessions.scope(dshSessionId(selection.parentSessionId));
6657
- if (scope === void 0) return false;
6658
- return addSelectionToConversation(this.ctx.conversation.input.for(scope), selection, comment);
7159
+ const input = this.currentParentInput();
7160
+ if (input === void 0 || !addSelectionToConversation(input, selection, comment)) return false;
7161
+ this.annotationPersistence.reconcile(selection.parentSessionId, input);
7162
+ return true;
7163
+ }
7164
+ /** Update an existing unsent annotation without adding a duplicate passage. */
7165
+ updateConversationAnnotation(annotationIndex, comment) {
7166
+ const sessionId = this.currentSessionId();
7167
+ const input = this.currentParentInput();
7168
+ if (sessionId === void 0 || input === void 0 || !updateConversationAnnotation(input, annotationIndex, comment)) return false;
7169
+ this.annotationPersistence.reconcile(sessionId, input);
7170
+ return true;
7171
+ }
7172
+ /** Mirror or recover the current Session's unsent annotation occurrence. */
7173
+ reconcileConversationAnnotationPersistence() {
7174
+ const sessionId = this.currentSessionId();
7175
+ const input = this.currentParentInput();
7176
+ if (sessionId !== void 0 && input !== void 0) this.annotationPersistence.reconcile(sessionId, input);
6659
7177
  }
6660
7178
  /** Number assigned to the next annotation shown beside the selected passage. */
6661
7179
  nextConversationAnnotationNumber() {
6662
- const sessionId = this.currentSessionId();
6663
- if (sessionId === void 0) return 1;
6664
- const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
6665
- if (scope === void 0) return 1;
6666
- return conversationAnnotations(this.ctx.conversation.input.for(scope).state.getSnapshot()).length + 1;
7180
+ const snapshot = this.currentConversationInputSnapshot();
7181
+ return snapshot === void 0 ? 1 : conversationAnnotations(snapshot).length + 1;
6667
7182
  }
6668
7183
  /** Remove the current Session's unsent selected-passage annotations. */
6669
7184
  removeConversationAnnotations() {
6670
7185
  const sessionId = this.currentSessionId();
6671
- if (sessionId === void 0) return false;
6672
- const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
6673
- if (scope === void 0) return false;
6674
- return removeConversationAnnotations(this.ctx.conversation.input.for(scope));
7186
+ const input = this.currentParentInput();
7187
+ if (sessionId === void 0 || input === void 0 || !removeConversationAnnotations(input)) return false;
7188
+ this.annotationPersistence.reconcile(sessionId, input);
7189
+ return true;
6675
7190
  }
6676
7191
  async retain(sessionId) {
6677
7192
  const binding = await this.waitForBinding(dshSessionId(sessionId));
@@ -6704,6 +7219,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6704
7219
  cwd(sessionId) {
6705
7220
  return this.ctx.sessions.list.getSnapshot().byId[dshSessionId(sessionId)]?.cwd;
6706
7221
  }
7222
+ currentParentInput() {
7223
+ const sessionId = this.currentSessionId();
7224
+ if (sessionId === void 0) return;
7225
+ const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
7226
+ return scope === void 0 ? void 0 : this.ctx.conversation.input.for(scope);
7227
+ }
6707
7228
  waitForBinding(sessionId) {
6708
7229
  const immediate = this.ctx.sessions.binding(sessionId);
6709
7230
  if (immediate !== void 0) return Promise.resolve(immediate);
@@ -6754,7 +7275,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6754
7275
  return !(target instanceof Element && target.closest([
6755
7276
  "[data-side-chat-panel]",
6756
7277
  ".dsh-side-chat-selection-actions",
6757
- ".dsh-side-chat-selection-comment"
7278
+ ".dsh-side-chat-selection-comment",
7279
+ ".dsh-side-chat-annotation-marker"
6758
7280
  ].join(", ")) !== null);
6759
7281
  }
6760
7282
  function focusParentComposer() {
@@ -6780,7 +7302,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6780
7302
  function Rc6SideChatOverlay({ controller, sessions }) {
6781
7303
  const state = (0, react.useSyncExternalStore)(controller.subscribe, controller.getSnapshot, controller.getSnapshot);
6782
7304
  const currentSessionId = (0, react.useSyncExternalStore)(sessions.subscribeList, () => sessions.currentSessionId(), () => sessions.currentSessionId());
7305
+ const composerInput = (0, react.useSyncExternalStore)(sessions.subscribeConversationInput, sessions.currentConversationInputSnapshot, sessions.currentConversationInputSnapshot);
7306
+ const annotations = (0, react.useMemo)(() => composerInput === void 0 ? [] : conversationSelectionAnnotations(composerInput), [composerInput]);
6783
7307
  const [selection, setSelection] = (0, react.useState)(null);
7308
+ const [editingAnnotation, setEditingAnnotation] = (0, react.useState)(null);
6784
7309
  const captureGeneration = (0, react.useRef)(0);
6785
7310
  const mouseDownPoint = (0, react.useRef)(null);
6786
7311
  const annotationEditing = (0, react.useRef)(false);
@@ -6823,6 +7348,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6823
7348
  annotationEditing.current = false;
6824
7349
  ++captureGeneration.current;
6825
7350
  setSelection(null);
7351
+ setEditingAnnotation(null);
6826
7352
  };
6827
7353
  const onMouseUp = (event) => {
6828
7354
  const start = mouseDownPoint.current;
@@ -6840,7 +7366,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6840
7366
  const onKeyUp = (event) => {
6841
7367
  if (event.key === "Escape") {
6842
7368
  ++captureGeneration.current;
7369
+ annotationEditing.current = false;
6843
7370
  setSelection(null);
7371
+ setEditingAnnotation(null);
6844
7372
  controller.close();
6845
7373
  return;
6846
7374
  }
@@ -6861,7 +7389,17 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6861
7389
  ++captureGeneration.current;
6862
7390
  annotationEditing.current = false;
6863
7391
  setSelection(null);
7392
+ setEditingAnnotation(null);
6864
7393
  }, [currentSessionId]);
7394
+ (0, react.useEffect)(() => {
7395
+ if (composerInput !== void 0) sessions.reconcileConversationAnnotationPersistence();
7396
+ }, [composerInput, sessions]);
7397
+ (0, react.useEffect)(() => {
7398
+ if (editingAnnotation === null) return;
7399
+ if (annotations.some((annotation) => annotation.annotationIndex === editingAnnotation.annotationIndex)) return;
7400
+ annotationEditing.current = false;
7401
+ setEditingAnnotation(null);
7402
+ }, [annotations, editingAnnotation]);
6865
7403
  const askDisabledReason = state.phase === "closed" ? void 0 : "Close the current Side Chat before starting another one.";
6866
7404
  const childFace = state.childSessionId === void 0 ? void 0 : sessions.face(state.childSessionId);
6867
7405
  const childCwd = state.childSessionId === void 0 ? void 0 : sessions.cwd(state.childSessionId);
@@ -6869,73 +7407,121 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6869
7407
  const locale = navigator.language.toLowerCase().startsWith("zh") ? "zh-CN" : "en";
6870
7408
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
6871
7409
  className: "dsh-side-chat-overlay",
6872
- children: [selection !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionActions, {
6873
- selection,
6874
- annotationNumber: sessions.nextConversationAnnotationNumber(),
6875
- ...askDisabledReason === void 0 ? {} : { askDisabledReason },
6876
- onAddToChat: (captured, comment) => {
6877
- try {
6878
- if (sessions.addSelectionToConversation(captured, comment)) focusParentComposer();
6879
- else sessions.notify({
7410
+ children: [
7411
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ConversationAnnotationMarkers, {
7412
+ annotations,
7413
+ ...editingAnnotation === null ? {} : { activeAnnotationIndex: editingAnnotation.annotationIndex },
7414
+ onEdit: (annotation, restoredSelection) => {
7415
+ annotationEditing.current = true;
7416
+ ++captureGeneration.current;
7417
+ setSelection(null);
7418
+ setEditingAnnotation({
7419
+ ...annotation,
7420
+ selection: restoredSelection
7421
+ });
7422
+ }
7423
+ }),
7424
+ selection !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionActions, {
7425
+ selection,
7426
+ annotationNumber: sessions.nextConversationAnnotationNumber(),
7427
+ ...askDisabledReason === void 0 ? {} : { askDisabledReason },
7428
+ onAddToChat: (captured, comment) => {
7429
+ try {
7430
+ if (sessions.addSelectionToConversation(captured, comment)) focusParentComposer();
7431
+ else sessions.notify({
7432
+ kind: "warning",
7433
+ text: "Could not add the selection to the current chat."
7434
+ });
7435
+ } catch {
7436
+ sessions.notify({
7437
+ kind: "warning",
7438
+ text: "Could not add the selection to the current chat."
7439
+ });
7440
+ }
7441
+ setSelection(null);
7442
+ },
7443
+ onAnnotationEditorChange: (open) => {
7444
+ annotationEditing.current = open;
7445
+ },
7446
+ onMoreDetails: (captured) => {
7447
+ const opened = controller.openDraft({ selection: captured });
7448
+ if (!opened.ok) sessions.notify({
6880
7449
  kind: "warning",
6881
- text: "Could not add the selection to the current chat."
7450
+ text: opened.error.message
6882
7451
  });
6883
- } catch {
6884
- sessions.notify({
7452
+ else controller.sendFirst(MORE_DETAILS_PROMPT);
7453
+ setSelection(null);
7454
+ },
7455
+ onAskInSideChat: (captured) => {
7456
+ const opened = controller.openDraft({ selection: captured });
7457
+ if (!opened.ok) sessions.notify({
6885
7458
  kind: "warning",
6886
- text: "Could not add the selection to the current chat."
7459
+ text: opened.error.message
6887
7460
  });
7461
+ setSelection(null);
7462
+ },
7463
+ onDismiss: () => {
7464
+ annotationEditing.current = false;
7465
+ setSelection(null);
6888
7466
  }
6889
- setSelection(null);
6890
- },
6891
- onAnnotationEditorChange: (open) => {
6892
- annotationEditing.current = open;
6893
- },
6894
- onMoreDetails: (captured) => {
6895
- const opened = controller.openDraft({ selection: captured });
6896
- if (!opened.ok) sessions.notify({
6897
- kind: "warning",
6898
- text: opened.error.message
6899
- });
6900
- else controller.sendFirst(MORE_DETAILS_PROMPT);
6901
- setSelection(null);
6902
- },
6903
- onAskInSideChat: (captured) => {
6904
- const opened = controller.openDraft({ selection: captured });
6905
- if (!opened.ok) sessions.notify({
6906
- kind: "warning",
6907
- text: opened.error.message
6908
- });
6909
- setSelection(null);
6910
- },
6911
- onDismiss: () => {
6912
- annotationEditing.current = false;
6913
- setSelection(null);
6914
- }
6915
- }), state.phase !== "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideChatPanel, {
6916
- state,
6917
- locale,
6918
- ...childFace === void 0 || inheritedThroughSeq === void 0 ? {} : { embeddedConversation: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArchivedConversation, {
6919
- face: childFace,
6920
- inheritedThroughSeq,
6921
- controller,
6922
- cwd: childCwd,
6923
- ...state.selection === void 0 ? {} : { selection: state.selection },
6924
- locale
6925
- }) },
6926
- onDraftChange: (draft) => {
6927
- controller.setDraft(draft);
6928
- },
6929
- onFirstSend: (question) => controller.sendFirst(question),
6930
- onClose: () => controller.close(),
6931
- onRetry: () => controller.retry(),
6932
- onFocusParent: () => {
6933
- if (state.parentSessionId !== void 0) sessions.openSession(state.parentSessionId);
6934
- },
6935
- onRemoveSelection: () => {
6936
- controller.clearSelection();
6937
- }
6938
- })]
7467
+ }),
7468
+ editingAnnotation !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionActions, {
7469
+ selection: editingAnnotation.selection,
7470
+ annotationNumber: editingAnnotation.annotationIndex + 1,
7471
+ annotationEditor: {
7472
+ ...editingAnnotation.comment === void 0 ? {} : { initialComment: editingAnnotation.comment },
7473
+ dialogLabel: "Edit annotation comment"
7474
+ },
7475
+ onAddToChat: (_captured, comment) => {
7476
+ try {
7477
+ if (!sessions.updateConversationAnnotation(editingAnnotation.annotationIndex, comment)) sessions.notify({
7478
+ kind: "warning",
7479
+ text: "Could not update the annotation."
7480
+ });
7481
+ } catch {
7482
+ sessions.notify({
7483
+ kind: "warning",
7484
+ text: "Could not update the annotation."
7485
+ });
7486
+ }
7487
+ annotationEditing.current = false;
7488
+ setEditingAnnotation(null);
7489
+ },
7490
+ onAnnotationEditorChange: (open) => {
7491
+ annotationEditing.current = open;
7492
+ },
7493
+ onMoreDetails: () => {},
7494
+ onAskInSideChat: () => {},
7495
+ onDismiss: () => {
7496
+ annotationEditing.current = false;
7497
+ setEditingAnnotation(null);
7498
+ }
7499
+ }, `annotation:${String(editingAnnotation.annotationIndex)}`),
7500
+ state.phase !== "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideChatPanel, {
7501
+ state,
7502
+ locale,
7503
+ ...childFace === void 0 || inheritedThroughSeq === void 0 ? {} : { embeddedConversation: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArchivedConversation, {
7504
+ face: childFace,
7505
+ inheritedThroughSeq,
7506
+ controller,
7507
+ cwd: childCwd,
7508
+ ...state.selection === void 0 ? {} : { selection: state.selection },
7509
+ locale
7510
+ }) },
7511
+ onDraftChange: (draft) => {
7512
+ controller.setDraft(draft);
7513
+ },
7514
+ onFirstSend: (question) => controller.sendFirst(question),
7515
+ onClose: () => controller.close(),
7516
+ onRetry: () => controller.retry(),
7517
+ onFocusParent: () => {
7518
+ if (state.parentSessionId !== void 0) sessions.openSession(state.parentSessionId);
7519
+ },
7520
+ onRemoveSelection: () => {
7521
+ controller.clearSelection();
7522
+ }
7523
+ })
7524
+ ]
6939
7525
  });
6940
7526
  }
6941
7527
  //#endregion
@@ -6995,6 +7581,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6995
7581
  exports.inject = inject;
6996
7582
  exports.name = name;
6997
7583
  exports.normalizeSelectedText = normalizeSelectedText;
7584
+ exports.restoreDomConversationSelection = restoreDomConversationSelection;
6998
7585
  exports.selectionFitsLimit = selectionFitsLimit;
6999
7586
  exports.summarizeSelection = summarizeSelection;
7000
7587
  exports.utf8ByteLength = utf8ByteLength;