dsh-session-manager 0.7.0 → 0.7.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
@@ -200,14 +200,14 @@ function isTopmostDialog(z) {
200
200
  "update.autoCheck": "自动检查更新",
201
201
  "update.autoCheck.enable": "开启",
202
202
  "settings.registry": "安装源",
203
- "settings.registry.npm": "npm 官方源 registry.npmjs.org",
204
- "settings.registry.china": "中国大陆镜像源 registry.npmmirror.com",
203
+ "settings.registry.npm": "npm 官方源 (npmjs.org)",
204
+ "settings.registry.china": "国内镜像源 (npmmirror.com)",
205
205
  "settings.title": "会话管理",
206
206
  "settings.pluginName": "dsh-session-manager",
207
207
  "settings.versionSection": "插件版本",
208
208
  "settings.prefSection": "偏好设置",
209
209
  "settings.dialogOpacity": "弹窗透明度",
210
- "settings.dialogOpacity.hint": "仅调整插件弹窗的背景透明度;文字、按钮、输入框和边框保持不透明。",
210
+ "settings.dialogOpacity.hint": "仅调整插件弹窗的背景透明度",
211
211
  "settings.dialogOpacity.value": "{value}%",
212
212
  "settings.dialogOpacity.reset": "恢复默认",
213
213
  "settings.projectSection": "项目",
@@ -264,6 +264,9 @@ function isTopmostDialog(z) {
264
264
  "confirm.delete.title": "删除会话",
265
265
  "confirm.delete.desc": "「{title}」:删除,不可恢复",
266
266
  "confirm.delete.running": "该会话正在运行,删除将立即中断它。",
267
+ "confirm.delete.subagents": "将连带删除 {count} 个关联的子智能体会话。",
268
+ "confirm.delete.previewLoading": "正在检查关联的子智能体会话…",
269
+ "confirm.delete.previewError": "检查关联子智能体会话失败,无法确认删除安全,请稍后重试。",
267
270
  "confirm.delete.confirm": "确认删除",
268
271
  "confirm.move.title": "移动会话到工作区",
269
272
  "confirm.move.desc": "「{title}」:移动至目标工作区",
@@ -468,14 +471,14 @@ function isTopmostDialog(z) {
468
471
  "update.autoCheck": "Automatically check for updates",
469
472
  "update.autoCheck.enable": "Enable",
470
473
  "settings.registry": "Install Source",
471
- "settings.registry.npm": "npm official registry.npmjs.org",
472
- "settings.registry.china": "China mainland mirror registry.npmmirror.com",
474
+ "settings.registry.npm": "Official npm (npmjs.org)",
475
+ "settings.registry.china": "China mirror (npmmirror.com)",
473
476
  "settings.title": "Session Manager",
474
477
  "settings.pluginName": "dsh-session-manager",
475
478
  "settings.versionSection": "Plugin Version",
476
479
  "settings.prefSection": "Preferences",
477
480
  "settings.dialogOpacity": "Dialog opacity",
478
- "settings.dialogOpacity.hint": "Adjusts the plugin dialog background only; text, buttons, inputs and borders stay opaque.",
481
+ "settings.dialogOpacity.hint": "Adjusts dialog background opacity only",
479
482
  "settings.dialogOpacity.value": "{value}%",
480
483
  "settings.dialogOpacity.reset": "Reset to default",
481
484
  "settings.projectSection": "Project",
@@ -599,6 +602,9 @@ function isTopmostDialog(z) {
599
602
  "confirm.delete.title": "Delete session",
600
603
  "confirm.delete.desc": "\"{title}\": Delete, cannot be undone",
601
604
  "confirm.delete.running": "This session is running; deleting will interrupt it immediately.",
605
+ "confirm.delete.subagents": "Will also delete {count} associated subagent session(s).",
606
+ "confirm.delete.previewLoading": "Checking for associated subagent sessions...",
607
+ "confirm.delete.previewError": "Failed to check associated subagents. Cannot verify deletion safety. Please try again later.",
602
608
  "confirm.delete.confirm": "Delete",
603
609
  "confirm.move.title": "Move session to workspace",
604
610
  "confirm.move.desc": "\"{title}\": Move to target workspace",
@@ -726,7 +732,7 @@ function isTopmostDialog(z) {
726
732
  // applied). Tooltip visibility is governed by the layering contract
727
733
  // above, not by this rule; it is kept as the scoped replacement for the
728
734
  // unscoped selector Issue #21 removed.
729
- ".sm-panelHeaderClose{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-height:26px;padding:0;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#555);cursor:pointer;flex:none;box-sizing:border-box;outline:none}.sm-panelHeaderClose:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderClose svg{display:block;width:14px;height:14px;margin:auto}.sm-panelHeaderGithub{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:6px;color:var(--dsw-alias-label-secondary,#555);text-decoration:none;flex:none;transition:background .15s,color .15s;cursor:pointer}.sm-panelHeaderGithub:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderGithub svg{display:block;width:16px;height:16px;fill:currentColor}.sm-panelHeaderLeft{display:flex;align-items:center;gap:4px;flex:none;position:relative;z-index:1}.sm-panelHeaderWhale{display:inline-flex;align-items:center;justify-content:center;position:relative;width:26px;height:26px;border-radius:6px;color:var(--dsw-alias-label-secondary,#555);text-decoration:none;flex:none;transition:background .15s,color .15s;cursor:pointer}.sm-panelHeaderWhale:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderWhale svg{display:block;width:16px;height:16px;margin:auto}.sm-panelHeaderWhale .sm-updateDot{position:absolute;top:2px;right:2px;width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-state-error-primary,#e53e3e);border:1.5px solid var(--dsw-alias-bg-layer-1,#fff)}.sm-panelHeaderWhale .sm-updateSpinner{position:absolute;inset:2px;border:2px solid transparent;border-top-color:var(--dsw-alias-state-business-primary,#356ae6);border-radius:50%;animation:sm-spin .8s linear infinite}@keyframes sm-spin{to{transform:rotate(360deg)}}.sm-updateDialogLayer{display:flex!important;align-items:center!important;justify-content:center!important;position:fixed;inset:0;padding:16px;box-sizing:border-box;background:transparent;border:0;box-shadow:none;z-index:10010;pointer-events:none}.sm-updateDialogLayer .sm-nativeDialog{position:relative;width:380px;max-width:calc(100vw - 32px);box-sizing:border-box;background:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);overflow:hidden;animation:sm-confirmPop .14s ease-out;pointer-events:auto}.sm-updateDialog .sm-nativeDialogHeader{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;min-height:46px;box-sizing:border-box}.sm-updateDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:15px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 80px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:0}.sm-updateDialog .sm-nativeDialogHeader .sm-panelHeaderClose{position:relative;z-index:1;margin-left:auto}.sm-updateDialog .sm-nativeDialogBody{padding:14px 16px;display:flex;flex-direction:column;gap:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-updateDialog .sm-nativeDialogFooter{display:flex;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:8px;margin-top:0}.sm-updateDialog .sm-nativeDialogFooter .sm-nativeDialogConfirm:only-child{margin-left:auto}.sm-updateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-updateDialog .sm-nativeDialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-updateDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-updateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}.sm-updateVersionGrid{display:grid;grid-template-columns:auto 1fr;gap:6px 12px;padding:12px;background:var(--dsw-alias-bg-layer-2,#fff);border:1px solid var(--dsw-alias-border-l2,#eee);border-radius:8px;font-size:13px;line-height:20px}.sm-updateVersionLabel{color:var(--dsw-alias-label-secondary,#666);font-weight:500}.sm-updateVersionValue{color:var(--dsw-alias-label-primary,#111);font-family:monospace;font-size:13px}.sm-updateStatusBox{margin-top:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-updateStatusBox.sm-warn{color:var(--dsw-alias-state-warn-label,#dd8629);background:var(--dsw-alias-state-warn-tertiary,#fef5e7);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-warn-primary,#f59e0b) 25%,transparent)}.sm-updateStatusBox.sm-error{color:var(--dsw-alias-state-error-primary,#ec1313);background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 8%,transparent);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 22%,transparent)}.sm-updateStatusBox.sm-success{color:var(--dsw-alias-state-success-primary,#22c55e);background:var(--dsw-alias-state-success-tertiary,#e6faed);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#22c55e) 25%,transparent)}.sm-settingsCard{background:var(--sm-dialog-surface);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;padding:16px 20px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111);box-sizing:border-box;width:100%}.sm-settingsHeader{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee)}.sm-settingsTitle{margin:0;font-size:16px;line-height:22px;font-weight:600;display:flex;align-items:center;gap:8px}.sm-settingsTag{font-size:12px;padding:2px 8px;border-radius:999px;background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#666);font-family:monospace}.sm-settingsSection{margin-top:14px;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2,#eee)}.sm-settingsSectionTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,#666);margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}.sm-settingsRow{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:32px}.sm-settingsActions{display:flex;align-items:center;gap:8px;margin-top:10px}.sm-settingsLink{color:var(--dsw-alias-state-business-primary,#356ae6);text-decoration:none}.sm-settingsLink:hover{text-decoration:underline}.sm-settingsCheckbox{display:inline-flex;align-items:center;gap:6px;cursor:pointer}.sm-settingsSelect{min-height:28px;height:28px;font-size:12px;line-height:20px;padding:3px 26px 3px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);cursor:pointer}.sm-panelHeaderClose:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderClose:disabled{opacity:.5;cursor:not-allowed}.sm-migrateCurrent{padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary,#111)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer{width:360px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer .sm-migrateDialog{position:relative;left:auto;top:auto;bottom:auto;transform:none;width:100%;max-width:calc(100vw - 32px);max-height:min(70vh,calc(100vh - 32px));z-index:auto;display:flex;flex-direction:column;overflow:hidden}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0;max-height:calc(100vh - 120px);overflow-y:auto}.sm-migrateConfirmLayer .sm-nativeDialogButton.sm-nativeDialogConfirm:hover:not(:disabled){background-color:var(--dsw-alias-button-info-hover,#4576f0);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-button-info-hover,#4576f0);filter:none}.sm-settingsSectionHeader{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.sm-settingsSectionHeader .sm-settingsSectionTitle{margin-bottom:0}.sm-settingsVersionActions{display:flex;align-items:center;gap:8px}.sm-settingsCheckBtn{min-height:26px;padding:2px 12px;font-size:12px;line-height:18px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:transparent;color:var(--dsw-alias-label-primary,#111);cursor:pointer;white-space:nowrap}.sm-settingsCheckBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-settingsRowInline{justify-content:flex-start;flex-wrap:wrap;gap:8px;align-items:center}.sm-settingsBadgeLink{display:inline-flex;align-items:center;gap:4px;padding:2px 8px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#555);font-size:12px;line-height:18px;text-decoration:none;cursor:pointer;transition:all .15s}.sm-settingsBadgeLink:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-state-business-primary,#356ae6);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-settingsBadgeLink svg{flex:none}.sm-tooltip{z-index:1100!important;box-shadow:none!important;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15))!important;filter:none!important}",
735
+ ".sm-panelHeaderClose{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;min-height:26px;padding:0;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#555);cursor:pointer;flex:none;box-sizing:border-box;outline:none}.sm-panelHeaderClose:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderClose svg{display:block;width:14px;height:14px;margin:auto}.sm-panelHeaderGithub{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;border-radius:6px;color:var(--dsw-alias-label-secondary,#555);text-decoration:none;flex:none;transition:background .15s,color .15s;cursor:pointer}.sm-panelHeaderGithub:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderGithub svg{display:block;width:16px;height:16px;fill:currentColor}.sm-panelHeaderLeft{display:flex;align-items:center;gap:4px;flex:none;position:relative;z-index:1}.sm-panelHeaderWhale{display:inline-flex;align-items:center;justify-content:center;position:relative;width:26px;height:26px;border-radius:6px;color:var(--dsw-alias-label-secondary,#555);text-decoration:none;flex:none;transition:background .15s,color .15s;cursor:pointer}.sm-panelHeaderWhale:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderWhale svg{display:block;width:16px;height:16px;margin:auto}.sm-panelHeaderWhale .sm-updateDot{position:absolute;top:2px;right:2px;width:7px;height:7px;border-radius:50%;background:var(--dsw-alias-state-error-primary,#e53e3e);border:1.5px solid var(--dsw-alias-bg-layer-1,#fff)}.sm-panelHeaderWhale .sm-updateSpinner{position:absolute;inset:2px;border:2px solid transparent;border-top-color:var(--dsw-alias-state-business-primary,#356ae6);border-radius:50%;animation:sm-spin .8s linear infinite}@keyframes sm-spin{to{transform:rotate(360deg)}}.sm-updateDialogLayer{display:flex!important;align-items:center!important;justify-content:center!important;position:fixed;inset:0;padding:16px;box-sizing:border-box;background:transparent;border:0;box-shadow:none;z-index:10010;pointer-events:none}.sm-updateDialogLayer .sm-nativeDialog{position:relative;width:380px;max-width:calc(100vw - 32px);box-sizing:border-box;background:var(--sm-dialog-fill);color:var(--dsw-alias-label-primary,#111);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.25);overflow:hidden;animation:sm-confirmPop .14s ease-out;pointer-events:auto}.sm-updateDialog .sm-nativeDialogHeader{position:relative;display:flex;align-items:center;justify-content:space-between;gap:8px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;min-height:46px;box-sizing:border-box}.sm-updateDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:15px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 80px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:0}.sm-updateDialog .sm-nativeDialogHeader .sm-panelHeaderClose{position:relative;z-index:1;margin-left:auto}.sm-updateDialog .sm-nativeDialogBody{padding:14px 16px;display:flex;flex-direction:column;gap:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-updateDialog .sm-nativeDialogFooter{display:flex;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:8px;margin-top:0}.sm-updateDialog .sm-nativeDialogFooter .sm-nativeDialogConfirm:only-child{margin-left:auto}.sm-updateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-updateDialog .sm-nativeDialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-updateDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-state-business-primary,#356ae6);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-updateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}.sm-updateVersionGrid{display:grid;grid-template-columns:auto 1fr;gap:6px 12px;padding:12px;background:var(--dsw-alias-bg-layer-2,#fff);border:1px solid var(--dsw-alias-border-l2,#eee);border-radius:8px;font-size:13px;line-height:20px}.sm-updateVersionLabel{color:var(--dsw-alias-label-secondary,#666);font-weight:500}.sm-updateVersionValue{color:var(--dsw-alias-label-primary,#111);font-family:monospace;font-size:13px}.sm-updateStatusBox{margin-top:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-updateStatusBox.sm-warn{color:var(--dsw-alias-state-warn-label,#dd8629);background:var(--dsw-alias-state-warn-tertiary,#fef5e7);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-warn-primary,#f59e0b) 25%,transparent)}.sm-updateStatusBox.sm-error{color:var(--dsw-alias-state-error-primary,#ec1313);background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 8%,transparent);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 22%,transparent)}.sm-updateStatusBox.sm-success{color:var(--dsw-alias-state-success-primary,#22c55e);background:var(--dsw-alias-state-success-tertiary,#e6faed);padding:8px 10px;border-radius:6px;border:1px solid color-mix(in srgb,var(--dsw-alias-state-success-primary,#22c55e) 25%,transparent)}.sm-settingsCard{background:var(--sm-dialog-surface);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;padding:16px 20px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111);box-sizing:border-box;width:100%}.sm-settingsHeader{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;padding-bottom:10px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee)}.sm-settingsTitle{margin:0;font-size:16px;line-height:22px;font-weight:600;display:flex;align-items:center;gap:8px}.sm-settingsTag{font-size:12px;padding:2px 8px;border-radius:999px;background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#666);font-family:monospace}.sm-settingsSection{margin-top:14px;padding-top:12px;border-top:1px solid var(--dsw-alias-border-l2,#eee)}.sm-settingsSectionTitle{font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,#666);margin-bottom:8px;text-transform:uppercase;letter-spacing:.5px}.sm-settingsRow{display:flex;align-items:center;justify-content:space-between;gap:16px;min-height:36px;margin-top:8px}.sm-settingsRow:first-of-type{margin-top:0}.sm-settingsRow>span:first-child{white-space:nowrap;flex-shrink:0}.sm-settingsActions{display:flex;align-items:center;gap:8px;margin-top:10px}.sm-settingsLink{color:var(--dsw-alias-state-business-primary,#356ae6);text-decoration:none}.sm-settingsLink:hover{text-decoration:underline}.sm-settingsCheckbox{display:inline-flex;align-items:center;gap:6px;cursor:pointer}.sm-settingsSelect{min-height:30px;height:30px;width:280px;min-width:280px;max-width:280px;flex:0 0 280px;box-sizing:border-box;font-size:12px;line-height:20px;padding:4px 26px 4px 10px;border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-primary,#111);cursor:pointer}.sm-settingsRowLeft{display:flex;flex-direction:column;align-items:flex-start;justify-content:center;gap:2px;min-width:0;flex:1 1 auto}.sm-settingsRowLeft>span:first-child{white-space:nowrap;flex-shrink:0}.sm-panelHeaderClose:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderClose:disabled{opacity:.5;cursor:not-allowed}.sm-migrateCurrent{padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background:var(--dsw-alias-bg-layer-2,#fff);font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary,#111)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer{width:360px;max-width:calc(100vw - 32px);max-height:calc(100vh - 32px);inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer .sm-migrateDialog{position:relative;left:auto;top:auto;bottom:auto;transform:none;width:100%;max-width:calc(100vw - 32px);max-height:min(70vh,calc(100vh - 32px));z-index:auto;display:flex;flex-direction:column;overflow:hidden}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0;max-height:calc(100vh - 120px);overflow-y:auto}.sm-migrateConfirmLayer .sm-nativeDialogButton.sm-nativeDialogConfirm:hover:not(:disabled){background-color:var(--dsw-alias-button-info-hover,#4576f0);color:var(--dsw-alias-label-primary-foreground,#fff);border-color:var(--dsw-alias-button-info-hover,#4576f0);filter:none}.sm-settingsSectionHeader{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.sm-settingsSectionHeader .sm-settingsSectionTitle{margin-bottom:0}.sm-settingsVersionActions{display:flex;align-items:center;gap:8px}.sm-settingsCheckBtn{min-height:26px;padding:2px 12px;font-size:12px;line-height:18px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:transparent;color:var(--dsw-alias-label-primary,#111);cursor:pointer;white-space:nowrap}.sm-settingsCheckBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-settingsRowInline{justify-content:flex-start;flex-wrap:wrap;gap:8px;align-items:center}.sm-settingsProjectLeft{display:flex;align-items:center;gap:8px;min-width:0;flex-wrap:nowrap}.sm-settingsProjectLabel{color:var(--dsw-alias-label-primary,#111);white-space:nowrap;flex-shrink:0}.sm-settingsBadgeActions{display:flex;align-items:center;gap:8px;margin-left:auto;flex:0 0 280px;width:280px;min-width:280px;max-width:280px;box-sizing:border-box;justify-content:flex-end}.sm-settingsBadgeActions>*{display:inline-flex;flex:1 1 0;min-width:0}.sm-settingsBadgeLink{display:inline-flex;align-items:center;justify-content:center;gap:6px;width:100%;padding:4px 10px;min-height:28px;height:28px;box-sizing:border-box;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:var(--dsw-alias-markdown-tag,#f1f3f5);color:var(--dsw-alias-label-secondary,#555);font-size:12px;line-height:18px;text-decoration:none;cursor:pointer;white-space:nowrap;transition:all .15s}.sm-settingsBadgeLink:hover{background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-state-business-primary,#356ae6);border-color:var(--dsw-alias-state-business-primary,#356ae6)}.sm-settingsBadgeLink svg{flex:none}.sm-tooltip{z-index:1100!important;box-shadow:none!important;border:1px solid var(--dsw-alias-border-l2,rgba(0,0,0,.15))!important;filter:none!important}",
730
736
 
731
737
  // Issue #23 — dialog opacity.
732
738
  //
@@ -768,14 +774,14 @@ function isTopmostDialog(z) {
768
774
  ".sm-panelDialog option:checked,.sm-nativeDialog option:checked,.sm-settingsCard option:checked,.sm-headerMenu option:checked{background-color:var(--dsw-alias-bg-layer-3,#fff);color:var(--dsw-alias-state-business-primary,#356ae6)}",
769
775
  ".sm-panelDialog option:disabled,.sm-nativeDialog option:disabled,.sm-settingsCard option:disabled,.sm-headerMenu option:disabled{color:var(--dsw-alias-label-tertiary,#888)}",
770
776
  ".sm-nativeDialog,.sm-panelDialog,.sm-migrateDialog,.sm-settingsCard{--sm-dialog-surface:var(--dsw-alias-bg-layer-1,var(--sm-dialog-surface-fallback,#fff));--sm-dialog-fill:color-mix(in srgb,var(--sm-dialog-surface) var(--sm-dialog-opacity,100%),transparent)}",
771
- ".sm-settingsSlider{display:flex;align-items:center;gap:8px;flex:1 1 auto;justify-content:flex-end;min-width:0}",
772
- ".sm-settingsRange{flex:1 1 120px;min-width:96px;max-width:220px;margin:0;cursor:pointer;accent-color:var(--dsw-alias-state-business-primary,#356ae6)}",
777
+ ".sm-settingsSlider{display:flex;align-items:center;gap:8px;flex:0 0 280px;width:280px;min-width:280px;max-width:280px;box-sizing:border-box;justify-content:flex-end}",
778
+ ".sm-settingsRange{flex:1 1 auto;min-width:70px;margin:0;cursor:pointer;accent-color:var(--dsw-alias-state-business-primary,#356ae6)}",
773
779
  ".sm-settingsRange:disabled{cursor:not-allowed}",
774
- ".sm-settingsRangeValue{min-width:38px;text-align:right;font-size:12px;line-height:18px;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary,#666)}",
775
- ".sm-settingsResetBtn{min-height:26px;padding:2px 10px;font-size:12px;line-height:18px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:transparent;color:var(--dsw-alias-label-secondary,#666);cursor:pointer;white-space:nowrap}",
780
+ ".sm-settingsRangeValue{min-width:38px;text-align:right;font-size:12px;line-height:18px;font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary,#666);flex-shrink:0}",
781
+ ".sm-settingsResetBtn{min-height:28px;height:28px;padding:2px 10px;font-size:12px;line-height:18px;border-radius:6px;border:1px solid var(--dsw-alias-border-l2,#ddd);background:transparent;color:var(--dsw-alias-label-secondary,#666);cursor:pointer;white-space:nowrap;flex:0 0 auto;box-sizing:border-box}",
776
782
  ".sm-settingsResetBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary,#111)}",
777
783
  ".sm-settingsResetBtn:disabled{opacity:.5;cursor:not-allowed}",
778
- ".sm-settingsHint{margin-top:4px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888)}",
784
+ ".sm-settingsHint{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888)}.sm-settingsHintInline{margin-left:0;font-weight:normal}",
779
785
 
780
786
  // DSH's own theme is the single source of colour. Every rule above reads
781
787
  // --dsw-alias-* tokens directly and none of them is redefined here: the
@@ -842,7 +848,7 @@ function isTopmostDialog(z) {
842
848
  ".sm-bulkDialog .sm-nativeDialog{width:100%;max-height:min(640px,calc(100vh - 32px))}",
843
849
  ".sm-bulkDialogBody{display:flex;flex-direction:column;gap:12px;min-height:0}",
844
850
  ".sm-bulkDialogSummary{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}",
845
- ".sm-bulkDialogWarn{display:flex;align-items:flex-start;gap:8px;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 8%,transparent);border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 25%,transparent);border-radius:8px;padding:8px 10px}",
851
+ ".sm-bulkDialogWarn{display:flex;align-items:flex-start;gap:8px;color:var(--dsw-alias-state-error-primary);font-size:12px;line-height:18px;background:color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 8%,transparent);border:1px solid color-mix(in srgb,var(--dsw-alias-state-error-primary,#ec1313) 25%,transparent);border-radius:8px;padding:8px 10px;white-space:pre-line}",
846
852
  ".sm-bulkSessionList{display:flex;flex-direction:column;gap:4px;max-height:200px;overflow:auto;border:1px solid var(--dsw-alias-border-l2,#eee);border-radius:8px;padding:6px}",
847
853
  ".sm-bulkSessionItem{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#666);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}",
848
854
  ".sm-bulkProgressBar{position:relative;height:8px;background:var(--dsw-alias-bg-skeleton,#0000000a);border-radius:4px;overflow:hidden}",
@@ -1131,6 +1137,10 @@ function isTopmostDialog(z) {
1131
1137
  if (zRef.current === null) {
1132
1138
  zRef.current = nextDialogZ();
1133
1139
  }
1140
+ useEffect(() => {
1141
+ registerDialogZ(zRef.current);
1142
+ return () => unregisterDialogZ(zRef.current);
1143
+ }, []);
1134
1144
  const root = getOverlayRoot();
1135
1145
  const portal = getPortalFn();
1136
1146
 
@@ -1158,6 +1168,8 @@ function isTopmostDialog(z) {
1158
1168
  zIndex: -1
1159
1169
  },
1160
1170
  onClick: (e) => {
1171
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
1172
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
1161
1173
  if (e.target === e.currentTarget && onBackdropClick) {
1162
1174
  onBackdropClick(e);
1163
1175
  }
@@ -2591,18 +2603,51 @@ function isTopmostDialog(z) {
2591
2603
  ].join(String.fromCharCode(10))
2592
2604
  };
2593
2605
  const promptFor = lang => CLIPBOARD_PROMPT_TEXT[lang] || CLIPBOARD_PROMPT_TEXT.zh;
2606
+ function isClickInsideDialog(e, dialogRef, layerRef) {
2607
+ if (!e || !e.target) return false;
2608
+ const target = e.target;
2609
+ if (dialogRef && dialogRef.current && typeof dialogRef.current.contains === "function" && dialogRef.current.contains(target)) {
2610
+ return true;
2611
+ }
2612
+ if (layerRef && layerRef.current && typeof layerRef.current.contains === "function" && layerRef.current.contains(target)) {
2613
+ return true;
2614
+ }
2615
+ if (typeof target.closest === "function") {
2616
+ if (dialogRef && dialogRef.current && target.closest(".sm-nativeDialog") === dialogRef.current) {
2617
+ return true;
2618
+ }
2619
+ if (layerRef && layerRef.current && target.closest(".sm-nativeDialogLayer") === layerRef.current) {
2620
+ return true;
2621
+ }
2622
+ }
2623
+ if (activeCustomMenu && typeof activeCustomMenu.contains === "function" && activeCustomMenu.contains(target)) {
2624
+ if (activeCustomSelect) {
2625
+ if (dialogRef && dialogRef.current && typeof dialogRef.current.contains === "function" && dialogRef.current.contains(activeCustomSelect)) {
2626
+ return true;
2627
+ }
2628
+ if (layerRef && layerRef.current && typeof layerRef.current.contains === "function" && layerRef.current.contains(activeCustomSelect)) {
2629
+ return true;
2630
+ }
2631
+ }
2632
+ }
2633
+ return false;
2634
+ }
2635
+
2594
2636
  function BatchPreviewDialog(props) {
2595
2637
  const t = typeof props.t === "function" ? props.t : (key) => key;
2596
2638
  const open = props.open === true;
2597
2639
  const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
2598
2640
  const onExecute = typeof props.onExecute === "function" ? props.onExecute : () => {};
2641
+ const danger = props.danger === true;
2599
2642
  const actionLabel = props.actionLabel || "";
2600
2643
  const summaryAction = props.summaryAction || actionLabel;
2644
+ const title = props.title || (props.action === "delete" ? (props.t ? t("confirm.delete.title") : "删除会话") : t("bulk.dialog.title", { action: actionLabel }));
2601
2645
  const sessions = Array.isArray(props.sessions) ? props.sessions : [];
2602
2646
  const warning = typeof props.warning === "string" ? props.warning : "";
2603
2647
  const confirmLabel = props.confirmLabel || t("bulk.dialog.execute");
2604
2648
  const cancelLabel = props.cancelLabel || t("bulk.dialog.cancel");
2605
- const danger = props.danger === true;
2649
+ const dialogRef = useRef(null);
2650
+ const layerRef = useRef(null);
2606
2651
  const [expanded, setExpanded] = useState(false);
2607
2652
  const [zIndex] = useState(() => open ? nextDialogZ() : 0);
2608
2653
  const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 320 });
@@ -2614,15 +2659,33 @@ function isTopmostDialog(z) {
2614
2659
  const handler = (e) => {
2615
2660
  if (e.key !== "Escape" || e.defaultPrevented) return;
2616
2661
  if (!isTopmostDialog(zIndex)) return;
2662
+ if (props.busy) return;
2617
2663
  e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
2618
2664
  };
2619
2665
  window.addEventListener("keydown", handler);
2666
+ const mountTime = Date.now();
2667
+ const clickHandler = (e) => {
2668
+ if (Date.now() - mountTime < 50) return;
2669
+ if (e.defaultPrevented) return;
2670
+ if (props.busy) return;
2671
+ if (!isTopmostDialog(zIndex)) return;
2672
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
2673
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
2674
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
2675
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
2676
+ escStateRef.current.onCancel();
2677
+ };
2678
+ window.addEventListener("click", clickHandler, true);
2620
2679
  return () => {
2621
2680
  unregisterDialogZ(zIndex);
2622
2681
  window.removeEventListener("keydown", handler);
2682
+ window.removeEventListener("click", clickHandler, true);
2623
2683
  };
2624
2684
  }, [open, zIndex]);
2625
2685
  if (!open) return null;
2686
+ const loading = props.loading === true;
2687
+ const hasError = Boolean(props.error);
2688
+ const confirmDisabled = loading || hasError;
2626
2689
  const showExpand = sessions.length > 12;
2627
2690
  const visible = expanded ? sessions : sessions.slice(0, 12);
2628
2691
  const topPx = floatingCoords ? floatingCoords.top : null;
@@ -2644,9 +2707,9 @@ function isTopmostDialog(z) {
2644
2707
  : {})
2645
2708
  };
2646
2709
  const portalOverlay = renderInOverlay;
2647
- return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2648
- h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-preview-title" },
2649
- h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-preview-title", className: "sm-nativeDialogTitle" }, t("bulk.dialog.title", { action: actionLabel }))),
2710
+ return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2711
+ h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-preview-title" },
2712
+ h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-preview-title", className: "sm-nativeDialogTitle" }, title)),
2650
2713
  h("div", { className: "sm-nativeDialogBody" },
2651
2714
  h("div", { className: "sm-bulkDialogSummary" }, t("bulk.dialog.summary", { count: sessions.length, action: actionLabel })),
2652
2715
  warning ? h("div", { className: "sm-bulkDialogWarn" }, warning) : null,
@@ -2657,7 +2720,12 @@ function isTopmostDialog(z) {
2657
2720
  ),
2658
2721
  h("div", { className: "sm-nativeDialogFooter" },
2659
2722
  h("button", { type: "button", className: "sm-nativeDialogButton sm-nativeDialogCancel", onClick: onCancel }, cancelLabel),
2660
- h("button", { type: "button", className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"), onClick: onExecute }, confirmLabel)
2723
+ h("button", {
2724
+ type: "button",
2725
+ className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"),
2726
+ disabled: props.busy || confirmDisabled,
2727
+ onClick: () => { if (!props.busy && !confirmDisabled) onExecute(); }
2728
+ }, confirmLabel)
2661
2729
  )
2662
2730
  )
2663
2731
  ));
@@ -2667,6 +2735,11 @@ function isTopmostDialog(z) {
2667
2735
  const t = typeof props.t === "function" ? props.t : (key) => key;
2668
2736
  const open = props.open === true;
2669
2737
  const [zIndex] = useState(() => open ? nextDialogZ() : 0);
2738
+ useEffect(() => {
2739
+ if (!open) return;
2740
+ registerDialogZ(zIndex);
2741
+ return () => unregisterDialogZ(zIndex);
2742
+ }, [open, zIndex]);
2670
2743
  const actionLabel = props.actionLabel || "";
2671
2744
  const done = Number.isInteger(props.done) ? props.done : 0;
2672
2745
  const total = Number.isInteger(props.total) ? props.total : 0;
@@ -2714,6 +2787,8 @@ function isTopmostDialog(z) {
2714
2787
  function BatchResultDialog(props) {
2715
2788
  const t = typeof props.t === "function" ? props.t : (key) => key;
2716
2789
  const open = props.open === true;
2790
+ const dialogRef = useRef(null);
2791
+ const layerRef = useRef(null);
2717
2792
  const [zIndex] = useState(() => open ? nextDialogZ() : 0);
2718
2793
  const actionLabel = props.actionLabel || "";
2719
2794
  const items = Array.isArray(props.items) ? props.items : [];
@@ -2733,9 +2808,22 @@ function isTopmostDialog(z) {
2733
2808
  e.preventDefault(); e.stopPropagation(); escStateRef.current.onClose();
2734
2809
  };
2735
2810
  window.addEventListener("keydown", handler);
2811
+ const mountTime = Date.now();
2812
+ const clickHandler = (e) => {
2813
+ if (Date.now() - mountTime < 50) return;
2814
+ if (e.defaultPrevented) return;
2815
+ if (!isTopmostDialog(zIndex)) return;
2816
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
2817
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
2818
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
2819
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
2820
+ escStateRef.current.onClose();
2821
+ };
2822
+ window.addEventListener("click", clickHandler, true);
2736
2823
  return () => {
2737
2824
  unregisterDialogZ(zIndex);
2738
2825
  window.removeEventListener("keydown", handler);
2826
+ window.removeEventListener("click", clickHandler, true);
2739
2827
  };
2740
2828
  }, [open, zIndex]);
2741
2829
  if (!open) return null;
@@ -2777,8 +2865,8 @@ function isTopmostDialog(z) {
2777
2865
  : {})
2778
2866
  };
2779
2867
  const portalOverlay = renderInOverlay;
2780
- return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2781
- h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-result-title" },
2868
+ return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2869
+ h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-batch-result-title" },
2782
2870
  h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-batch-result-title", className: "sm-nativeDialogTitle" }, t("bulk.result.title", { action: actionLabel }))),
2783
2871
  h("div", { className: "sm-nativeDialogBody" },
2784
2872
  renderGroup("bulk.result.successGroup", groups.success),
@@ -2826,6 +2914,8 @@ function isTopmostDialog(z) {
2826
2914
  function BulkTagInputDialog(props) {
2827
2915
  const t = typeof props.t === "function" ? props.t : (key) => key;
2828
2916
  const open = props.open === true;
2917
+ const dialogRef = useRef(null);
2918
+ const layerRef = useRef(null);
2829
2919
  const [zIndex] = useState(() => open ? nextDialogZ() : 0);
2830
2920
  const title = props.title || t("bulk.tagsAdd");
2831
2921
  const description = props.description || "";
@@ -2847,9 +2937,22 @@ function isTopmostDialog(z) {
2847
2937
  e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
2848
2938
  };
2849
2939
  window.addEventListener("keydown", handler);
2940
+ const mountTime = Date.now();
2941
+ const clickHandler = (e) => {
2942
+ if (Date.now() - mountTime < 50) return;
2943
+ if (e.defaultPrevented) return;
2944
+ if (!isTopmostDialog(zIndex)) return;
2945
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
2946
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
2947
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
2948
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
2949
+ escStateRef.current.onCancel();
2950
+ };
2951
+ window.addEventListener("click", clickHandler, true);
2850
2952
  return () => {
2851
2953
  unregisterDialogZ(zIndex);
2852
2954
  window.removeEventListener("keydown", handler);
2955
+ window.removeEventListener("click", clickHandler, true);
2853
2956
  };
2854
2957
  }, [open, zIndex]);
2855
2958
  if (!open) return null;
@@ -2876,8 +2979,8 @@ function isTopmostDialog(z) {
2876
2979
  : {})
2877
2980
  };
2878
2981
  const portalOverlay = renderInOverlay;
2879
- return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2880
- h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-tags-title" },
2982
+ return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2983
+ h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-tags-title" },
2881
2984
  h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-bulk-tags-title", className: "sm-nativeDialogTitle" }, title)),
2882
2985
  h("div", { className: "sm-nativeDialogBody" },
2883
2986
  description ? h("div", { className: "sm-bulkDialogSummary" }, description) : null,
@@ -2894,6 +2997,8 @@ function isTopmostDialog(z) {
2894
2997
  function BulkChoiceDialog(props) {
2895
2998
  const t = typeof props.t === "function" ? props.t : (key) => key;
2896
2999
  const open = props.open === true;
3000
+ const dialogRef = useRef(null);
3001
+ const layerRef = useRef(null);
2897
3002
  const [zIndex] = useState(() => open ? nextDialogZ() : 0);
2898
3003
  const title = props.title || "";
2899
3004
  const description = props.description || "";
@@ -2915,9 +3020,22 @@ function isTopmostDialog(z) {
2915
3020
  e.preventDefault(); e.stopPropagation(); escStateRef.current.onCancel();
2916
3021
  };
2917
3022
  window.addEventListener("keydown", handler);
3023
+ const mountTime = Date.now();
3024
+ const clickHandler = (e) => {
3025
+ if (Date.now() - mountTime < 50) return;
3026
+ if (e.defaultPrevented) return;
3027
+ if (!isTopmostDialog(zIndex)) return;
3028
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
3029
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
3030
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3031
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
3032
+ escStateRef.current.onCancel();
3033
+ };
3034
+ window.addEventListener("click", clickHandler, true);
2918
3035
  return () => {
2919
3036
  unregisterDialogZ(zIndex);
2920
3037
  window.removeEventListener("keydown", handler);
3038
+ window.removeEventListener("click", clickHandler, true);
2921
3039
  };
2922
3040
  }, [open, zIndex]);
2923
3041
  if (!open) return null;
@@ -2940,8 +3058,8 @@ function isTopmostDialog(z) {
2940
3058
  : {})
2941
3059
  };
2942
3060
  const portalOverlay = renderInOverlay;
2943
- return portalOverlay(h("div", { className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
2944
- h("section", { className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-choice-title" },
3061
+ return portalOverlay(h("div", { ref: layerRef, className: "sm-nativeDialogLayer sm-bulkDialog" + (hasCoords ? " sm-bulkDialog-anchored" : ""), role: "presentation", style: layerStyle },
3062
+ h("section", { ref: dialogRef, className: "sm-nativeDialog", style: { pointerEvents: "auto" }, role: "dialog", "aria-modal": "true", "aria-labelledby": "sm-bulk-choice-title" },
2945
3063
  h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-bulk-choice-title", className: "sm-nativeDialogTitle" }, title)),
2946
3064
  h("div", { className: "sm-nativeDialogBody" },
2947
3065
  description ? h("div", { className: "sm-bulkDialogSummary" }, description) : null,
@@ -3167,6 +3285,8 @@ function isTopmostDialog(z) {
3167
3285
  const onConfirm = typeof props.onConfirm === "function" ? props.onConfirm : () => {};
3168
3286
  const busy = props.busy === true;
3169
3287
  const danger = props.danger === true;
3288
+ const dialogRef = useRef(null);
3289
+ const layerRef = useRef(null);
3170
3290
  // Claim a fresh z-index so this popup sits above any earlier popup.
3171
3291
  const [zIndex] = useState(() => open ? nextDialogZ() : 0);
3172
3292
  const title = props.title || "";
@@ -3202,9 +3322,23 @@ function isTopmostDialog(z) {
3202
3322
  if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
3203
3323
  };
3204
3324
  window.addEventListener("keydown", handler);
3325
+ const mountTime = Date.now();
3326
+ const clickHandler = (e) => {
3327
+ if (Date.now() - mountTime < 50) return;
3328
+ if (e.defaultPrevented) return;
3329
+ if (escStateRef.current.busy) return;
3330
+ if (!isTopmostDialog(effectiveZ)) return;
3331
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
3332
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
3333
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3334
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
3335
+ escStateRef.current.onCancel();
3336
+ };
3337
+ window.addEventListener("click", clickHandler, true);
3205
3338
  return () => {
3206
3339
  unregisterDialogZ(effectiveZ);
3207
3340
  window.removeEventListener("keydown", handler);
3341
+ window.removeEventListener("click", clickHandler, true);
3208
3342
  };
3209
3343
  }, [open, zIndex]);
3210
3344
 
@@ -3232,13 +3366,17 @@ function isTopmostDialog(z) {
3232
3366
  : {})
3233
3367
  };
3234
3368
 
3369
+ const confirmDisabled = props.confirmDisabled === true;
3370
+
3235
3371
  return renderInOverlay(
3236
3372
  h("div", {
3373
+ ref: layerRef,
3237
3374
  className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
3238
3375
  style: layerStyle,
3239
3376
  role: "presentation"
3240
3377
  },
3241
3378
  h("section", {
3379
+ ref: dialogRef,
3242
3380
  className: "sm-nativeDialog",
3243
3381
  style: { pointerEvents: "auto" },
3244
3382
  role: "dialog",
@@ -3262,8 +3400,8 @@ function isTopmostDialog(z) {
3262
3400
  h("button", {
3263
3401
  type: "button",
3264
3402
  className: "sm-nativeDialogButton" + (danger ? " sm-nativeDialogDanger" : " sm-nativeDialogConfirm"),
3265
- disabled: busy,
3266
- onClick: () => { if (!busy) onConfirm(); }
3403
+ disabled: busy || confirmDisabled,
3404
+ onClick: () => { if (!busy && !confirmDisabled) onConfirm(); }
3267
3405
  }, confirmLabel)
3268
3406
  )
3269
3407
  )
@@ -3276,6 +3414,8 @@ function isTopmostDialog(z) {
3276
3414
  const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
3277
3415
  const onConfirm = typeof props.onConfirm === "function" ? props.onConfirm : () => {};
3278
3416
  const busy = props.busy === true;
3417
+ const dialogRef = useRef(null);
3418
+ const layerRef = useRef(null);
3279
3419
  const title = props.title || t("confirm.move.title");
3280
3420
  const description = props.description || "";
3281
3421
  const currentWorkspaceId = props.currentWorkspaceId || "";
@@ -3324,9 +3464,23 @@ function isTopmostDialog(z) {
3324
3464
  if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
3325
3465
  };
3326
3466
  window.addEventListener("keydown", handler);
3467
+ const mountTime = Date.now();
3468
+ const clickHandler = (e) => {
3469
+ if (Date.now() - mountTime < 50) return;
3470
+ if (e.defaultPrevented) return;
3471
+ if (escStateRef.current.busy) return;
3472
+ if (!isTopmostDialog(effectiveZ)) return;
3473
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
3474
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
3475
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3476
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
3477
+ escStateRef.current.onCancel();
3478
+ };
3479
+ window.addEventListener("click", clickHandler, true);
3327
3480
  return () => {
3328
3481
  unregisterDialogZ(effectiveZ);
3329
3482
  window.removeEventListener("keydown", handler);
3483
+ window.removeEventListener("click", clickHandler, true);
3330
3484
  };
3331
3485
  }, [open, zIndex]);
3332
3486
  if (!open) return null;
@@ -3384,12 +3538,14 @@ function isTopmostDialog(z) {
3384
3538
  };
3385
3539
  return renderInOverlay(
3386
3540
  h("div", {
3541
+ ref: layerRef,
3387
3542
  className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
3388
3543
  style: layerStyle,
3389
3544
  role: "presentation",
3390
3545
  onKeyDown
3391
3546
  },
3392
3547
  h("section", {
3548
+ ref: dialogRef,
3393
3549
  className: "sm-nativeDialog",
3394
3550
  style: { pointerEvents: "auto" },
3395
3551
  role: "dialog",
@@ -3425,6 +3581,8 @@ function isTopmostDialog(z) {
3425
3581
  const onCancel = typeof props.onCancel === "function" ? props.onCancel : () => {};
3426
3582
  const onRun = typeof props.onRun === "function" ? props.onRun : () => {};
3427
3583
  const busy = props.busy === true;
3584
+ const dialogRef = useRef(null);
3585
+ const layerRef = useRef(null);
3428
3586
  const sessionId = props.sessionId || "";
3429
3587
  const description = props.description || "";
3430
3588
  const fallbackPreset = props.currentPreset || "";
@@ -3483,9 +3641,23 @@ function isTopmostDialog(z) {
3483
3641
  if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
3484
3642
  };
3485
3643
  window.addEventListener("keydown", handler);
3644
+ const mountTime = Date.now();
3645
+ const clickHandler = (e) => {
3646
+ if (Date.now() - mountTime < 50) return;
3647
+ if (e.defaultPrevented) return;
3648
+ if (escStateRef.current.busy) return;
3649
+ if (!isTopmostDialog(effectiveZ)) return;
3650
+ if (isClickInsideDialog(e, dialogRef, layerRef)) return;
3651
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
3652
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3653
+ if (e && typeof e.stopImmediatePropagation === "function") e.stopImmediatePropagation();
3654
+ escStateRef.current.onCancel();
3655
+ };
3656
+ window.addEventListener("click", clickHandler, true);
3486
3657
  return () => {
3487
3658
  unregisterDialogZ(effectiveZ);
3488
3659
  window.removeEventListener("keydown", handler);
3660
+ window.removeEventListener("click", clickHandler, true);
3489
3661
  };
3490
3662
  }, [open, zIndex]);
3491
3663
  if (!open) return null;
@@ -3542,11 +3714,13 @@ function isTopmostDialog(z) {
3542
3714
  };
3543
3715
  return renderInOverlay(
3544
3716
  h("div", {
3717
+ ref: layerRef,
3545
3718
  className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
3546
3719
  role: "presentation",
3547
3720
  style: layerStyle
3548
3721
  },
3549
3722
  h("section", {
3723
+ ref: dialogRef,
3550
3724
  className: "sm-nativeDialog",
3551
3725
  style: { pointerEvents: "auto" },
3552
3726
  role: "dialog",
@@ -3575,7 +3749,7 @@ function isTopmostDialog(z) {
3575
3749
  ));
3576
3750
  }
3577
3751
 
3578
- const CURRENT_VERSION = "0.7.0";
3752
+ const CURRENT_VERSION = "0.7.1";
3579
3753
 
3580
3754
  function compareSemver(v1, v2) {
3581
3755
  if (typeof v1 !== "string" || typeof v2 !== "string") return 0;
@@ -3636,7 +3810,11 @@ function isTopmostDialog(z) {
3636
3810
  application: null,
3637
3811
  dialogOpen: false,
3638
3812
  checkedAt: null,
3813
+ lastAttemptAt: null,
3639
3814
  },
3815
+ CHECK_INTERVAL_MS: 6 * 60 * 60 * 1000,
3816
+ RETRY_COOLDOWN_MS: 30 * 60 * 1000,
3817
+ lastFailedAt: null,
3640
3818
  listeners: new Set(),
3641
3819
  getSnapshot() { return this.state; },
3642
3820
  subscribe(cb) {
@@ -3671,6 +3849,29 @@ function isTopmostDialog(z) {
3671
3849
  } catch (_) {}
3672
3850
  this._notify();
3673
3851
  },
3852
+ shouldAutoCheck(now = Date.now()) {
3853
+ if (!this.getAutoCheck()) return false;
3854
+ if (this.state.status === "checking" || this.state.status === "updating") return false;
3855
+ if (this.state.status === "available") return false;
3856
+ if (this.lastFailedAt && (now - this.lastFailedAt < this.RETRY_COOLDOWN_MS)) {
3857
+ return false;
3858
+ }
3859
+ if (this.state.checkedAt && (now - this.state.checkedAt < this.CHECK_INTERVAL_MS)) {
3860
+ return false;
3861
+ }
3862
+ return true;
3863
+ },
3864
+ async maybeAutoCheck(options = {}) {
3865
+ const now = typeof options.now === "number" ? options.now : Date.now();
3866
+ if (!this.shouldAutoCheck(now)) return this.state;
3867
+ return this.checkForUpdate({
3868
+ silent: true,
3869
+ openOnFound: false,
3870
+ openDialog: false,
3871
+ ...options,
3872
+ manual: false
3873
+ });
3874
+ },
3674
3875
  // Dialog opacity preference (Issue #23). Reuses the same localStorage
3675
3876
  // backed preference store as autoCheck / registry instead of adding a
3676
3877
  // second storage mechanism.
@@ -3733,7 +3934,17 @@ function isTopmostDialog(z) {
3733
3934
  }
3734
3935
  this._notify();
3735
3936
 
3937
+ const timeoutMs = typeof options.timeoutMs === "number" ? options.timeoutMs : 10000;
3938
+ let timeoutTimer = null;
3939
+ const abortController = typeof AbortController !== "undefined" ? new AbortController() : null;
3940
+
3736
3941
  try {
3942
+ if (abortController) {
3943
+ timeoutTimer = setTimeout(() => {
3944
+ abortController.abort(new Error("检查更新超时"));
3945
+ }, timeoutMs);
3946
+ }
3947
+
3737
3948
  let res = null;
3738
3949
  if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
3739
3950
  const testOverride = window.__DSH_SM_TEST_UPDATE__;
@@ -3747,12 +3958,16 @@ function isTopmostDialog(z) {
3747
3958
  } else {
3748
3959
  const registryUrl = this.getRegistryUrl();
3749
3960
  const registryParam = encodeURIComponent(registryUrl);
3961
+ const fetchOpts = abortController ? { signal: abortController.signal } : undefined;
3750
3962
  try {
3751
- res = await fetchApi("/update/check?registry=" + registryParam);
3963
+ res = await fetchApi("/update/check?registry=" + registryParam, fetchOpts);
3752
3964
  } catch (fetchErr) {
3965
+ if (abortController?.signal?.aborted || fetchErr.name === "AbortError" || fetchErr.message?.includes("超时")) {
3966
+ throw new Error("检查更新超时");
3967
+ }
3753
3968
  try {
3754
3969
  const base = registryUrl.endsWith("/") ? registryUrl : registryUrl + "/";
3755
- const npmRes = await fetch(base + "dsh-session-manager/latest");
3970
+ const npmRes = await fetch(base + "dsh-session-manager/latest", fetchOpts);
3756
3971
  if (npmRes.ok) {
3757
3972
  const npmData = await npmRes.json();
3758
3973
  if (npmData && npmData.version) {
@@ -3762,7 +3977,11 @@ function isTopmostDialog(z) {
3762
3977
  res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
3763
3978
  }
3764
3979
  }
3765
- } catch (_) {}
3980
+ } catch (_) {
3981
+ if (abortController?.signal?.aborted || fetchErr.name === "AbortError" || fetchErr.message?.includes("超时")) {
3982
+ throw new Error("检查更新超时");
3983
+ }
3984
+ }
3766
3985
  if (!res) throw fetchErr;
3767
3986
  }
3768
3987
  }
@@ -3778,7 +3997,10 @@ function isTopmostDialog(z) {
3778
3997
 
3779
3998
  this.state.currentVersion = currentVersion;
3780
3999
  this.state.latestVersion = latestVersion;
3781
- this.state.checkedAt = Date.now();
4000
+ const now = Date.now();
4001
+ this.state.checkedAt = now;
4002
+ this.state.lastAttemptAt = now;
4003
+ this.lastFailedAt = null;
3782
4004
 
3783
4005
  if (hasUpdate) {
3784
4006
  this.state.status = "available";
@@ -3794,13 +4016,18 @@ function isTopmostDialog(z) {
3794
4016
  this._notify();
3795
4017
  return this.state;
3796
4018
  } catch (err) {
4019
+ const now = Date.now();
3797
4020
  this.state.status = "error";
3798
- this.state.error = err.message || "检查更新失败";
4021
+ this.state.error = (abortController?.signal?.aborted ? "检查更新超时" : (err.message || "检查更新失败"));
4022
+ this.state.lastAttemptAt = now;
4023
+ this.lastFailedAt = now;
3799
4024
  if (shouldOpenDialog) {
3800
4025
  this.state.dialogOpen = true;
3801
4026
  }
3802
4027
  this._notify();
3803
4028
  return this.state;
4029
+ } finally {
4030
+ if (timeoutTimer) clearTimeout(timeoutTimer);
3804
4031
  }
3805
4032
  },
3806
4033
  async startUpdate(options = {}) {
@@ -3864,8 +4091,15 @@ function isTopmostDialog(z) {
3864
4091
  listeners: new Set(),
3865
4092
  getSnapshot() { return this.open; },
3866
4093
  subscribe(cb) { this.listeners.add(cb); return () => this.listeners.delete(cb); },
3867
- set(v) { if (this.open === v) return; this.open = v; for (const fn of [...this.listeners]) fn(); },
3868
- toggle() { this.open = !this.open; for (const fn of [...this.listeners]) fn(); },
4094
+ set(v) {
4095
+ if (this.open === v) return;
4096
+ this.open = v;
4097
+ if (this.open) {
4098
+ try { updateStore.maybeAutoCheck().catch(() => {}); } catch (_) {}
4099
+ }
4100
+ for (const fn of [...this.listeners]) fn();
4101
+ },
4102
+ toggle() { this.set(!this.open); },
3869
4103
  // Pending action queued by the title-bar buttons (e.g. 移动至工作区).
3870
4104
  // The SessionManagerPanel consumes this on mount so it can pre-open
3871
4105
  // the matching inner dialog (move / delete / migrate) next to itself.
@@ -3979,6 +4213,29 @@ function isTopmostDialog(z) {
3979
4213
  const [now, setNow] = useState(() => Date.now());
3980
4214
  const [moveFor, setMoveFor] = useState(null);
3981
4215
  const [confirmFor, setConfirmFor] = useState(null);
4216
+ const [confirmPreviewState, setConfirmPreviewState] = useState({ loading: false, error: null, subagentCount: 0 });
4217
+ useEffect(() => {
4218
+ if (!confirmFor || !confirmFor.id) {
4219
+ setConfirmPreviewState({ loading: false, error: null, subagentCount: 0 });
4220
+ return;
4221
+ }
4222
+ let alive = true;
4223
+ setConfirmPreviewState({ loading: true, error: null, subagentCount: 0 });
4224
+ fetchApi("/delete-preview?sessionId=" + encodeURIComponent(confirmFor.id))
4225
+ .then((res) => {
4226
+ if (!alive) return;
4227
+ if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
4228
+ setConfirmPreviewState({ loading: false, error: null, subagentCount: res.result.subagentCount });
4229
+ } else {
4230
+ setConfirmPreviewState({ loading: false, error: res?.error || "获取子智能体预览失败", subagentCount: 0 });
4231
+ }
4232
+ })
4233
+ .catch((err) => {
4234
+ if (!alive) return;
4235
+ setConfirmPreviewState({ loading: false, error: err instanceof Error ? err.message : String(err), subagentCount: 0 });
4236
+ });
4237
+ return () => { alive = false; };
4238
+ }, [confirmFor?.id]);
3982
4239
  const [workspaces, setWorkspaces] = useState([]);
3983
4240
  const [createdTimes, setCreatedTimes] = useState({});
3984
4241
  const [updatedTimes, setUpdatedTimes] = useState({});
@@ -4167,7 +4424,59 @@ function isTopmostDialog(z) {
4167
4424
  };
4168
4425
  const summaryAction = actionSummaryMap[action] || resolvedLabel;
4169
4426
  if (needsConfirm) {
4170
- setBulkPreview({ action, payload, actionLabel: summaryAction, sessions, warning: action === "delete" ? t("bulk.dialog.warning.delete") : "" });
4427
+ const baseWarning = action === "delete" ? t("bulk.dialog.warning.delete") : "";
4428
+ if (action === "delete") {
4429
+ setBulkPreview({
4430
+ action,
4431
+ payload,
4432
+ actionLabel: summaryAction,
4433
+ sessions,
4434
+ warning: baseWarning,
4435
+ loading: true,
4436
+ error: null
4437
+ });
4438
+ fetchApi("/delete-preview?sessionIds=" + encodeURIComponent(ids.join(",")))
4439
+ .then((res) => {
4440
+ if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
4441
+ const subCount = res.result.subagentCount;
4442
+ setBulkPreview((prev) => {
4443
+ if (!prev || prev.action !== "delete") return prev;
4444
+ const subText = subCount > 0 ? t("confirm.delete.subagents", { count: subCount }) : "";
4445
+ return {
4446
+ ...prev,
4447
+ loading: false,
4448
+ error: null,
4449
+ warning: subText ? `${subText}\n${baseWarning}` : baseWarning
4450
+ };
4451
+ });
4452
+ } else {
4453
+ const errMsg = (res && res.error) || t("confirm.delete.previewError") || "检查关联子智能体会话失败,请稍后重试";
4454
+ setBulkPreview((prev) => {
4455
+ if (!prev || prev.action !== "delete") return prev;
4456
+ return {
4457
+ ...prev,
4458
+ loading: false,
4459
+ error: errMsg,
4460
+ warning: `${errMsg}\n${baseWarning}`
4461
+ };
4462
+ });
4463
+ }
4464
+ })
4465
+ .catch((err) => {
4466
+ const errMsg = (err && err.message) || t("confirm.delete.previewError") || "检查关联子智能体会话失败,请稍后重试";
4467
+ setBulkPreview((prev) => {
4468
+ if (!prev || prev.action !== "delete") return prev;
4469
+ return {
4470
+ ...prev,
4471
+ loading: false,
4472
+ error: errMsg,
4473
+ warning: `${errMsg}\n${baseWarning}`
4474
+ };
4475
+ });
4476
+ });
4477
+ return;
4478
+ }
4479
+ setBulkPreview({ action, payload, actionLabel: summaryAction, sessions, warning: baseWarning });
4171
4480
  return;
4172
4481
  }
4173
4482
  void executeBulk({ action, payload, actionLabel: resolvedLabel, ids, sessions });
@@ -4460,28 +4769,56 @@ function isTopmostDialog(z) {
4460
4769
  : h("div", { className: "sm-list" }, rows.map((s, i) => renderRow(s, i)));
4461
4770
 
4462
4771
  const allWorkspaceRows = useMemo(() => {
4463
- const byId = list?.byId || {};
4772
+ const hasSessionList = Array.isArray(list?.ids);
4773
+ const sessionsByWorkspace = new Map();
4774
+ for (const ws of workspaces) {
4775
+ sessionsByWorkspace.set(ws.id, []);
4776
+ }
4777
+ if (hasSessionList) {
4778
+ for (const s of allRows) {
4779
+ const matchedWsIds = rowWorkspaces(s, workspaceIndex);
4780
+ for (const wsId of matchedWsIds) {
4781
+ const wsList = sessionsByWorkspace.get(wsId);
4782
+ if (wsList) wsList.push(s);
4783
+ }
4784
+ }
4785
+ }
4464
4786
  return workspaces.map(ws => {
4465
- const sids = Array.isArray(ws.sessionIds) ? ws.sessionIds : [];
4787
+ const wsSessions = sessionsByWorkspace.get(ws.id) || [];
4788
+ let sessionCount = 0;
4466
4789
  let latestSessionTime = null;
4467
- for (const sid of sids) {
4468
- const s = byId[sid];
4469
- const rawTime = s ? (s.updatedAt ?? s.lastModified ?? s.mtime ?? s.createdAt) : null;
4470
- const st = sessionTime(rawTime) ?? sessionTime(updatedTimes[sid]) ?? sessionTime(createdTimes[sid]);
4471
- if (st !== null) {
4472
- if (latestSessionTime === null || st > latestSessionTime) {
4473
- latestSessionTime = st;
4790
+ if (hasSessionList) {
4791
+ sessionCount = wsSessions.length;
4792
+ for (const s of wsSessions) {
4793
+ const st = sessionTime(s?.updatedAt) ?? sessionTime(s?.createdAt);
4794
+ if (st !== null) {
4795
+ if (latestSessionTime === null || st > latestSessionTime) {
4796
+ latestSessionTime = st;
4797
+ }
4798
+ }
4799
+ }
4800
+ } else {
4801
+ const sids = Array.isArray(ws.sessionIds) ? ws.sessionIds : [];
4802
+ const byId = list?.byId || {};
4803
+ for (const sid of sids) {
4804
+ const s = byId[sid];
4805
+ if (s && (s.origin === "subagent" || (s.blank && s.id !== list?.current))) continue;
4806
+ sessionCount++;
4807
+ const st = sessionTime(s?.updatedAt) ?? sessionTime(s?.createdAt);
4808
+ if (st !== null) {
4809
+ if (latestSessionTime === null || st > latestSessionTime) {
4810
+ latestSessionTime = st;
4811
+ }
4474
4812
  }
4475
4813
  }
4476
4814
  }
4477
- const wsSelfTime = sessionTime(ws.updatedAt) ?? sessionTime(ws.createdAt);
4478
- const resolvedTime = latestSessionTime !== null ? latestSessionTime : wsSelfTime;
4479
4815
  return {
4480
4816
  ...ws,
4481
- latestUpdatedAt: resolvedTime
4817
+ sessionCount,
4818
+ latestUpdatedAt: latestSessionTime
4482
4819
  };
4483
4820
  });
4484
- }, [workspaces, list?.byId, updatedTimes, createdTimes]);
4821
+ }, [workspaces, allRows, workspaceIndex, list?.ids, list?.byId, list?.current]);
4485
4822
 
4486
4823
  const filteredWorkspaceRows = useMemo(() => {
4487
4824
  const needle = wsQuery.trim().toLowerCase();
@@ -4632,7 +4969,7 @@ function isTopmostDialog(z) {
4632
4969
  const isBusy = workspaceArchiveStore.isBusy(ws.id);
4633
4970
  const title = ws.title || ws.name || ws.id;
4634
4971
  const path = ws.path || "";
4635
- const sessionCount = Array.isArray(ws.sessionIds) ? ws.sessionIds.length : 0;
4972
+ const sessionCount = typeof ws.sessionCount === "number" ? ws.sessionCount : (Array.isArray(ws.sessionIds) ? ws.sessionIds.length : 0);
4636
4973
  const timeFormatted = ws.latestUpdatedAt !== null
4637
4974
  ? t("workspace.lastUpdated", { time: formatRelative(ws.latestUpdatedAt, now) })
4638
4975
  : "—";
@@ -4689,13 +5026,12 @@ function isTopmostDialog(z) {
4689
5026
  },
4690
5027
  h("div", { className: "sm-rowCheckboxSlot" + ((wsSelectedIds.size > 0 || wsSelectModeEnabled) ? " sm-rowCheckboxSlot-visible" : "") }, checkbox),
4691
5028
  h("div", { className: "sm-rowMain" },
4692
- h("div", { className: "sm-rowTitle" },
5029
+ h("div", { className: "sm-rowTitle", title: path || title },
4693
5030
  h("span", null, title),
4694
5031
  isArchived ? h("span", { className: "sm-badge sm-badgeArchived" }, t("workspace.badge.archived")) : null
4695
5032
  ),
4696
5033
  h("div", { className: "sm-rowSecondary" },
4697
5034
  h("div", { className: "sm-rowMeta" },
4698
- (path ? (shortPath(path) + " · ") : "") +
4699
5035
  t("workspace.sessions", { count: sessionCount }) +
4700
5036
  " · " +
4701
5037
  timeFormatted
@@ -4726,8 +5062,23 @@ function isTopmostDialog(z) {
4726
5062
  // without re-subscribing on every render. The panel listener
4727
5063
  // returns early when any inner dialog is open so the child
4728
5064
  // dialog's own window listener gets the first shot at Esc.
5065
+ const panelRef = useRef(null);
4729
5066
  const escStateRef = useRef({});
4730
- escStateRef.current = { busyId, confirmFor, moveFor, migrateFor, annotationFor, wsBulkBusy, onPanelClose };
5067
+ escStateRef.current = {
5068
+ busyId,
5069
+ confirmFor,
5070
+ moveFor,
5071
+ migrateFor,
5072
+ annotationFor,
5073
+ bulkPreview,
5074
+ bulkProgress,
5075
+ bulkResult,
5076
+ bulkBusy,
5077
+ bulkTagDraft,
5078
+ bulkPresetDraft,
5079
+ wsBulkBusy,
5080
+ onPanelClose
5081
+ };
4731
5082
  useEffect(() => {
4732
5083
  if (!open) return;
4733
5084
  const handler = (e) => {
@@ -4735,8 +5086,10 @@ function isTopmostDialog(z) {
4735
5086
  if (e.defaultPrevented) return;
4736
5087
  if (e.isComposing || e.keyCode === 229) return;
4737
5088
  const s = escStateRef.current;
4738
- if (s.busyId !== null || s.wsBulkBusy) return;
4739
- if (s.confirmFor || s.moveFor || s.migrateFor || s.annotationFor || (activeDialogZStack && activeDialogZStack.length > 0)) return;
5089
+ if (s.busyId !== null || s.wsBulkBusy || s.bulkBusy) return;
5090
+ if (s.confirmFor || s.moveFor || s.migrateFor || s.annotationFor || s.bulkPreview || s.bulkProgress || s.bulkResult || s.bulkTagDraft || s.bulkPresetDraft) return;
5091
+ if (typeof updateStore !== "undefined" && updateStore && typeof updateStore.getSnapshot === "function" && updateStore.getSnapshot()?.dialogOpen) return;
5092
+ if (activeDialogZStack && activeDialogZStack.length > 0) return;
4740
5093
  e.preventDefault();
4741
5094
  e.stopPropagation();
4742
5095
  s.onPanelClose();
@@ -4750,7 +5103,28 @@ function isTopmostDialog(z) {
4750
5103
  if (ae && typeof ae.blur === "function" && ae !== document.body) ae.blur();
4751
5104
  };
4752
5105
  window.addEventListener("keydown", handler);
4753
- return () => window.removeEventListener("keydown", handler);
5106
+ const mountTime = Date.now();
5107
+ const clickHandler = (e) => {
5108
+ if (Date.now() - mountTime < 50) return;
5109
+ if (e.defaultPrevented) return;
5110
+ const s = escStateRef.current;
5111
+ if (s.busyId !== null || s.wsBulkBusy || s.bulkBusy) return;
5112
+ if (s.annotationFor !== null) return;
5113
+ if (s.confirmFor || s.moveFor || s.migrateFor) return;
5114
+ if (s.bulkPreview || s.bulkProgress || s.bulkResult || s.bulkTagDraft || s.bulkPresetDraft) return;
5115
+ if (typeof updateStore !== "undefined" && updateStore && typeof updateStore.getSnapshot === "function" && updateStore.getSnapshot()?.dialogOpen) return;
5116
+ if (activeDialogZStack && activeDialogZStack.length > 0) return;
5117
+ if (panelRef.current && typeof panelRef.current.contains === "function" && panelRef.current.contains(e.target)) return;
5118
+ if (e.target && typeof e.target.closest === "function") {
5119
+ if (e.target.closest(".sm-nativeDialog, .sm-panelDialog, .sm-bulkDialog, .sm-annotationDialog, .sm-annotationSurface, .sm-tooltip, .sm-footerBtn")) return;
5120
+ }
5121
+ s.onPanelClose();
5122
+ };
5123
+ window.addEventListener("click", clickHandler);
5124
+ return () => {
5125
+ window.removeEventListener("keydown", handler);
5126
+ window.removeEventListener("click", clickHandler);
5127
+ };
4754
5128
  }, [open]);
4755
5129
  // The panel is a document-level floating window, so it is portaled into
4756
5130
  // the plugin's overlay root like every other dialog here (issue #28).
@@ -4773,6 +5147,7 @@ function isTopmostDialog(z) {
4773
5147
  role: "presentation"
4774
5148
  },
4775
5149
  h("section", {
5150
+ ref: panelRef,
4776
5151
  className: "sm-nativeDialog sm-panelDialog",
4777
5152
  role: "dialog",
4778
5153
  "aria-modal": "true",
@@ -5076,13 +5451,27 @@ function isTopmostDialog(z) {
5076
5451
  onClose: () => { if (busyId === null) setConfirmFor(null); },
5077
5452
  title: t("confirm.delete.title"),
5078
5453
  description: (confirmFor.displayTitle && t("confirm.delete.desc", { title: confirmFor.displayTitle })) || "",
5079
- warning: confirmFor.running ? (t("confirm.delete.running") + " " + t("bulk.dialog.warning.delete")) : t("bulk.dialog.warning.delete"),
5454
+ warning: (() => {
5455
+ const baseWarning = (confirmFor.running ? (t("confirm.delete.running") + " " + t("bulk.dialog.warning.delete")) : t("bulk.dialog.warning.delete"));
5456
+ if (confirmPreviewState.loading) {
5457
+ const loadingMsg = t("confirm.delete.previewLoading") || "正在检查关联的子智能体会话…";
5458
+ return `${loadingMsg}\n${baseWarning}`;
5459
+ }
5460
+ if (confirmPreviewState.error) {
5461
+ const errorMsg = confirmPreviewState.error;
5462
+ return `${errorMsg}\n${baseWarning}`;
5463
+ }
5464
+ const subagentWarning = confirmPreviewState.subagentCount > 0 ? t("confirm.delete.subagents", { count: confirmPreviewState.subagentCount }) : "";
5465
+ return subagentWarning ? `${subagentWarning}\n${baseWarning}` : baseWarning;
5466
+ })(),
5467
+ confirmDisabled: confirmPreviewState.loading || Boolean(confirmPreviewState.error),
5080
5468
  confirmLabel: t("confirm.delete.confirm"),
5081
5469
  cancelLabel: t("confirm.cancel"),
5082
5470
  busy: busyId !== null,
5083
5471
  danger: true,
5084
5472
  onCancel: () => { if (busyId === null) setConfirmFor(null); },
5085
5473
  onConfirm: () => {
5474
+ if (confirmPreviewState.loading || confirmPreviewState.error) return;
5086
5475
  const target = confirmFor;
5087
5476
  setConfirmFor(null);
5088
5477
  runRow(target.id, () => onRemove(target.id));
@@ -5168,12 +5557,16 @@ function isTopmostDialog(z) {
5168
5557
  delete: t("bulk.confirm.delete")
5169
5558
  })[action] || t("bulk.dialog.execute");
5170
5559
  const bulkPreviewDialog = bulkPreview ? h(BatchPreviewDialog, {
5171
- open: true, t, actionLabel: bulkPreview.actionLabel,
5560
+ open: true, t, action: bulkPreview.action, actionLabel: bulkPreview.actionLabel,
5561
+ title: bulkPreview.action === "delete" ? t("confirm.delete.title") : undefined,
5172
5562
  sessions: bulkPreview.sessions, warning: bulkPreview.warning,
5173
5563
  confirmLabel: bulkConfirmLabelFor(bulkPreview.action),
5174
5564
  danger: bulkPreview.action === "delete",
5565
+ loading: bulkPreview.loading === true,
5566
+ error: bulkPreview.error || null,
5175
5567
  onCancel: () => setBulkPreview(null),
5176
5568
  onExecute: () => {
5569
+ if (bulkPreview.loading || bulkPreview.error) return;
5177
5570
  const preview = bulkPreview;
5178
5571
  setBulkPreview(null);
5179
5572
  void executeBulk({
@@ -5279,6 +5672,29 @@ function isTopmostDialog(z) {
5279
5672
 
5280
5673
  const [confirmFor, setConfirmFor] = useState(null);
5281
5674
  const [confirmAnchor, setConfirmAnchor] = useState(null);
5675
+ const [confirmPreviewState, setConfirmPreviewState] = useState({ loading: false, error: null, subagentCount: 0 });
5676
+ useEffect(() => {
5677
+ if (!confirmFor || !confirmFor.id) {
5678
+ setConfirmPreviewState({ loading: false, error: null, subagentCount: 0 });
5679
+ return;
5680
+ }
5681
+ let alive = true;
5682
+ setConfirmPreviewState({ loading: true, error: null, subagentCount: 0 });
5683
+ fetchApi("/delete-preview?sessionId=" + encodeURIComponent(confirmFor.id))
5684
+ .then((res) => {
5685
+ if (!alive) return;
5686
+ if (res && res.ok && res.result && typeof res.result.subagentCount === "number") {
5687
+ setConfirmPreviewState({ loading: false, error: null, subagentCount: res.result.subagentCount });
5688
+ } else {
5689
+ setConfirmPreviewState({ loading: false, error: res?.error || (t ? t("confirm.delete.previewError") : "检查关联子智能体会话失败,请稍后重试"), subagentCount: 0 });
5690
+ }
5691
+ })
5692
+ .catch((err) => {
5693
+ if (!alive) return;
5694
+ setConfirmPreviewState({ loading: false, error: (err && err.message) || (t ? t("confirm.delete.previewError") : "检查关联子智能体会话失败,请稍后重试"), subagentCount: 0 });
5695
+ });
5696
+ return () => { alive = false; };
5697
+ }, [confirmFor?.id]);
5282
5698
  const [moveFor, setMoveFor] = useState(null);
5283
5699
  const [moveAnchor, setMoveAnchor] = useState(null);
5284
5700
  const [workspaces, setWorkspaces] = useState([]);
@@ -5608,13 +6024,30 @@ function isTopmostDialog(z) {
5608
6024
  onClose: () => setConfirmFor(null),
5609
6025
  onCancel: () => setConfirmFor(null),
5610
6026
  onConfirm: () => {
6027
+ if (confirmPreviewState.loading || confirmPreviewState.error) return;
5611
6028
  const target = confirmFor;
5612
6029
  setConfirmFor(null);
5613
6030
  runWithAlert("delete", () => onRemove(target.id));
5614
6031
  },
5615
6032
  title: t ? t("confirm.delete.title") : "删除会话",
5616
6033
  description: (confirmFor && confirmFor.displayTitle && (t ? t("confirm.delete.desc", { title: confirmFor.displayTitle }) : ("「" + confirmFor.displayTitle + "」:删除,不可恢复"))) || "",
5617
- warning: (confirmFor && confirmFor.running && t ? t("confirm.delete.running") + " " : "") + (t ? t("bulk.dialog.warning.delete") : "删除操作不可撤销,请确认后再继续。"),
6034
+ warning: (() => {
6035
+ const baseWarn = (confirmFor && confirmFor.running && t ? t("confirm.delete.running") + " " : "") +
6036
+ (t ? t("bulk.dialog.warning.delete") : "删除操作不可撤销,请确认后再继续。");
6037
+ if (confirmPreviewState.loading) {
6038
+ const loadingMsg = (t ? t("confirm.delete.previewLoading") : "") || "正在检查关联的子智能体会话…";
6039
+ return `${loadingMsg}\n${baseWarn}`;
6040
+ }
6041
+ if (confirmPreviewState.error) {
6042
+ const errorMsg = confirmPreviewState.error;
6043
+ return `${errorMsg}\n${baseWarn}`;
6044
+ }
6045
+ const subagentsWarn = confirmPreviewState.subagentCount > 0
6046
+ ? (t ? t("confirm.delete.subagents", { count: confirmPreviewState.subagentCount }) : `将连带删除 ${confirmPreviewState.subagentCount} 个关联的子智能体会话。`)
6047
+ : "";
6048
+ return subagentsWarn ? `${subagentsWarn}\n${baseWarn}` : baseWarn;
6049
+ })(),
6050
+ confirmDisabled: confirmPreviewState.loading || Boolean(confirmPreviewState.error),
5618
6051
  confirmLabel: t ? t("confirm.delete.confirm") : "确认删除",
5619
6052
  cancelLabel: t ? t("confirm.cancel") : "取消",
5620
6053
  busy: false,
@@ -6011,18 +6444,6 @@ function isTopmostDialog(z) {
6011
6444
  ),
6012
6445
  h("div", { className: "sm-settingsSection" },
6013
6446
  h("div", { className: "sm-settingsSectionTitle" }, t("settings.prefSection")),
6014
- h("div", { className: "sm-settingsRow" },
6015
- h("span", null, t("settings.registry")),
6016
- h("select", {
6017
- className: "sm-settingsSelect sm-viewSelect",
6018
- value: currentRegistry,
6019
- onChange: onRegistryChange,
6020
- "aria-label": t("settings.registry")
6021
- },
6022
- h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
6023
- h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
6024
- )
6025
- ),
6026
6447
  h("div", { className: "sm-settingsRow" },
6027
6448
  h("span", null, t("update.autoCheck")),
6028
6449
  h("label", { className: "sm-settingsCheckbox" },
@@ -6036,7 +6457,22 @@ function isTopmostDialog(z) {
6036
6457
  )
6037
6458
  ),
6038
6459
  h("div", { className: "sm-settingsRow" },
6039
- h("span", null, t("settings.dialogOpacity")),
6460
+ h("span", null, t("settings.registry")),
6461
+ h("select", {
6462
+ className: "sm-settingsSelect",
6463
+ value: currentRegistry,
6464
+ onChange: onRegistryChange,
6465
+ "aria-label": t("settings.registry")
6466
+ },
6467
+ h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
6468
+ h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
6469
+ )
6470
+ ),
6471
+ h("div", { className: "sm-settingsRow" },
6472
+ h("div", { className: "sm-settingsRowLeft" },
6473
+ h("span", null, t("settings.dialogOpacity")),
6474
+ h("span", { className: "sm-settingsHint sm-settingsHintInline" }, t("settings.dialogOpacity.hint"))
6475
+ ),
6040
6476
  h("div", { className: "sm-settingsSlider" },
6041
6477
  h("input", {
6042
6478
  type: "range",
@@ -6060,39 +6496,42 @@ function isTopmostDialog(z) {
6060
6496
  onClick: () => updateStore.resetDialogOpacity()
6061
6497
  }, t("settings.dialogOpacity.reset"))
6062
6498
  )
6063
- ),
6064
- h("div", { className: "sm-settingsHint" }, t("settings.dialogOpacity.hint"))
6499
+ )
6065
6500
  ),
6066
6501
  h("div", { className: "sm-settingsSection" },
6067
6502
  h("div", { className: "sm-settingsSectionTitle" }, t("settings.projectSection")),
6068
- h("div", { className: "sm-settingsRow sm-settingsRowInline" },
6069
- h("span", null, t("settings.github")),
6070
- h("a", {
6071
- href: "https://github.com/hkkz9522/dsh-session-manager",
6072
- target: "_blank",
6073
- rel: "noopener noreferrer",
6074
- className: "sm-settingsLink"
6075
- }, "hkkz9522/dsh-session-manager"),
6076
- renderTip(t("settings.star.tip"), h("a", {
6077
- href: "https://github.com/hkkz9522/dsh-session-manager",
6078
- target: "_blank",
6079
- rel: "noopener noreferrer",
6080
- className: "sm-settingsBadgeLink",
6081
- "aria-label": t("settings.star.tip")
6082
- },
6083
- h(StarIcon, { size: 14 }),
6084
- h("span", null, t("settings.star"))
6085
- )),
6086
- renderTip(t("settings.feedback.tip"), h("a", {
6087
- href: "https://github.com/hkkz9522/dsh-session-manager/issues",
6088
- target: "_blank",
6089
- rel: "noopener noreferrer",
6090
- className: "sm-settingsBadgeLink",
6091
- "aria-label": t("settings.feedback.tip")
6092
- },
6093
- h(IssueIcon, { size: 14 }),
6094
- h("span", null, t("settings.feedback"))
6095
- ))
6503
+ h("div", { className: "sm-settingsRow" },
6504
+ h("div", { className: "sm-settingsProjectLeft" },
6505
+ h("span", { className: "sm-settingsProjectLabel" }, t("settings.github")),
6506
+ h("a", {
6507
+ href: "https://github.com/hkkz9522/dsh-session-manager",
6508
+ target: "_blank",
6509
+ rel: "noopener noreferrer",
6510
+ className: "sm-settingsLink"
6511
+ }, "hkkz9522/dsh-session-manager")
6512
+ ),
6513
+ h("div", { className: "sm-settingsBadgeActions" },
6514
+ renderTip(t("settings.star.tip"), h("a", {
6515
+ href: "https://github.com/hkkz9522/dsh-session-manager",
6516
+ target: "_blank",
6517
+ rel: "noopener noreferrer",
6518
+ className: "sm-settingsBadgeLink",
6519
+ "aria-label": t("settings.star.tip")
6520
+ },
6521
+ h(StarIcon, { size: 14 }),
6522
+ h("span", null, t("settings.star"))
6523
+ )),
6524
+ renderTip(t("settings.feedback.tip"), h("a", {
6525
+ href: "https://github.com/hkkz9522/dsh-session-manager/issues",
6526
+ target: "_blank",
6527
+ rel: "noopener noreferrer",
6528
+ className: "sm-settingsBadgeLink",
6529
+ "aria-label": t("settings.feedback.tip")
6530
+ },
6531
+ h(IssueIcon, { size: 14 }),
6532
+ h("span", null, t("settings.feedback"))
6533
+ ))
6534
+ )
6096
6535
  )
6097
6536
  )
6098
6537
  );
@@ -6186,7 +6625,18 @@ function isTopmostDialog(z) {
6186
6625
  onRemove: async (sessionId) => {
6187
6626
  const wasCurrent = isCurrentSession(sessionId);
6188
6627
  const response = await callApi("/delete", { sessionId });
6189
- if (!response.ok) throw new Error(response.error || "delete failed");
6628
+ if (!response.ok) {
6629
+ if (Array.isArray(response.deletedSubagents) && response.deletedSubagents.length > 0) {
6630
+ try { await annotationStore.load(true); } catch (_) {}
6631
+ try { await ctx.sessions?.refresh?.(); } catch (_) {}
6632
+ try { await ctx.workspaces?.refresh?.(); } catch (_) {}
6633
+ }
6634
+ const err = new Error(response.error || "delete failed");
6635
+ err.deletedSubagents = response.deletedSubagents || [];
6636
+ err.remainingSessions = response.remainingSessions || [sessionId];
6637
+ err.partialFailure = Boolean(response.partialFailure);
6638
+ throw err;
6639
+ }
6190
6640
  await annotationStore.load(true);
6191
6641
  if (response.result?.warning) window.alert(response.result.warning);
6192
6642
  if (wasCurrent || isCurrentSession(sessionId)) {
@@ -6320,7 +6770,7 @@ function isTopmostDialog(z) {
6320
6770
  ctx.effect(() => {
6321
6771
  if (!updateStore.getAutoCheck()) return;
6322
6772
  const timer = setTimeout(() => {
6323
- updateStore.checkForUpdate({ silent: true, openOnFound: false, openDialog: false }).catch(() => {});
6773
+ updateStore.maybeAutoCheck({ isStartup: true }).catch(() => {});
6324
6774
  }, 1500);
6325
6775
  return () => {
6326
6776
  try {
@@ -6381,8 +6831,18 @@ function isTopmostDialog(z) {
6381
6831
  exports.apply = apply;
6382
6832
  exports.inject = inject;
6383
6833
  exports.updateStore = updateStore;
6834
+ exports.panelStore = panelStore;
6384
6835
  exports.compareSemver = compareSemver;
6836
+ exports.OverlayLayer = OverlayLayer;
6385
6837
  exports.UpdateDialog = UpdateDialog;
6838
+ exports.ConfirmDialog = ConfirmDialog;
6839
+ exports.MoveDialog = MoveDialog;
6840
+ exports.MigratePresetDialog = MigratePresetDialog;
6841
+ exports.BatchPreviewDialog = BatchPreviewDialog;
6842
+ exports.BatchResultDialog = BatchResultDialog;
6843
+ exports.BulkTagInputDialog = BulkTagInputDialog;
6844
+ exports.BulkChoiceDialog = BulkChoiceDialog;
6845
+ exports.AnnotationDialog = AnnotationDialog;
6386
6846
  exports.SessionManagerSettingsCard = SessionManagerSettingsCard;
6387
6847
  exports.WhaleIcon = WhaleIcon;
6388
6848
  exports.NpmIcon = NpmIcon;