@ahggg/dsh-side-chat 0.3.0 → 0.4.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 (45) hide show
  1. package/README.md +8 -6
  2. package/README.zh-CN.md +8 -6
  3. package/lib/client/apply.d.ts.map +1 -1
  4. package/lib/client/apply.js +7 -1
  5. package/lib/client/apply.js.map +1 -1
  6. package/lib/client/panel/SelectionQuote.d.ts +6 -4
  7. package/lib/client/panel/SelectionQuote.d.ts.map +1 -1
  8. package/lib/client/panel/SelectionQuote.js +32 -9
  9. package/lib/client/panel/SelectionQuote.js.map +1 -1
  10. package/lib/client/panel/SideChatPanel.d.ts +1 -2
  11. package/lib/client/panel/SideChatPanel.d.ts.map +1 -1
  12. package/lib/client/panel/SideChatPanel.js +2 -2
  13. package/lib/client/panel/SideChatPanel.js.map +1 -1
  14. package/lib/client/panel/messages.d.ts +2 -2
  15. package/lib/client/panel/messages.d.ts.map +1 -1
  16. package/lib/client/panel/messages.js +4 -4
  17. package/lib/client/panel/messages.js.map +1 -1
  18. package/lib/client/parent-composer/ParentConversationAnnotations.d.ts +27 -0
  19. package/lib/client/parent-composer/ParentConversationAnnotations.d.ts.map +1 -0
  20. package/lib/client/parent-composer/ParentConversationAnnotations.js +97 -0
  21. package/lib/client/parent-composer/ParentConversationAnnotations.js.map +1 -0
  22. package/lib/client/parent-composer/add-to-conversation.d.ts +64 -0
  23. package/lib/client/parent-composer/add-to-conversation.d.ts.map +1 -1
  24. package/lib/client/parent-composer/add-to-conversation.js +182 -0
  25. package/lib/client/parent-composer/add-to-conversation.js.map +1 -1
  26. package/lib/client/rc6/ArchivedConversation.d.ts +1 -2
  27. package/lib/client/rc6/ArchivedConversation.d.ts.map +1 -1
  28. package/lib/client/rc6/ArchivedConversation.js +2 -2
  29. package/lib/client/rc6/ArchivedConversation.js.map +1 -1
  30. package/lib/client/rc6/Rc6SideChatOverlay.d.ts.map +1 -1
  31. package/lib/client/rc6/Rc6SideChatOverlay.js +48 -10
  32. package/lib/client/rc6/Rc6SideChatOverlay.js.map +1 -1
  33. package/lib/client/rc6/context.d.ts +6 -1
  34. package/lib/client/rc6/context.d.ts.map +1 -1
  35. package/lib/client/rc6/sessions-adapter.d.ts +6 -0
  36. package/lib/client/rc6/sessions-adapter.d.ts.map +1 -1
  37. package/lib/client/rc6/sessions-adapter.js +30 -0
  38. package/lib/client/rc6/sessions-adapter.js.map +1 -1
  39. package/lib/client/selection/SelectionActions.d.ts +4 -1
  40. package/lib/client/selection/SelectionActions.d.ts.map +1 -1
  41. package/lib/client/selection/SelectionActions.js +62 -3
  42. package/lib/client/selection/SelectionActions.js.map +1 -1
  43. package/lib/client.js +619 -179
  44. package/lib/client.js.map +1 -1
  45. package/package.json +2 -1
package/lib/client.js CHANGED
@@ -8,7 +8,422 @@ 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 max-width: 100%;\n border-color: transparent;\n background: transparent;\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-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 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:hover .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 transform: translate(var(--dsh-side-chat-quote-offset-x, 0px), 0);\n visibility: visible;\n}\n.dsh-side-chat-quote[data-expanded] .dsh-side-chat-quote-details { pointer-events: auto; }\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-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-details-header button {\n min-height: 28px;\n padding-inline: 10px;\n border: 1px solid var(--side-chat-border);\n border-radius: 999px;\n background: var(--side-chat-bg);\n color: inherit;\n cursor: pointer;\n}\n.dsh-side-chat-quote pre { max-height: 180px; margin: 8px 0 0; overflow: auto; white-space: pre-wrap; font: inherit; }\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.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@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 { 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 max-width: 100%;\n border-color: transparent;\n background: transparent;\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-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";
12
+ //#endregion
13
+ //#region src/client/parent-composer/add-to-conversation.ts
14
+ const SELECTION_REFERENCE_SOURCE = "dsh-side-chat-selection";
15
+ const OBJECT_REPLACEMENT_CHARACTER = "";
16
+ function escapeXmlText(value) {
17
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
18
+ }
19
+ function annotationFromSelection(selection, comment) {
20
+ const trimmedComment = comment?.trim();
21
+ return {
22
+ text: selection.text,
23
+ ...trimmedComment === void 0 || trimmedComment.length === 0 ? {} : { comment: trimmedComment }
24
+ };
25
+ }
26
+ function encodeSelectionReference(annotations) {
27
+ return JSON.stringify({
28
+ version: 1,
29
+ annotations
30
+ });
31
+ }
32
+ function isAnnotation(value) {
33
+ if (typeof value !== "object" || value === null) return false;
34
+ const annotation = value;
35
+ return typeof annotation.text === "string" && (annotation.comment === void 0 || typeof annotation.comment === "string");
36
+ }
37
+ function decodeSelectionReference(ref) {
38
+ 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;
42
+ }
43
+ function selectedContext(annotations) {
44
+ return [
45
+ "<selected_context>",
46
+ ...annotations.flatMap((annotation, index) => annotation.comment === void 0 ? [
47
+ `<annotation index="${String(index + 1)}">`,
48
+ escapeXmlText(annotation.text),
49
+ "</annotation>"
50
+ ] : [
51
+ `<annotation index="${String(index + 1)}">`,
52
+ "<selected_text>",
53
+ escapeXmlText(annotation.text),
54
+ "</selected_text>",
55
+ "<user_comment>",
56
+ escapeXmlText(annotation.comment),
57
+ "</user_comment>",
58
+ "</annotation>"
59
+ ]),
60
+ "</selected_context>"
61
+ ].join("\n");
62
+ }
63
+ function selectionOccurrences(snapshot) {
64
+ return snapshot.occurrences.filter((occurrence) => occurrence.source === SELECTION_REFERENCE_SOURCE);
65
+ }
66
+ /** Read all plugin annotations represented by the current DSH input occurrence. */
67
+ function conversationAnnotations(snapshot) {
68
+ return selectionOccurrences(snapshot).flatMap((occurrence) => {
69
+ try {
70
+ return [...decodeSelectionReference(occurrence.ref)];
71
+ } catch {
72
+ return [];
73
+ }
74
+ });
75
+ }
76
+ function draftWithoutSelectionOccurrences(snapshot) {
77
+ const occurrences = [...selectionOccurrences(snapshot)].sort((a, b) => b.offset - a.offset);
78
+ let draft = snapshot.draft;
79
+ for (const occurrence of occurrences) draft = draft.slice(0, occurrence.offset) + draft.slice(occurrence.offset + 1);
80
+ if (occurrences.some((occurrence) => occurrence.offset === 0)) {
81
+ if (draft.startsWith("\n\n")) draft = draft.slice(2);
82
+ else if (draft.startsWith("\n")) draft = draft.slice(1);
83
+ }
84
+ return draft;
85
+ }
86
+ /** Remove every unsent plugin annotation while preserving the user's draft. */
87
+ function removeConversationAnnotations(input) {
88
+ const snapshot = input.state.getSnapshot();
89
+ if (selectionOccurrences(snapshot).length === 0) return false;
90
+ input.setDraft(draftWithoutSelectionOccurrences(snapshot));
91
+ return true;
92
+ }
93
+ /** Reference codec used by DSH's native composer chip and submit pipeline. */
94
+ const selectionReferenceSource = {
95
+ trigger: "@",
96
+ name: SELECTION_REFERENCE_SOURCE,
97
+ order: 1e3,
98
+ candidates: async () => [],
99
+ onPick: () => void 0,
100
+ codec: {
101
+ clipboardText: (ref) => decodeSelectionReference(ref).map((annotation) => annotation.text).join("\n\n"),
102
+ serialize: async (ref, signal) => {
103
+ if (signal.aborted) throw signal.reason;
104
+ return selectedContext(decodeSelectionReference(ref));
105
+ }
106
+ }
107
+ };
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)];
112
+ const draft = draftWithoutSelectionOccurrences(before);
113
+ if (selectionOccurrences(before).length > 0) input.setDraft(draft);
114
+ const insertionState = input.state.getSnapshot();
115
+ if (!input.insertReference({
116
+ source: SELECTION_REFERENCE_SOURCE,
117
+ ref: encodeSelectionReference(annotations),
118
+ label: "__dsh_side_chat_annotations__",
119
+ clipboardText: annotations.map((annotation) => annotation.text).join("\n\n")
120
+ }, {
121
+ start: 0,
122
+ end: 0,
123
+ draftRev: insertionState.draftRev
124
+ })) return false;
125
+ input.setDraft(`${OBJECT_REPLACEMENT_CHARACTER}\n\n${draft}`);
126
+ return true;
127
+ }
128
+ function unescapeXmlText(value) {
129
+ return value.replaceAll("&lt;", "<").replaceAll("&gt;", ">").replaceAll("&amp;", "&");
130
+ }
131
+ function parseAnnotationBody(body) {
132
+ const selectedText = /^<selected_text>\n([\s\S]*?)\n<\/selected_text>(?:\n<user_comment>\n([\s\S]*?)\n<\/user_comment>)?$/u.exec(body);
133
+ if (selectedText === null) return { text: unescapeXmlText(body) };
134
+ const comment = selectedText[2];
135
+ return {
136
+ text: unescapeXmlText(selectedText[1] ?? ""),
137
+ ...comment === void 0 ? {} : { comment: unescapeXmlText(comment) }
138
+ };
139
+ }
140
+ /** Parse the durable model form back into the user-facing annotation capsule. */
141
+ function parseAnnotatedConversationPrompt(text) {
142
+ const current = /^<selected_context>\n([\s\S]*?)\n<\/selected_context>\s*/u.exec(text);
143
+ if (current !== null) {
144
+ const annotations = [];
145
+ for (const match of current[1]?.matchAll(/<annotation(?: index="\d+")?>\n([\s\S]*?)\n<\/annotation>/gu) ?? []) annotations.push(parseAnnotationBody(match[1] ?? ""));
146
+ if (annotations.length > 0) return {
147
+ annotations,
148
+ message: text.slice(current[0].length).trim()
149
+ };
150
+ }
151
+ const legacyXml = /^<selected_context source="current-conversation" event-seq="(\d+)">\n?([\s\S]*?)\n?<\/selected_context>\s*/u.exec(text);
152
+ if (legacyXml !== null) return {
153
+ annotations: [{ text: unescapeXmlText(legacyXml[2] ?? "") }],
154
+ message: text.slice(legacyXml[0].length).trim()
155
+ };
156
+ const legacyText = /^Selected passage from the current conversation \(message (\d+)\):\n([\s\S]*?)\nEnd selected passage\.\s*/u.exec(text);
157
+ if (legacyText === null) return void 0;
158
+ return {
159
+ annotations: [{ text: legacyText[2] ?? "" }],
160
+ message: text.slice(legacyText[0].length).trim()
161
+ };
162
+ }
163
+ /** Add the selected quote to the first child prompt. */
164
+ function buildSideChatPrompt(selection, question) {
165
+ const trimmed = question.trim();
166
+ if (selection === void 0) return [{
167
+ type: "text",
168
+ text: trimmed
169
+ }];
170
+ return [{
171
+ type: "text",
172
+ text: [
173
+ `<selected_context source="current-conversation" event-seq="${selection.atSeq}">`,
174
+ escapeXmlText(selection.text),
175
+ "</selected_context>",
176
+ "",
177
+ "<user_question>",
178
+ escapeXmlText(trimmed),
179
+ "</user_question>"
180
+ ].join("\n")
181
+ }];
182
+ }
183
+ //#endregion
184
+ //#region src/client/panel/messages.ts
185
+ const SIDE_CHAT_MESSAGES = Object.freeze({
186
+ en: Object.freeze({
187
+ title: "Side Chat",
188
+ close: "Close Side Chat",
189
+ placeholder: "Ask about this in a Side Chat",
190
+ send: "Send",
191
+ selectedPassage: "Selected passage",
192
+ selectionAttachments: (count) => `${String(count)} ${count === 1 ? "annotation" : "annotations"}`,
193
+ selectionPreviewLabel: "Selected text",
194
+ selectionCommentLabel: "User comment",
195
+ removeSelection: "Remove annotation",
196
+ expand: "Expand",
197
+ collapse: "Collapse",
198
+ temporary: "Archived when closed; history remains on disk",
199
+ referenceOnly: "Inherits the complete parent conversation prefix",
200
+ cannotReopen: "No reopen action",
201
+ sharedWorkspace: "Shares the parent workspace",
202
+ retry: "Retry",
203
+ genericError: "Side Chat error",
204
+ closeError: "Could not close the Side Chat"
205
+ }),
206
+ "zh-CN": Object.freeze({
207
+ title: "侧边对话",
208
+ close: "关闭侧边对话",
209
+ placeholder: "在侧边对话中询问这段内容",
210
+ send: "发送",
211
+ selectedPassage: "所选段落",
212
+ selectionAttachments: (count) => `${String(count)} 条引用`,
213
+ selectionPreviewLabel: "所选文本",
214
+ selectionCommentLabel: "用户批注",
215
+ removeSelection: "移除引用",
216
+ expand: "展开",
217
+ collapse: "收起",
218
+ temporary: "关闭时归档;历史仍保存在磁盘上",
219
+ referenceOnly: "完整继承父会话对话前缀",
220
+ cannotReopen: "不提供重新打开操作",
221
+ sharedWorkspace: "与父会话共享工作区",
222
+ retry: "重试",
223
+ genericError: "侧边对话错误",
224
+ closeError: "无法关闭侧边对话"
225
+ })
226
+ });
227
+ //#endregion
228
+ //#region src/client/panel/SelectionQuote.tsx
229
+ /** Selected passage displayed separately from the user's first question. */
230
+ function SelectionQuote({ selections, messages, onRemove }) {
231
+ const [expanded, setExpanded] = (0, react.useState)(false);
232
+ const [hovered, setHovered] = (0, react.useState)(false);
233
+ const quoteRef = (0, react.useRef)(null);
234
+ const detailsRef = (0, react.useRef)(null);
235
+ const leaveTimerRef = (0, react.useRef)();
236
+ const keepHoverOpen = () => {
237
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
238
+ leaveTimerRef.current = void 0;
239
+ setHovered(true);
240
+ };
241
+ const closeHoverAfterGrace = () => {
242
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
243
+ leaveTimerRef.current = window.setTimeout(() => {
244
+ leaveTimerRef.current = void 0;
245
+ setHovered(false);
246
+ }, 220);
247
+ };
248
+ (0, react.useEffect)(() => () => {
249
+ if (leaveTimerRef.current !== void 0) window.clearTimeout(leaveTimerRef.current);
250
+ }, []);
251
+ const constrainDetailsToBoundary = () => {
252
+ const details = detailsRef.current;
253
+ const boundary = quoteRef.current?.closest(".dsh-side-chat-panel, [data-composer-seat], [data-chat-flow-kind]");
254
+ if (details === null) return;
255
+ details.style.setProperty("--dsh-side-chat-quote-offset-x", "0px");
256
+ const detailsRect = details.getBoundingClientRect();
257
+ const boundaryRect = boundary?.getBoundingClientRect();
258
+ const leftEdge = (boundaryRect?.left ?? 0) + 16;
259
+ const rightEdge = (boundaryRect?.right ?? window.innerWidth) - 16;
260
+ const offset = detailsRect.left < leftEdge ? leftEdge - detailsRect.left : detailsRect.right > rightEdge ? rightEdge - detailsRect.right : 0;
261
+ details.style.setProperty("--dsh-side-chat-quote-offset-x", `${String(offset)}px`);
262
+ };
263
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
264
+ ref: quoteRef,
265
+ className: "dsh-side-chat-quote",
266
+ "aria-label": messages.selectedPassage,
267
+ "data-expanded": expanded || void 0,
268
+ "data-hovered": hovered || void 0,
269
+ onMouseEnter: () => {
270
+ keepHoverOpen();
271
+ constrainDetailsToBoundary();
272
+ },
273
+ onMouseLeave: closeHoverAfterGrace,
274
+ onFocusCapture: constrainDetailsToBoundary,
275
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
276
+ className: "dsh-side-chat-quote-chip",
277
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
278
+ type: "button",
279
+ className: "dsh-side-chat-quote-trigger",
280
+ "aria-expanded": expanded,
281
+ "aria-label": `${expanded ? messages.collapse : messages.expand}: ${messages.selectedPassage}`,
282
+ onClick: () => {
283
+ setExpanded((value) => !value);
284
+ },
285
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
286
+ className: "dsh-side-chat-quote-icon",
287
+ viewBox: "0 0 24 24",
288
+ "aria-hidden": "true",
289
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 8h8M8 12h5" })]
290
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: messages.selectionAttachments(selections.length) })]
291
+ }), onRemove !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
292
+ type: "button",
293
+ className: "dsh-side-chat-quote-remove",
294
+ "aria-label": messages.removeSelection,
295
+ onClick: onRemove,
296
+ children: "×"
297
+ })]
298
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
299
+ ref: detailsRef,
300
+ className: "dsh-side-chat-quote-details",
301
+ role: "tooltip",
302
+ children: selections.map((selection, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
303
+ className: "dsh-side-chat-quote-detail",
304
+ children: [
305
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
306
+ className: "dsh-side-chat-quote-details-header",
307
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [
308
+ String(index + 1),
309
+ ". ",
310
+ messages.selectionPreviewLabel,
311
+ ":"
312
+ ] })
313
+ }),
314
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: selection.text }),
315
+ selection.comment !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
316
+ className: "dsh-side-chat-quote-comment",
317
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [messages.selectionCommentLabel, ":"] }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: selection.comment })]
318
+ })
319
+ ]
320
+ }, `${String(index)}-${selection.text}`))
321
+ })]
322
+ });
323
+ }
324
+ //#endregion
325
+ //#region src/client/parent-composer/ParentConversationAnnotations.tsx
326
+ function currentLocale() {
327
+ return navigator.language.toLowerCase().startsWith("zh") ? "zh-CN" : "en";
328
+ }
329
+ /** The interactive annotation capsule occupying the reserved first composer row. */
330
+ function ParentComposerAnnotations({ input, onRemove, locale = currentLocale() }) {
331
+ const annotations = conversationAnnotations(input);
332
+ if (annotations.length === 0) return null;
333
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
334
+ className: "dsh-side-chat-parent-annotation-dock",
335
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
336
+ selections: annotations,
337
+ messages: SIDE_CHAT_MESSAGES[locale],
338
+ onRemove
339
+ })
340
+ });
341
+ }
342
+ function contentText$1(content) {
343
+ return content.map((block) => {
344
+ if (typeof block !== "object" || block === null) return "";
345
+ const value = block;
346
+ return value.type === "text" && typeof value.text === "string" ? value.text : "";
347
+ }).join("");
348
+ }
349
+ function visibleMessage(message) {
350
+ return /^<user_question>\n?([\s\S]*?)\n?<\/user_question>$/u.exec(message)?.[1]?.trim() ?? message;
351
+ }
352
+ function replaceTextContent(content, message) {
353
+ let replaced = false;
354
+ const next = content.flatMap((block) => {
355
+ if (typeof block !== "object" || block === null) return [block];
356
+ const value = block;
357
+ if (value.type !== "text" || typeof value.text !== "string") return [block];
358
+ if (replaced) return [];
359
+ replaced = true;
360
+ return [{
361
+ ...value,
362
+ text: message
363
+ }];
364
+ });
365
+ return replaced ? next : [{
366
+ type: "text",
367
+ text: message
368
+ }, ...next];
369
+ }
370
+ /** Wrap DSH's own user renderer only when this plugin's durable prefix exists. */
371
+ function annotatedUserMessageRenderer(Original) {
372
+ return function AnnotatedUserMessageRenderer(props) {
373
+ const parsed = parseAnnotatedConversationPrompt(contentText$1(props.node.data.content));
374
+ if (parsed === void 0) return (0, react.createElement)(Original, props);
375
+ const node = {
376
+ ...props.node,
377
+ data: {
378
+ ...props.node.data,
379
+ content: replaceTextContent(props.node.data.content, visibleMessage(parsed.message))
380
+ }
381
+ };
382
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
383
+ className: "dsh-side-chat-parent-user-message",
384
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
385
+ selections: parsed.annotations,
386
+ messages: SIDE_CHAT_MESSAGES[currentLocale()]
387
+ }), (0, react.createElement)(Original, {
388
+ ...props,
389
+ node
390
+ })]
391
+ });
392
+ };
393
+ }
394
+ /** Mount the composer capsule and a thin wrapper around DSH's user renderers. */
395
+ function mountParentConversationAnnotations(ctx, removeAnnotations) {
396
+ const slots = ctx.slots;
397
+ const removeDock = slots.inject("conversation.input.dock", () => slots.register({
398
+ name: "conversation.input.dock",
399
+ id: "dsh-side-chat-annotations",
400
+ order: -100
401
+ }, ({ input }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ParentComposerAnnotations, {
402
+ input,
403
+ onRemove: removeAnnotations
404
+ })));
405
+ const shadow = (key) => slots.inject("conversation.chat.node", () => {
406
+ const ShadowedUserMessage = (props) => {
407
+ const original = slots.entries("conversation.chat.node").find((entry) => entry.options.key === key && entry.component !== ShadowedUserMessage && (entry.options.priority ?? 0) >= 0)?.component;
408
+ if (original === void 0) return null;
409
+ const Renderer = annotatedUserMessageRenderer(original);
410
+ return (0, react.createElement)(Renderer, props);
411
+ };
412
+ return slots.register({
413
+ name: "conversation.chat.node",
414
+ key,
415
+ priority: -100,
416
+ locale: "conversation"
417
+ }, ShadowedUserMessage);
418
+ });
419
+ const removeUser = shadow("user");
420
+ const removeSteering = shadow("steering");
421
+ return () => {
422
+ removeSteering();
423
+ removeUser();
424
+ removeDock();
425
+ };
426
+ }
12
427
  //#endregion
13
428
  //#region src/shared/observable.ts
14
429
  /** Immutable-value observable with contained subscriber failures. */
@@ -47,31 +462,6 @@ window.__ModuleLoader__.load({
47
462
  this.listeners.clear();
48
463
  }
49
464
  };
50
- //#endregion
51
- //#region src/client/parent-composer/add-to-conversation.ts
52
- function escapeXmlText(value) {
53
- return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
54
- }
55
- /** Add the selected quote to the first child prompt. */
56
- function buildSideChatPrompt(selection, question) {
57
- const trimmed = question.trim();
58
- if (selection === void 0) return [{
59
- type: "text",
60
- text: trimmed
61
- }];
62
- return [{
63
- type: "text",
64
- text: [
65
- `<selected_context source="current-conversation" event-seq="${selection.atSeq}">`,
66
- escapeXmlText(selection.text),
67
- "</selected_context>",
68
- "",
69
- "<user_question>",
70
- escapeXmlText(trimmed),
71
- "</user_question>"
72
- ].join("\n")
73
- }];
74
- }
75
465
  Object.freeze({
76
466
  repository: "https://github.com/deepseek-ai/deepseek-harness",
77
467
  npmPackage: "@deepseek-ai/dsh",
@@ -4785,120 +5175,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4785
5175
  };
4786
5176
  }
4787
5177
  //#endregion
4788
- //#region src/client/panel/messages.ts
4789
- const SIDE_CHAT_MESSAGES = Object.freeze({
4790
- en: Object.freeze({
4791
- title: "Side Chat",
4792
- close: "Close Side Chat",
4793
- placeholder: "Ask about this in a Side Chat",
4794
- send: "Send",
4795
- selectedPassage: "Selected passage",
4796
- selectionAttachment: "1 annotation",
4797
- selectionPreviewLabel: "Selected text",
4798
- removeSelection: "Remove annotation",
4799
- expand: "Expand",
4800
- collapse: "Collapse",
4801
- copy: "Copy",
4802
- temporary: "Archived when closed; history remains on disk",
4803
- referenceOnly: "Inherits the complete parent conversation prefix",
4804
- cannotReopen: "No reopen action",
4805
- sharedWorkspace: "Shares the parent workspace",
4806
- retry: "Retry",
4807
- genericError: "Side Chat error",
4808
- closeError: "Could not close the Side Chat"
4809
- }),
4810
- "zh-CN": Object.freeze({
4811
- title: "侧边对话",
4812
- close: "关闭侧边对话",
4813
- placeholder: "在侧边对话中询问这段内容",
4814
- send: "发送",
4815
- selectedPassage: "所选段落",
4816
- selectionAttachment: "1 条引用",
4817
- selectionPreviewLabel: "所选文本",
4818
- removeSelection: "移除引用",
4819
- expand: "展开",
4820
- collapse: "收起",
4821
- copy: "复制",
4822
- temporary: "关闭时归档;历史仍保存在磁盘上",
4823
- referenceOnly: "完整继承父会话对话前缀",
4824
- cannotReopen: "不提供重新打开操作",
4825
- sharedWorkspace: "与父会话共享工作区",
4826
- retry: "重试",
4827
- genericError: "侧边对话错误",
4828
- closeError: "无法关闭侧边对话"
4829
- })
4830
- });
4831
- //#endregion
4832
- //#region src/client/panel/SelectionQuote.tsx
4833
- /** Selected passage displayed separately from the user's first question. */
4834
- function SelectionQuote({ selection, messages, onCopy, onRemove }) {
4835
- const [expanded, setExpanded] = (0, react.useState)(false);
4836
- const quoteRef = (0, react.useRef)(null);
4837
- const detailsRef = (0, react.useRef)(null);
4838
- const constrainDetailsToPanel = () => {
4839
- const details = detailsRef.current;
4840
- const panel = quoteRef.current?.closest(".dsh-side-chat-panel");
4841
- if (details === null || panel === void 0 || panel === null) return;
4842
- details.style.setProperty("--dsh-side-chat-quote-offset-x", "0px");
4843
- const detailsRect = details.getBoundingClientRect();
4844
- const panelRect = panel.getBoundingClientRect();
4845
- const leftEdge = panelRect.left + 16;
4846
- const rightEdge = panelRect.right - 16;
4847
- const offset = detailsRect.left < leftEdge ? leftEdge - detailsRect.left : detailsRect.right > rightEdge ? rightEdge - detailsRect.right : 0;
4848
- details.style.setProperty("--dsh-side-chat-quote-offset-x", `${String(offset)}px`);
4849
- };
4850
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
4851
- ref: quoteRef,
4852
- className: "dsh-side-chat-quote",
4853
- "aria-label": messages.selectedPassage,
4854
- "data-expanded": expanded || void 0,
4855
- onMouseEnter: constrainDetailsToPanel,
4856
- onFocusCapture: constrainDetailsToPanel,
4857
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4858
- className: "dsh-side-chat-quote-chip",
4859
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
4860
- type: "button",
4861
- className: "dsh-side-chat-quote-trigger",
4862
- "aria-expanded": expanded,
4863
- "aria-label": `${expanded ? messages.collapse : messages.expand}: ${messages.selectedPassage}`,
4864
- onClick: () => {
4865
- setExpanded((value) => !value);
4866
- },
4867
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
4868
- className: "dsh-side-chat-quote-icon",
4869
- viewBox: "0 0 24 24",
4870
- "aria-hidden": "true",
4871
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M21 15a4 4 0 0 1-4 4H7l-4 4V7a4 4 0 0 1 4-4h10a4 4 0 0 1 4 4Z" }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M8 8h8M8 12h5" })]
4872
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: messages.selectionAttachment })]
4873
- }), onRemove !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4874
- type: "button",
4875
- className: "dsh-side-chat-quote-remove",
4876
- "aria-label": messages.removeSelection,
4877
- onClick: onRemove,
4878
- children: "×"
4879
- })]
4880
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4881
- ref: detailsRef,
4882
- className: "dsh-side-chat-quote-details",
4883
- role: "tooltip",
4884
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4885
- className: "dsh-side-chat-quote-details-header",
4886
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("strong", { children: [
4887
- "1. ",
4888
- messages.selectionPreviewLabel,
4889
- ":"
4890
- ] }), onCopy !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4891
- type: "button",
4892
- onClick: () => {
4893
- onCopy(selection.text);
4894
- },
4895
- children: messages.copy
4896
- })]
4897
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", { children: selection.text })]
4898
- })]
4899
- });
4900
- }
4901
- //#endregion
4902
5178
  //#region src/client/panel/SendIcon.tsx
4903
5179
  /** Arrow used by DSH's native 34px primary send button. */
4904
5180
  function SendIcon() {
@@ -4977,7 +5253,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4977
5253
  }
4978
5254
  //#endregion
4979
5255
  //#region src/client/panel/SideChatPanel.tsx
4980
- function SideChatPanel({ state, locale = "en", embeddedConversation, onDraftChange, onFirstSend, onClose, onRetry, onFocusParent, onCopySelection, onRemoveSelection }) {
5256
+ function SideChatPanel({ state, locale = "en", embeddedConversation, onDraftChange, onFirstSend, onClose, onRetry, onFocusParent, onRemoveSelection }) {
4981
5257
  const messages = SIDE_CHAT_MESSAGES[locale];
4982
5258
  const [submitting, setSubmitting] = (0, react.useState)(false);
4983
5259
  const draftRef = useAutoGrowingTextarea(state.draft);
@@ -5023,9 +5299,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5023
5299
  },
5024
5300
  children: [
5025
5301
  state.selection !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
5026
- selection: state.selection,
5302
+ selections: [state.selection],
5027
5303
  messages,
5028
- ...onCopySelection === void 0 ? {} : { onCopy: onCopySelection },
5029
5304
  ...onRemoveSelection === void 0 ? {} : { onRemove: onRemoveSelection }
5030
5305
  }),
5031
5306
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
@@ -5172,16 +5447,103 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5172
5447
  }
5173
5448
  //#endregion
5174
5449
  //#region src/client/selection/SelectionActions.tsx
5175
- function SelectionActions({ selection, askDisabledReason, onMoreDetails, onAskInSideChat, onDismiss }) {
5450
+ function clamp(value, minimum, maximum) {
5451
+ return Math.min(Math.max(minimum, value), Math.max(minimum, maximum));
5452
+ }
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)("");
5456
+ const commentRef = (0, react.useRef)(null);
5176
5457
  const center = selection.rect.x + selection.rect.width / 2;
5177
5458
  const style = {
5178
5459
  left: Math.min(Math.max(8, center), selection.rect.viewportWidth - 8),
5179
5460
  top: selection.rect.y < 56 ? selection.rect.y + selection.rect.height + 8 : selection.rect.y - 8,
5180
5461
  transform: selection.rect.y < 56 ? "translate(0, 0)" : "translate(0, -100%)"
5181
5462
  };
5463
+ const editorWidth = Math.min(420, selection.rect.viewportWidth - 16);
5464
+ const editorAbove = selection.rect.y - 118;
5465
+ const editorStyle = {
5466
+ left: clamp(selection.rect.x + selection.rect.width + 28, 8, selection.rect.viewportWidth - editorWidth - 8),
5467
+ top: editorAbove >= 8 ? editorAbove : clamp(selection.rect.y + selection.rect.height + 12, 8, selection.rect.viewportHeight - 126),
5468
+ width: editorWidth
5469
+ };
5470
+ 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
5473
+ };
5182
5474
  const keepSelection = (event) => {
5183
5475
  event.preventDefault();
5184
5476
  };
5477
+ (0, react.useEffect)(() => {
5478
+ if (editingAnnotation) commentRef.current?.focus();
5479
+ }, [editingAnnotation]);
5480
+ const closeEditor = () => {
5481
+ setEditingAnnotation(false);
5482
+ setComment("");
5483
+ onAnnotationEditorChange?.(false);
5484
+ };
5485
+ const saveAnnotation = () => {
5486
+ const trimmed = comment.trim();
5487
+ onAddToChat(selection, trimmed.length === 0 ? void 0 : trimmed);
5488
+ onAnnotationEditorChange?.(false);
5489
+ onDismiss();
5490
+ };
5491
+ const submitAnnotation = (event) => {
5492
+ event.preventDefault();
5493
+ saveAnnotation();
5494
+ };
5495
+ const annotationKeyDown = (event) => {
5496
+ if (event.key === "Escape") {
5497
+ event.preventDefault();
5498
+ event.stopPropagation();
5499
+ closeEditor();
5500
+ return;
5501
+ }
5502
+ if (event.key === "Enter" && !event.shiftKey) {
5503
+ event.preventDefault();
5504
+ saveAnnotation();
5505
+ }
5506
+ };
5507
+ if (editingAnnotation) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
5508
+ className: "dsh-side-chat-selection-marker",
5509
+ "aria-hidden": "true",
5510
+ style: markerStyle,
5511
+ children: String(annotationNumber)
5512
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
5513
+ className: "dsh-side-chat-selection-comment",
5514
+ role: "dialog",
5515
+ "aria-label": "Add annotation comment",
5516
+ style: editorStyle,
5517
+ onSubmit: submitAnnotation,
5518
+ onMouseDown: (event) => {
5519
+ event.stopPropagation();
5520
+ },
5521
+ onKeyUp: (event) => {
5522
+ event.stopPropagation();
5523
+ },
5524
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
5525
+ ref: commentRef,
5526
+ value: comment,
5527
+ rows: 2,
5528
+ "aria-label": "Optional annotation comment",
5529
+ placeholder: "Add an optional comment…",
5530
+ onChange: (event) => {
5531
+ setComment(event.currentTarget.value);
5532
+ },
5533
+ onKeyDown: annotationKeyDown
5534
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5535
+ className: "dsh-side-chat-selection-comment-actions",
5536
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5537
+ type: "button",
5538
+ onClick: closeEditor,
5539
+ children: "Cancel"
5540
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5541
+ type: "submit",
5542
+ className: "dsh-side-chat-selection-comment-save",
5543
+ children: "Save"
5544
+ })]
5545
+ })]
5546
+ })] });
5185
5547
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5186
5548
  className: "dsh-side-chat-selection-actions",
5187
5549
  role: "toolbar",
@@ -5191,25 +5553,36 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5191
5553
  onKeyDown: (event) => {
5192
5554
  if (event.key === "Escape") onDismiss();
5193
5555
  },
5194
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5195
- type: "button",
5196
- disabled: askDisabledReason !== void 0,
5197
- title: askDisabledReason,
5198
- onClick: () => {
5199
- onMoreDetails(selection);
5200
- onDismiss();
5201
- },
5202
- children: "More details"
5203
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5204
- type: "button",
5205
- disabled: askDisabledReason !== void 0,
5206
- title: askDisabledReason,
5207
- onClick: () => {
5208
- onAskInSideChat(selection);
5209
- onDismiss();
5210
- },
5211
- children: "Ask in side chat"
5212
- })]
5556
+ children: [
5557
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5558
+ type: "button",
5559
+ onClick: () => {
5560
+ setEditingAnnotation(true);
5561
+ onAnnotationEditorChange?.(true);
5562
+ },
5563
+ children: "Add to chat"
5564
+ }),
5565
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5566
+ type: "button",
5567
+ disabled: askDisabledReason !== void 0,
5568
+ title: askDisabledReason,
5569
+ onClick: () => {
5570
+ onMoreDetails(selection);
5571
+ onDismiss();
5572
+ },
5573
+ children: "More details"
5574
+ }),
5575
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
5576
+ type: "button",
5577
+ disabled: askDisabledReason !== void 0,
5578
+ title: askDisabledReason,
5579
+ onClick: () => {
5580
+ onAskInSideChat(selection);
5581
+ onDismiss();
5582
+ },
5583
+ children: "Ask in side chat"
5584
+ })
5585
+ ]
5213
5586
  });
5214
5587
  }
5215
5588
  //#endregion
@@ -5481,7 +5854,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5481
5854
  });
5482
5855
  }
5483
5856
  /** Functional rc.6 conversation surface bound to a non-current child Session. */
5484
- function ArchivedConversation({ face, inheritedThroughSeq, controller, selection, locale = "en", onCopySelection }) {
5857
+ function ArchivedConversation({ face, inheritedThroughSeq, controller, selection, locale = "en" }) {
5485
5858
  const snapshot = (0, react.useSyncExternalStore)((listener) => face.subscribe(listener), () => face.getSnapshot(), () => face.getSnapshot());
5486
5859
  const [draft, setDraft] = (0, react.useState)("");
5487
5860
  const [sending, setSending] = (0, react.useState)(false);
@@ -5528,9 +5901,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5528
5901
  nodes.map((node) => selection !== void 0 && node === annotatedUserNode ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5529
5902
  className: "dsh-side-chat-annotated-user-message",
5530
5903
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionQuote, {
5531
- selection,
5532
- messages: SIDE_CHAT_MESSAGES[locale],
5533
- ...onCopySelection === void 0 ? {} : { onCopy: onCopySelection }
5904
+ selections: [selection],
5905
+ messages: SIDE_CHAT_MESSAGES[locale]
5534
5906
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageRow, { node })]
5535
5907
  }, `${node.kind}-${String(node.seq)}`) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MessageRow, { node }, `${node.kind}-${String(node.seq)}`)),
5536
5908
  snapshot.partial !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
@@ -5769,6 +6141,29 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5769
6141
  return node !== void 0 && node.visibility === "visible" && node.kind === fragment.nodeKind && node.anchorSeq === fragment.seq && locationSettled(node.location);
5770
6142
  });
5771
6143
  }
6144
+ /** Add one selected passage to the native composer of its parent Session. */
6145
+ addSelectionToConversation(selection, comment) {
6146
+ if (this.currentSessionId() !== selection.parentSessionId) return false;
6147
+ const scope = this.ctx.sessions.scope(dshSessionId(selection.parentSessionId));
6148
+ if (scope === void 0) return false;
6149
+ return addSelectionToConversation(this.ctx.conversation.input.for(scope), selection, comment);
6150
+ }
6151
+ /** Number assigned to the next annotation shown beside the selected passage. */
6152
+ nextConversationAnnotationNumber() {
6153
+ const sessionId = this.currentSessionId();
6154
+ if (sessionId === void 0) return 1;
6155
+ const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
6156
+ if (scope === void 0) return 1;
6157
+ return conversationAnnotations(this.ctx.conversation.input.for(scope).state.getSnapshot()).length + 1;
6158
+ }
6159
+ /** Remove the current Session's unsent selected-passage annotations. */
6160
+ removeConversationAnnotations() {
6161
+ const sessionId = this.currentSessionId();
6162
+ if (sessionId === void 0) return false;
6163
+ const scope = this.ctx.sessions.scope(dshSessionId(sessionId));
6164
+ if (scope === void 0) return false;
6165
+ return removeConversationAnnotations(this.ctx.conversation.input.for(scope));
6166
+ }
5772
6167
  async retain(sessionId) {
5773
6168
  const binding = await this.waitForBinding(dshSessionId(sessionId));
5774
6169
  await binding.session.open();
@@ -5844,7 +6239,30 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5844
6239
  function captureEvent(event) {
5845
6240
  if (event instanceof KeyboardEvent && event.key === "Escape") return false;
5846
6241
  const target = event.target;
5847
- return !(target instanceof Element && target.closest("[data-side-chat-panel], .dsh-side-chat-selection-actions") !== null);
6242
+ return !(target instanceof Element && target.closest([
6243
+ "[data-side-chat-panel]",
6244
+ ".dsh-side-chat-selection-actions",
6245
+ ".dsh-side-chat-selection-comment"
6246
+ ].join(", ")) !== null);
6247
+ }
6248
+ function focusParentComposer() {
6249
+ const input = document.querySelector([
6250
+ "[data-composer-seat] textarea",
6251
+ "[data-composer-seat] [role=\"textbox\"]",
6252
+ "[data-composer-seat] [contenteditable=\"true\"]"
6253
+ ].join(", "));
6254
+ if (input === null) return;
6255
+ input.focus();
6256
+ if (input instanceof HTMLTextAreaElement) {
6257
+ input.setSelectionRange(input.value.length, input.value.length);
6258
+ return;
6259
+ }
6260
+ const range = document.createRange();
6261
+ range.selectNodeContents(input);
6262
+ range.collapse(false);
6263
+ const selection = window.getSelection();
6264
+ selection?.removeAllRanges();
6265
+ selection?.addRange(range);
5848
6266
  }
5849
6267
  /** rc.6 compatibility surface: selection toolbar plus a non-current child conversation panel. */
5850
6268
  function Rc6SideChatOverlay({ controller, sessions }) {
@@ -5853,6 +6271,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5853
6271
  const [selection, setSelection] = (0, react.useState)(null);
5854
6272
  const captureGeneration = (0, react.useRef)(0);
5855
6273
  const mouseDownPoint = (0, react.useRef)(null);
6274
+ const annotationEditing = (0, react.useRef)(false);
5856
6275
  const capture = (0, react.useCallback)(async () => {
5857
6276
  const generation = ++captureGeneration.current;
5858
6277
  const parentSessionId = sessions.currentSessionId();
@@ -5889,6 +6308,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5889
6308
  x: event.clientX,
5890
6309
  y: event.clientY
5891
6310
  };
6311
+ annotationEditing.current = false;
5892
6312
  ++captureGeneration.current;
5893
6313
  setSelection(null);
5894
6314
  };
@@ -5899,6 +6319,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5899
6319
  if (start === null || Math.abs(event.clientX - start.x) > 2 || Math.abs(event.clientY - start.y) > 2 || event.detail > 1 || event.shiftKey) capture();
5900
6320
  };
5901
6321
  const onSelectionChange = () => {
6322
+ if (annotationEditing.current) return;
5902
6323
  const browserSelection = window.getSelection();
5903
6324
  if (browserSelection !== null && !browserSelection.isCollapsed) return;
5904
6325
  ++captureGeneration.current;
@@ -5926,25 +6347,37 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5926
6347
  }, [capture, controller]);
5927
6348
  (0, react.useEffect)(() => {
5928
6349
  ++captureGeneration.current;
6350
+ annotationEditing.current = false;
5929
6351
  setSelection(null);
5930
6352
  }, [currentSessionId]);
5931
6353
  const askDisabledReason = state.phase === "closed" ? void 0 : "Close the current Side Chat before starting another one.";
5932
6354
  const childFace = state.childSessionId === void 0 ? void 0 : sessions.face(state.childSessionId);
5933
6355
  const inheritedThroughSeq = state.inheritedThroughSeq;
5934
6356
  const locale = navigator.language.toLowerCase().startsWith("zh") ? "zh-CN" : "en";
5935
- const copySelection = (text) => {
5936
- navigator.clipboard.writeText(text).catch(() => {
5937
- sessions.notify({
5938
- kind: "warning",
5939
- text: "Could not copy the selected text."
5940
- });
5941
- });
5942
- };
5943
6357
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
5944
6358
  className: "dsh-side-chat-overlay",
5945
6359
  children: [selection !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SelectionActions, {
5946
6360
  selection,
6361
+ annotationNumber: sessions.nextConversationAnnotationNumber(),
5947
6362
  ...askDisabledReason === void 0 ? {} : { askDisabledReason },
6363
+ onAddToChat: (captured, comment) => {
6364
+ try {
6365
+ if (sessions.addSelectionToConversation(captured, comment)) focusParentComposer();
6366
+ else sessions.notify({
6367
+ kind: "warning",
6368
+ text: "Could not add the selection to the current chat."
6369
+ });
6370
+ } catch {
6371
+ sessions.notify({
6372
+ kind: "warning",
6373
+ text: "Could not add the selection to the current chat."
6374
+ });
6375
+ }
6376
+ setSelection(null);
6377
+ },
6378
+ onAnnotationEditorChange: (open) => {
6379
+ annotationEditing.current = open;
6380
+ },
5948
6381
  onMoreDetails: (captured) => {
5949
6382
  const opened = controller.openDraft({ selection: captured });
5950
6383
  if (!opened.ok) sessions.notify({
@@ -5963,6 +6396,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5963
6396
  setSelection(null);
5964
6397
  },
5965
6398
  onDismiss: () => {
6399
+ annotationEditing.current = false;
5966
6400
  setSelection(null);
5967
6401
  }
5968
6402
  }), state.phase !== "closed" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SideChatPanel, {
@@ -5973,8 +6407,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5973
6407
  inheritedThroughSeq,
5974
6408
  controller,
5975
6409
  ...state.selection === void 0 ? {} : { selection: state.selection },
5976
- locale,
5977
- onCopySelection: copySelection
6410
+ locale
5978
6411
  }) },
5979
6412
  onDraftChange: (draft) => {
5980
6413
  controller.setDraft(draft);
@@ -5985,7 +6418,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5985
6418
  onFocusParent: () => {
5986
6419
  if (state.parentSessionId !== void 0) sessions.openSession(state.parentSessionId);
5987
6420
  },
5988
- onCopySelection: copySelection,
5989
6421
  onRemoveSelection: () => {
5990
6422
  controller.clearSelection();
5991
6423
  }
@@ -5996,6 +6428,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5996
6428
  //#region src/client/apply.ts
5997
6429
  const name = "side-chat-client";
5998
6430
  const inject = [
6431
+ "conversation",
6432
+ "inputTriggers",
5999
6433
  "remote",
6000
6434
  "sessions",
6001
6435
  "slots"
@@ -6008,7 +6442,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6008
6442
  document.head.append(stylesheet);
6009
6443
  const clientCtx = ctx;
6010
6444
  const mounted = await mountArchivedRemote(clientCtx);
6445
+ const removeSelectionReferenceSource = clientCtx.inputTriggers.registerSource(selectionReferenceSource);
6011
6446
  const sessions = new Rc6SideChatSessions(clientCtx);
6447
+ const removeParentAnnotations = mountParentConversationAnnotations(clientCtx, () => {
6448
+ sessions.removeConversationAnnotations();
6449
+ });
6012
6450
  const controller = new SideChatController(mounted.remote, sessions);
6013
6451
  const removeOverlay = clientCtx.slots.inject("shell.overlay", () => clientCtx.slots.register({
6014
6452
  name: "shell.overlay",
@@ -6022,6 +6460,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
6022
6460
  try {
6023
6461
  await controller.dispose();
6024
6462
  } finally {
6463
+ removeParentAnnotations();
6464
+ removeSelectionReferenceSource();
6025
6465
  removeOverlay();
6026
6466
  await mounted.dispose();
6027
6467
  stylesheet.remove();