dsh-diff-approval 0.22.2 → 0.23.1

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.
package/lib/client.js CHANGED
@@ -21,7 +21,7 @@ window.__ModuleLoader__.load({
21
21
  let react_dom = require("react-dom");
22
22
  let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
23
23
  //#region \0dsh-css:/home/runner/work/dsh-diff-approval/dsh-diff-approval/src/client/PendingPanel.module.css.mjs
24
- const css = ".F1KBNa_panelFailure{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:8px;padding:8px 10px;font-size:12px;line-height:16px;display:flex}.F1KBNa_panelFailureText{min-width:0}.F1KBNa_panelFailureRetry{border:1px solid var(--dsw-alias-border-l2);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex:none;margin-left:auto;padding:2px 8px}.F1KBNa_panelFailureRetry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_headerEntry{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:relative}.F1KBNa_headerEntry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_headerEntry[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.F1KBNa_headerEntry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_headerEntryCount{box-sizing:border-box;background:var(--dsw-alias-button-primary-fill);min-width:14px;height:14px;color:var(--dsw-alias-label-primary-foreground);text-align:center;font-variant-numeric:tabular-nums;pointer-events:none;border-radius:7px;padding:0 3px;font-size:10px;line-height:14px;position:absolute;top:-1px;right:-1px}.F1KBNa_headerEntry svg{display:block}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_coverBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_panelDocked{width:100%;max-width:none;height:100%;box-shadow:none;border:none;border-radius:0;position:static;inset:auto}.F1KBNa_dockHost{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);min-width:72px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelector[data-recording]{box-shadow:inset 0 0 0 1px var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-secondary)}.F1KBNa_settingsReset{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;margin-left:6px;padding:0;display:inline-flex}.F1KBNa_settingsReset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_settingsReset:disabled{opacity:.4;cursor:default}.F1KBNa_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin:16px 0 8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{height:132px;overflow-y:auto}.F1KBNa_mdPreviewWrap{flex:1;min-width:0;min-height:0;display:flex;position:relative}.F1KBNa_mdPreviewBody{min-width:0;min-height:0;color:var(--dsw-alias-label-primary);flex:1;padding:12px 16px;position:relative;overflow:auto}.F1KBNa_mdPreviewContent{width:100%;min-width:0;margin:0 auto}.F1KBNa_mdPreviewSingle{display:block}.F1KBNa_mdPreviewDouble{display:flex}.F1KBNa_mdPreviewBody .mdBlock{border-radius:4px;margin-bottom:12px;padding:2px 6px}.F1KBNa_mdPreviewBody .mdAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_mdPreviewBody .mdDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_mdPreviewBody .mdWordDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdWordAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdDouble{flex-direction:column;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleRow{align-items:flex-start;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleCol{flex:1;min-width:0}.F1KBNa_mdPreviewBody .mdDoubleRule{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:0 12px}.F1KBNa_mdPreviewFallback{font-family:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 16px;font-size:12px;line-height:18px}.F1KBNa_mdPreviewBody{word-break:break-word;font-size:13px;line-height:20px}.F1KBNa_mdPreviewBody>:first-child{margin-top:0}.F1KBNa_mdPreviewBody>:last-child{margin-bottom:0}.F1KBNa_mdPreviewBody h1,.F1KBNa_mdPreviewBody h2,.F1KBNa_mdPreviewBody h3,.F1KBNa_mdPreviewBody h4,.F1KBNa_mdPreviewBody h5,.F1KBNa_mdPreviewBody h6{margin:16px 0 8px;font-weight:600;line-height:1.3}.F1KBNa_mdPreviewBody h1{font-size:22px}.F1KBNa_mdPreviewBody h2{font-size:19px}.F1KBNa_mdPreviewBody h3{font-size:16px}.F1KBNa_mdPreviewBody h4{font-size:15px}.F1KBNa_mdPreviewBody h5{font-size:14px}.F1KBNa_mdPreviewBody h6{font-size:13px}.F1KBNa_mdPreviewBody p{margin:8px 0}.F1KBNa_mdPreviewBody ul,.F1KBNa_mdPreviewBody ol{margin:8px 0;padding-left:22px}.F1KBNa_mdPreviewBody li{margin:2px 0}.F1KBNa_mdPreviewBody a{color:var(--dsw-alias-state-business-primary);text-decoration:none}.F1KBNa_mdPreviewBody a:hover{text-decoration:underline}.F1KBNa_mdPreviewBody code{font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:4px;padding:1px 5px;font-size:12.5px}.F1KBNa_mdPreviewBody pre{border:1px solid var(--dsw-alias-border-l1);font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:8px;margin:8px 0;padding:10px 12px;font-size:12.5px;line-height:18px;overflow:auto}.F1KBNa_mdPreviewBody pre code{background:0 0;padding:0}.F1KBNa_mdPreviewBody blockquote{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);margin:8px 0;padding:0 12px}.F1KBNa_mdPreviewBody hr{background:var(--dsw-alias-border-l1);border:none;height:1px;margin:16px 0}.F1KBNa_mdPreviewBody table{border-collapse:collapse;margin:8px 0}.F1KBNa_mdPreviewBody th,.F1KBNa_mdPreviewBody td{border:1px solid var(--dsw-alias-border-l1);padding:4px 10px}.F1KBNa_mdPreviewBody img{max-width:100%}.F1KBNa_mdPreviewBody .mdImageFallback{border:1px dashed var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block) 45%, transparent);width:100%;min-height:120px;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-markdown-code-block);text-align:center;white-space:pre-wrap;word-break:break-all;border-radius:4px;justify-content:center;align-items:center;margin:0 auto;padding:8px 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListKnob{z-index:39;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);opacity:.45;width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;box-shadow:var(--dsw-shadow-lv2);border-radius:8px;justify-content:center;align-items:center;padding:0;transition:opacity .12s;display:inline-flex;position:absolute}.F1KBNa_fileListKnob:hover,.F1KBNa_fileListKnob:focus-visible{opacity:1;background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-interactive-bg-hover), var(--dsw-alias-interactive-bg-hover))}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);transform-origin:0 0;border-radius:12px;flex-direction:column;padding:6px 8px 10px;animation:.14s ease-out F1KBNa_fileListGrow;display:flex;position:absolute;overflow:hidden}@keyframes F1KBNa_fileListGrow{0%{opacity:0;transform:scale(.92)}to{opacity:1;transform:scale(1)}}@media (prefers-reduced-motion:reduce){.F1KBNa_fileListFloat{animation:none}}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:scroll}.F1KBNa_bulkActions{flex:none;gap:6px;padding:8px 8px 0 0;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;touch-action:none;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_floatResizeHandle{z-index:41;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;background:0 0;border-radius:4px;position:absolute}.F1KBNa_floatResizeHandle:hover{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-border-l2), var(--dsw-alias-border-l2))}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_confirmBackdrop{z-index:55;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{flex:none;justify-content:flex-end;align-items:center;gap:8px;display:flex}.F1KBNa_pickerCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:420px;max-width:100%;height:70%;max-height:100%;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.F1KBNa_pickerTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:20px}.F1KBNa_pickerClose{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;top:10px;right:10px}.F1KBNa_pickerClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_pickerForm{flex:none;gap:8px;display:flex}.F1KBNa_pickerInput{border:1px solid var(--dsw-alias-border-l1);min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;flex:auto;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_pickerInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_tree{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex:auto;min-height:0;padding:4px 2px 4px 4px;overflow:auto scroll}.F1KBNa_treeRow{border-radius:6px;align-items:center;gap:2px;padding-right:4px;display:flex}.F1KBNa_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_treeRow[data-selected]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}.F1KBNa_treeCaret{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_treeCaret:hover{color:var(--dsw-alias-label-primary)}.F1KBNa_treeName{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:6px;padding:2px 4px;font-family:inherit;font-size:12px;line-height:18px;display:flex}.F1KBNa_treeName:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_treeNote{color:var(--dsw-alias-label-tertiary);margin:2px 0;font-size:12px;line-height:18px}.F1KBNa_pickerIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_pickerName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_pickerNote{color:var(--dsw-alias-label-tertiary);flex:none;margin:0;font-size:12px;line-height:18px}.F1KBNa_pickerCheck{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;margin-right:auto;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_groupHead{align-items:center;gap:4px;margin:8px 0 4px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton{box-sizing:border-box;border-radius:6px;justify-content:center;align-items:center;width:20px;height:20px;min-height:0;padding:0;display:inline-flex}.F1KBNa_groupHead>.F1KBNa_group{margin:0}.F1KBNa_emptyActions{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:baseline;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;font:var(--dsw-font-markdown-code-block);overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffPath{white-space:nowrap;scrollbar-width:none;min-width:0;color:var(--dsw-alias-label-primary);font:var(--dsw-font-markdown-code-block);-webkit-user-select:text;user-select:text;flex:1;font-size:12px;line-height:18px;overflow:auto hidden}.F1KBNa_diffPath::-webkit-scrollbar{display:none}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_searchToggle{border:1px solid var(--dsw-alias-border-l1);min-height:25px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_searchToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_searchToggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchMatch{color:inherit;background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{color:inherit;background-color:#facc1599;border-radius:2px}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(0)}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_presentationSelect{cursor:pointer;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_presentationSelect:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_chip{justify-content:flex-end;align-items:center;gap:5px;min-width:0;padding-right:14px;display:inline-flex}.F1KBNa_chipLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_coverHost{align-items:center;display:inline-flex;position:relative}.F1KBNa_coverCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:4px;padding:6px;display:flex}.F1KBNa_coverPopover{z-index:50;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_coverNotice{z-index:80;pointer-events:none;animation:1.25s ease-out forwards F1KBNa_coverNoticeFade;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_coverNoticeCard{gap:4px;padding:6px 8px}@keyframes F1KBNa_coverNoticeFade{0%,78%{opacity:1}to{opacity:0}}.F1KBNa_coverNoticeGlyph{width:44px;height:44px;color:var(--dsw-alias-label-tertiary);border-radius:10px;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_coverNoticeGlyph[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_coverNoticeGlyph[data-changed]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_coverNoticeText{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.F1KBNa_coverButton{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_coverButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_coverButton[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_presentationHost{align-items:center;display:inline-flex}.F1KBNa_chipPresentation{min-width:36px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:20px;flex:none;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_chipPresentation:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_mirrored{transform:scaleX(-1)}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{flex-direction:column;flex:1;min-height:0;display:flex;position:relative}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{min-width:0;height:var(--dsh-scrollbar-width,8px);flex:1 1 0;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 26%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 24%, transparent)}";
24
+ const css = ".F1KBNa_panelFailure{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);color:var(--dsw-alias-label-primary);border-radius:8px;align-items:center;gap:8px;padding:8px 10px;font-size:12px;line-height:16px;display:flex}.F1KBNa_panelFailureText{min-width:0}.F1KBNa_panelFailureRetry{border:1px solid var(--dsw-alias-border-l2);color:inherit;font:inherit;cursor:pointer;background:0 0;border-radius:6px;flex:none;margin-left:auto;padding:2px 8px}.F1KBNa_panelFailureRetry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_layer{box-sizing:border-box;flex:none;align-items:center;width:calc(100% + 4px);height:42px;margin:4px -2px;display:flex;position:relative}.F1KBNa_headerEntry{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:28px;flex:none;justify-content:center;align-items:center;padding:6px;display:inline-flex;position:relative}.F1KBNa_headerEntry:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_headerEntry[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid);color:var(--dsw-alias-label-primary)}.F1KBNa_headerEntry:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_headerEntryCount{box-sizing:border-box;background:var(--dsw-alias-button-primary-fill);min-width:14px;height:14px;color:var(--dsw-alias-label-primary-foreground);text-align:center;font-variant-numeric:tabular-nums;pointer-events:none;border-radius:7px;padding:0 3px;font-size:10px;line-height:14px;position:absolute;top:-1px;right:-1px}.F1KBNa_headerEntry svg{display:block}.F1KBNa_footerButtons{align-items:center;width:100%;display:flex}.F1KBNa_badge{box-sizing:border-box;width:100%;height:42px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border:none;border-radius:12px;align-items:center;gap:8px;padding:0 10px 0 8px;font-family:inherit;font-size:14px;line-height:22px;display:flex;overflow:hidden}.F1KBNa_badge:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_badge[data-active]{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_badge:disabled{color:var(--dsw-alias-label-tertiary);cursor:default;background:0 0}.F1KBNa_badgeLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.F1KBNa_badgeCount{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;margin-left:auto;font-size:12px;line-height:16px}.F1KBNa_layer.F1KBNa_rail{width:36px;height:36px;margin:8px 0 10px}.F1KBNa_rail .F1KBNa_badge{border-radius:50%;justify-content:center;gap:0;width:36px;height:36px;padding:0}.F1KBNa_rail .F1KBNa_badgeLabel{display:none}.F1KBNa_rail .F1KBNa_badgeCount{box-sizing:border-box;background:var(--dsw-alias-state-business-primary);min-width:18px;height:18px;color:var(--dsw-alias-label-primary-foreground);font-variant-numeric:tabular-nums;border-radius:9px;justify-content:center;align-items:center;padding:0 4px;font-size:11px;line-height:18px;display:flex;position:absolute;top:-3px;right:-7px}.F1KBNa_coverBackdrop{z-index:29;background:var(--dsw-specific-sidebar-fill);position:fixed;inset:0}.F1KBNa_panel{z-index:30;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:auto;max-width:none;box-shadow:var(--dsw-shadow-lv2);--dsh-scrollbar-thumb:var(--dsw-alias-scrollbar-bg-l2);--dsh-scrollbar-thumb-hover:var(--dsw-alias-scrollbar-hover-l2);border-radius:12px;flex-direction:column;display:flex;position:fixed;inset:8px 8px 128px;overflow:hidden}.F1KBNa_panelDocked{width:100%;max-width:none;height:100%;box-shadow:none;border:none;border-radius:0;position:static;inset:auto}.F1KBNa_dockHost{flex-direction:column;min-height:0;display:flex;position:absolute;inset:0}.F1KBNa_header{box-sizing:border-box;border-bottom:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;justify-content:space-between;align-items:center;min-height:44px;padding:10px 12px;display:flex}.F1KBNa_headerActions{align-items:center;gap:2px;display:flex}.F1KBNa_settingsPage{padding:8px 12px}.F1KBNa_settingsGroup{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupHeader{width:100%;color:var(--dsw-alias-label-primary);font:inherit;cursor:pointer;text-align:left;background:0 0;border:none;align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsGroupText{text-align:left;flex-direction:column;flex:1;gap:2px;min-width:0;display:flex}.F1KBNa_settingsGroupTitle{font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsGroupDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsGroupChevron{margin-left:auto;transition:transform .15s}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupChevron{transform:rotate(180deg)}.F1KBNa_settingsGroup[data-open] .F1KBNa_settingsGroupHeader{border-bottom:1px solid var(--dsw-alias-border-l2)}.F1KBNa_settingsGroupBody{flex-direction:column;display:flex}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow{padding-left:16px}.F1KBNa_settingsGroupBody .F1KBNa_settingsRow:last-child,.F1KBNa_settingsPage>.F1KBNa_settingsRow:last-child{border-bottom:none}.F1KBNa_settingsRow{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:16px 0;display:flex}.F1KBNa_settingsRowText{flex-direction:column;flex:1;gap:4px;min-width:0;padding-right:48px;display:flex}.F1KBNa_settingsRowTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px}.F1KBNa_settingsRowDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px}.F1KBNa_settingsSelector{background:var(--dsw-alias-bg-module-platform);min-width:72px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;justify-content:center;align-items:center;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.F1KBNa_settingsSelector:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_settingsSelector[data-recording]{box-shadow:inset 0 0 0 1px var(--dsw-alias-state-business-primary);color:var(--dsw-alias-label-secondary)}.F1KBNa_settingsReset{width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;margin-left:6px;padding:0;display:inline-flex}.F1KBNa_settingsReset:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_settingsReset:disabled{opacity:.4;cursor:default}.F1KBNa_colorPicker{position:relative}.F1KBNa_colorPickerTrigger{background:var(--dsw-alias-bg-module-platform);width:120px;height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_colorPickerTrigger:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_colorSwatch{border:1px solid var(--dsw-alias-border-l2);border-radius:50%;flex:none;width:24px;height:24px}.F1KBNa_colorValue{text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;flex:1;min-width:0;overflow:hidden}.F1KBNa_colorPickerChevron{flex:none}.F1KBNa_colorBackdrop{z-index:40;position:fixed;inset:0}.F1KBNa_colorPickerPopover{z-index:41;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:10px;padding:10px;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_colorPickerPanel{flex-direction:column;gap:8px;display:flex}.F1KBNa_colorPickerInputRow{align-items:center;gap:8px;display:flex}.F1KBNa_colorPickerPreview{border:1px solid var(--dsw-alias-border-l2);border-radius:6px;flex:none;width:22px;height:22px}.F1KBNa_colorPickerInput{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-module-platform);min-width:0;height:30px;font:inherit;color:var(--dsw-alias-label-primary);border-radius:8px;flex:1;padding:0 8px;font-size:12px;line-height:28px}.F1KBNa_colorPickerInput:focus{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-1px}.F1KBNa_colorSv{border:1px solid var(--dsw-alias-border-l1);cursor:crosshair;touch-action:none;border-radius:8px;height:140px;position:relative}.F1KBNa_colorSvCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:14px;height:14px;position:absolute;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_colorHue{border:1px solid var(--dsw-alias-border-l1);cursor:pointer;touch-action:none;border-radius:7px;height:14px;position:relative}.F1KBNa_colorHueCursor{pointer-events:none;border:2px solid #fff;border-radius:50%;width:16px;height:16px;position:absolute;top:50%;transform:translate(-50%,-50%);box-shadow:0 0 0 1px #00000080}.F1KBNa_diffPreview{z-index:2;border:1px solid var(--dsw-alias-border-l1);font:var(--dsw-font-markdown-code-block);background:var(--dsw-alias-markdown-code-block);border-radius:8px;margin:16px 0 8px;padding:8px;position:sticky;top:0;overflow:hidden}.F1KBNa_diffPreviewTitle{color:var(--dsw-alias-label-tertiary);margin-bottom:6px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_diffPreviewScroll{height:132px;overflow-y:auto}.F1KBNa_mdPreviewWrap{isolation:isolate;flex:1;min-width:0;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_mdPreviewBody{min-width:0;min-height:0;color:var(--dsw-alias-label-primary);flex:1;padding:12px 16px;position:relative;overflow:auto}.F1KBNa_mdPreviewContent{width:100%;min-width:0;margin:0 auto}.F1KBNa_mdPreviewSingle{display:block}.F1KBNa_mdPreviewDouble{display:flex}.F1KBNa_mdPreviewBody .mdBlock{border-radius:4px;margin-bottom:12px;padding:2px 6px}.F1KBNa_mdPreviewBody .mdAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_mdPreviewBody .mdDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_mdPreviewBody .mdWordDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdWordAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 34%, transparent);border-radius:2px;padding:0 1px}.F1KBNa_mdPreviewBody .mdDouble{flex-direction:column;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleRow{align-items:flex-start;width:100%;min-width:0;display:flex}.F1KBNa_mdPreviewBody .mdDoubleCol{flex:1;min-width:0}.F1KBNa_mdPreviewBody .mdDoubleRule{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:0 12px}.F1KBNa_mdPreviewFallback{font-family:var(--dsw-font-markdown-code-block);color:var(--dsw-alias-label-tertiary);padding:12px 16px;font-size:12px;line-height:18px}.F1KBNa_mdPreviewBody{word-break:break-word;font-size:13px;line-height:20px}.F1KBNa_mdPreviewBody>:first-child{margin-top:0}.F1KBNa_mdPreviewBody>:last-child{margin-bottom:0}.F1KBNa_mdPreviewBody h1,.F1KBNa_mdPreviewBody h2,.F1KBNa_mdPreviewBody h3,.F1KBNa_mdPreviewBody h4,.F1KBNa_mdPreviewBody h5,.F1KBNa_mdPreviewBody h6{margin:16px 0 8px;font-weight:600;line-height:1.3}.F1KBNa_mdPreviewBody h1{font-size:22px}.F1KBNa_mdPreviewBody h2{font-size:19px}.F1KBNa_mdPreviewBody h3{font-size:16px}.F1KBNa_mdPreviewBody h4{font-size:15px}.F1KBNa_mdPreviewBody h5{font-size:14px}.F1KBNa_mdPreviewBody h6{font-size:13px}.F1KBNa_mdPreviewBody p{margin:8px 0}.F1KBNa_mdPreviewBody ul,.F1KBNa_mdPreviewBody ol{margin:8px 0;padding-left:22px}.F1KBNa_mdPreviewBody li{margin:2px 0}.F1KBNa_mdPreviewBody a{color:var(--dsw-alias-state-business-primary);text-decoration:none}.F1KBNa_mdPreviewBody a:hover{text-decoration:underline}.F1KBNa_mdPreviewBody code{font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:4px;padding:1px 5px;font-size:12.5px}.F1KBNa_mdPreviewBody pre{border:1px solid var(--dsw-alias-border-l1);font-family:var(--dsw-font-markdown-code-block);background:#9e9e9e40;border-radius:8px;margin:8px 0;padding:10px 12px;font-size:12.5px;line-height:18px;overflow:auto}.F1KBNa_mdPreviewBody pre code{background:0 0;padding:0}.F1KBNa_mdPreviewBody blockquote{border-left:3px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-secondary);margin:8px 0;padding:0 12px}.F1KBNa_mdPreviewBody hr{background:var(--dsw-alias-border-l1);border:none;height:1px;margin:16px 0}.F1KBNa_mdPreviewBody table{border-collapse:collapse;margin:8px 0}.F1KBNa_mdPreviewBody th,.F1KBNa_mdPreviewBody td{border:1px solid var(--dsw-alias-border-l1);padding:4px 10px}.F1KBNa_mdPreviewBody img{max-width:100%}.F1KBNa_mdPreviewBody .mdImageFallback{border:1px dashed var(--dsw-alias-border-l2);background:color-mix(in srgb, var(--dsw-alias-markdown-code-block) 45%, transparent);width:100%;min-height:120px;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-markdown-code-block);text-align:center;white-space:pre-wrap;word-break:break-all;border-radius:4px;justify-content:center;align-items:center;margin:0 auto;padding:8px 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_toggle{border:1px solid var(--dsw-alias-border-l2);cursor:pointer;background:0 0;border-radius:18px;flex:none;width:60px;height:36px;padding:0;position:relative}.F1KBNa_toggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_toggle:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:2px}.F1KBNa_toggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleOn:hover{background:var(--dsw-alias-state-business-primary)}.F1KBNa_toggleThumb{background:var(--dsw-alias-label-primary);border-radius:50%;width:28px;height:28px;transition:left .12s;position:absolute;top:3px;left:3px}.F1KBNa_toggleOn .F1KBNa_toggleThumb{background:#fff;left:27px}.F1KBNa_stepper{align-items:center;gap:6px;display:inline-flex}.F1KBNa_stepperButton{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-module-platform);width:32px;height:32px;color:var(--dsw-alias-label-primary);cursor:pointer;border-radius:8px;padding:0;position:relative}.F1KBNa_stepperButton:before,.F1KBNa_stepperButton:after{content:\"\";background:currentColor;position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_stepperButton:before{width:10px;height:1px}.F1KBNa_stepperButton:after{width:1px;height:10px;display:none}.F1KBNa_stepperButtonUp:after{display:block}.F1KBNa_stepperButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_stepperButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_stepperValue{text-align:center;min-width:2ch;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;font-size:14px;line-height:22px}.F1KBNa_states{flex-direction:column;flex:1;min-height:0;padding:4px 12px 12px;display:flex;overflow-y:auto}.F1KBNa_split{flex:1;align-items:stretch;min-height:0;display:flex;position:relative}.F1KBNa_fileListKnob{z-index:39;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:28px;height:28px;color:var(--dsw-alias-label-primary);cursor:pointer;box-shadow:var(--dsw-elevation-prominent);border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute}.F1KBNa_fileListKnob[data-open]{box-shadow:none;opacity:0}.F1KBNa_fileListKnob:not([data-open]){animation:.32s ease-in-out .5s both F1KBNa_fileListKnobIn}@keyframes F1KBNa_fileListKnobIn{0%{opacity:0}to{opacity:1}}.F1KBNa_fileListKnob:hover,.F1KBNa_fileListKnob:focus-visible{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-interactive-bg-hover), var(--dsw-alias-interactive-bg-hover))}.F1KBNa_fileListFloat{z-index:40;box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);box-shadow:none;transform-origin:0 0;border-radius:12px;flex-direction:column;padding:6px 8px 10px;display:flex;position:absolute;overflow:hidden}.F1KBNa_fileListFloatClosing{pointer-events:none;animation:.14s ease-in forwards F1KBNa_fileListShrink}@keyframes F1KBNa_fileListShrink{0%{opacity:1;transform:scale(1)}to{opacity:0;transform:scale(.96)}}.F1KBNa_fileList{box-sizing:border-box;border-right:1px solid var(--dsw-alias-border-l2);flex-direction:column;flex:none;width:240px;min-height:0;padding:4px 8px 12px;display:flex}.F1KBNa_listScroll{flex:1;min-height:0;overflow-y:scroll}.F1KBNa_bulkActions{flex:none;gap:6px;padding:8px 8px 0 0;display:flex}.F1KBNa_bulkActions .F1KBNa_action{text-align:center;flex:1}.F1KBNa_resizeHandle{cursor:col-resize;touch-action:none;background:0 0;flex:none;width:5px;margin:0 -2px}.F1KBNa_resizeHandle:hover{background:var(--dsw-alias-border-l2)}.F1KBNa_floatResizeHandle{z-index:41;cursor:col-resize;-webkit-user-select:none;user-select:none;touch-action:none;background:0 0;border-radius:4px;position:absolute}.F1KBNa_floatResizeHandle:hover{background-color:var(--dsw-alias-bg-base);background-image:linear-gradient(var(--dsw-alias-border-l2), var(--dsw-alias-border-l2))}.F1KBNa_detail{flex-direction:column;flex:1;min-width:0;min-height:0;display:flex}.F1KBNa_detailEmpty{color:var(--dsw-alias-label-tertiary);text-align:center;flex:1;justify-content:center;align-items:center;margin:0;padding:24px;font-size:12px;line-height:18px;display:flex}.F1KBNa_confirmBackdrop{z-index:55;background:color-mix(in srgb, var(--dsw-alias-bg-base) 55%, transparent);justify-content:center;align-items:center;padding:24px;display:flex;position:absolute;inset:0}.F1KBNa_confirmCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:340px;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:12px;padding:16px;display:flex}.F1KBNa_confirmText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);overflow-wrap:anywhere;margin:0;line-height:1.5}.F1KBNa_confirmActions{flex:none;justify-content:flex-end;align-items:center;gap:8px;display:flex}.F1KBNa_pickerCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);width:420px;max-width:100%;height:70%;max-height:100%;box-shadow:var(--dsw-shadow-lv3);border-radius:12px;flex-direction:column;gap:8px;padding:14px 16px 16px;display:flex;position:relative;overflow:hidden}.F1KBNa_pickerTitle{color:var(--dsw-alias-label-primary);flex:none;font-size:13px;font-weight:500;line-height:20px}.F1KBNa_pickerClose{width:22px;height:22px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:6px;justify-content:center;align-items:center;padding:0;display:inline-flex;position:absolute;top:10px;right:10px}.F1KBNa_pickerClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_pickerForm{flex:none;gap:8px;display:flex}.F1KBNa_pickerInput{border:1px solid var(--dsw-alias-border-l1);min-width:0;color:var(--dsw-alias-label-primary);background:0 0;border-radius:8px;flex:auto;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_pickerInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_tree{border:1px solid var(--dsw-alias-border-l1);border-radius:8px;flex:auto;min-height:0;padding:4px 2px 4px 4px;overflow:auto scroll}.F1KBNa_treeRow{border-radius:6px;align-items:center;gap:2px;padding-right:4px;display:flex}.F1KBNa_treeRow:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_treeRow[data-selected]{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 18%, transparent)}.F1KBNa_treeCaret{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:0;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_treeCaret:hover{color:var(--dsw-alias-label-primary)}.F1KBNa_treeName{min-width:0;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer;background:0 0;border:0;border-radius:6px;flex:auto;align-items:center;gap:6px;padding:2px 4px;font-family:inherit;font-size:12px;line-height:18px;display:flex}.F1KBNa_treeName:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_treeNote{color:var(--dsw-alias-label-tertiary);margin:2px 0;font-size:12px;line-height:18px}.F1KBNa_pickerIcon{width:16px;height:16px;color:var(--dsw-alias-label-tertiary);flex:none;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_pickerName{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_pickerNote{color:var(--dsw-alias-label-tertiary);flex:none;margin:0;font-size:12px;line-height:18px}.F1KBNa_pickerCheck{color:var(--dsw-alias-label-secondary);cursor:pointer;align-items:center;gap:6px;margin-right:auto;font-size:12px;line-height:18px;display:flex}.F1KBNa_title{color:var(--dsw-alias-label-primary);font-size:13px;font-weight:500;line-height:20px}.F1KBNa_note,.F1KBNa_readError,.F1KBNa_hint{color:var(--dsw-alias-label-tertiary);margin:4px 0;font-size:12px;line-height:18px}.F1KBNa_noteCentered{text-align:center;margin:auto}.F1KBNa_emptyState{flex-direction:column;align-items:center;gap:10px;margin:auto;display:flex}.F1KBNa_importButton{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:5px 14px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_importButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_importButton:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_importNote{color:var(--dsw-alias-label-tertiary);text-align:center;margin:0;font-size:12px;line-height:18px}.F1KBNa_readError{color:var(--dsw-alias-state-error-primary)}.F1KBNa_group{color:var(--dsw-alias-label-tertiary);margin:8px 0 4px;font-size:12px;font-weight:500;line-height:16px}.F1KBNa_groupHead{align-items:center;gap:4px;margin:8px 0 4px;padding-right:8px;display:flex}.F1KBNa_action.F1KBNa_addButton{box-sizing:border-box;border-radius:6px;justify-content:center;align-items:center;width:20px;height:20px;min-height:0;padding:0;display:inline-flex}.F1KBNa_groupHead>.F1KBNa_group{margin:0}.F1KBNa_emptyActions{flex-wrap:wrap;justify-content:center;gap:8px;display:flex}.F1KBNa_rows{margin:0;padding:0;list-style:none}.F1KBNa_row{border:1px solid #0000;border-radius:10px;margin:2px 0}.F1KBNa_rowHead{width:100%;color:var(--dsw-alias-label-primary);font:inherit;text-align:left;cursor:pointer;background:0 0;border:none;border-radius:10px;align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_rowHead:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_rowHead[data-selected]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_rowPath{text-overflow:ellipsis;white-space:nowrap;min-width:0;margin-left:4px;font-size:12px;line-height:18px;position:relative;top:1px;overflow:hidden}.F1KBNa_kindTag{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_kindHint{color:var(--dsw-alias-label-tertiary);flex:none;font-size:12px;line-height:16px}.F1KBNa_divergedHint,.F1KBNa_missingHint{border-bottom:1px solid var(--dsw-alias-border-l2);margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missing{border:1px solid var(--dsw-alias-state-warn-primary);color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary));white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_rowFailed{border:1px solid var(--dsw-alias-state-error-primary);color:var(--dsw-alias-state-error-primary);white-space:nowrap;border-radius:6px;flex:none;padding:1px 6px;font-size:11px;line-height:14px}.F1KBNa_actionError{border-bottom:1px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;margin:0;padding:6px 8px;font-size:12px;line-height:18px}.F1KBNa_missingHint{color:var(--dsw-alias-state-warn-label,var(--dsw-alias-state-warn-primary))}.F1KBNa_rowMeta{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;flex:none;gap:6px;margin-left:auto;font-size:12px;line-height:16px;display:inline-flex}.F1KBNa_addCount{color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_delCount{color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 60%, var(--dsw-alias-label-primary))}.F1KBNa_diff{background:var(--dsw-alias-markdown-code-block);flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffHeader{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_panelDocked .F1KBNa_diffHeader{background:var(--dsw-alias-bg-base)}.F1KBNa_diffPath{white-space:nowrap;scrollbar-width:none;min-width:0;color:var(--dsw-alias-label-primary);-webkit-user-select:text;user-select:text;flex:1;margin-left:4px;font-size:12px;line-height:18px;position:relative;top:1px;overflow:auto hidden}.F1KBNa_diffPath::-webkit-scrollbar{display:none}.F1KBNa_diffActions{border-bottom:1px solid var(--dsw-alias-border-l2);align-items:center;gap:8px;padding:6px 8px;display:flex}.F1KBNa_diffStats{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:12px;line-height:16px}.F1KBNa_flexSpacer{flex:1}.F1KBNa_divider{background:var(--dsw-alias-border-l1);align-self:stretch;width:1px;margin:2px 0}.F1KBNa_action{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_action:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_action:disabled{color:var(--dsw-alias-label-tertiary);cursor:default}.F1KBNa_actionPrimary{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_actionPrimary:hover:not(:disabled){background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_actionPrimary:disabled{background:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:.55}.F1KBNa_actionQuietDisabled:disabled{cursor:pointer;color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1);background:0 0}.F1KBNa_actionPrimary.F1KBNa_actionQuietDisabled:disabled{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50);opacity:1}.F1KBNa_iconAction{justify-content:center;align-items:center;min-height:25px;padding:4px 6px;display:inline-flex}.F1KBNa_close{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_close:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expand{cursor:pointer;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_expand:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_expandExpanded svg{transform:rotate(180deg)}.F1KBNa_diffBodyWrap{isolation:isolate;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBody{min-width:0;font:var(--dsw-font-markdown-code-block);-webkit-text-size-adjust:100%;text-size-adjust:100%;cursor:text;outline:none;flex:1;padding:0;position:relative;overflow:auto}.F1KBNa_diffBody::-webkit-scrollbar,.F1KBNa_diffBody::-webkit-scrollbar-track,.F1KBNa_diffBody::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_blockActions{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);z-index:2;border-radius:10px;align-items:center;gap:9px;padding:5px;display:flex;position:absolute;right:8px}.F1KBNa_blockActionsDivider{background:var(--dsw-alias-border-l2);flex:none;align-self:stretch;width:1px;margin:2px 0}.F1KBNa_blockPosition{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;margin-top:1px;margin-left:7px;font-size:12px;line-height:16px}.F1KBNa_searchBar{z-index:3;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-markdown-code-block);box-shadow:var(--dsw-shadow-lv1);border-radius:10px;align-items:center;gap:4px;padding:4px;display:flex;position:absolute;top:8px;right:8px}.F1KBNa_searchInput{border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);width:150px;color:var(--dsw-alias-label-primary);border-radius:6px;outline:none;padding:3px 8px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_searchInput:focus{border-color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchCount{text-align:center;min-width:34px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:12px;line-height:16px}.F1KBNa_searchToggle{border:1px solid var(--dsw-alias-border-l1);min-height:25px;color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;justify-content:center;align-items:center;padding:4px 6px;display:inline-flex}.F1KBNa_searchToggle:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_searchToggleOn{border-color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-state-business-primary)}.F1KBNa_searchMatch{color:inherit;background-color:#facc1542;border-radius:2px}.F1KBNa_searchMatchCurrent{color:inherit;background-color:#facc1599;border-radius:2px}.F1KBNa_blockFlash{z-index:1;box-sizing:border-box;border:2px solid var(--dsw-alias-state-business-primary);pointer-events:none;border-radius:4px;animation:1s ease-out forwards F1KBNa_diffFlashFade;position:absolute;left:0;right:0}.F1KBNa_blockFlashShake{animation:.7s ease-out forwards F1KBNa_diffFlashShake}.F1KBNa_discussionRow{display:table-row}.F1KBNa_discussionCell{display:table-cell}.F1KBNa_discussionPin{width:0;height:0;position:sticky;left:0}.F1KBNa_discussion{z-index:2;box-sizing:border-box;background:var(--dsw-alias-bg-base);border-left:3px solid var(--dsw-alias-label-secondary);flex-direction:column;display:flex;position:absolute;top:0;left:0;overflow:hidden}.F1KBNa_discussionHead,.F1KBNa_discussionBody{font:var(--dsw-font-markdown-code-block)}.F1KBNa_discussionBody{flex-direction:column;flex:auto;min-height:0;padding:0 12px;display:flex;overflow:hidden}.F1KBNa_discussion[data-lost]{border-left-color:var(--dsw-alias-state-warn-primary,var(--dsw-alias-label-tertiary))}.F1KBNa_discussion[data-lost] .F1KBNa_discussionAnswer{color:var(--dsw-alias-label-secondary)}.F1KBNa_discussionAnswer{color:var(--dsw-alias-label-primary);font-family:inherit;font-size:calc(1em * var(--dsh-diff-font-scale,1));line-height:var(--dsh-diff-line-height,22px);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:0}.F1KBNa_discussionUser{padding:calc(var(--dsh-diff-line-height,22px) * .2) calc(var(--dsh-diff-line-height,22px) * .5);margin:calc(var(--dsh-diff-line-height,22px) * .3) 0 calc(var(--dsh-diff-line-height,22px) * .3) auto;box-sizing:border-box;background:var(--dsw-specific-bubble,var(--dsw-alias-bg-layer-2,var(--dsw-alias-interactive-bg-hover)));width:fit-content;max-width:82%;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:calc(1em * var(--dsh-diff-font-scale,1));line-height:var(--dsh-diff-line-height,22px);white-space:pre-wrap;overflow-wrap:anywhere;border-radius:8px}.F1KBNa_discussionNote{color:var(--dsw-alias-label-secondary);font-family:inherit;font-size:calc(1em * var(--dsh-diff-font-scale,1));line-height:var(--dsh-diff-line-height,22px);white-space:pre-wrap;overflow-wrap:anywhere;margin:0;padding:0}.F1KBNa_discussionNote[data-diff-discussion-hidden]{color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionHead{box-sizing:border-box;height:var(--dsh-diff-line-height,22px);flex:none;align-items:center;gap:8px;padding:0 12px;font-size:12px;line-height:16px;display:flex}.F1KBNa_discussionCompose{box-sizing:border-box;height:calc(var(--dsh-diff-line-height,22px) * 2);flex:none;align-items:center;gap:8px;margin:0 -6px;padding:0;display:flex}.F1KBNa_discussionInput{box-sizing:border-box;border:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);min-width:0;color:var(--dsw-alias-label-primary);font-family:inherit;font-size:calc(1em * var(--dsh-diff-font-scale,1));border-radius:6px;flex:auto;padding:3px 8px;line-height:18px}.F1KBNa_discussionToggle{width:18px;height:18px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_discussionToggle:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_discussionRangeWrap{font:var(--dsw-font-markdown-code-block);flex:none}.F1KBNa_discussionRange{color:var(--dsw-alias-label-tertiary);font-family:inherit;font-size:calc(1em * var(--dsh-diff-font-scale,1))}.F1KBNa_discussionInput:focus{border-color:var(--dsw-alias-state-business-primary);outline:none}.F1KBNa_discussionInput::placeholder{font-family:inherit;font-size:inherit;color:var(--dsw-alias-label-tertiary)}.F1KBNa_discussionSend{box-sizing:border-box;white-space:nowrap;flex:none;justify-content:center;align-items:center;gap:6px;padding-left:9px;padding-right:9px;display:inline-flex}.F1KBNa_rowDiscussed{background-image:linear-gradient(color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent), color-mix(in srgb, var(--dsw-alias-label-secondary) 14%, transparent))}@keyframes F1KBNa_diffFlashFade{0%{opacity:1}to{opacity:0}}@keyframes F1KBNa_diffFlashShake{0%{opacity:1;transform:translateY(0)}10%{transform:translateY(1px)}20%{transform:translateY(-1px)}30%{transform:translateY(1px)}40%{transform:translateY(-1px)}50%{transform:translateY(1px)}60%{transform:translateY(-1px)}70%{opacity:1;transform:translateY(0)}to{opacity:0;transform:translateY(0)}}.F1KBNa_overviewRuler{pointer-events:none;opacity:.5;width:4px;position:absolute;top:0;bottom:0;right:0}.F1KBNa_overviewMarker{border-radius:2px;width:100%;min-height:2px;position:absolute;right:0}.F1KBNa_markerDel{background-color:var(--dsw-alias-state-error-primary)}.F1KBNa_markerAdd{background-color:var(--dsw-alias-state-success-primary)}.F1KBNa_lines{border-spacing:0;width:max-content;min-width:100%;font-size:calc(1em * var(--dsh-diff-font-scale,1));display:table}.F1KBNa_line{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);-webkit-user-select:none;user-select:none;display:table-row}.F1KBNa_vSpacer{display:table-row}.F1KBNa_gutter{box-sizing:border-box;text-align:right;width:44px;color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;-webkit-user-select:none;user-select:none;cursor:default;padding-right:10px;display:table-cell}.F1KBNa_code{white-space:pre;-webkit-user-select:text;user-select:text;display:table-cell}.F1KBNa_context{color:var(--dsw-alias-label-primary)}.F1KBNa_del{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_add{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_statusBar{box-sizing:border-box;border-top:1px solid var(--dsw-alias-border-l2);height:34px;color:var(--dsw-alias-label-tertiary);font-family:var(--dsw-font-markdown-code-block);font-variant-numeric:tabular-nums;flex:none;align-items:center;gap:8px;padding:0 8px;font-size:12px;line-height:18px;display:flex}.F1KBNa_statusAction{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);white-space:nowrap;cursor:pointer;background:0 0;border-radius:8px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px}.F1KBNa_statusAction:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langSelect{border:1px solid var(--dsw-alias-border-l1);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:8px;flex:none;align-items:center;gap:4px;padding:3px 12px;font-family:inherit;font-size:12px;line-height:18px;display:inline-flex}.F1KBNa_langSelect:hover{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_langLabel{text-overflow:ellipsis;white-space:nowrap;max-width:140px;overflow:hidden}.F1KBNa_presentationSelect{cursor:pointer;height:28px;color:var(--dsw-alias-label-tertiary);background:0 0;border:none;border-radius:28px;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_presentationSelect:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_chip{justify-content:flex-end;align-items:center;gap:5px;min-width:0;padding-right:14px;display:inline-flex}.F1KBNa_chipLabel{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.F1KBNa_coverHost{align-items:center;display:inline-flex;position:relative}.F1KBNa_coverCard{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv2);border-radius:12px;align-items:center;gap:4px;padding:6px;display:flex}.F1KBNa_coverPopover{z-index:50;position:absolute;top:calc(100% + 6px);right:0}.F1KBNa_coverNotice{z-index:80;pointer-events:none;animation:1.25s ease-out forwards F1KBNa_coverNoticeFade;position:fixed;top:50%;left:50%;transform:translate(-50%,-50%)}.F1KBNa_coverNoticeCard{gap:4px;padding:6px 8px}@keyframes F1KBNa_coverNoticeFade{0%,78%{opacity:1}to{opacity:0}}.F1KBNa_coverNoticeGlyph{width:44px;height:44px;color:var(--dsw-alias-label-tertiary);border-radius:10px;justify-content:center;align-items:center;display:inline-flex}.F1KBNa_coverNoticeGlyph[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_coverNoticeGlyph[data-changed]{background:var(--dsw-alias-interactive-bg-hover)}.F1KBNa_coverNoticeText{clip-path:inset(50%);white-space:nowrap;width:1px;height:1px;position:absolute;overflow:hidden}.F1KBNa_coverButton{width:32px;height:32px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:8px;justify-content:center;align-items:center;padding:0;display:inline-flex}.F1KBNa_coverButton:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_coverButton[data-on]{color:var(--dsw-alias-label-primary)}.F1KBNa_presentationHost{align-items:center;display:inline-flex}.F1KBNa_chipPresentation{min-width:36px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:20px;flex:none;justify-content:center;align-items:center;gap:2px;padding:0 6px;display:inline-flex}.F1KBNa_chipPresentation:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.F1KBNa_mirrored{transform:scaleX(-1)}.F1KBNa_notice{z-index:60;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-base);max-width:360px;box-shadow:var(--dsw-shadow-lv3);border-radius:10px;align-items:flex-start;gap:12px;padding:12px 14px;display:flex;position:fixed;bottom:24px;right:24px}.F1KBNa_noticeText{font:var(--dsw-font-caption);color:var(--dsw-alias-label-primary);flex:1;margin:0;line-height:1.45}.F1KBNa_noticeButton{border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);font:var(--dsw-font-caption);cursor:pointer;border-radius:6px;flex:none;padding:4px 10px}.F1KBNa_noticeButton:hover{background:var(--dsw-alias-interactive-bg-hover-solid)}.F1KBNa_wrap .F1KBNa_line{height:auto;min-height:var(--dsh-diff-line-height,22px)}.F1KBNa_subline{height:var(--dsh-diff-line-height,22px);line-height:var(--dsh-diff-line-height,22px);white-space:pre;display:block;overflow:hidden}.F1KBNa_wrapActive{background:var(--dsw-alias-state-business-primary);border-color:var(--dsw-alias-state-business-primary);color:var(--dsw-static-neutral-bluish-50)}.F1KBNa_wrapActive:hover{background:color-mix(in srgb, var(--dsw-alias-state-business-primary) 85%, var(--dsw-static-neutral-bluish-1000))}.F1KBNa_splitRoot{isolation:isolate;flex-direction:column;flex:1;min-height:0;display:flex;position:relative;overflow:hidden}.F1KBNa_diffBodySplit{flex:1;min-height:0;overflow-x:hidden}.F1KBNa_splitCols{width:100%;min-width:0;display:flex}.F1KBNa_splitCol{box-sizing:border-box;flex:1 1 0;min-width:0;overflow:hidden}.F1KBNa_splitDivider{background:var(--dsw-alias-border-l2);flex:0 0 1px}.F1KBNa_splitCol .F1KBNa_gutter,.F1KBNa_splitCol .F1KBNa_code{vertical-align:top}.F1KBNa_splitHScrollRow{border-top:1px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-base);flex:none;width:100%;min-width:0;display:flex}.F1KBNa_splitHScroll{min-width:0;height:var(--dsh-scrollbar-width,8px);flex:1 1 0;overflow:auto hidden}.F1KBNa_splitHScroll::-webkit-scrollbar{height:var(--dsh-scrollbar-width,8px)}.F1KBNa_splitHScroll::-webkit-scrollbar-track{cursor:default}.F1KBNa_splitHScroll::-webkit-scrollbar-thumb{cursor:default}.F1KBNa_splitHScrollFill{height:1px}.F1KBNa_splitLdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_splitLadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_splitRdel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 12%, transparent)}.F1KBNa_splitRadd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 10%, transparent)}.F1KBNa_intraDel{background-color:color-mix(in srgb, var(--dsh-diff-del-color,var(--dsw-alias-state-error-primary)) 26%, transparent);text-decoration:line-through}.F1KBNa_intraAdd{background-color:color-mix(in srgb, var(--dsh-diff-add-color,var(--dsw-alias-state-success-primary)) 24%, transparent)}";
25
25
  const tagId = "dsh-diff-approval/PendingPanel.module.css";
26
26
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
27
27
  const tag = document.createElement("style");
@@ -31,204 +31,223 @@ window.__ModuleLoader__.load({
31
31
  document.head.appendChild(tag);
32
32
  }
33
33
  var PendingPanel_module_css_default = {
34
- "coverNoticeFade": "F1KBNa_coverNoticeFade",
35
- "stepperValue": "F1KBNa_stepperValue",
36
- "splitHScrollFill": "F1KBNa_splitHScrollFill",
37
- "title": "F1KBNa_title",
38
- "coverPopover": "F1KBNa_coverPopover",
39
- "colorPickerPreview": "F1KBNa_colorPickerPreview",
34
+ "wrap": "F1KBNa_wrap",
35
+ "colorPickerChevron": "F1KBNa_colorPickerChevron",
36
+ "headerActions": "F1KBNa_headerActions",
37
+ "pickerIcon": "F1KBNa_pickerIcon",
38
+ "searchToggle": "F1KBNa_searchToggle",
39
+ "settingsGroup": "F1KBNa_settingsGroup",
40
+ "mdPreviewBody": "F1KBNa_mdPreviewBody",
40
41
  "mirrored": "F1KBNa_mirrored",
41
- "confirmText": "F1KBNa_confirmText",
42
- "diff": "F1KBNa_diff",
43
- "mdPreviewWrap": "F1KBNa_mdPreviewWrap",
44
- "headerEntry": "F1KBNa_headerEntry",
42
+ "wrapActive": "F1KBNa_wrapActive",
43
+ "settingsGroupDesc": "F1KBNa_settingsGroupDesc",
44
+ "pickerForm": "F1KBNa_pickerForm",
45
+ "importButton": "F1KBNa_importButton",
46
+ "splitRadd": "F1KBNa_splitRadd",
45
47
  "colorHueCursor": "F1KBNa_colorHueCursor",
46
- "statusBar": "F1KBNa_statusBar",
47
- "settingsGroupBody": "F1KBNa_settingsGroupBody",
48
- "toggleThumb": "F1KBNa_toggleThumb",
49
- "fileListFloat": "F1KBNa_fileListFloat",
50
- "panel": "F1KBNa_panel",
51
48
  "groupHead": "F1KBNa_groupHead",
52
- "colorPickerTrigger": "F1KBNa_colorPickerTrigger",
53
- "rail": "F1KBNa_rail",
49
+ "fileListKnobIn": "F1KBNa_fileListKnobIn",
50
+ "diffFlashFade": "F1KBNa_diffFlashFade",
51
+ "coverHost": "F1KBNa_coverHost",
52
+ "pickerName": "F1KBNa_pickerName",
53
+ "colorPickerPanel": "F1KBNa_colorPickerPanel",
54
+ "stepperValue": "F1KBNa_stepperValue",
55
+ "stepperButton": "F1KBNa_stepperButton",
56
+ "discussionCell": "F1KBNa_discussionCell",
54
57
  "layer": "F1KBNa_layer",
55
- "colorPicker": "F1KBNa_colorPicker",
56
- "colorSwatch": "F1KBNa_colorSwatch",
57
- "panelFailureText": "F1KBNa_panelFailureText",
58
- "mdPreviewBody": "F1KBNa_mdPreviewBody",
59
- "settingsPage": "F1KBNa_settingsPage",
60
- "pickerIcon": "F1KBNa_pickerIcon",
61
- "actionError": "F1KBNa_actionError",
62
- "delCount": "F1KBNa_delCount",
63
- "pickerCard": "F1KBNa_pickerCard",
64
- "note": "F1KBNa_note",
65
- "emptyActions": "F1KBNa_emptyActions",
66
- "close": "F1KBNa_close",
67
- "split": "F1KBNa_split",
68
- "blockActions": "F1KBNa_blockActions",
58
+ "line": "F1KBNa_line",
59
+ "chipLabel": "F1KBNa_chipLabel",
60
+ "footerButtons": "F1KBNa_footerButtons",
61
+ "searchInput": "F1KBNa_searchInput",
62
+ "searchCount": "F1KBNa_searchCount",
63
+ "discussionCompose": "F1KBNa_discussionCompose",
64
+ "toggle": "F1KBNa_toggle",
69
65
  "searchMatchCurrent": "F1KBNa_searchMatchCurrent",
66
+ "rowDiscussed": "F1KBNa_rowDiscussed",
67
+ "coverNotice": "F1KBNa_coverNotice",
68
+ "diffPath": "F1KBNa_diffPath",
69
+ "fileListShrink": "F1KBNa_fileListShrink",
70
+ "dockHost": "F1KBNa_dockHost",
71
+ "noteCentered": "F1KBNa_noteCentered",
72
+ "stepper": "F1KBNa_stepper",
73
+ "colorValue": "F1KBNa_colorValue",
74
+ "addButton": "F1KBNa_addButton",
75
+ "settingsGroupTitle": "F1KBNa_settingsGroupTitle",
76
+ "colorSwatch": "F1KBNa_colorSwatch",
70
77
  "searchMatch": "F1KBNa_searchMatch",
71
- "markerDel": "F1KBNa_markerDel",
72
- "add": "F1KBNa_add",
73
- "chipLabel": "F1KBNa_chipLabel",
74
- "chipPresentation": "F1KBNa_chipPresentation",
75
- "splitHScrollRow": "F1KBNa_splitHScrollRow",
76
- "searchToggleOn": "F1KBNa_searchToggleOn",
78
+ "statusAction": "F1KBNa_statusAction",
77
79
  "importNote": "F1KBNa_importNote",
80
+ "settingsPage": "F1KBNa_settingsPage",
78
81
  "chip": "F1KBNa_chip",
79
- "splitLdel": "F1KBNa_splitLdel",
80
- "importButton": "F1KBNa_importButton",
81
- "missing": "F1KBNa_missing",
82
+ "context": "F1KBNa_context",
83
+ "coverNoticeCard": "F1KBNa_coverNoticeCard",
84
+ "presentationHost": "F1KBNa_presentationHost",
85
+ "emptyActions": "F1KBNa_emptyActions",
82
86
  "splitLadd": "F1KBNa_splitLadd",
83
- "pickerClose": "F1KBNa_pickerClose",
84
- "gutter": "F1KBNa_gutter",
85
- "kindTag": "F1KBNa_kindTag",
86
- "addButton": "F1KBNa_addButton",
87
- "intraDel": "F1KBNa_intraDel",
88
- "splitCol": "F1KBNa_splitCol",
89
- "header": "F1KBNa_header",
90
87
  "addCount": "F1KBNa_addCount",
91
- "langSelect": "F1KBNa_langSelect",
92
- "noticeButton": "F1KBNa_noticeButton",
88
+ "settingsGroupBody": "F1KBNa_settingsGroupBody",
93
89
  "mdPreviewSingle": "F1KBNa_mdPreviewSingle",
94
- "settingsGroupTitle": "F1KBNa_settingsGroupTitle",
95
90
  "diffBodyWrap": "F1KBNa_diffBodyWrap",
96
- "splitRoot": "F1KBNa_splitRoot",
97
- "colorValue": "F1KBNa_colorValue",
98
- "colorBackdrop": "F1KBNa_colorBackdrop",
99
- "colorPickerInputRow": "F1KBNa_colorPickerInputRow",
100
- "panelFailureRetry": "F1KBNa_panelFailureRetry",
101
- "pickerCheck": "F1KBNa_pickerCheck",
102
- "colorPickerInput": "F1KBNa_colorPickerInput",
91
+ "diffPreview": "F1KBNa_diffPreview",
92
+ "action": "F1KBNa_action",
93
+ "discussionRow": "F1KBNa_discussionRow",
94
+ "confirmBackdrop": "F1KBNa_confirmBackdrop",
95
+ "treeRow": "F1KBNa_treeRow",
96
+ "discussionToggle": "F1KBNa_discussionToggle",
97
+ "discussionRange": "F1KBNa_discussionRange",
98
+ "gutter": "F1KBNa_gutter",
103
99
  "settingsGroupText": "F1KBNa_settingsGroupText",
104
- "colorPickerPanel": "F1KBNa_colorPickerPanel",
105
- "toggleOn": "F1KBNa_toggleOn",
106
- "context": "F1KBNa_context",
107
- "stepperButtonUp": "F1KBNa_stepperButtonUp",
108
- "diffPath": "F1KBNa_diffPath",
109
- "listScroll": "F1KBNa_listScroll",
110
- "pickerForm": "F1KBNa_pickerForm",
111
- "readError": "F1KBNa_readError",
112
- "markerAdd": "F1KBNa_markerAdd",
113
- "dockHost": "F1KBNa_dockHost",
114
- "diffPreviewScroll": "F1KBNa_diffPreviewScroll",
115
- "stepperButton": "F1KBNa_stepperButton",
116
- "diffFlashShake": "F1KBNa_diffFlashShake",
117
- "mdPreviewFallback": "F1KBNa_mdPreviewFallback",
118
- "code": "F1KBNa_code",
119
- "coverNoticeText": "F1KBNa_coverNoticeText",
120
- "splitRdel": "F1KBNa_splitRdel",
121
- "noticeText": "F1KBNa_noticeText",
122
- "diffBody": "F1KBNa_diffBody",
123
- "fileListKnob": "F1KBNa_fileListKnob",
100
+ "colorSv": "F1KBNa_colorSv",
124
101
  "divergedHint": "F1KBNa_divergedHint",
125
- "wrapActive": "F1KBNa_wrapActive",
102
+ "mdPreviewWrap": "F1KBNa_mdPreviewWrap",
103
+ "del": "F1KBNa_del",
104
+ "actionError": "F1KBNa_actionError",
105
+ "badgeCount": "F1KBNa_badgeCount",
106
+ "header": "F1KBNa_header",
107
+ "fileList": "F1KBNa_fileList",
108
+ "pickerNote": "F1KBNa_pickerNote",
109
+ "colorPickerInput": "F1KBNa_colorPickerInput",
110
+ "chipPresentation": "F1KBNa_chipPresentation",
111
+ "split": "F1KBNa_split",
126
112
  "tree": "F1KBNa_tree",
127
- "settingsRow": "F1KBNa_settingsRow",
113
+ "close": "F1KBNa_close",
114
+ "panelDocked": "F1KBNa_panelDocked",
115
+ "actionPrimary": "F1KBNa_actionPrimary",
116
+ "discussionPin": "F1KBNa_discussionPin",
117
+ "splitLdel": "F1KBNa_splitLdel",
118
+ "fileListFloatClosing": "F1KBNa_fileListFloatClosing",
119
+ "pickerCheck": "F1KBNa_pickerCheck",
120
+ "overviewMarker": "F1KBNa_overviewMarker",
121
+ "delCount": "F1KBNa_delCount",
122
+ "divider": "F1KBNa_divider",
123
+ "coverNoticeText": "F1KBNa_coverNoticeText",
124
+ "panel": "F1KBNa_panel",
125
+ "splitRdel": "F1KBNa_splitRdel",
128
126
  "detail": "F1KBNa_detail",
129
- "settingsReset": "F1KBNa_settingsReset",
130
- "colorPickerChevron": "F1KBNa_colorPickerChevron",
131
- "stepper": "F1KBNa_stepper",
132
- "action": "F1KBNa_action",
133
- "pickerName": "F1KBNa_pickerName",
134
- "colorSvCursor": "F1KBNa_colorSvCursor",
135
- "rowFailed": "F1KBNa_rowFailed",
127
+ "intraDel": "F1KBNa_intraDel",
128
+ "panelFailure": "F1KBNa_panelFailure",
129
+ "discussionAnswer": "F1KBNa_discussionAnswer",
130
+ "splitHScrollFill": "F1KBNa_splitHScrollFill",
131
+ "colorHue": "F1KBNa_colorHue",
132
+ "emptyState": "F1KBNa_emptyState",
133
+ "blockFlashShake": "F1KBNa_blockFlashShake",
134
+ "colorPickerPreview": "F1KBNa_colorPickerPreview",
135
+ "blockActionsDivider": "F1KBNa_blockActionsDivider",
136
+ "lines": "F1KBNa_lines",
136
137
  "rowMeta": "F1KBNa_rowMeta",
138
+ "noticeText": "F1KBNa_noticeText",
139
+ "group": "F1KBNa_group",
140
+ "coverNoticeGlyph": "F1KBNa_coverNoticeGlyph",
141
+ "colorPickerTrigger": "F1KBNa_colorPickerTrigger",
142
+ "row": "F1KBNa_row",
137
143
  "flexSpacer": "F1KBNa_flexSpacer",
144
+ "missingHint": "F1KBNa_missingHint",
145
+ "blockActions": "F1KBNa_blockActions",
146
+ "kindTag": "F1KBNa_kindTag",
147
+ "discussionInput": "F1KBNa_discussionInput",
148
+ "markerDel": "F1KBNa_markerDel",
149
+ "listScroll": "F1KBNa_listScroll",
150
+ "resizeHandle": "F1KBNa_resizeHandle",
151
+ "panelFailureText": "F1KBNa_panelFailureText",
152
+ "diffStats": "F1KBNa_diffStats",
138
153
  "hint": "F1KBNa_hint",
139
- "actionPrimary": "F1KBNa_actionPrimary",
154
+ "mdPreviewContent": "F1KBNa_mdPreviewContent",
155
+ "badgeLabel": "F1KBNa_badgeLabel",
156
+ "bulkActions": "F1KBNa_bulkActions",
157
+ "settingsGroupHeader": "F1KBNa_settingsGroupHeader",
158
+ "detailEmpty": "F1KBNa_detailEmpty",
159
+ "expandExpanded": "F1KBNa_expandExpanded",
160
+ "diffFlashShake": "F1KBNa_diffFlashShake",
161
+ "presentationSelect": "F1KBNa_presentationSelect",
162
+ "coverPopover": "F1KBNa_coverPopover",
163
+ "add": "F1KBNa_add",
164
+ "coverButton": "F1KBNa_coverButton",
165
+ "pickerInput": "F1KBNa_pickerInput",
166
+ "note": "F1KBNa_note",
167
+ "rowHead": "F1KBNa_rowHead",
168
+ "toggleThumb": "F1KBNa_toggleThumb",
169
+ "discussionSend": "F1KBNa_discussionSend",
170
+ "treeCaret": "F1KBNa_treeCaret",
140
171
  "settingsSelector": "F1KBNa_settingsSelector",
141
- "settingsGroupDesc": "F1KBNa_settingsGroupDesc",
142
- "footerButtons": "F1KBNa_footerButtons",
143
- "fileListGrow": "F1KBNa_fileListGrow",
172
+ "confirmActions": "F1KBNa_confirmActions",
173
+ "title": "F1KBNa_title",
174
+ "panelFailureRetry": "F1KBNa_panelFailureRetry",
175
+ "colorPickerInputRow": "F1KBNa_colorPickerInputRow",
176
+ "fileListFloat": "F1KBNa_fileListFloat",
144
177
  "settingsRowTitle": "F1KBNa_settingsRowTitle",
145
- "settingsRowText": "F1KBNa_settingsRowText",
146
- "confirmBackdrop": "F1KBNa_confirmBackdrop",
147
- "diffHeader": "F1KBNa_diffHeader",
148
- "expand": "F1KBNa_expand",
149
- "expandExpanded": "F1KBNa_expandExpanded",
150
- "blockPosition": "F1KBNa_blockPosition",
151
- "searchInput": "F1KBNa_searchInput",
152
- "searchCount": "F1KBNa_searchCount",
153
- "states": "F1KBNa_states",
154
- "mdPreviewContent": "F1KBNa_mdPreviewContent",
178
+ "pickerTitle": "F1KBNa_pickerTitle",
179
+ "iconAction": "F1KBNa_iconAction",
180
+ "intraAdd": "F1KBNa_intraAdd",
155
181
  "confirmCard": "F1KBNa_confirmCard",
156
- "colorPickerPopover": "F1KBNa_colorPickerPopover",
157
- "rowHead": "F1KBNa_rowHead",
158
- "rowPath": "F1KBNa_rowPath",
159
- "toggle": "F1KBNa_toggle",
160
- "overviewMarker": "F1KBNa_overviewMarker",
161
- "vSpacer": "F1KBNa_vSpacer",
162
- "langLabel": "F1KBNa_langLabel",
163
- "badgeCount": "F1KBNa_badgeCount",
182
+ "splitHScrollRow": "F1KBNa_splitHScrollRow",
183
+ "missing": "F1KBNa_missing",
184
+ "headerEntry": "F1KBNa_headerEntry",
185
+ "blockPosition": "F1KBNa_blockPosition",
186
+ "discussionRangeWrap": "F1KBNa_discussionRangeWrap",
187
+ "kindHint": "F1KBNa_kindHint",
188
+ "headerEntryCount": "F1KBNa_headerEntryCount",
189
+ "rail": "F1KBNa_rail",
164
190
  "splitDivider": "F1KBNa_splitDivider",
165
- "panelFailure": "F1KBNa_panelFailure",
166
- "presentationSelect": "F1KBNa_presentationSelect",
167
- "presentationHost": "F1KBNa_presentationHost",
168
- "row": "F1KBNa_row",
169
- "coverCard": "F1KBNa_coverCard",
170
- "splitRadd": "F1KBNa_splitRadd",
171
- "resizeHandle": "F1KBNa_resizeHandle",
172
- "searchToggle": "F1KBNa_searchToggle",
191
+ "diffPreviewTitle": "F1KBNa_diffPreviewTitle",
192
+ "searchToggleOn": "F1KBNa_searchToggleOn",
193
+ "discussionNote": "F1KBNa_discussionNote",
194
+ "pickerCard": "F1KBNa_pickerCard",
195
+ "diffActions": "F1KBNa_diffActions",
173
196
  "notice": "F1KBNa_notice",
174
- "panelDocked": "F1KBNa_panelDocked",
175
- "wrap": "F1KBNa_wrap",
176
- "badge": "F1KBNa_badge",
197
+ "settingsGroupChevron": "F1KBNa_settingsGroupChevron",
198
+ "fileListKnob": "F1KBNa_fileListKnob",
199
+ "discussionUser": "F1KBNa_discussionUser",
200
+ "confirmText": "F1KBNa_confirmText",
201
+ "states": "F1KBNa_states",
202
+ "noticeButton": "F1KBNa_noticeButton",
203
+ "overviewRuler": "F1KBNa_overviewRuler",
204
+ "rowFailed": "F1KBNa_rowFailed",
205
+ "settingsRow": "F1KBNa_settingsRow",
206
+ "diffPreviewScroll": "F1KBNa_diffPreviewScroll",
207
+ "discussionBody": "F1KBNa_discussionBody",
208
+ "code": "F1KBNa_code",
209
+ "subline": "F1KBNa_subline",
210
+ "splitRoot": "F1KBNa_splitRoot",
211
+ "readError": "F1KBNa_readError",
212
+ "mdPreviewFallback": "F1KBNa_mdPreviewFallback",
213
+ "splitCols": "F1KBNa_splitCols",
214
+ "discussionHead": "F1KBNa_discussionHead",
215
+ "pickerClose": "F1KBNa_pickerClose",
216
+ "settingsRowText": "F1KBNa_settingsRowText",
217
+ "blockFlash": "F1KBNa_blockFlash",
218
+ "langSelect": "F1KBNa_langSelect",
219
+ "treeNote": "F1KBNa_treeNote",
220
+ "rows": "F1KBNa_rows",
221
+ "diffBody": "F1KBNa_diffBody",
222
+ "statusBar": "F1KBNa_statusBar",
223
+ "toggleOn": "F1KBNa_toggleOn",
224
+ "searchBar": "F1KBNa_searchBar",
225
+ "vSpacer": "F1KBNa_vSpacer",
226
+ "rowPath": "F1KBNa_rowPath",
227
+ "colorBackdrop": "F1KBNa_colorBackdrop",
177
228
  "coverBackdrop": "F1KBNa_coverBackdrop",
178
- "divider": "F1KBNa_divider",
229
+ "colorPicker": "F1KBNa_colorPicker",
179
230
  "splitHScroll": "F1KBNa_splitHScroll",
180
- "diffPreviewTitle": "F1KBNa_diffPreviewTitle",
181
- "iconAction": "F1KBNa_iconAction",
182
- "intraAdd": "F1KBNa_intraAdd",
183
- "settingsGroup": "F1KBNa_settingsGroup",
184
- "overviewRuler": "F1KBNa_overviewRuler",
231
+ "colorSvCursor": "F1KBNa_colorSvCursor",
232
+ "diffHeader": "F1KBNa_diffHeader",
233
+ "expand": "F1KBNa_expand",
234
+ "colorPickerPopover": "F1KBNa_colorPickerPopover",
235
+ "discussion": "F1KBNa_discussion",
236
+ "markerAdd": "F1KBNa_markerAdd",
237
+ "settingsRowDesc": "F1KBNa_settingsRowDesc",
185
238
  "actionQuietDisabled": "F1KBNa_actionQuietDisabled",
186
- "treeNote": "F1KBNa_treeNote",
187
- "subline": "F1KBNa_subline",
188
- "floatResizeHandle": "F1KBNa_floatResizeHandle",
189
239
  "diffBodySplit": "F1KBNa_diffBodySplit",
190
- "headerActions": "F1KBNa_headerActions",
191
- "noteCentered": "F1KBNa_noteCentered",
192
- "group": "F1KBNa_group",
193
- "coverHost": "F1KBNa_coverHost",
194
- "blockFlashShake": "F1KBNa_blockFlashShake",
195
- "emptyState": "F1KBNa_emptyState",
196
- "colorSv": "F1KBNa_colorSv",
197
- "colorHue": "F1KBNa_colorHue",
198
- "treeCaret": "F1KBNa_treeCaret",
199
- "diffFlashFade": "F1KBNa_diffFlashFade",
200
240
  "mdPreviewDouble": "F1KBNa_mdPreviewDouble",
201
- "pickerTitle": "F1KBNa_pickerTitle",
202
- "statusAction": "F1KBNa_statusAction",
203
- "pickerInput": "F1KBNa_pickerInput",
204
- "bulkActions": "F1KBNa_bulkActions",
205
- "treeRow": "F1KBNa_treeRow",
206
- "coverButton": "F1KBNa_coverButton",
207
- "del": "F1KBNa_del",
208
- "lines": "F1KBNa_lines",
209
- "missingHint": "F1KBNa_missingHint",
210
- "settingsGroupHeader": "F1KBNa_settingsGroupHeader",
211
- "detailEmpty": "F1KBNa_detailEmpty",
241
+ "stepperButtonUp": "F1KBNa_stepperButtonUp",
242
+ "settingsReset": "F1KBNa_settingsReset",
243
+ "floatResizeHandle": "F1KBNa_floatResizeHandle",
244
+ "diff": "F1KBNa_diff",
245
+ "splitCol": "F1KBNa_splitCol",
212
246
  "treeName": "F1KBNa_treeName",
213
- "headerEntryCount": "F1KBNa_headerEntryCount",
214
- "settingsGroupChevron": "F1KBNa_settingsGroupChevron",
215
- "settingsRowDesc": "F1KBNa_settingsRowDesc",
216
- "diffPreview": "F1KBNa_diffPreview",
217
- "kindHint": "F1KBNa_kindHint",
218
- "diffStats": "F1KBNa_diffStats",
219
- "fileList": "F1KBNa_fileList",
220
- "splitCols": "F1KBNa_splitCols",
221
- "badgeLabel": "F1KBNa_badgeLabel",
222
- "confirmActions": "F1KBNa_confirmActions",
223
- "pickerNote": "F1KBNa_pickerNote",
224
- "searchBar": "F1KBNa_searchBar",
225
- "coverNoticeGlyph": "F1KBNa_coverNoticeGlyph",
226
- "blockFlash": "F1KBNa_blockFlash",
227
- "line": "F1KBNa_line",
228
- "rows": "F1KBNa_rows",
229
- "coverNoticeCard": "F1KBNa_coverNoticeCard",
230
- "diffActions": "F1KBNa_diffActions",
231
- "coverNotice": "F1KBNa_coverNotice"
247
+ "coverCard": "F1KBNa_coverCard",
248
+ "coverNoticeFade": "F1KBNa_coverNoticeFade",
249
+ "badge": "F1KBNa_badge",
250
+ "langLabel": "F1KBNa_langLabel"
232
251
  };
233
252
  //#endregion
234
253
  //#region lib/types/client/PathPicker.js
@@ -757,6 +776,7 @@ window.__ModuleLoader__.load({
757
776
  const PRESENTATION_KEY = "diff-approval:presentation";
758
777
  const FLOAT_COVER_KEY = "diff-approval:float-cover";
759
778
  const FILE_LIST_FLOAT_KEY = "diff-approval:file-list-float";
779
+ const COMMENT_MODE_PREVIEW_KEY = "diff-approval:comment-mode-preview";
760
780
  const WRAP_PREFIX = "diff-approval:wrap:";
761
781
  /** The floating panel's default coverage: the header and both sidebars, not the
762
782
  * composer. */
@@ -1059,6 +1079,24 @@ window.__ModuleLoader__.load({
1059
1079
  localStorage.setItem(MD_PREVIEW_KEY, value ? "1" : "0");
1060
1080
  }
1061
1081
  /**
1082
+ * Whether commenting on a diff range is offered: the selection frame's comment button,
1083
+ * and the chord that stands for it. Defaults to off while the mode is a preview (see
1084
+ * {@link COMMENT_MODE_PREVIEW_KEY}); only an explicit `'1'` enables it. This gates
1085
+ * STARTING a thread, not the threads themselves — one already written keeps rendering,
1086
+ * so turning the mode off never hides work or interrupts an answer on its way back.
1087
+ * @returns whether comment mode is on.
1088
+ */
1089
+ function commentModeEnabled() {
1090
+ return localStorage.getItem(COMMENT_MODE_PREVIEW_KEY) === "1";
1091
+ }
1092
+ /** Window event: comment mode was toggled (see {@link setCommentModeEnabled}). */
1093
+ const COMMENT_MODE_CHANGED_EVENT = "diff-approval:comment-mode";
1094
+ /** Persist the comment-mode preference. */
1095
+ function setCommentModeEnabled(value) {
1096
+ localStorage.setItem(COMMENT_MODE_PREVIEW_KEY, value ? "1" : "0");
1097
+ if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent(COMMENT_MODE_CHANGED_EVENT));
1098
+ }
1099
+ /**
1062
1100
  * The Markdown-preview content max width, in pixels (single column). Defaults to
1063
1101
  * 800; the double-column view totals 2x this. An out-of-range or non-integer
1064
1102
  * value falls back to the default.
@@ -1110,6 +1148,7 @@ window.__ModuleLoader__.load({
1110
1148
  jumpUp: "Ctrl+ArrowUp",
1111
1149
  jumpDown: "Ctrl+ArrowDown",
1112
1150
  copyRef: "Ctrl+L",
1151
+ addComment: "Ctrl+K",
1113
1152
  openSearch: "Ctrl+F",
1114
1153
  searchNext: "F3",
1115
1154
  searchPrev: "Shift+F3",
@@ -2683,6 +2722,215 @@ window.__ModuleLoader__.load({
2683
2722
  if (text === "") return [];
2684
2723
  return (text.endsWith("\n") ? text.slice(0, -1) : text).split("\n");
2685
2724
  }
2725
+ /**
2726
+ * The newest turns that fit a size budget, and how many older ones were left out.
2727
+ * A thread grows without bound, so the block shows its tail and says what it is
2728
+ * hiding rather than clipping silently; the hidden note costs one row of the
2729
+ * budget itself. Sizes are in whatever unit the caller budgets in (the panel uses
2730
+ * code rows, fractions included, and rounds the total up once).
2731
+ *
2732
+ * @param messages - the whole thread, oldest first.
2733
+ * @param sizeOf - the size one message needs when rendered (text plus its chrome).
2734
+ * @param capRows - the body budget.
2735
+ * @returns the messages to render, the count left out, and the size they need.
2736
+ */
2737
+ function discussionTail(messages, sizeOf, capRows) {
2738
+ let rows = 0;
2739
+ let keep = 0;
2740
+ for (let index = messages.length - 1; index >= 0; index--) {
2741
+ const size = Math.max(1, sizeOf(messages[index]));
2742
+ const reserve = index > 0 ? 1 : 0;
2743
+ if (keep > 0 && rows + size + reserve > capRows) break;
2744
+ rows += size;
2745
+ keep += 1;
2746
+ }
2747
+ const hidden = messages.length - keep;
2748
+ return {
2749
+ messages: messages.slice(hidden),
2750
+ hidden,
2751
+ rows: rows + (hidden > 0 ? 1 : 0)
2752
+ };
2753
+ }
2754
+ /**
2755
+ * An answer with its blank lines dropped.
2756
+ *
2757
+ * The thread is plain text laid out in code rows, so a blank line between two
2758
+ * paragraphs costs a whole row of height and reads as a gap in the code it
2759
+ * annotates. The prompt asks the agent not to write them; this is what makes a
2760
+ * stray one harmless, and both the render and the row measurement run the answer
2761
+ * through it so the two can never disagree about how tall a turn is. What the user
2762
+ * typed is shown exactly as typed.
2763
+ *
2764
+ * @param text - the answer text.
2765
+ * @returns the same text without empty (or whitespace-only) lines.
2766
+ */
2767
+ function stripBlankLines(text) {
2768
+ return text.split("\n").filter((line) => line.trim() !== "").join("\n");
2769
+ }
2770
+ /**
2771
+ * The text of one turn as the thread shows it: an answer loses its blank lines, a
2772
+ * first-person turn keeps every one of them.
2773
+ *
2774
+ * @param message - the turn to render.
2775
+ * @returns the text to lay out and to render.
2776
+ */
2777
+ function discussionText(message) {
2778
+ return message.role === "assistant" ? stripBlankLines(message.text) : message.text;
2779
+ }
2780
+ /**
2781
+ * How many rows a block reserves, so the diff's height table stays exact.
2782
+ * @param discussion - the discussion to measure.
2783
+ * @returns the row count the block contributes.
2784
+ */
2785
+ function discussionRows(discussion) {
2786
+ if (discussion.collapsed) return 1;
2787
+ return 1 + Math.max(1, discussion.bodyRows ?? 2);
2788
+ }
2789
+ /**
2790
+ * Extra rows to add to each diff row's height: the block hangs below its range's
2791
+ * last row, so a block's rows belong to that row's entry in the height table.
2792
+ * Several blocks on one row sum up.
2793
+ *
2794
+ * @param discussions - the blocks currently attached to this file.
2795
+ * @param rowCount - how many rows the diff has (clamps a stale anchor).
2796
+ * @returns a map from row index to the rows added below it.
2797
+ */
2798
+ function discussionRowExtras(discussions, rowCount) {
2799
+ const extras = /* @__PURE__ */ new Map();
2800
+ for (const discussion of discussions) {
2801
+ const last = Math.max(0, Math.min(discussion.anchor.end, Math.max(0, rowCount - 1)));
2802
+ extras.set(last, (extras.get(last) ?? 0) + discussionRows(discussion));
2803
+ }
2804
+ return extras;
2805
+ }
2806
+ /**
2807
+ * The discussion that already covers any part of this range. A row belongs to one
2808
+ * annotation at most, so a selection that touches an existing block offers no
2809
+ * second one - otherwise two blocks would describe the same line.
2810
+ *
2811
+ * @param discussions - the blocks currently attached to this file.
2812
+ * @param anchor - the candidate range.
2813
+ * @returns the overlapping discussion, or `undefined`.
2814
+ */
2815
+ function discussionOverlapping(discussions, anchor) {
2816
+ return discussions.find((entry) => entry.anchor.start <= anchor.end && anchor.start <= entry.anchor.end);
2817
+ }
2818
+ /**
2819
+ * Re-anchor one discussion against the current rows: the rows whose new-file line
2820
+ * falls inside the annotation's line range. When no line matches any more, the
2821
+ * block keeps the rows it last matched and is marked lost, so it stays where the
2822
+ * user last saw it and can only be deleted.
2823
+ *
2824
+ * @param discussion - the block to re-anchor.
2825
+ * @param lineOf - the new-file line number of a row, or `undefined` for a row that has none.
2826
+ * @param rowCount - how many rows the current model has.
2827
+ * @returns the re-anchored discussion (the same object when nothing moved).
2828
+ */
2829
+ function remapDiscussion(discussion, lineOf, rowCount) {
2830
+ if (discussion.lost === true) return discussion;
2831
+ let start = -1;
2832
+ let end = -1;
2833
+ for (let row = 0; row < rowCount; row++) {
2834
+ const line = lineOf(row);
2835
+ if (line === void 0 || line < discussion.anchor.startLine || line > discussion.anchor.endLine) continue;
2836
+ if (start === -1) start = row;
2837
+ end = row;
2838
+ }
2839
+ if (start === -1) return {
2840
+ ...discussion,
2841
+ lost: true
2842
+ };
2843
+ if (start === discussion.anchor.start && end === discussion.anchor.end) return discussion;
2844
+ return {
2845
+ ...discussion,
2846
+ anchor: {
2847
+ ...discussion.anchor,
2848
+ start,
2849
+ end
2850
+ }
2851
+ };
2852
+ }
2853
+ /**
2854
+ * Decide the selection frame's contents.
2855
+ *
2856
+ * Keep/revert needs covered change blocks; commenting needs a range that has no
2857
+ * discussion yet. A frame with neither would be an empty floating box, so it is
2858
+ * not rendered at all.
2859
+ *
2860
+ * @param options - whether change blocks are covered, and whether this range already has a discussion.
2861
+ * @returns the three flags the caller branches on.
2862
+ */
2863
+ function selectionFrame(options) {
2864
+ const keepRevert = options.coversBlocks;
2865
+ const comment = !options.hasDiscussion;
2866
+ return {
2867
+ keepRevert,
2868
+ comment,
2869
+ visible: keepRevert || comment
2870
+ };
2871
+ }
2872
+ //#endregion
2873
+ //#region lib/types/client/scroll-follow.js
2874
+ /**
2875
+ * Whether the follow animation can drive the frame, or the render has to place it.
2876
+ *
2877
+ * A scroller with nothing to scroll has an INACTIVE timeline. Measured in a browser: the
2878
+ * animation reports a null current time and its transform is never applied at all, which
2879
+ * left the frame wherever the render had put it — the wrapper's top edge, i.e. the top of
2880
+ * the viewport — on a file short enough that the code does not scroll. There is nothing
2881
+ * to follow in that case either, so the clamp at rest is already exact; the same holds
2882
+ * before the box has been measured, and where the browser has no scroll timelines.
2883
+ *
2884
+ * @param hasTimeline - whether the browser supports scroll-driven animations.
2885
+ * @param viewportHeight - the scroller's client height (0 before it is measured).
2886
+ * @param maxScroll - the scroller's maximum `scrollTop` (0 when it does not scroll).
2887
+ * @returns whether the animation, rather than the render, places the frame.
2888
+ */
2889
+ function frameFollowIsAnimated(hasTimeline, viewportHeight, maxScroll) {
2890
+ return hasTimeline && viewportHeight > 0 && maxScroll > 0;
2891
+ }
2892
+ /**
2893
+ * The floating action frame's vertical position, as scroll-driven keyframes.
2894
+ *
2895
+ * The frame follows the row its anchor ends on — a point in the scroller's CONTENT
2896
+ * coordinates — and is clamped into the visible area, so that it stays clickable when
2897
+ * that row is off-screen. Written the direct way ("read `scrollTop`, subtract, clamp")
2898
+ * it has to be recomputed on the main thread for every scroll event, which leaves it a
2899
+ * frame behind the code the compositor has already moved. The same clamp expressed as
2900
+ * keyframes over the scroll range becomes a scroll-driven animation, which the browser
2901
+ * runs off the main thread: the code and the frame never disagree about the offset.
2902
+ *
2903
+ * The clamp is piecewise linear in the scroll offset, with exactly two corners — where
2904
+ * the frame stops being held down by the viewport's bottom edge, and where it reaches
2905
+ * the viewport's top edge and stays there — so listing those stops makes the animation
2906
+ * reproduce it exactly, not approximately.
2907
+ *
2908
+ * @param anchorTop - the anchor's offset in the scroller's content, in px.
2909
+ * @param maxScroll - the scroller's maximum `scrollTop` (0 when it does not scroll).
2910
+ * @param viewportHeight - the scroller's client height, in px.
2911
+ * @param frameHeight - the frame's own height, which the clamp has to keep on screen.
2912
+ * @returns the keyframe stops: `offset` is the scroll progress (0-1) and `y` the frame's
2913
+ * position in px from the viewport's top. Ascending, deduplicated, and including the
2914
+ * corners; with nothing to scroll there is a single stop, the clamp being constant.
2915
+ */
2916
+ function frameFollowKeyframes(anchorTop, maxScroll, viewportHeight, frameHeight) {
2917
+ const limit = Math.max(0, viewportHeight - frameHeight);
2918
+ const at = (progress) => Math.min(limit, Math.max(0, anchorTop - progress * maxScroll));
2919
+ if (maxScroll <= 0) return [{
2920
+ offset: 0,
2921
+ y: at(0)
2922
+ }];
2923
+ const offsets = [
2924
+ 0,
2925
+ (anchorTop - limit) / maxScroll,
2926
+ anchorTop / maxScroll,
2927
+ 1
2928
+ ].filter((offset) => offset >= 0 && offset <= 1);
2929
+ return [...new Set(offsets)].sort((left, right) => left - right).map((offset) => ({
2930
+ offset,
2931
+ y: at(offset)
2932
+ }));
2933
+ }
2686
2934
  //#endregion
2687
2935
  //#region node_modules/.pnpm/marked@18.0.11/node_modules/marked/lib/marked.esm.js
2688
2936
  /**
@@ -19188,6 +19436,9 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
19188
19436
  * scrollbar strip stays clear). */
19189
19437
  const FLOAT_GRIP_WIDTH_PX = 9;
19190
19438
  const FLOAT_GRIP_OVERHANG_PX = 3;
19439
+ /** How long the floating file list takes to fold away once it is put back — the
19440
+ * `fileListShrink` animation's duration, which the panel holds the card for. */
19441
+ const FILE_LIST_FOLD_MS = 140;
19191
19442
  /** Normalize a path for comparison: forward slashes, no trailing slash. */
19192
19443
  function normalizeDiffPath(p) {
19193
19444
  return p.replaceAll("\\", "/").replace(/\/+$/, "");
@@ -19285,8 +19536,32 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
19285
19536
  })] })]
19286
19537
  });
19287
19538
  }
19539
+ /** Return/enter glyph for the comment button: the key's own corner arrow, drawn on
19540
+ * MarkdownModeIcon's 14-grid so the two read at the same weight. It is what tells
19541
+ * the user that Enter sends the comment, without spending a row on the hint. */
19542
+ function ReturnIcon({ size = 12 }) {
19543
+ return (0, react_jsx_runtime.jsxs)("svg", {
19544
+ width: size,
19545
+ height: size,
19546
+ viewBox: "0 0 14 14",
19547
+ fill: "none",
19548
+ xmlns: "http://www.w3.org/2000/svg",
19549
+ "aria-hidden": "true",
19550
+ children: [(0, react_jsx_runtime.jsx)("path", {
19551
+ d: "M11.5 3.5 H4.5 V10.5",
19552
+ stroke: "currentColor",
19553
+ strokeWidth: "1.2",
19554
+ fill: "none"
19555
+ }), (0, react_jsx_runtime.jsx)("path", {
19556
+ d: "M2.5 8.5 L4.5 10.5 L6.5 8.5",
19557
+ stroke: "currentColor",
19558
+ strokeWidth: "1.2",
19559
+ fill: "none"
19560
+ })]
19561
+ });
19562
+ }
19288
19563
  /** Total width of the two line-number gutters, subtracted from the code width
19289
- * when measuring wrapped line heights. */
19564
+ * when measuring wrapped line heights. */
19290
19565
  const WRAP_GUTTERS_PX = 88;
19291
19566
  /** How long a requested dock may take to actually show the panel before the
19292
19567
  * overlay steps in. The tab body mounts a frame or two after the ask, so the
@@ -19424,11 +19699,27 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
19424
19699
  if (font !== void 0) ctx.font = font;
19425
19700
  return (text) => ctx.measureText(text).width;
19426
19701
  }
19702
+ /** How long a question the session has let go stays "queued" before the block hands
19703
+ * its writing row back. The local submission echo and the host's queue row are a
19704
+ * round trip apart, so releasing on the first idle notification would take the row
19705
+ * back while the prompt is still on its way. */
19706
+ const DISCUSSION_RELEASE_GRACE_MS = 2500;
19427
19707
  /** The overview ruler's width in px (mirrors `.overviewRuler`). The flash is
19428
19708
  * kept off it even when the scroller has no vertical scrollbar. */
19429
19709
  const OVERVIEW_RULER_WIDTH_PX = 4;
19710
+ /** The cap on a user bubble, as a share of the thread's width (mirrors
19711
+ * `.discussionUser`'s `max-width`, which is the chat's own `.userStack` cap). The
19712
+ * wrap measurement has to know it, since the bubble wraps at its cap, not at the
19713
+ * width of the block. */
19714
+ const DISCUSSION_BUBBLE_MAX_WIDTH = .82;
19715
+ /** The bubble's horizontal padding, as a share of a code row (mirrors
19716
+ * `.discussionUser`): its own 0.5 per side, and no margin outside it, so the fill is
19717
+ * flush with the thread's right column and this is what comes off the wrap width. */
19718
+ const DISCUSSION_BUBBLE_SIDE_PADDING_ROWS = .5;
19430
19719
  /** Rows rendered beyond the visible window in each direction. */
19431
19720
  const OVERSCAN_ROWS = 8;
19721
+ /** The identity a file with no discussions shares, so memos stay stable. */
19722
+ const EMPTY_DISCUSSIONS = [];
19432
19723
  /** Height of the floating per-block Keep/Revert frame in px: 26px actions +
19433
19724
  * 5px frame padding on each side + 1px border on each side, plus a little
19434
19725
  * breathing room so the bottom padding never sits flush against it. */
@@ -19785,7 +20076,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
19785
20076
  * is `wrappedLines.length * 22` by construction.
19786
20077
  */
19787
20078
  const DiffRow = (0, react.memo)(function DiffRow(props) {
19788
- const { index, row, runs, focused, searchHit, searchCurrent, searchQuery, searchOptions, onRowHover, wrappedLines } = props;
20079
+ const { index, row, runs, focused, discussed, searchHit, searchCurrent, searchQuery, searchOptions, onRowHover, wrappedLines } = props;
19789
20080
  const lineNumber = row.kind === "del" ? row.oldLine : row.newLine;
19790
20081
  const sideRuns = row.kind === "del" ? runs?.oldRuns : runs?.newRuns;
19791
20082
  const lineRuns = lineNumber === void 0 ? void 0 : sideRuns?.[lineNumber - 1];
@@ -19804,9 +20095,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
19804
20095
  });
19805
20096
  }
19806
20097
  return (0, react_jsx_runtime.jsxs)("div", {
19807
- className: `${PendingPanel_module_css_default.line} ${ROW_CLASS[row.kind]}`,
20098
+ className: `${PendingPanel_module_css_default.line} ${ROW_CLASS[row.kind]}${discussed ? ` ${PendingPanel_module_css_default.rowDiscussed}` : ""}`,
19808
20099
  "data-diff-line": row.kind,
19809
20100
  "data-diff-row": index,
20101
+ "data-diff-discussion-band": discussed ? "" : void 0,
19810
20102
  "data-diff-focused": focused ? "" : void 0,
19811
20103
  "data-diff-search": searchHit ? searchCurrent ? "current" : "hit" : void 0,
19812
20104
  onMouseEnter: () => {
@@ -20830,6 +21122,23 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
20830
21122
  };
20831
21123
  }
20832
21124
  /**
21125
+ * Convert row-run ruler markers to the preview's fraction-of-rows shape. The
21126
+ * preview has no discussion blocks (they are a code-view feature), so a fraction
21127
+ * of the row count is exact there and stays the cheap conversion.
21128
+ *
21129
+ * @param markers - row runs, as the shared computation returns them.
21130
+ * @param rowCount - how many rows the diff has.
21131
+ * @returns markers positioned as percentages of the row count.
21132
+ */
21133
+ function previewRulerMarkersOf(markers, rowCount) {
21134
+ if (rowCount === 0) return [];
21135
+ return markers.map((marker) => ({
21136
+ top: marker.start / rowCount * 100,
21137
+ height: (marker.end - marker.start + 1) / rowCount * 100,
21138
+ kind: marker.kind
21139
+ }));
21140
+ }
21141
+ /**
20833
21142
  * Measure the single-column preview's change blocks to position its ruler
20834
21143
  * markers by RENDERED height, so a tall block (an inline image, a large code
20835
21144
  * fence) is not miscounted by source-line fractions. `offsetTop`/`offsetHeight`
@@ -20901,7 +21210,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
20901
21210
  });
20902
21211
  }
20903
21212
  /** The selected file's diff, actions, jump controls, and copy toolbar. */
20904
- function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, landingTop, landingTick, failedMessage, onPasteReference, onToast, t, onKeep, onRevert, onRefreshVcs, onBlockKeep, onBlockRevert, onOpen, onPreviewImage }) {
21213
+ function PendingDiff({ file, busy, workspacePath, jumpSignal, undoFlash, landingTop, landingTick, failedMessage, commentSkill, onPasteReference, onAskAgent, watchChat, onToast, t, onKeep, onRevert, onRefreshVcs, onBlockKeep, onBlockRevert, onOpen, onPreviewImage }) {
20905
21214
  const [langOverride, setLangOverride] = (0, react.useState)(void 0);
20906
21215
  const [langMenuOpen, setLangMenuOpen] = (0, react.useState)(false);
20907
21216
  const langMenuItems = (0, react.useMemo)(() => [{
@@ -20986,16 +21295,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
20986
21295
  ]);
20987
21296
  const rulerMarkers = (0, react.useMemo)(() => {
20988
21297
  const rows = model.diff.rows;
20989
- const total = rows.length;
20990
- if (total === 0) return [];
21298
+ if (rows.length === 0) return [];
20991
21299
  const markers = [];
20992
21300
  let runStart = -1;
20993
21301
  let runKind = "del";
20994
21302
  const flush = (end) => {
20995
- const span = end - runStart + 1;
20996
21303
  markers.push({
20997
- top: runStart / total * 100,
20998
- height: span / total * 100,
21304
+ start: runStart,
21305
+ end,
20999
21306
  kind: runKind
21000
21307
  });
21001
21308
  };
@@ -21024,7 +21331,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21024
21331
  const body = mdPreviewBodyRef.current;
21025
21332
  if (body === null) return;
21026
21333
  const measured = markdownPreviewMarkers(body);
21027
- setMdRulerMarkers(measured.length > 0 ? measured : rulerMarkers);
21334
+ setMdRulerMarkers(measured.length > 0 ? measured : previewRulerMarkersOf(rulerMarkers, model.diff.rows.length));
21028
21335
  }, [
21029
21336
  previewActive,
21030
21337
  splitView,
@@ -21046,6 +21353,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21046
21353
  ]);
21047
21354
  const [splitVisible, setSplitVisible] = (0, react.useState)(void 0);
21048
21355
  const bodyRef = (0, react.useRef)(null);
21356
+ /** The scroll box's non-scrolling parent, which carries the chrome painted over
21357
+ * it (discussion blocks, action frames, the search bar) — see the wheel effect. */
21358
+ const bodyWrapRef = (0, react.useRef)(null);
21359
+ const frameRef = (0, react.useRef)(null);
21049
21360
  const [focus, setFocus] = (0, react.useState)(0);
21050
21361
  const [scrollTick, setScrollTick] = (0, react.useState)(0);
21051
21362
  const [scrollTop, setScrollTop] = (0, react.useState)(0);
@@ -21054,6 +21365,47 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21054
21365
  const [hScrollbarPx, setHScrollbarPx] = (0, react.useState)(0);
21055
21366
  const [hoveredBlock, setHoveredBlock] = (0, react.useState)(void 0);
21056
21367
  const [selection, setSelection] = (0, react.useState)(void 0);
21368
+ const [commentMode, setCommentMode] = (0, react.useState)(commentModeEnabled);
21369
+ const [discussionsByFile, setDiscussionsByFile] = (0, react.useState)({});
21370
+ const discussions = discussionsByFile[file.id] ?? EMPTY_DISCUSSIONS;
21371
+ const setDiscussions = (update) => {
21372
+ setDiscussionsByFile((all) => ({
21373
+ ...all,
21374
+ [file.id]: update(all[file.id] ?? EMPTY_DISCUSSIONS)
21375
+ }));
21376
+ };
21377
+ /** Which block's overflow menu is open, if any. */
21378
+ const [discussionMenuFor, setDiscussionMenuFor] = (0, react.useState)(void 0);
21379
+ const discussionMenuItems = (0, react.useMemo)(() => [{
21380
+ id: "delete",
21381
+ label: t("action.delete")
21382
+ }], [t]);
21383
+ /** The session's chat, watched so a discussion can show the answer it asked for. */
21384
+ const [chat, setChat] = (0, react.useState)({
21385
+ running: false,
21386
+ nodes: [],
21387
+ partial: "",
21388
+ error: void 0,
21389
+ queued: void 0
21390
+ });
21391
+ /** The same view, readable from a timer callback (which closes over nothing fresh). */
21392
+ const chatRef = (0, react.useRef)(chat);
21393
+ chatRef.current = chat;
21394
+ /** The armed "the session let our prompt go" release, if any. */
21395
+ const releaseTimerRef = (0, react.useRef)(void 0);
21396
+ /** The discussion waiting for an answer, and the transcript length it started at. */
21397
+ const pendingAskRef = (0, react.useRef)(void 0);
21398
+ /** The compose inputs, so a freshly created block can take the caret. */
21399
+ const discussionInputEls = (0, react.useRef)(/* @__PURE__ */ new Map());
21400
+ /** The block whose input should be focused once it is on screen. */
21401
+ const focusPendingRef = (0, react.useRef)(void 0);
21402
+ /**
21403
+ * The block whose input should take the caret back when the compose row returns
21404
+ * after a send. The row is gone while the turn runs, so the caret has nowhere to
21405
+ * live; this is cleared by the first thing the user does anywhere, because that
21406
+ * means they moved on and the caret is not ours to move again.
21407
+ */
21408
+ const discussionRefocusRef = (0, react.useRef)(void 0);
21057
21409
  const [previewFrame, setPreviewFrame] = (0, react.useState)(void 0);
21058
21410
  const [previewCovered, setPreviewCovered] = (0, react.useState)([]);
21059
21411
  const [previewSelectionFrame, setPreviewSelectionFrame] = (0, react.useState)(void 0);
@@ -21586,15 +21938,133 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21586
21938
  const tabPx = tabWidthSpaces * measure(" ");
21587
21939
  return rows.map((row) => wrapInto(row.text, wrapping, measure, tabPx));
21588
21940
  }, [
21589
- langWrap,
21941
+ langWrap,
21942
+ bodyWidth,
21943
+ rows,
21944
+ tabWidthSpaces
21945
+ ]);
21946
+ const discussionRightInsetPx = (() => {
21947
+ const scroller = bodyRef.current;
21948
+ if (scroller === null) return OVERVIEW_RULER_WIDTH_PX;
21949
+ return scroller.offsetWidth - scroller.clientWidth > 0 ? 0 : OVERVIEW_RULER_WIDTH_PX;
21950
+ })();
21951
+ /**
21952
+ * How many code rows one message occupies when the block renders it, at the code's
21953
+ * own font and the width that turn actually gets — the same canvas measurement the
21954
+ * diff's own wrap mode uses, so the block's height stays exact and the last line is
21955
+ * never clipped. A bubble's own padding counts too: half a row above and below add
21956
+ * up to a whole one.
21957
+ *
21958
+ * @param text - the message text.
21959
+ * @param role - who said it: the two sides wrap at different widths.
21960
+ * @returns the occupied row count (whole: a bubble's chrome is a whole row).
21961
+ */
21962
+ const messageRowsOf = (0, react.useCallback)((text, role) => {
21963
+ const lines = text.split("\n");
21964
+ const bubble = role === "user";
21965
+ const chrome = bubble ? 1 : 0;
21966
+ const measure = makeMeasurer(codeFontOf());
21967
+ if (measure === void 0 || bodyWidth === 0) return lines.length + chrome;
21968
+ const body = Math.max(0, bodyWidth - discussionRightInsetPx - 3 - 24);
21969
+ const wrapping = (bubble ? body * DISCUSSION_BUBBLE_MAX_WIDTH - 2 * DISCUSSION_BUBBLE_SIDE_PADDING_ROWS * ROW_HEIGHT_PX : body) - measure("0");
21970
+ if (wrapping <= 0) return lines.length + chrome;
21971
+ const tabPx = tabWidthSpaces * measure(" ");
21972
+ return chrome + lines.reduce((rows, line) => rows + Math.max(1, wrapInto(line, wrapping, measure, tabPx).length), 0);
21973
+ }, [
21590
21974
  bodyWidth,
21591
- rows,
21592
- tabWidthSpaces
21975
+ tabWidthSpaces,
21976
+ discussionRightInsetPx
21593
21977
  ]);
21978
+ /**
21979
+ * The size one rendered message needs in code rows: its wrapped lines plus its own
21980
+ * padding — which for a bubble is exactly one row (half a row above, half below).
21981
+ * Every turn is therefore a whole number of rows and the thread stays on the code's
21982
+ * own grid.
21983
+ *
21984
+ * @param message - the message to size.
21985
+ * @returns its size in code rows.
21986
+ */
21987
+ const messageSizeOf = (0, react.useCallback)((message) => {
21988
+ return messageRowsOf(discussionText(message), message.role);
21989
+ }, [messageRowsOf]);
21990
+ /**
21991
+ * The thread as the block will render it, plus the body height that follows from
21992
+ * it: the newest turns that fit the cap, an optional "older" note, the answer in
21993
+ * flight (or the failure note), and the compose row the user writes in.
21994
+ *
21995
+ * @param discussion - the block to lay out.
21996
+ * @returns the messages to render, the hidden count, and the body height.
21997
+ */
21998
+ const layoutDiscussion = (0, react.useCallback)((discussion) => {
21999
+ const answer = discussion.reply === void 0 ? void 0 : stripBlankLines(discussion.reply);
22000
+ const stoppedNote = discussion.stopped === true && (answer === void 0 || answer === "") && discussion.failed !== true;
22001
+ const trailing = discussion.lost === true ? 1 : answer !== void 0 && answer !== "" ? messageSizeOf({
22002
+ role: "assistant",
22003
+ text: answer
22004
+ }) : discussion.failed === true || discussion.asking === true ? 1 : 2 + (stoppedNote ? 1 : 0);
22005
+ const tailCap = 12 - trailing - (discussion.lost === true ? 1 : 0);
22006
+ const tail = discussionTail(discussion.messages, messageSizeOf, Math.max(1, tailCap));
22007
+ return {
22008
+ messages: tail.messages,
22009
+ hidden: tail.hidden,
22010
+ rows: Math.ceil(tail.rows + trailing)
22011
+ };
22012
+ }, [messageSizeOf]);
22013
+ /**
22014
+ * The discussions as the render will draw them: the body height the measurement
22015
+ * above arrived at, the turns it kept, and the text those turns actually show.
22016
+ * The text goes through `discussionText` here as well as in the measurement, so
22017
+ * an answer with a blank line is drawn without one AND counted without one — the
22018
+ * two can never disagree (see `stripBlankLines`).
22019
+ */
22020
+ const laidDiscussions = (0, react.useMemo)(() => discussions.map((discussion) => {
22021
+ const laid = layoutDiscussion(discussion);
22022
+ return {
22023
+ ...discussion,
22024
+ bodyRows: laid.rows,
22025
+ hidden: laid.hidden,
22026
+ messages: laid.messages.map((message) => ({
22027
+ ...message,
22028
+ text: discussionText(message)
22029
+ })),
22030
+ ...discussion.reply === void 0 ? {} : { reply: stripBlankLines(discussion.reply) }
22031
+ };
22032
+ }), [discussions, layoutDiscussion]);
22033
+ const discussionExtras = (0, react.useMemo)(() => discussionRowExtras(laidDiscussions, rows.length), [laidDiscussions, rows.length]);
22034
+ const discussionsAtRow = (0, react.useMemo)(() => {
22035
+ const byRow = /* @__PURE__ */ new Map();
22036
+ for (const discussion of laidDiscussions) {
22037
+ const row = Math.max(0, Math.min(discussion.anchor.end, Math.max(0, rows.length - 1)));
22038
+ const list = byRow.get(row);
22039
+ if (list === void 0) byRow.set(row, [discussion]);
22040
+ else list.push(discussion);
22041
+ }
22042
+ return byRow;
22043
+ }, [laidDiscussions, rows.length]);
22044
+ /**
22045
+ * The rows a discussion annotates. They carry their own wash, so the mark scrolls with
22046
+ * the code in both axes with no positioning at all — the overlay this replaces had to
22047
+ * be counter-translated on every horizontal scroll and trailed the text.
22048
+ */
22049
+ const discussedRows = (0, react.useMemo)(() => {
22050
+ const set = /* @__PURE__ */ new Set();
22051
+ for (const discussion of laidDiscussions) for (let row = Math.max(0, discussion.anchor.start); row <= Math.min(discussion.anchor.end, rowCount - 1); row++) set.add(row);
22052
+ return set;
22053
+ }, [laidDiscussions, rowCount]);
21594
22054
  const rowHeights = (0, react.useMemo)(() => {
21595
- if (rowWrapped === null) return null;
21596
- return rowWrapped.map((lines) => lines.length * ROW_HEIGHT_PX);
21597
- }, [rowWrapped]);
22055
+ const wrapped = rowWrapped === null ? null : rowWrapped.map((lines) => lines.length * ROW_HEIGHT_PX);
22056
+ if (discussionExtras.size === 0) return wrapped;
22057
+ const heights = wrapped === null ? new Array(rows.length).fill(ROW_HEIGHT_PX) : [...wrapped];
22058
+ for (const [after, extra] of discussionExtras) {
22059
+ const index = Math.max(0, Math.min(after, heights.length - 1));
22060
+ heights[index] = (heights[index] ?? ROW_HEIGHT_PX) + extra * ROW_HEIGHT_PX;
22061
+ }
22062
+ return heights;
22063
+ }, [
22064
+ rowWrapped,
22065
+ discussionExtras,
22066
+ rows.length
22067
+ ]);
21598
22068
  const rowOffsets = (0, react.useMemo)(() => {
21599
22069
  if (rowHeights === null) return null;
21600
22070
  const offs = new Array(rowHeights.length + 1);
@@ -21611,6 +22081,377 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21611
22081
  if (rowOffsets === null) return (to - from + 1) * ROW_HEIGHT_PX;
21612
22082
  return Math.max(0, offsetOf(to + 1) - offsetOf(from));
21613
22083
  };
22084
+ /**
22085
+ * Whether the height table carries measured (wrapped) row heights. It is the
22086
+ * signal the landing effect waits for; a discussion's reserved rows are a table
22087
+ * of their own and must not read as "the measurement just became ready".
22088
+ */
22089
+ const offsetsFromWrap = rowWrapped !== null;
22090
+ const rulerMarkersNow = totalHeight <= 0 ? [] : rowOffsets === null ? previewRulerMarkersOf(rulerMarkers, rowCount) : rulerMarkers.map((marker) => ({
22091
+ top: offsetOf(marker.start) / totalHeight * 100,
22092
+ height: (offsetOf(marker.end + 1) - offsetOf(marker.start)) / totalHeight * 100,
22093
+ kind: marker.kind
22094
+ }));
22095
+ const pendingScrollShiftRef = (0, react.useRef)(0);
22096
+ (0, react.useLayoutEffect)(() => {
22097
+ const shift = pendingScrollShiftRef.current;
22098
+ pendingScrollShiftRef.current = 0;
22099
+ const body = bodyRef.current;
22100
+ if (shift === 0 || body === null) return;
22101
+ body.scrollTop += shift;
22102
+ setScrollTop(body.scrollTop);
22103
+ }, [discussions]);
22104
+ /** Patch one discussion in place, without touching the others or the file key. */
22105
+ const updateDiscussion = (0, react.useCallback)((id, patch) => {
22106
+ setDiscussionsByFile((all) => {
22107
+ const list = all[file.id] ?? EMPTY_DISCUSSIONS;
22108
+ return {
22109
+ ...all,
22110
+ [file.id]: list.map((entry) => entry.id === id ? {
22111
+ ...entry,
22112
+ ...patch
22113
+ } : entry)
22114
+ };
22115
+ });
22116
+ }, [file.id]);
22117
+ const watchChatRef = (0, react.useRef)(watchChat);
22118
+ watchChatRef.current = watchChat;
22119
+ (0, react.useEffect)(() => {
22120
+ let stop;
22121
+ try {
22122
+ stop = watchChatRef.current(file.sessionId, setChat);
22123
+ } catch {}
22124
+ return () => {
22125
+ stop?.();
22126
+ };
22127
+ }, [file.sessionId]);
22128
+ (0, react.useEffect)(() => {
22129
+ const pending = pendingAskRef.current;
22130
+ if (pending === void 0) return;
22131
+ let asked = -1;
22132
+ for (let index = chat.nodes.length - 1; index >= pending.baseline; index--) {
22133
+ const node = chat.nodes[index];
22134
+ if (node.kind === "user" && node.text.includes(pending.needle)) {
22135
+ asked = index;
22136
+ break;
22137
+ }
22138
+ }
22139
+ const ours = asked >= 0;
22140
+ const held = chat.queued === void 0 ? void 0 : chat.queued.some((text) => text.includes(pending.needle));
22141
+ let segmentEnd = chat.nodes.length;
22142
+ for (let index = Math.max(0, asked + 1); index < chat.nodes.length; index++) if (chat.nodes[index]?.kind === "user") {
22143
+ segmentEnd = index;
22144
+ break;
22145
+ }
22146
+ const tail = asked >= 0 ? chat.nodes.slice(asked + 1, segmentEnd) : [];
22147
+ const settled = tail.filter((node) => node.kind === "assistant" && node.text !== "").at(-1)?.text ?? "";
22148
+ const stopped = ours && tail.some((node) => node.kind === "assistant" && node.interrupted === true);
22149
+ const closeOut = () => {
22150
+ const current = pendingAskRef.current;
22151
+ if (current === void 0 || current.id !== pending.id) return;
22152
+ const view = chatRef.current;
22153
+ if (view.running) return;
22154
+ let found = -1;
22155
+ for (let index = view.nodes.length - 1; index >= current.baseline; index--) {
22156
+ const node = view.nodes[index];
22157
+ if (node !== void 0 && node.kind === "user" && node.text.includes(current.needle)) {
22158
+ found = index;
22159
+ break;
22160
+ }
22161
+ }
22162
+ if (found < 0) {
22163
+ if (view.queued === void 0 || view.queued.some((text) => text.includes(current.needle))) return;
22164
+ } else if (view.nodes.slice(found + 1).some((node) => node.kind === "assistant" && node.text !== "")) return;
22165
+ pendingAskRef.current = void 0;
22166
+ updateDiscussion(current.id, found >= 0 ? {
22167
+ asking: false,
22168
+ queued: false,
22169
+ failed: false,
22170
+ reply: "",
22171
+ stopped: true
22172
+ } : {
22173
+ asking: false,
22174
+ queued: false,
22175
+ failed: false,
22176
+ reply: ""
22177
+ });
22178
+ };
22179
+ const clearRelease = () => {
22180
+ if (releaseTimerRef.current === void 0) return;
22181
+ window.clearTimeout(releaseTimerRef.current);
22182
+ releaseTimerRef.current = void 0;
22183
+ };
22184
+ /** Arm the one "no answer is coming" timer, if it is not already running. */
22185
+ const armCloseOut = () => {
22186
+ if (releaseTimerRef.current !== void 0) return;
22187
+ releaseTimerRef.current = window.setTimeout(() => {
22188
+ releaseTimerRef.current = void 0;
22189
+ closeOut();
22190
+ }, DISCUSSION_RELEASE_GRACE_MS);
22191
+ };
22192
+ if (chat.error !== void 0) {
22193
+ clearRelease();
22194
+ pendingAskRef.current = void 0;
22195
+ updateDiscussion(pending.id, {
22196
+ asking: false,
22197
+ queued: false,
22198
+ failed: true,
22199
+ reply: ""
22200
+ });
22201
+ return;
22202
+ }
22203
+ if (chat.running) {
22204
+ if (!ours) {
22205
+ updateDiscussion(pending.id, {
22206
+ asking: true,
22207
+ queued: true,
22208
+ failed: false,
22209
+ reply: ""
22210
+ });
22211
+ return;
22212
+ }
22213
+ clearRelease();
22214
+ const streaming = chat.partial !== "" ? chat.partial : settled;
22215
+ if (streaming !== "") updateDiscussion(pending.id, {
22216
+ asking: true,
22217
+ queued: false,
22218
+ failed: false,
22219
+ reply: streaming
22220
+ });
22221
+ return;
22222
+ }
22223
+ if (settled === "") {
22224
+ if (stopped) {
22225
+ clearRelease();
22226
+ closeOut();
22227
+ return;
22228
+ }
22229
+ if (!ours) {
22230
+ if (held === false) armCloseOut();
22231
+ else clearRelease();
22232
+ updateDiscussion(pending.id, {
22233
+ asking: true,
22234
+ queued: true,
22235
+ failed: false,
22236
+ reply: ""
22237
+ });
22238
+ return;
22239
+ }
22240
+ armCloseOut();
22241
+ return;
22242
+ }
22243
+ clearRelease();
22244
+ pendingAskRef.current = void 0;
22245
+ setDiscussionsByFile((all) => {
22246
+ const list = all[file.id] ?? EMPTY_DISCUSSIONS;
22247
+ return {
22248
+ ...all,
22249
+ [file.id]: list.map((entry) => entry.id === pending.id ? {
22250
+ ...entry,
22251
+ asking: false,
22252
+ queued: false,
22253
+ failed: false,
22254
+ reply: "",
22255
+ stopped,
22256
+ messages: [...entry.messages, {
22257
+ role: "assistant",
22258
+ text: settled
22259
+ }]
22260
+ } : entry)
22261
+ };
22262
+ });
22263
+ }, [
22264
+ chat,
22265
+ updateDiscussion,
22266
+ file.id
22267
+ ]);
22268
+ /**
22269
+ * Re-anchor every block whenever the rows are rebuilt (a keep/revert or an edit
22270
+ * rewrites them). The anchor's new-file lines are what survive; a block whose
22271
+ * lines are all gone keeps the rows it last matched and is marked lost, so it
22272
+ * stays where the user last saw it.
22273
+ */
22274
+ (0, react.useEffect)(() => {
22275
+ setDiscussionsByFile((all) => {
22276
+ const list = all[file.id] ?? EMPTY_DISCUSSIONS;
22277
+ const next = list.map((discussion) => remapDiscussion(discussion, (row) => {
22278
+ const entry = model.diff.rows[row];
22279
+ return entry?.newLine ?? entry?.oldLine;
22280
+ }, model.diff.rows.length));
22281
+ return next.some((discussion, index) => discussion !== list[index]) ? {
22282
+ ...all,
22283
+ [file.id]: next
22284
+ } : all;
22285
+ });
22286
+ }, [model, file.id]);
22287
+ (0, react.useEffect)(() => {
22288
+ const fresh = focusPendingRef.current;
22289
+ const id = fresh ?? discussionRefocusRef.current;
22290
+ if (id === void 0) return;
22291
+ const input = discussionInputEls.current.get(id);
22292
+ if (input === void 0) return;
22293
+ if (fresh !== void 0) focusPendingRef.current = void 0;
22294
+ else discussionRefocusRef.current = void 0;
22295
+ input.focus();
22296
+ try {
22297
+ input.setSelectionRange(input.value.length, input.value.length);
22298
+ } catch {}
22299
+ }, [laidDiscussions]);
22300
+ (0, react.useEffect)(() => {
22301
+ const drop = () => {
22302
+ discussionRefocusRef.current = void 0;
22303
+ };
22304
+ document.addEventListener("pointerdown", drop, true);
22305
+ document.addEventListener("keydown", drop, true);
22306
+ return () => {
22307
+ document.removeEventListener("pointerdown", drop, true);
22308
+ document.removeEventListener("keydown", drop, true);
22309
+ };
22310
+ }, []);
22311
+ (0, react.useEffect)(() => {
22312
+ const wrap = bodyWrapRef.current;
22313
+ if (wrap === null) return;
22314
+ const onWheel = (event) => {
22315
+ const body = bodyRef.current;
22316
+ const target = event.target;
22317
+ if (body === null || !(target instanceof Element)) return;
22318
+ if (target.closest("[data-diff-body]") !== null) return;
22319
+ const per = event.deltaMode === 1 ? ROW_HEIGHT_PX : event.deltaMode === 2 ? body.clientHeight : 1;
22320
+ const top = body.scrollTop;
22321
+ const left = body.scrollLeft;
22322
+ body.scrollTop = top + event.deltaY * per;
22323
+ body.scrollLeft = left + event.deltaX * per;
22324
+ if (body.scrollTop !== top || body.scrollLeft !== left) event.preventDefault();
22325
+ };
22326
+ wrap.addEventListener("wheel", onWheel, { passive: false });
22327
+ return () => {
22328
+ wrap.removeEventListener("wheel", onWheel);
22329
+ };
22330
+ }, [ROW_HEIGHT_PX]);
22331
+ /** Start a discussion on the current selection (no-op on a range that has one). */
22332
+ const addDiscussion = () => {
22333
+ if (!commentMode) return;
22334
+ if (selection === void 0) return;
22335
+ if (discussionOverlapping(discussions, selection) !== void 0) return;
22336
+ const first = model.diff.rows[selection.start];
22337
+ const last = model.diff.rows[selection.end] ?? first;
22338
+ const startLine = first?.newLine ?? first?.oldLine;
22339
+ if (startLine === void 0) return;
22340
+ const endLine = last?.newLine ?? last?.oldLine ?? startLine;
22341
+ const body = bodyRef.current;
22342
+ if (body !== null && offsetOf(selection.start) - body.scrollTop < 0) pendingScrollShiftRef.current += 3 * ROW_HEIGHT_PX;
22343
+ const id = `discussion-${Date.now().toString(36)}-${discussions.length}`;
22344
+ setDiscussions((current) => [...current, {
22345
+ id,
22346
+ anchor: {
22347
+ start: selection.start,
22348
+ end: selection.end,
22349
+ startLine,
22350
+ endLine
22351
+ },
22352
+ messages: [],
22353
+ draft: "",
22354
+ collapsed: false
22355
+ }]);
22356
+ focusPendingRef.current = id;
22357
+ const live = window.getSelection();
22358
+ if (typeof live?.removeAllRanges === "function") live.removeAllRanges();
22359
+ selectionTextRef.current = "";
22360
+ setSelection(void 0);
22361
+ };
22362
+ const addDiscussionRef = (0, react.useRef)(addDiscussion);
22363
+ addDiscussionRef.current = addDiscussion;
22364
+ /**
22365
+ * Fold or unfold one block, keeping the code the user is reading in place.
22366
+ * @param id - the block to fold.
22367
+ * @param collapsed - the state to set (defaults to the opposite of the current).
22368
+ */
22369
+ const setDiscussionCollapsed = (id, collapsed) => {
22370
+ const discussion = discussions.find((entry) => entry.id === id);
22371
+ if (discussion === void 0) return;
22372
+ const next = collapsed ?? !discussion.collapsed;
22373
+ if (next === discussion.collapsed) return;
22374
+ const shift = ((next ? 1 : discussionRows(discussion)) - discussionRows(discussion)) * ROW_HEIGHT_PX;
22375
+ const body = bodyRef.current;
22376
+ if (body !== null && offsetOf(discussion.anchor.start) - body.scrollTop < 0) pendingScrollShiftRef.current += shift;
22377
+ setDiscussions((current) => current.map((entry) => entry.id === id ? {
22378
+ ...entry,
22379
+ collapsed: next
22380
+ } : entry));
22381
+ };
22382
+ /** Fold or unfold one block from its header arrow. */
22383
+ const toggleDiscussion = (id) => {
22384
+ setDiscussionCollapsed(id);
22385
+ };
22386
+ /**
22387
+ * Send one turn of a discussion to the agent.
22388
+ *
22389
+ * The first turn is the annotation: the `(path:lines)` reference, the user's
22390
+ * words and the length policy. Later turns are follow-ups in the same thread -
22391
+ * the reference rides along so the agent keeps answering about these rows, and
22392
+ * the answer is appended rather than replacing the previous one. When this build
22393
+ * has no send verb, the text goes to the composer instead (the route the copy
22394
+ * reference already used).
22395
+ *
22396
+ * @param id - the discussion to ask in.
22397
+ */
22398
+ const sendDiscussion = (id) => {
22399
+ const discussion = discussions.find((entry) => entry.id === id);
22400
+ if (discussion === void 0 || discussion.lost === true) return;
22401
+ const text = discussion.draft.trim();
22402
+ if (text === "") return;
22403
+ const reference = `(${discussionLineRange(discussion.anchor)})`;
22404
+ const marker = `${t("discussion.marker")} ${reference}`;
22405
+ const needle = `${marker}\n${text.split("\n")[0] ?? ""}`;
22406
+ const prompt = `${marker}\n${text}\n\n${commentSkill === void 0 ? t("discussion.promptRule") : t("discussion.promptRuleSkill", { skill: commentSkill })}`;
22407
+ const asked = {
22408
+ role: "user",
22409
+ text
22410
+ };
22411
+ if (!onAskAgent(file.sessionId, prompt)) {
22412
+ onPasteReference(file.sessionId, `${reference}\n${text}`);
22413
+ setDiscussions((current) => current.map((entry) => entry.id === id ? {
22414
+ ...entry,
22415
+ messages: [...entry.messages, asked],
22416
+ draft: ""
22417
+ } : entry));
22418
+ return;
22419
+ }
22420
+ pendingAskRef.current = {
22421
+ id,
22422
+ baseline: chat.nodes.length,
22423
+ needle
22424
+ };
22425
+ discussionRefocusRef.current = id;
22426
+ setDiscussions((current) => current.map((entry) => entry.id === id ? {
22427
+ ...entry,
22428
+ messages: [...entry.messages, asked],
22429
+ draft: "",
22430
+ asking: true,
22431
+ queued: false,
22432
+ failed: false,
22433
+ reply: "",
22434
+ collapsed: false
22435
+ } : entry));
22436
+ };
22437
+ /** Discard one block, keeping the code the user is reading in place. */
22438
+ const removeDiscussion = (id) => {
22439
+ const discussion = discussions.find((entry) => entry.id === id);
22440
+ if (discussion === void 0) return;
22441
+ const shift = discussionRows(discussion) * ROW_HEIGHT_PX * -1;
22442
+ const body = bodyRef.current;
22443
+ if (body !== null && offsetOf(discussion.anchor.start) - body.scrollTop < 0) pendingScrollShiftRef.current += shift;
22444
+ setDiscussions((current) => current.filter((entry) => entry.id !== id));
22445
+ };
22446
+ /**
22447
+ * The commented rows as a `path:lines` label - the same reference vocabulary the
22448
+ * copy control uses, so a discussion names where it sits in the file. It reads
22449
+ * the stored lines rather than the current rows, so a block whose lines are gone
22450
+ * still says what it was about.
22451
+ * @param anchor - the discussion's anchor.
22452
+ * @returns the reference label.
22453
+ */
22454
+ const discussionLineRange = (anchor) => referenceLabelOf(file.path, workspacePath, anchor.startLine, anchor.endLine);
21614
22455
  const rowAtY = (y) => {
21615
22456
  if (rowOffsets === null) return Math.floor(y / ROW_HEIGHT_PX);
21616
22457
  if (y <= 0) return 0;
@@ -21653,15 +22494,17 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21653
22494
  newRange: splitView ? splitVisible?.newRange : newWindow,
21654
22495
  live: splitView ? splitVisible?.live ?? false : viewportHeight > 0
21655
22496
  });
21656
- const blockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
21657
- const blockActionsTop = blockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(blockEnd + 1) - scrollTop - 2, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
22497
+ const hoveredBlockEnd = hoveredBlock === void 0 ? void 0 : model.blocks[hoveredBlock]?.end;
21658
22498
  const selectionBlockEnd = (() => {
21659
- if (coveredBlockIndices.length === 0) return void 0;
21660
- const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
21661
- if (lastIndex === void 0) return void 0;
21662
- return model.blocks[lastIndex]?.end;
22499
+ if (coveredBlockIndices.length > 0) {
22500
+ const lastIndex = coveredBlockIndices[coveredBlockIndices.length - 1];
22501
+ if (lastIndex !== void 0) {
22502
+ const end = model.blocks[lastIndex]?.end;
22503
+ if (end !== void 0) return end;
22504
+ }
22505
+ }
22506
+ return selection?.end;
21663
22507
  })();
21664
- const selectionActionsTop = selectionBlockEnd === void 0 ? 0 : Math.max(0, Math.min(offsetOf(selectionBlockEnd + 1) - scrollTop - 2, Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX)));
21665
22508
  const widestLine = (0, react.useMemo)(() => {
21666
22509
  let widest = 0;
21667
22510
  for (const row of model.diff.rows) if (row.text.length > widest) widest = row.text.length;
@@ -21700,7 +22543,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21700
22543
  }, [
21701
22544
  file.id,
21702
22545
  langWrap,
21703
- previewActive
22546
+ previewActive,
22547
+ splitView
21704
22548
  ]);
21705
22549
  (0, react.useLayoutEffect)(() => {
21706
22550
  if (rowCount === 0) return;
@@ -21735,7 +22579,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21735
22579
  setScrollTop(clamped);
21736
22580
  }, [
21737
22581
  scrollTick,
21738
- rowOffsets === null,
22582
+ offsetsFromWrap,
21739
22583
  previewActive
21740
22584
  ]);
21741
22585
  const wrapArmedRef = (0, react.useRef)(0);
@@ -21955,6 +22799,34 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
21955
22799
  window.removeEventListener("keydown", onKeyDown, true);
21956
22800
  };
21957
22801
  }, [copySelection]);
22802
+ (0, react.useEffect)(() => {
22803
+ const onCommentMode = () => {
22804
+ setCommentMode(commentModeEnabled());
22805
+ };
22806
+ window.addEventListener(COMMENT_MODE_CHANGED_EVENT, onCommentMode);
22807
+ return () => {
22808
+ window.removeEventListener(COMMENT_MODE_CHANGED_EVENT, onCommentMode);
22809
+ };
22810
+ }, []);
22811
+ const frameForSelection = !splitView && selection !== void 0 ? selectionFrame({
22812
+ coversBlocks: selectionRange !== void 0,
22813
+ hasDiscussion: discussionOverlapping(discussions, selection) !== void 0
22814
+ }) : void 0;
22815
+ const selectionCommentOffered = commentMode && frameForSelection?.comment === true;
22816
+ const selectionFrameVisible = frameForSelection !== void 0 && (frameForSelection.keepRevert || selectionCommentOffered);
22817
+ (0, react.useEffect)(() => {
22818
+ if (!selectionCommentOffered) return;
22819
+ const onKeyDown = (event) => {
22820
+ if (!matchesShortcut(event, keybindingOf("addComment"))) return;
22821
+ if (isTextFieldEvent(event) || pathPickerOpen()) return;
22822
+ event.preventDefault();
22823
+ addDiscussionRef.current();
22824
+ };
22825
+ window.addEventListener("keydown", onKeyDown, true);
22826
+ return () => {
22827
+ window.removeEventListener("keydown", onKeyDown, true);
22828
+ };
22829
+ }, [selectionCommentOffered]);
21958
22830
  (0, react.useEffect)(() => {
21959
22831
  const onKeyDown = (event) => {
21960
22832
  if (!matchesShortcut(event, keybindingOf("openSearch"))) return;
@@ -22195,6 +23067,35 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22195
23067
  })
22196
23068
  ]
22197
23069
  }) : null;
23070
+ const frameAnchorEnd = selectionFrameVisible ? selectionBlockEnd : hoveredBlockEnd;
23071
+ const frameAnchorTop = frameAnchorEnd === void 0 ? 0 : offsetOf(frameAnchorEnd + 1) - 2;
23072
+ const frameLimit = Math.max(0, viewportHeight - BLOCK_ACTIONS_FRAME_PX);
23073
+ const maxScroll = Math.max(0, totalHeight - viewportHeight);
23074
+ const frameFollowsScroll = frameFollowIsAnimated(typeof ScrollTimeline !== "undefined", viewportHeight, maxScroll);
23075
+ const frameTop = frameFollowsScroll ? 0 : Math.max(0, Math.min(frameAnchorTop - scrollTop, frameLimit));
23076
+ (0, react.useLayoutEffect)(() => {
23077
+ const element = frameRef.current;
23078
+ const body = bodyRef.current;
23079
+ if (!frameFollowsScroll || frameAnchorEnd === void 0 || element === null || body === null) return;
23080
+ const keyframes = frameFollowKeyframes(frameAnchorTop, maxScroll, viewportHeight, BLOCK_ACTIONS_FRAME_PX).map((stop) => ({
23081
+ offset: stop.offset,
23082
+ transform: `translateY(${stop.y}px)`
23083
+ }));
23084
+ const animation = element.animate(keyframes, {
23085
+ duration: 1e3,
23086
+ fill: "both"
23087
+ });
23088
+ animation.timeline = new ScrollTimeline({ source: body });
23089
+ return () => {
23090
+ animation.cancel();
23091
+ };
23092
+ }, [
23093
+ frameFollowsScroll,
23094
+ frameAnchorEnd,
23095
+ frameAnchorTop,
23096
+ maxScroll,
23097
+ viewportHeight
23098
+ ]);
22198
23099
  return (0, react_jsx_runtime.jsxs)("div", {
22199
23100
  className: PendingPanel_module_css_default.diff,
22200
23101
  "data-diff-approval-diff": true,
@@ -22539,6 +23440,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22539
23440
  onVisibleLines: onSplitVisibleLines
22540
23441
  }) : (0, react_jsx_runtime.jsxs)("div", {
22541
23442
  className: PendingPanel_module_css_default.diffBodyWrap,
23443
+ ref: bodyWrapRef,
22542
23444
  onMouseLeave: () => {
22543
23445
  setHoveredBlock(void 0);
22544
23446
  },
@@ -22564,18 +23466,176 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22564
23466
  }),
22565
23467
  visibleRows.map((row, offset) => {
22566
23468
  const index = start + offset;
22567
- return (0, react_jsx_runtime.jsx)(DiffRow, {
23469
+ const blocks = discussionsAtRow.get(index) ?? [];
23470
+ return (0, react_jsx_runtime.jsxs)(react.Fragment, { children: [(0, react_jsx_runtime.jsx)(DiffRow, {
22568
23471
  index,
22569
23472
  row,
22570
23473
  runs,
22571
23474
  focused: inFocusedBlock(index),
23475
+ discussed: discussedRows.has(index),
22572
23476
  searchHit: searchHitSet.has(index),
22573
23477
  searchCurrent: index === currentSearchRow,
22574
23478
  searchQuery,
22575
23479
  searchOptions: search.options,
22576
23480
  onRowHover,
22577
23481
  wrappedLines: rowWrapped?.[index]
22578
- }, index);
23482
+ }), blocks.map((discussion) => {
23483
+ const rows = discussionRows(discussion);
23484
+ return (0, react_jsx_runtime.jsxs)("div", {
23485
+ className: PendingPanel_module_css_default.discussionRow,
23486
+ "data-diff-discussion-space": rows,
23487
+ style: { height: rows * ROW_HEIGHT_PX },
23488
+ children: [
23489
+ (0, react_jsx_runtime.jsx)("div", {
23490
+ className: PendingPanel_module_css_default.gutter,
23491
+ "aria-hidden": "true"
23492
+ }),
23493
+ (0, react_jsx_runtime.jsx)("div", {
23494
+ className: PendingPanel_module_css_default.gutter,
23495
+ "aria-hidden": "true"
23496
+ }),
23497
+ (0, react_jsx_runtime.jsx)("div", {
23498
+ className: PendingPanel_module_css_default.discussionCell,
23499
+ children: (0, react_jsx_runtime.jsx)("div", {
23500
+ className: PendingPanel_module_css_default.discussionPin,
23501
+ style: { marginLeft: -88 },
23502
+ children: (0, react_jsx_runtime.jsxs)("div", {
23503
+ className: PendingPanel_module_css_default.discussion,
23504
+ "data-diff-discussion": true,
23505
+ "data-lost": discussion.lost === true ? "" : void 0,
23506
+ style: {
23507
+ width: Math.max(0, bodyWidth - discussionRightInsetPx),
23508
+ height: rows * ROW_HEIGHT_PX
23509
+ },
23510
+ children: [(0, react_jsx_runtime.jsxs)("div", {
23511
+ className: PendingPanel_module_css_default.discussionHead,
23512
+ children: [
23513
+ (0, react_jsx_runtime.jsx)("button", {
23514
+ type: "button",
23515
+ className: PendingPanel_module_css_default.discussionToggle,
23516
+ "data-diff-discussion-toggle": true,
23517
+ "aria-expanded": !discussion.collapsed,
23518
+ "aria-label": t(discussion.collapsed ? "action.discussionExpand" : "action.discussionCollapse"),
23519
+ onClick: () => {
23520
+ toggleDiscussion(discussion.id);
23521
+ },
23522
+ children: discussion.collapsed ? (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutline14, { size: 12 }) : (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutline14, { size: 12 })
23523
+ }),
23524
+ (0, react_jsx_runtime.jsx)("span", {
23525
+ className: PendingPanel_module_css_default.discussionRangeWrap,
23526
+ children: (0, react_jsx_runtime.jsx)("span", {
23527
+ className: PendingPanel_module_css_default.discussionRange,
23528
+ "data-diff-discussion-range": true,
23529
+ children: discussionLineRange(discussion.anchor)
23530
+ })
23531
+ }),
23532
+ (0, react_jsx_runtime.jsx)("span", { className: PendingPanel_module_css_default.flexSpacer }),
23533
+ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
23534
+ open: discussionMenuFor === discussion.id,
23535
+ portal: true,
23536
+ compact: true,
23537
+ align: "end",
23538
+ items: discussionMenuItems,
23539
+ onSelect: (id) => {
23540
+ if (id === "delete") removeDiscussion(discussion.id);
23541
+ setDiscussionMenuFor(void 0);
23542
+ },
23543
+ onClose: () => {
23544
+ setDiscussionMenuFor(void 0);
23545
+ },
23546
+ anchor: (0, react_jsx_runtime.jsx)("button", {
23547
+ type: "button",
23548
+ className: PendingPanel_module_css_default.discussionToggle,
23549
+ "data-diff-discussion-menu": true,
23550
+ "aria-label": t("action.more"),
23551
+ onClick: () => {
23552
+ setDiscussionMenuFor((current) => current === discussion.id ? void 0 : discussion.id);
23553
+ },
23554
+ children: "⋯"
23555
+ })
23556
+ })
23557
+ ]
23558
+ }), !discussion.collapsed && (0, react_jsx_runtime.jsxs)("div", {
23559
+ className: PendingPanel_module_css_default.discussionBody,
23560
+ children: [
23561
+ discussion.lost === true && (0, react_jsx_runtime.jsx)("p", {
23562
+ className: PendingPanel_module_css_default.discussionNote,
23563
+ "data-diff-discussion-lost": true,
23564
+ children: t("discussion.lost")
23565
+ }),
23566
+ discussion.hidden !== void 0 && discussion.hidden > 0 && (0, react_jsx_runtime.jsx)("p", {
23567
+ className: PendingPanel_module_css_default.discussionNote,
23568
+ "data-diff-discussion-hidden": true,
23569
+ children: t("discussion.hidden", { count: discussion.hidden })
23570
+ }),
23571
+ discussion.stopped === true && (discussion.reply === void 0 || discussion.reply === "") && discussion.failed !== true && (0, react_jsx_runtime.jsx)("p", {
23572
+ className: PendingPanel_module_css_default.discussionNote,
23573
+ "data-diff-discussion-stopped": true,
23574
+ children: t("discussion.stopped")
23575
+ }),
23576
+ discussion.messages.map((message, index) => message.role === "user" ? (0, react_jsx_runtime.jsx)("p", {
23577
+ className: PendingPanel_module_css_default.discussionUser,
23578
+ "data-diff-discussion-user": true,
23579
+ children: message.text
23580
+ }, `u${index}`) : (0, react_jsx_runtime.jsx)("p", {
23581
+ className: PendingPanel_module_css_default.discussionAnswer,
23582
+ "data-diff-discussion-reply": true,
23583
+ children: message.text
23584
+ }, `a${index}`)),
23585
+ discussion.reply !== void 0 && discussion.reply !== "" ? (0, react_jsx_runtime.jsx)("p", {
23586
+ className: PendingPanel_module_css_default.discussionAnswer,
23587
+ "data-diff-discussion-reply": true,
23588
+ children: discussion.reply
23589
+ }) : discussion.lost === true ? null : discussion.failed === true ? (0, react_jsx_runtime.jsx)("p", {
23590
+ className: PendingPanel_module_css_default.discussionNote,
23591
+ "data-diff-discussion-failed": true,
23592
+ children: t("discussion.failed")
23593
+ }) : discussion.asking === true ? (0, react_jsx_runtime.jsx)("p", {
23594
+ className: PendingPanel_module_css_default.discussionNote,
23595
+ "data-diff-discussion-asking": true,
23596
+ children: discussion.queued === true ? t("discussion.queued") : t("discussion.thinking")
23597
+ }) : (0, react_jsx_runtime.jsxs)("div", {
23598
+ className: PendingPanel_module_css_default.discussionCompose,
23599
+ children: [(0, react_jsx_runtime.jsx)("input", {
23600
+ className: PendingPanel_module_css_default.discussionInput,
23601
+ "data-diff-discussion-input": true,
23602
+ ref: (element) => {
23603
+ if (element === null) discussionInputEls.current.delete(discussion.id);
23604
+ else discussionInputEls.current.set(discussion.id, element);
23605
+ },
23606
+ value: discussion.draft,
23607
+ placeholder: t("discussion.placeholder"),
23608
+ onChange: (event) => {
23609
+ const value = event.target.value;
23610
+ setDiscussions((current) => current.map((entry) => entry.id === discussion.id ? {
23611
+ ...entry,
23612
+ draft: value
23613
+ } : entry));
23614
+ },
23615
+ onKeyDown: (event) => {
23616
+ if (event.key !== "Enter") return;
23617
+ if (event.nativeEvent.isComposing || event.keyCode === 229) return;
23618
+ event.preventDefault();
23619
+ sendDiscussion(discussion.id);
23620
+ }
23621
+ }), (0, react_jsx_runtime.jsxs)("button", {
23622
+ type: "button",
23623
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary} ${PendingPanel_module_css_default.discussionSend}`,
23624
+ "data-diff-discussion-send": true,
23625
+ onClick: () => {
23626
+ sendDiscussion(discussion.id);
23627
+ },
23628
+ children: [t("action.comment"), (0, react_jsx_runtime.jsx)(ReturnIcon, {})]
23629
+ })]
23630
+ })
23631
+ ]
23632
+ })]
23633
+ }, discussion.id)
23634
+ })
23635
+ })
23636
+ ]
23637
+ }, discussion.id);
23638
+ })] }, index);
22579
23639
  }),
22580
23640
  end < rowCount && (0, react_jsx_runtime.jsx)("div", {
22581
23641
  className: PendingPanel_module_css_default.vSpacer,
@@ -22585,33 +23645,57 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22585
23645
  ]
22586
23646
  })
22587
23647
  }),
22588
- selectionRange !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
23648
+ selectionFrameVisible ? (0, react_jsx_runtime.jsxs)("div", {
23649
+ ref: frameRef,
22589
23650
  className: PendingPanel_module_css_default.blockActions,
22590
23651
  "data-diff-selection-actions": true,
22591
- style: { top: selectionActionsTop },
22592
- children: [(0, react_jsx_runtime.jsx)("button", {
22593
- type: "button",
22594
- className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
22595
- "data-diff-selection-keep": true,
22596
- disabled: busy,
22597
- onClick: () => {
22598
- handleSelectionAction("keep");
22599
- },
22600
- children: t("action.keep")
22601
- }), (0, react_jsx_runtime.jsx)("button", {
22602
- type: "button",
22603
- className: PendingPanel_module_css_default.action,
22604
- "data-diff-selection-revert": true,
22605
- disabled: busy,
22606
- onClick: () => {
22607
- handleSelectionAction("revert");
22608
- },
22609
- children: t("action.revert")
22610
- })]
23652
+ style: { top: frameTop },
23653
+ children: [
23654
+ (0, react_jsx_runtime.jsx)("button", {
23655
+ type: "button",
23656
+ className: `${PendingPanel_module_css_default.action} ${PendingPanel_module_css_default.actionPrimary}`,
23657
+ "data-diff-selection-keep": true,
23658
+ hidden: selectionRange === void 0,
23659
+ disabled: busy,
23660
+ onClick: () => {
23661
+ handleSelectionAction("keep");
23662
+ },
23663
+ children: t("action.keep")
23664
+ }),
23665
+ (0, react_jsx_runtime.jsx)("button", {
23666
+ type: "button",
23667
+ className: PendingPanel_module_css_default.action,
23668
+ "data-diff-selection-revert": true,
23669
+ hidden: selectionRange === void 0,
23670
+ disabled: busy,
23671
+ onClick: () => {
23672
+ handleSelectionAction("revert");
23673
+ },
23674
+ children: t("action.revert")
23675
+ }),
23676
+ selectionRange !== void 0 && selectionCommentOffered && (0, react_jsx_runtime.jsx)("span", {
23677
+ className: PendingPanel_module_css_default.blockActionsDivider,
23678
+ "data-diff-selection-divider": true,
23679
+ "aria-hidden": "true"
23680
+ }),
23681
+ selectionCommentOffered && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
23682
+ label: withChord(t("action.comment"), "addComment"),
23683
+ side: "bottom",
23684
+ delayMs: 500,
23685
+ children: (0, react_jsx_runtime.jsx)("button", {
23686
+ type: "button",
23687
+ className: PendingPanel_module_css_default.action,
23688
+ "data-diff-selection-comment": true,
23689
+ onClick: addDiscussion,
23690
+ children: t("action.comment")
23691
+ })
23692
+ })
23693
+ ]
22611
23694
  }) : hoveredBlock !== void 0 && model.blocks[hoveredBlock] !== void 0 ? (0, react_jsx_runtime.jsxs)("div", {
23695
+ ref: frameRef,
22612
23696
  className: PendingPanel_module_css_default.blockActions,
22613
23697
  "data-diff-block-actions": true,
22614
- style: { top: blockActionsTop },
23698
+ style: { top: frameTop },
22615
23699
  children: [
22616
23700
  (0, react_jsx_runtime.jsx)("span", {
22617
23701
  className: PendingPanel_module_css_default.blockPosition,
@@ -22680,7 +23764,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22680
23764
  "data-diff-approval-ruler": true,
22681
23765
  "aria-hidden": "true",
22682
23766
  style: { bottom: hScrollbarPx },
22683
- children: rulerMarkers.map((marker, index) => (0, react_jsx_runtime.jsx)("div", {
23767
+ children: rulerMarkersNow.map((marker, index) => (0, react_jsx_runtime.jsx)("div", {
22684
23768
  className: `${PendingPanel_module_css_default.overviewMarker} ${marker.kind === "del" ? PendingPanel_module_css_default.markerDel : PendingPanel_module_css_default.markerAdd}`,
22685
23769
  "data-diff-ruler-marker": marker.kind,
22686
23770
  style: {
@@ -22778,7 +23862,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22778
23862
  });
22779
23863
  }
22780
23864
  /** Render the pending-edit review panel and its unified footer action. */
22781
- function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPreviewImage, onPasteReference, onUndo, onRedo, onImportVcs, onRefreshVcs, onBrowse, onAddPath, onKeepAll, onRevertAll, onAckRedoCleared, collapseSidebar, t, docked = false, dockHost, onOpenDock, closeDock, useDock }) {
23865
+ function PendingPanel({ wide, useSessions, usePending, onRefresh, onKeep, onRevert, onBlockKeep, onBlockRevert, onOpen, onPreviewImage, onPasteReference, onAskAgent, watchChat, onUndo, onRedo, onImportVcs, onRefreshVcs, onBrowse, onAddPath, onKeepAll, onRevertAll, onAckRedoCleared, collapseSidebar, t, docked = false, dockHost, onOpenDock, closeDock, useDock }) {
22782
23866
  const current = useSessions((state) => state.current);
22783
23867
  const currentBlank = useSessions((state) => {
22784
23868
  const id = state.current;
@@ -22982,17 +24066,51 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
22982
24066
  * reader's choice always wins over the default.
22983
24067
  */
22984
24068
  const startListOpenRef = (0, react.useRef)(false);
24069
+ const [floatClosing, setFloatClosing] = (0, react.useState)(false);
24070
+ const foldTimerRef = (0, react.useRef)(void 0);
24071
+ (0, react.useEffect)(() => () => {
24072
+ if (foldTimerRef.current !== void 0) window.clearTimeout(foldTimerRef.current);
24073
+ }, []);
24074
+ /** Fold the card away, giving the exit animation its `FILE_LIST_FOLD_MS` first; `then`
24075
+ * runs once it has gone, for callers with work to do the moment it is folded. */
24076
+ const foldCardAway = (then) => {
24077
+ if (foldTimerRef.current !== void 0) window.clearTimeout(foldTimerRef.current);
24078
+ setFloatClosing(true);
24079
+ foldTimerRef.current = window.setTimeout(() => {
24080
+ foldTimerRef.current = void 0;
24081
+ setFloatClosing(false);
24082
+ setFloatOpen(false);
24083
+ then?.();
24084
+ }, FILE_LIST_FOLD_MS);
24085
+ };
22985
24086
  const toggleFileList = () => {
22986
24087
  startListOpenRef.current = false;
22987
- setFloatOpen((value) => !value);
24088
+ if (floatClosing) {
24089
+ if (foldTimerRef.current !== void 0) window.clearTimeout(foldTimerRef.current);
24090
+ foldTimerRef.current = void 0;
24091
+ setFloatClosing(false);
24092
+ return;
24093
+ }
24094
+ if (floatOpen) {
24095
+ foldCardAway();
24096
+ return;
24097
+ }
24098
+ setFloatOpen(true);
22988
24099
  };
22989
24100
  /** Flip the always-fold preference, remembered for the next open. */
22990
24101
  const toggleForceFloat = () => {
22991
24102
  startListOpenRef.current = false;
22992
24103
  const next = !forceFloat;
22993
- setForceFloat(next);
22994
- setFileListFloat(next);
22995
- if (next) setFloatOpen(false);
24104
+ const apply = () => {
24105
+ setForceFloat(next);
24106
+ setFileListFloat(next);
24107
+ if (next) setFloatOpen(false);
24108
+ };
24109
+ if (next && floatOpen) {
24110
+ foldCardAway(apply);
24111
+ return;
24112
+ }
24113
+ apply();
22996
24114
  };
22997
24115
  (0, react.useEffect)(() => {
22998
24116
  const onResize = () => {
@@ -23022,13 +24140,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
23022
24140
  const onPointerDown = (event) => {
23023
24141
  const target = event.target;
23024
24142
  if (target instanceof Element && (target.closest("[data-diff-floating-file-list]") !== null || target.closest("[data-diff-file-list-toggle]") !== null || target.closest("[data-diff-float-resize]") !== null)) return;
23025
- setFloatOpen(false);
24143
+ if (floatClosing) return;
24144
+ foldCardAway();
23026
24145
  };
23027
24146
  el.addEventListener("pointerdown", onPointerDown, true);
23028
24147
  return () => {
23029
24148
  el.removeEventListener("pointerdown", onPointerDown, true);
23030
24149
  };
23031
- }, [floatMode, floatOpen]);
24150
+ }, [
24151
+ floatMode,
24152
+ floatOpen,
24153
+ floatClosing
24154
+ ]);
23032
24155
  const measureFloatBox = () => {
23033
24156
  if (!floatMode) return;
23034
24157
  const panel = panelRef.current;
@@ -23880,6 +25003,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
23880
25003
  top: (floatBox?.top ?? 0) + FLOAT_LIST_MARGIN_PX
23881
25004
  },
23882
25005
  "data-diff-file-list-toggle": true,
25006
+ "data-open": floatOpen || void 0,
23883
25007
  "aria-label": t(floatOpen ? "action.hideFileList" : "action.showFileList"),
23884
25008
  "aria-expanded": floatOpen,
23885
25009
  onClick: toggleFileList,
@@ -23912,7 +25036,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
23912
25036
  landingTop: landing !== void 0 && landing.fileId === selectedFile.id ? landing.top : void 0,
23913
25037
  landingTick: landing !== void 0 && landing.fileId === selectedFile.id ? landing.n : 0,
23914
25038
  failedMessage: failed.get(selectedFile.id),
25039
+ commentSkill: snapshot.commentSkill,
23915
25040
  onPasteReference,
25041
+ onAskAgent,
25042
+ watchChat,
23916
25043
  onToast: showCopyToast,
23917
25044
  t,
23918
25045
  onKeep: keepWithPrompt,
@@ -23927,7 +25054,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
23927
25054
  })
23928
25055
  }),
23929
25056
  floatCard !== void 0 && (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)("div", {
23930
- className: PendingPanel_module_css_default.fileListFloat,
25057
+ className: floatClosing ? `${PendingPanel_module_css_default.fileListFloat} ${PendingPanel_module_css_default.fileListFloatClosing}` : PendingPanel_module_css_default.fileListFloat,
23931
25058
  style: {
23932
25059
  left: floatCard.left,
23933
25060
  top: floatCard.top,
@@ -24706,6 +25833,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
24706
25833
  */
24707
25834
  function DiffApprovalSettingsTab({ t }) {
24708
25835
  const [pasteOnCopy, setPasteOnCopyState] = (0, react.useState)(pasteOnCopyEnabled);
25836
+ const [commentMode, setCommentModeState] = (0, react.useState)(commentModeEnabled);
24709
25837
  const [includeUntracked, setIncludeUntrackedState] = (0, react.useState)(includeUntrackedEnabled);
24710
25838
  const [confirmFileRemove, setConfirmFileRemoveState] = (0, react.useState)(confirmFileRemoveEnabled);
24711
25839
  const [tab, setTabState] = (0, react.useState)(tabWidth);
@@ -24762,6 +25890,10 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
24762
25890
  setPasteOnCopyState(value);
24763
25891
  setPasteOnCopyEnabled(value);
24764
25892
  };
25893
+ const setCommentMode = (value) => {
25894
+ setCommentModeState(value);
25895
+ setCommentModeEnabled(value);
25896
+ };
24765
25897
  const setIncludeUntracked = (value) => {
24766
25898
  setIncludeUntrackedState(value);
24767
25899
  setIncludeUntrackedEnabled(value);
@@ -24931,6 +26063,14 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
24931
26063
  onSelect: setPasteOnCopy,
24932
26064
  dataAttribute: "data-diff-paste-on-copy-select",
24933
26065
  t
26066
+ }),
26067
+ (0, react_jsx_runtime.jsx)(PreferenceRow, {
26068
+ title: t("panel.commentMode"),
26069
+ description: t("panel.commentModeDesc"),
26070
+ value: commentMode,
26071
+ onSelect: setCommentMode,
26072
+ dataAttribute: "data-diff-comment-mode-select",
26073
+ t
24934
26074
  })
24935
26075
  ]
24936
26076
  })]
@@ -25202,13 +26342,18 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25202
26342
  const file = pendingFileOf(row);
25203
26343
  if (file !== void 0) files.push(file);
25204
26344
  }
25205
- return value.redoCleared === true ? {
26345
+ const redoCleared = value.redoCleared;
26346
+ const skill = value.commentSkill;
26347
+ const commentSkill = typeof skill === "string" && skill.length > 0 ? skill : void 0;
26348
+ return redoCleared === true ? {
25206
26349
  files,
25207
26350
  workspacePath,
25208
- redoCleared: true
26351
+ redoCleared: true,
26352
+ commentSkill
25209
26353
  } : {
25210
26354
  files,
25211
- workspacePath
26355
+ workspacePath,
26356
+ commentSkill
25212
26357
  };
25213
26358
  }
25214
26359
  /** Narrow one action endpoint's value; a malformed wire value is an action failure. */
@@ -25463,12 +26608,13 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25463
26608
  return;
25464
26609
  }
25465
26610
  try {
25466
- const { files, workspacePath, redoCleared: cleared } = await port.list(sessionId);
26611
+ const { files, workspacePath, redoCleared: cleared, commentSkill } = await port.list(sessionId);
25467
26612
  if (cleared) redoCleared = true;
25468
26613
  publish({
25469
26614
  read: true,
25470
26615
  files,
25471
26616
  workspacePath,
26617
+ commentSkill,
25472
26618
  busy: EMPTY_BUSY,
25473
26619
  failed: failedOf(snapshot)
25474
26620
  });
@@ -25477,6 +26623,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25477
26623
  read: true,
25478
26624
  files: snapshot.files,
25479
26625
  workspacePath: snapshot.workspacePath,
26626
+ commentSkill: snapshot.commentSkill,
25480
26627
  error: error instanceof Error ? error.message : String(error),
25481
26628
  busy: snapshot.busy,
25482
26629
  failed: failedOf(snapshot)
@@ -25761,6 +26908,184 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25761
26908
  };
25762
26909
  }
25763
26910
  //#endregion
26911
+ //#region lib/types/client/chat-bridge.js
26912
+ /**
26913
+ * The panel's one connection to the session's chat: send one prompt, and watch
26914
+ * the transcript so a discussion can show its answer where it was asked.
26915
+ *
26916
+ * Everything here is deliberately defensive. The surfaces it uses (the scoped
26917
+ * `conversation` input face, the `sessions` binding, the `chat` view target) are
26918
+ * public types but not plugin-documented API, so a build that lacks one reports
26919
+ * "unavailable" and the caller falls back to the composer route it already had.
26920
+ *
26921
+ * @module dsh-diff-approval/client/chat-bridge
26922
+ */
26923
+ /** Join the text blocks of one message body. */
26924
+ function textOf(blocks) {
26925
+ if (!Array.isArray(blocks)) return "";
26926
+ return blocks.filter((block) => typeof block === "object" && block !== null && (block.kind === "text" || block.type === "text")).map((block) => typeof block.text === "string" ? block.text : "").filter((text) => text !== "").join("\n").trim();
26927
+ }
26928
+ /** The node kinds that carry a message the human sent. */
26929
+ const HUMAN_KINDS = /* @__PURE__ */ new Set(["user", "steering"]);
26930
+ /** Reduce the durable transcript to the nodes a discussion reads. */
26931
+ function nodesOf(nodes) {
26932
+ if (!Array.isArray(nodes)) return [];
26933
+ const views = [];
26934
+ for (const node of nodes) {
26935
+ if (typeof node !== "object" || node === null) continue;
26936
+ const record = node;
26937
+ const kind = typeof record.kind === "string" ? record.kind : "unknown";
26938
+ if (kind === "assistant") views.push(record.interrupted === true ? {
26939
+ kind,
26940
+ text: textOf(record.blocks),
26941
+ interrupted: true
26942
+ } : {
26943
+ kind,
26944
+ text: textOf(record.blocks)
26945
+ });
26946
+ else if (HUMAN_KINDS.has(kind)) views.push({
26947
+ kind: "user",
26948
+ text: textOf(record.content)
26949
+ });
26950
+ }
26951
+ return views;
26952
+ }
26953
+ /**
26954
+ * The prompts the session is still holding, from the two places that know: its inbox
26955
+ * queue (`QueuedMessage[]`, whose `text` is the prompt) and the local submission
26956
+ * echoes (`pendingSubmissions`, dropped only once the durable message is observed).
26957
+ * `undefined` when the snapshot does not publish a queue at all, so a caller can tell
26958
+ * "nothing is waiting" from "this build cannot say".
26959
+ *
26960
+ * @param session - the session-state snapshot, or undefined.
26961
+ * @returns the waiting prompt texts, or undefined on a build that cannot say.
26962
+ */
26963
+ function queuedOf(session) {
26964
+ const queue = session?.queue;
26965
+ if (!Array.isArray(queue)) return void 0;
26966
+ const pending = Array.isArray(session?.pendingSubmissions) ? session.pendingSubmissions : [];
26967
+ const texts = [];
26968
+ for (const entry of [...queue, ...pending]) {
26969
+ if (typeof entry !== "object" || entry === null) continue;
26970
+ const record = entry;
26971
+ const text = typeof record.text === "string" && record.text !== "" ? record.text : typeof record.preview === "string" ? record.preview : "";
26972
+ if (text !== "") texts.push(text);
26973
+ }
26974
+ return texts;
26975
+ }
26976
+ /**
26977
+ * Build the bridge over the client context. Every verb takes the session it
26978
+ * addresses, so one bridge serves whichever session the panel is showing.
26979
+ * @param ctx - the plugin's client context.
26980
+ * @returns the bridge (its verbs report unavailability instead of throwing).
26981
+ */
26982
+ function createChatBridge(ctx) {
26983
+ const scoped = (sessionId) => {
26984
+ try {
26985
+ const sessions = ctx.get("sessions");
26986
+ const actx = sessions?.scope?.(sessionId);
26987
+ if (actx === void 0) return void 0;
26988
+ return {
26989
+ actx,
26990
+ binding: sessions?.binding?.(sessionId)
26991
+ };
26992
+ } catch {
26993
+ return;
26994
+ }
26995
+ };
26996
+ const ask = (sessionId, text) => {
26997
+ const target = scoped(sessionId);
26998
+ if (target === void 0) return false;
26999
+ try {
27000
+ const conversation = target.actx.get("conversation");
27001
+ if (typeof conversation?.send === "function") {
27002
+ Promise.resolve(conversation.send(text)).catch(() => {});
27003
+ return true;
27004
+ }
27005
+ const input = conversation?.input?.for?.(target.actx);
27006
+ if (typeof input?.setDraft !== "function" || typeof input.submit !== "function") return false;
27007
+ const previous = (() => {
27008
+ try {
27009
+ const state = input.state?.getSnapshot?.();
27010
+ return typeof state?.draft === "string" ? state.draft : "";
27011
+ } catch {
27012
+ return "";
27013
+ }
27014
+ })();
27015
+ input.setDraft(text);
27016
+ input.submit("queue");
27017
+ if (previous !== "") window.setTimeout(() => {
27018
+ try {
27019
+ input.setDraft(previous);
27020
+ } catch {}
27021
+ }, 0);
27022
+ return true;
27023
+ } catch {
27024
+ return false;
27025
+ }
27026
+ };
27027
+ const currentView = (sessionId) => {
27028
+ const target = scoped(sessionId);
27029
+ if (target === void 0) return {
27030
+ running: false,
27031
+ nodes: [],
27032
+ partial: "",
27033
+ error: void 0,
27034
+ queued: void 0
27035
+ };
27036
+ const session = (() => {
27037
+ try {
27038
+ const snapshot = target.binding?.session?.getSnapshot?.();
27039
+ return typeof snapshot === "object" && snapshot !== null ? snapshot : void 0;
27040
+ } catch {
27041
+ return;
27042
+ }
27043
+ })();
27044
+ const legacy = (() => {
27045
+ try {
27046
+ const value = ctx.get("uiConversation")?.binding?.(sessionId)?.target?.("chat")?.getSnapshot?.();
27047
+ return typeof value === "object" && value !== null ? value : void 0;
27048
+ } catch {
27049
+ return;
27050
+ }
27051
+ })()?.legacy ?? {};
27052
+ const partial = (() => {
27053
+ const value = legacy.partial;
27054
+ return value == null ? "" : textOf(value.blocks);
27055
+ })();
27056
+ const error = session?.promptError;
27057
+ return {
27058
+ running: session?.running === true,
27059
+ nodes: nodesOf(legacy.nodes),
27060
+ partial,
27061
+ error: error == null ? void 0 : String(error),
27062
+ queued: queuedOf(session)
27063
+ };
27064
+ };
27065
+ const watch = (sessionId, listener) => {
27066
+ if (scoped(sessionId) === void 0) {
27067
+ listener(currentView(sessionId));
27068
+ return () => {};
27069
+ }
27070
+ const unsubscribes = [];
27071
+ const notify = () => {
27072
+ listener(currentView(sessionId));
27073
+ };
27074
+ try {
27075
+ const stop = ctx.get("uiConversation")?.binding?.(sessionId)?.target?.("chat")?.subscribe?.(notify);
27076
+ if (typeof stop === "function") unsubscribes.push(stop);
27077
+ } catch {}
27078
+ notify();
27079
+ return () => {
27080
+ for (const stop of unsubscribes) stop();
27081
+ };
27082
+ };
27083
+ return {
27084
+ ask,
27085
+ watch
27086
+ };
27087
+ }
27088
+ //#endregion
25764
27089
  //#region lib/types/client/header-entry.js
25765
27090
  /**
25766
27091
  * The pending-changes entry in the Session header.
@@ -25875,6 +27200,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25875
27200
  "panel.diffDelColor": "删除颜色",
25876
27201
  "panel.diffDelColorDesc": "删除行的基础色;行背景与逐词差异由它派生。默认色:{default}。",
25877
27202
  "panel.quickSummon": "快速呼出",
27203
+ "panel.commentMode": "评论模式",
27204
+ "panel.commentModeDesc": "选中差异行后可以直接就这几行向智能体提问,回答就显示在这几行下方。",
25878
27205
  "panel.quickSummonDesc": "用键盘快捷键打开/关闭差异面板。点击右侧按钮后按下新的按键组合即可修改。",
25879
27206
  "panel.recordShortcut": "按下快捷键…",
25880
27207
  "settings.keybindings": "快捷键",
@@ -25888,6 +27215,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25888
27215
  "panel.key.jumpUp": "跳转到上一个差异块",
25889
27216
  "panel.key.jumpDown": "跳转到下一个差异块",
25890
27217
  "panel.key.copyRef": "复制引用",
27218
+ "panel.key.addComment": "在选中行上新增评论",
25891
27219
  "panel.key.openSearch": "打开差异搜索",
25892
27220
  "panel.key.searchNext": "下一个搜索结果",
25893
27221
  "panel.key.searchPrev": "上一个搜索结果",
@@ -25908,6 +27236,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
25908
27236
  "row.added": "+{added}",
25909
27237
  "row.removed": "-{removed}",
25910
27238
  "action.keep": "保留",
27239
+ "action.comment": "评论",
27240
+ "action.more": "更多",
27241
+ "action.discussionExpand": "展开",
27242
+ "action.discussionCollapse": "收起",
27243
+ "discussion.placeholder": "写下你的评论…",
27244
+ "discussion.marker": "[评论]",
27245
+ "discussion.promptRule": "(回答只针对这几行,不超过 3 行;行与行之间不要留空行;用纯文本,不要 Markdown 装饰;要求详细时不受长度限制。细则见 dsh-diff-approval-comment skill。)",
27246
+ "discussion.promptRuleSkill": "(这是一条代码批注:先加载 {skill} skill,按它的规则回答。)",
27247
+ "discussion.thinking": "思考中…",
27248
+ "discussion.queued": "排队等待中…",
27249
+ "discussion.lost": "这段代码已经改动,批注的锚点找不到了(不能再评论,可删除)。",
27250
+ "discussion.hidden": "更早的 {count} 条已省略",
27251
+ "discussion.failed": "这次提问失败了,可以再试一次。",
27252
+ "discussion.stopped": "这次回答被停掉了,可以再问一次。",
25911
27253
  "action.revert": "回退",
25912
27254
  "action.delete": "删除",
25913
27255
  "action.keepAll": "全部保留",
@@ -26059,6 +27401,8 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
26059
27401
  "panel.diffDelColor": "Removed color",
26060
27402
  "panel.diffDelColorDesc": "Base color for removed lines; the row background and intra-line diff are derived from it. Default: {default}.",
26061
27403
  "panel.quickSummon": "Quick summon",
27404
+ "panel.commentMode": "Comment mode",
27405
+ "panel.commentModeDesc": "Ask the agent about the rows you select in the diff; the answer appears in a thread right below them.",
26062
27406
  "panel.quickSummonDesc": "Open or close the diff panel with a keyboard shortcut. Click the button and press a new chord to change it.",
26063
27407
  "panel.recordShortcut": "Press keys…",
26064
27408
  "settings.keybindings": "Shortcuts",
@@ -26072,6 +27416,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
26072
27416
  "panel.key.jumpUp": "Jump to the previous diff block",
26073
27417
  "panel.key.jumpDown": "Jump to the next diff block",
26074
27418
  "panel.key.copyRef": "Copy reference",
27419
+ "panel.key.addComment": "Comment on the selected rows",
26075
27420
  "panel.key.openSearch": "Open diff search",
26076
27421
  "panel.key.searchNext": "Next search result",
26077
27422
  "panel.key.searchPrev": "Previous search result",
@@ -26092,6 +27437,20 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
26092
27437
  "row.added": "+{added}",
26093
27438
  "row.removed": "-{removed}",
26094
27439
  "action.keep": "Keep",
27440
+ "action.comment": "Comment",
27441
+ "action.more": "More",
27442
+ "action.discussionExpand": "Expand",
27443
+ "action.discussionCollapse": "Collapse",
27444
+ "discussion.placeholder": "Write your comment…",
27445
+ "discussion.marker": "[Review]",
27446
+ "discussion.promptRule": "(Answer only about these lines, in at most 3 lines, with no blank line between them, as plain text without Markdown decoration; ignore the length limit if my annotation asks for detail. Full rules: the dsh-diff-approval-comment skill.)",
27447
+ "discussion.promptRuleSkill": "(This is a comment on a few diff lines: load the {skill} skill first and answer by its rules.)",
27448
+ "discussion.thinking": "Thinking…",
27449
+ "discussion.queued": "Queued…",
27450
+ "discussion.lost": "This code has changed and the annotation no longer anchors to it (it cannot be commented on again; delete it if it is done).",
27451
+ "discussion.hidden": "{count} earlier turns omitted",
27452
+ "discussion.failed": "That question failed; you can try again.",
27453
+ "discussion.stopped": "That answer was stopped; you can ask again.",
26095
27454
  "action.revert": "Revert",
26096
27455
  "action.delete": "Delete",
26097
27456
  "action.keepAll": "Keep all",
@@ -26308,6 +27667,7 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
26308
27667
  const t = ctx.locale.bind(NS);
26309
27668
  const store = createPendingDiffStore(createDiffApprovalPort(ctx.get("connection").rpc));
26310
27669
  let currentSessionId;
27670
+ const chat = createChatBridge(ctx);
26311
27671
  let remapFile = () => {};
26312
27672
  const access = conversationAccess(ctx, () => currentSessionId);
26313
27673
  ctx.effect(() => {
@@ -26376,6 +27736,11 @@ XID_Start XIDS`.split(/\s/).map((p) => [w(p), p]));
26376
27736
  conversationAccess(ctx, () => sessionId).appendDraft(text);
26377
27737
  }, reference);
26378
27738
  },
27739
+ onAskAgent: (sessionId, text) => {
27740
+ currentSessionId = sessionId;
27741
+ return chat.ask(sessionId, text);
27742
+ },
27743
+ watchChat: (sessionId, listener) => chat.watch(sessionId, listener),
26379
27744
  collapseSidebar
26380
27745
  });
26381
27746
  seat(ctx.slots, "sidebar.footer.action", () => ctx.slots.register({