dsh-session-manager 0.5.4 → 0.6.2

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,17 @@ window.__ModuleLoader__.load({
21
21
  const P = require("@deepseek-ai/dsh-client-ui-primitives");
22
22
  if (typeof window !== "undefined") {
23
23
  window.__smReact = React;
24
- window.__smReactDOM = React.createPortal ? React : null;
24
+ let rdomModule = null;
25
+ try { rdomModule = require("react-dom"); } catch (_) {}
26
+ if (!rdomModule) {
27
+ try { rdomModule = require("react-dom/client"); } catch (_) {}
28
+ }
29
+ if (!rdomModule && typeof window.ReactDOM !== "undefined") {
30
+ rdomModule = window.ReactDOM;
31
+ }
32
+ window.__smReactDOM = (rdomModule && typeof rdomModule.createPortal === "function")
33
+ ? rdomModule
34
+ : (typeof React.createPortal === "function" ? React : null);
25
35
  // Tiny imperative portal helper: takes a React element + a host
26
36
  // DOM node, creates a React root on the host (lazily), and re-renders
27
37
  // the element into it on each call. Used by ConfirmDialog to escape
@@ -48,9 +58,16 @@ window.__ModuleLoader__.load({
48
58
  // this counter on mount, writes it to inline style.zIndex, and never
49
59
  // recycles within a session, so the most-recently opened popup is
50
60
  // always the topmost one.
51
- let dialogZStackCounter = 11000;
61
+ let dialogZStackCounter = 100000;
52
62
  function nextDialogZ() { return ++dialogZStackCounter; }
53
63
 
64
+ function renderTip(label, node, side = "bottom", portal = true) {
65
+ if (!label || !node) return node;
66
+ if (P && typeof P.Tooltip === "function") {
67
+ return h(P.Tooltip, { label, side, portal, align: "center" }, node);
68
+ }
69
+ return node;
70
+ }
54
71
 
55
72
  const NS = "session-manager";
56
73
  const API = "/session-manager/api";
@@ -119,6 +136,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
119
136
  "marks.tags.clear": "清空标签",
120
137
  "marks.note.clear": "清空备注",
121
138
  "header.aria": "会话操作",
139
+ "header.more": "更多操作",
122
140
  "menu.open": "打开",
123
141
  "menu.archive": "归档会话",
124
142
  "menu.unarchive": "移出归档",
@@ -129,6 +147,38 @@ function nextDialogZ() { return ++dialogZStackCounter; }
129
147
  "footer.label": "会话管理",
130
148
  "panel.title": "会话管理",
131
149
  "panel.github.title": "欢迎Star和提交Issue",
150
+ "panel.update.title": "检查更新",
151
+ "panel.update.badge": "有新版本可用",
152
+ "update.title": "检查更新",
153
+ "update.newVersion": "发现新版本",
154
+ "update.currentVersion": "当前版本",
155
+ "update.latestVersion": "最新版本",
156
+ "update.isLatest": "当前已是最新版本",
157
+ "update.checking": "正在检查更新…",
158
+ "update.installing": "正在通过插件管理器安装新版本…",
159
+ "update.btn.check": "检查更新",
160
+ "update.btn.update": "更新到 v{version}",
161
+ "update.btn.updating": "更新中…",
162
+ "update.btn.later": "稍后",
163
+ "update.btn.done": "好的",
164
+ "update.btn.retry": "重试",
165
+ "update.btn.close": "关闭",
166
+ "update.done.restart": "更新已安装(v{from} → v{to}),重启 DSH 后生效。",
167
+ "update.done.applied": "更新已应用!",
168
+ "update.error": "更新遇到问题",
169
+ "update.autoCheck": "自动检查更新",
170
+ "update.autoCheck.enable": "开启",
171
+ "settings.registry": "安装源",
172
+ "settings.registry.npm": "npm 官方源 registry.npmjs.org",
173
+ "settings.registry.china": "中国大陆镜像源 registry.npmmirror.com",
174
+ "settings.title": "会话管理",
175
+ "settings.pluginName": "dsh-session-manager",
176
+ "settings.versionSection": "插件版本",
177
+ "settings.prefSection": "偏好设置",
178
+ "settings.projectSection": "项目",
179
+ "settings.github": "GitHub 仓库",
180
+ "settings.star": "感谢Star",
181
+ "settings.feedback": "欢迎反馈",
132
182
  "panel.search": "搜索标题、ID、标签或备注",
133
183
  "panel.workspace": "工作区",
134
184
  "panel.workspace.all": "全部工作区",
@@ -303,6 +353,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
303
353
  "marks.tags.clear": "Clear tags",
304
354
  "marks.note.clear": "Clear note",
305
355
  "header.aria": "Session actions",
356
+ "header.more": "More actions",
306
357
  "menu.open": "Open",
307
358
  "menu.archive": "Archive session",
308
359
  "menu.unarchive": "Unarchive session",
@@ -313,6 +364,38 @@ function nextDialogZ() { return ++dialogZStackCounter; }
313
364
  "footer.label": "Sessions",
314
365
  "panel.title": "Session manager",
315
366
  "panel.github.title": "Star the project or open an issue",
367
+ "panel.update.title": "Check for updates",
368
+ "panel.update.badge": "New version available",
369
+ "update.title": "Check for Updates",
370
+ "update.newVersion": "New Version Available",
371
+ "update.currentVersion": "Current Version",
372
+ "update.latestVersion": "Latest Version",
373
+ "update.isLatest": "Up to date",
374
+ "update.checking": "Checking for updates…",
375
+ "update.installing": "Installing update via plugin manager…",
376
+ "update.btn.check": "Check for Updates",
377
+ "update.btn.update": "Update to v{version}",
378
+ "update.btn.updating": "Updating…",
379
+ "update.btn.later": "Later",
380
+ "update.btn.done": "OK",
381
+ "update.btn.retry": "Retry",
382
+ "update.btn.close": "Close",
383
+ "update.done.restart": "Update installed (v{from} → v{to}). Please restart DSH.",
384
+ "update.done.applied": "Update applied successfully!",
385
+ "update.error": "Update Error",
386
+ "update.autoCheck": "Automatically check for updates",
387
+ "update.autoCheck.enable": "Enable",
388
+ "settings.registry": "Install Source",
389
+ "settings.registry.npm": "npm official registry.npmjs.org",
390
+ "settings.registry.china": "China mainland mirror registry.npmmirror.com",
391
+ "settings.title": "Session Manager",
392
+ "settings.pluginName": "dsh-session-manager",
393
+ "settings.versionSection": "Plugin Version",
394
+ "settings.prefSection": "Preferences",
395
+ "settings.projectSection": "Project",
396
+ "settings.github": "GitHub Repository",
397
+ "settings.star": "Star on GitHub",
398
+ "settings.feedback": "Feedback / Issues",
316
399
  "panel.search": "Search title, ID, tags or notes",
317
400
  "panel.workspace": "Workspace",
318
401
  "panel.workspace.all": "All workspaces",
@@ -469,17 +552,17 @@ function nextDialogZ() { return ++dialogZStackCounter; }
469
552
  ".sm-moveItem:hover{background:var(--dsw-alias-interactive-bg-hover)}",
470
553
  ".sm-moveItemSelected{border-color:var(--dsw-alias-accent-primary);background:var(--dsw-alias-accent-primary-bg)}",
471
554
  ".sm-moveItemName{color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}",
472
- ".sm-moveItemMeta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.sm-panelModal{width:760px;max-width:92vw}.sm-panelModal .sm-rowActions{flex-wrap:wrap;justify-content:flex-end}.sm-headerMenu{position:absolute;right:0;top:100%;z-index:50;display:flex;flex-direction:column;min-width:160px;padding:4px;background:var(--dsw-alias-surface-l1);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;box-shadow:0 4px 16px rgba(0,0,0,.12)}.sm-headerMenuItem{display:flex;align-items:center;width:100%;text-align:left;background:0 0;border:0;border-radius:6px;color:var(--dsw-alias-label-primary);cursor:pointer;padding:6px 10px;font-size:13px;line-height:18px}.sm-headerMenuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-headerMenuItemDanger{color:var(--dsw-alias-state-error-primary)}.sm-headerBtn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;height:auto;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-fill-l2);border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;padding:4px 12px;font-size:13px;line-height:18px;white-space:nowrap;transition:background .15s,color .15s,border-color .15s}.sm-headerBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1)}.sm-headerBtn:focus-visible{outline:2px solid var(--dsw-alias-accent-primary);outline-offset:1px}.sm-headerBtn svg{width:16px;height:16px}.sm-migratePanel{display:flex;flex-direction:column;gap:14px;min-width:480px}.sm-migrateRow{display:flex;flex-direction:column;gap:8px}.sm-migrateRow>label{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:16px;font-weight:500}.sm-migrateChips{display:flex;flex-wrap:wrap;gap:6px}.sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:transparent;cursor:pointer;font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary);white-space:nowrap}.sm-migrateChip:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-migrateChip:disabled{opacity:.5;cursor:not-allowed}.sm-migrateChipOn{background:var(--dsw-alias-accent-primary);color:#fff;border-color:var(--dsw-alias-accent-primary)}.sm-migrateEmpty{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.sm-migratePreview{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}.sm-migrateWarn{padding:10px 12px;border:1px solid rgba(217,119,6,.25);border-radius:8px;background:rgba(217,119,6,.08);color:var(--dsw-alias-label-secondary);font-size:13px;line-height:18px}.sm-migrateList{max-height:200px;overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:8px}.sm-headerBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1)}.sm-headerBtnDanger{background:var(--dsw-alias-state-error-tertiary);color:var(--dsw-alias-state-error-primary);border-color:var(--dsw-alias-state-error-primary);font-weight:500}.sm-headerBtnDanger:hover:not(:disabled){background:#d92d20!important;color:#fff!important;border-color:#d92d20!important}.sm-header{display:inline-flex;align-items:center;gap:6px}.sm-annotationToggleOpen{position:relative;z-index:10004}.sm-headerBtnActive{background:var(--dsw-alias-fill-l3);color:var(--dsw-alias-label-primary)}",
473
- ".sm-panelDialog{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:600px;max-width:calc(100vw - 32px);max-height:560px;height:auto;box-sizing:border-box;display:flex;flex-direction:column;gap:0;background:var(--dsw-alias-surface-l1,#fff);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;z-index:9999;opacity:1}.sm-panelDialog .sm-nativeDialogHeader{display:flex;align-items:center;gap:8px;padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none}.sm-panelDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center;flex:1 1 auto}.sm-panelDialog .sm-nativeDialogHeaderActions{display:flex;align-items:center;gap:6px;flex:none}.sm-panelDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;flex:1 1 auto}.sm-nativeDialogFooter,.sm-bulkDialog .sm-nativeDialogFooter,.sm-confirmDialog .sm-nativeDialogFooter,.sm-migrateDialog .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:6px;margin-top:0}.sm-panelDialog .sm-panel{display:flex;flex-direction:column;gap:6px;min-height:0;flex:1 1 auto;overflow:auto;padding:8px 12px}.sm-panelDialog .sm-list{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;overflow:auto}.sm-panelDialog .sm-row{display:flex;align-items:center;gap:8px;padding:6px 10px;min-height:36px;border:1px solid transparent;border-radius:8px;background:transparent;flex-shrink:0}.sm-panelDialog .sm-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-panelDialog .sm-rowCurrent{background:var(--dsw-alias-fill-l2);border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-panelDialog .sm-rowMain{display:flex;align-items:stretch!important;gap:8px;min-width:0;flex:1 1 auto;overflow:visible;text-align:left!important}.sm-panelDialog .sm-rowTitle{min-width:0;flex:1 1 0%;width:100%;align-self:stretch;display:flex;align-items:center;justify-content:flex-start;gap:6px;font-size:12px;line-height:16px;overflow:hidden;text-align:left!important;direction:ltr!important}.sm-confirmDialog{z-index:10000}.sm-confirmDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--dsw-alias-surface-l1,#fff);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);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-confirmDialog .sm-nativeDialogHeader{padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee)}.sm-confirmDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:100%}.sm-confirmDialog .sm-nativeDialogBody{padding:10px 16px;display:flex;flex-direction:column;gap:8px;min-height:0}.sm-confirmDialog .sm-nativeDialogDescription{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);white-space:pre-wrap}.sm-confirmDialog .sm-warn{padding:6px 10px;font-size:12px;line-height:16px;margin-top:0}.sm-confirmDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-confirmDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary);text-align:center}.sm-confirmDialog .sm-nativeDialogCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-confirmDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-confirmDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}@keyframes sm-confirmPop{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sm-confirmDialog.sm-nativeDialog{padding:0;width:auto;max-width:none}.sm-panelDialog .sm-rowTitle>span:first-child{display:block;min-width:0;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:auto;text-align:left!important;direction:ltr!important;unicode-bidi:plaintext}.sm-panelDialog .sm-rowMeta{display:none}.sm-panelDialog .sm-rowActions{display:flex;gap:2px;flex:none;justify-content:flex-end}.sm-panelDialog .sm-rowActions .sm-rowBtn{min-height:22px;padding:0 7px;font-size:11px;line-height:18px;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap}.sm-rowBtn.sm-markIcon{padding:0 6px;font-size:13px;line-height:18px}.sm-panelDialog .sm-rowActions .sm-rowBtn:hover{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-rowActions .sm-rowBtnDanger{color:var(--dsw-alias-state-error-primary)}.sm-panelDialog .sm-filter{flex:none;padding:6px 12px 4px;gap:4px;display:flex;flex-wrap:wrap}.sm-panelDialog .sm-filterBtn{min-height:24px;padding:2px 10px;font-size:11px;line-height:16px;border-radius:4px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}.sm-panelDialog .sm-filterBtn.sm-on{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-badge{font-size:10px;line-height:14px;padding:0 5px;border-radius:6px;flex:none}.sm-panelDialog .sm-error{padding:6px 10px;margin:0;font-size:12px;line-height:16px}.sm-panelDialog .sm-nativeDialogButton{min-height:28px;padding:3px 12px;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer}.sm-panelDialog .sm-nativeDialogCancel{background:transparent}.sm-panelDialog .sm-nativeDialogGhost{background:transparent;border-color:var(--dsw-alias-border-l2)}.sm-panelDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-confirmDialog .sm-nativeDialogDanger,.sm-migrateDialog .sm-nativeDialogDanger,.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-confirmDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-migrateDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-panelDialog .sm-empty{padding:18px 0;font-size:12px;color:var(--dsw-alias-label-tertiary);text-align:center}.sm-panelDialog .sm-footError{font-size:11px;color:var(--dsw-alias-state-error-primary);margin-right:auto;line-height:20px}.sm-panelDialog .sm-moveLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.sm-migrateDialog .sm-nativeDialogFooter{flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-migrateDialog .sm-migrateChip{cursor:pointer;pointer-events:auto;position:relative;z-index:1}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog.sm-nativeDialogLayer{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:auto;z-index:10001}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:360px;max-width:calc(100vw - 32px);max-height:min(70vh,520px);box-sizing:border-box;background-color:#ffffff;background-color:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;padding:0;display:flex;flex-direction:column;gap:0;opacity:1}.sm-migrateDialog{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:min(70vh,520px);box-sizing:border-box;display:flex;flex-direction:column;gap:0;background-color:#ffffff;background-color:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;opacity:1;z-index:10001;backdrop-filter:none;-webkit-backdrop-filter:none}.sm-migrateDialog .sm-nativeDialogHeader{padding:12px 18px;border-bottom:1px solid #eee;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;color:#111;color:var(--dsw-alias-label-primary,#111);text-align:center;width:100%}.sm-migrateDialog .sm-migratePanel{padding:12px 18px;display:flex;flex-direction:column;gap:14px;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogBody{padding:0;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0;gap:8px;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-migrateRow>label{color:#444;color:var(--dsw-alias-label-secondary,#444)}.sm-migrateDialog .sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);background-color:#f5f5f5;background-color:var(--dsw-alias-fill-l2,#f5f5f5);color:#111;color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px;cursor:pointer;pointer-events:auto;position:relative;z-index:1;white-space:nowrap}.sm-migrateDialog .sm-migrateChip:hover:not(:disabled){background-color:#e8e8e8;background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-migrateChipOn{background-color:#356ae6;background-color:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:#356ae6;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateDialog .sm-migrateChip.sm-migrateChipOn:hover:not(:disabled){background-color:#4576f0;background-color:var(--dsw-alias-accent-primary-hover,#4576f0);color:#fff;border-color:#4576f0;border-color:var(--dsw-alias-accent-primary-hover,#4576f0);filter:none}.sm-migrateDialog .sm-migrateChipOn:hover:not(:disabled){filter:brightness(.92)}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog .sm-migrateEmpty{color:#888;color:var(--dsw-alias-label-tertiary,#888)}.sm-migrateDialog .sm-migratePreview{padding:10px 12px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background-color:#f5f5f5;background-color:var(--dsw-alias-fill-l2,#f5f5f5);color:#111;color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px}.sm-migrateDialog .sm-migrateWarn{padding:10px 12px;border:1px solid rgba(217,119,6,.25);border-radius:8px;background-color:rgba(217,119,6,.08);color:#444;color:var(--dsw-alias-label-secondary,#444);font-size:13px;line-height:18px}.sm-migrateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background-color:#fff;background-color:var(--dsw-alias-fill-l2,#fff);color:#111;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-migrateDialog .sm-nativeDialogButton:hover:not(:disabled){background-color:#e8e8e8;background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-nativeDialogConfirm{background-color:#356ae6;background-color:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:#356ae6;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}",
474
- ".sm-panelDialog .sm-nativeDialogHeader{display:flex;align-items:center;gap:8px}.sm-panelHeaderClose{min-height:26px;padding:2px 9px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#555);cursor:pointer;font-size:12px;line-height:18px;flex:none}.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-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-panelHeaderSelect{min-height:26px;padding:2px 9px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#555);cursor:pointer;font-size:12px;line-height:18px;display:inline-flex;align-items:center;gap:4px}.sm-panelHeaderSelect:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderSelect:disabled{opacity:.5;cursor:not-allowed}.sm-panelHeaderSelect.sm-on{background:var(--dsw-alias-accent-primary-bg,rgba(53,106,230,.12));border-color:var(--dsw-alias-accent-primary,#356ae6);color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateCurrent{padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background:var(--dsw-alias-fill-l2,#f5f5f5);font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary,#111)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer{width:360px;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:none;max-height:min(70vh,520px);z-index:auto}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0}.sm-migrateConfirmLayer .sm-nativeDialogButton.sm-nativeDialogConfirm:hover:not(:disabled){background-color:#4576f0;background-color:var(--dsw-alias-accent-primary-hover,#4576f0);color:#fff;border-color:#4576f0;border-color:var(--dsw-alias-accent-primary-hover,#4576f0);filter:none}",
555
+ ".sm-moveItemMeta{color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.sm-panelModal{width:760px;max-width:92vw}.sm-panelModal .sm-rowActions{flex-wrap:wrap;justify-content:flex-end}.sm-headerMenu{position:absolute;right:0;top:100%;margin-top:4px;z-index:50;display:flex;flex-direction:column;min-width:140px;padding:4px;background:var(--dsw-alias-surface-l1,#fff);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;box-shadow:0 4px 16px rgba(0,0,0,.15)}.sm-headerMenuItem{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:0 0;border:0;border-radius:6px;color:var(--dsw-alias-label-primary,#111);cursor:pointer;padding:6px 10px;font-size:13px;line-height:18px;white-space:nowrap}.sm-headerMenuItem:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-headerMenuItem .sm-headerBtnIcon{width:20px;min-width:20px;text-align:center;flex-shrink:0}.sm-headerMenuItemDanger{color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-headerMenuItemDanger:hover{background:rgba(217,45,32,.08)}.sm-headerBtn{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;height:32px;box-sizing:border-box;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-surface-l1,#fff);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;padding:0 10px;font-size:13px;line-height:1;white-space:nowrap;transition:background .15s,color .15s,border-color .15s;flex-shrink:0}.sm-headerBtn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-border-l1)}.sm-headerBtn:focus-visible{outline:2px solid var(--dsw-alias-accent-primary);outline-offset:1px}.sm-headerBtn svg{width:16px;height:16px;display:block;margin:auto;flex-shrink:0}.sm-migratePanel{display:flex;flex-direction:column;gap:14px;min-width:480px}.sm-migrateRow{display:flex;flex-direction:column;gap:8px}.sm-migrateRow>label{color:var(--dsw-alias-label-secondary);font-size:12px;line-height:16px;font-weight:500}.sm-migrateChips{display:flex;flex-wrap:wrap;gap:6px}.sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:transparent;cursor:pointer;font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary);white-space:nowrap}.sm-migrateChip:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-migrateChip:disabled{opacity:.5;cursor:not-allowed}.sm-migrateChipOn{background:var(--dsw-alias-accent-primary);color:#fff;border-color:var(--dsw-alias-accent-primary)}.sm-migrateEmpty{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.sm-migratePreview{padding:10px 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}.sm-migrateWarn{padding:10px 12px;border:1px solid rgba(217,119,6,.25);border-radius:8px;background:rgba(217,119,6,.08);color:var(--dsw-alias-label-secondary);font-size:13px;line-height:18px}.sm-migrateList{max-height:200px;overflow:auto;border:1px solid var(--dsw-alias-border-l2);border-radius:8px}.sm-headerBtnDanger{background:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-state-error-primary,#d92d20);border-color:var(--dsw-alias-state-error-primary,#d92d20);font-weight:500}.sm-headerBtnDanger:hover:not(:disabled){background:var(--dsw-alias-state-error-primary,#d92d20)!important;color:#fff!important;border-color:var(--dsw-alias-state-error-primary,#d92d20)!important}.sm-header{display:inline-flex;align-items:center;gap:6px;flex-wrap:nowrap}.sm-headerSecondaryActions{display:inline-flex;align-items:center;gap:6px;flex-wrap:nowrap}.sm-headerCompactMenu{display:none;position:relative}.sm-headerCompactMenuBtn{width:32px;min-width:32px;height:32px;padding:0;justify-content:center;font-size:16px;line-height:1}.sm-headerBtnIcon{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;font-size:14px;line-height:1;vertical-align:middle;flex-shrink:0}.sm-headerBtn.sm-markIcon{width:32px;min-width:32px;height:32px;padding:0;justify-content:center}.sm-headerBtn.sm-markIcon .sm-headerBtnIcon{width:16px;height:16px;font-size:15px;line-height:1}.sm-headerCompactMenuBtn .sm-headerBtnIcon{width:16px;height:16px;font-size:16px;line-height:1}.sm-annotationToggleOpen{position:relative;z-index:100004}.sm-headerBtnActive{background:var(--dsw-alias-fill-l3);color:var(--dsw-alias-label-primary)}@container (max-width:720px){.sm-headerBtn{width:32px;min-width:32px;height:32px;padding:0;justify-content:center}.sm-headerBtnLabel,.sm-priorityText,.sm-priorityBadge{display:none}.sm-headerBtn.sm-headerBtn-withBadge{width:auto;min-width:32px;padding:0 6px}}@container (max-width:520px){.sm-headerSecondaryActions,.sm-headerSecondaryAction{display:none!important}.sm-headerCompactMenu{display:inline-flex}}",
556
+ ".sm-panelDialog{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);width:600px;max-width:calc(100vw - 32px);max-height:560px;height:auto;box-sizing:border-box;display:flex;flex-direction:column;gap:0;background:var(--dsw-alias-surface-l1,#fff);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;z-index:9999;opacity:1}.sm-panelDialog .sm-nativeDialogHeader{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;position:relative;min-height:46px;box-sizing:border-box}.sm-panelDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;min-width:0;max-width:calc(100% - 140px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;text-align:center;pointer-events:auto;z-index:0}.sm-panelDialog .sm-nativeDialogHeaderActions{display:flex;align-items:center;gap:6px;flex:none;position:relative;z-index:1;margin-left:auto}.sm-nativeDialogFooter,.sm-bulkDialog .sm-nativeDialogFooter,.sm-confirmDialog .sm-nativeDialogFooter,.sm-migrateDialog .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:6px;margin-top:0}.sm-panelDialog .sm-panel{display:flex;flex-direction:column;gap:6px;min-height:0;flex:1 1 auto;overflow:auto;padding:8px 12px}.sm-panelDialog .sm-list{display:flex;flex-direction:column;gap:2px;flex:1 1 auto;min-height:0;overflow:auto}.sm-panelDialog .sm-row{display:flex;align-items:center;gap:8px;padding:6px 10px;min-height:36px;border:1px solid transparent;border-radius:8px;background:transparent;flex-shrink:0}.sm-panelDialog .sm-row:hover{background:var(--dsw-alias-interactive-bg-hover)}.sm-panelDialog .sm-rowCurrent{background:var(--dsw-alias-fill-l2);border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-panelDialog .sm-rowMain{display:flex;align-items:stretch!important;gap:8px;min-width:0;flex:1 1 auto;overflow:visible;text-align:left!important}.sm-panelDialog .sm-rowTitle{min-width:0;flex:1 1 0%;width:100%;align-self:stretch;display:flex;align-items:center;justify-content:flex-start;gap:6px;font-size:12px;line-height:16px;overflow:hidden;text-align:left!important;direction:ltr!important}.sm-confirmDialog{z-index:10000}.sm-confirmDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px)}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--dsw-alias-surface-l1,#fff);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);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-confirmDialog .sm-nativeDialogHeader{position:relative;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);display:flex;align-items:center;justify-content:center;min-height:44px;box-sizing:border-box}.sm-confirmDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm-confirmDialog .sm-nativeDialogBody{padding:10px 16px;display:flex;flex-direction:column;gap:8px;min-height:0}.sm-confirmDialog .sm-nativeDialogDescription{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary);white-space:pre-wrap}.sm-confirmDialog .sm-warn{padding:6px 10px;font-size:12px;line-height:16px;margin-top:0}.sm-confirmDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-confirmDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;cursor:pointer;background:transparent;color:var(--dsw-alias-label-primary);text-align:center}.sm-confirmDialog .sm-nativeDialogCancel:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.sm-confirmDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-confirmDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}@keyframes sm-confirmPop{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}.sm-confirmDialog.sm-nativeDialog{padding:0;width:auto;max-width:none}.sm-panelDialog .sm-rowTitle>span:first-child{display:block;min-width:0;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;flex:1 1 auto;width:auto;text-align:left!important;direction:ltr!important;unicode-bidi:plaintext}.sm-panelDialog .sm-rowMeta{display:none}.sm-panelDialog .sm-rowActions{display:flex;gap:2px;flex:none;justify-content:flex-end}.sm-panelDialog .sm-rowActions .sm-rowBtn{min-height:22px;padding:0 7px;font-size:11px;line-height:18px;border-radius:6px;border:1px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer;white-space:nowrap}.sm-rowBtn.sm-markIcon{padding:0 6px;font-size:13px;line-height:18px}.sm-panelDialog .sm-rowActions .sm-rowBtn:hover{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-rowActions .sm-rowBtnDanger{color:var(--dsw-alias-state-error-primary)}.sm-panelDialog .sm-filter{flex:none;padding:6px 12px 4px;gap:4px;display:flex;flex-wrap:wrap}.sm-panelDialog .sm-filterBtn{min-height:24px;padding:2px 10px;font-size:11px;line-height:16px;border-radius:4px;border:1px solid var(--dsw-alias-border-l2);background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}.sm-panelDialog .sm-filterBtn.sm-on{background:var(--dsw-alias-fill-l2);color:var(--dsw-alias-label-primary)}.sm-panelDialog .sm-badge{font-size:10px;line-height:14px;padding:0 5px;border-radius:6px;flex:none}.sm-panelDialog .sm-error{padding:6px 10px;margin:0;font-size:12px;line-height:16px}.sm-panelDialog .sm-nativeDialogButton{min-height:28px;padding:3px 12px;font-size:12px;line-height:18px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer}.sm-panelDialog .sm-nativeDialogCancel{background:transparent}.sm-panelDialog .sm-nativeDialogGhost{background:transparent;border-color:var(--dsw-alias-border-l2)}.sm-panelDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-confirmDialog .sm-nativeDialogDanger,.sm-migrateDialog .sm-nativeDialogDanger,.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-confirmDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-migrateDialog .sm-nativeDialogDanger:hover:not(:disabled),.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-panelDialog .sm-empty{padding:18px 0;font-size:12px;color:var(--dsw-alias-label-tertiary);text-align:center}.sm-panelDialog .sm-footError{font-size:11px;color:var(--dsw-alias-state-error-primary);margin-right:auto;line-height:20px}.sm-panelDialog .sm-moveLabel{font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary)}.sm-migrateDialog .sm-nativeDialogFooter{flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0}.sm-migrateDialog .sm-migrateChip{cursor:pointer;pointer-events:auto;position:relative;z-index:1}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog.sm-nativeDialogLayer{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:auto;z-index:10001}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:360px;max-width:calc(100vw - 32px);max-height:min(70vh,520px);box-sizing:border-box;background-color:#ffffff;background-color:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;padding:0;display:flex;flex-direction:column;gap:0;opacity:1}.sm-migrateDialog{position:fixed;left:50vw;top:auto;bottom:48px;transform:translateX(-50%);width:min(560px,calc(100vw - 32px));max-height:min(70vh,520px);box-sizing:border-box;display:flex;flex-direction:column;gap:0;background-color:#ffffff;background-color:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:12px;box-shadow:0 16px 48px rgba(0,0,0,.45);overflow:hidden;opacity:1;z-index:10001;backdrop-filter:none;-webkit-backdrop-filter:none}.sm-migrateDialog .sm-nativeDialogHeader{padding:12px 18px;border-bottom:1px solid #eee;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff);position:relative;display:flex;align-items:center;justify-content:center;min-height:44px;box-sizing:border-box}.sm-migrateDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;color:#111;color:var(--dsw-alias-label-primary,#111);text-align:center;width:auto;max-width:calc(100% - 36px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm-migrateDialog .sm-migratePanel{padding:12px 18px;display:flex;flex-direction:column;gap:14px;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogBody{padding:0;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-nativeDialogFooter{padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);flex:none;flex-wrap:wrap;justify-content:space-between;gap:6px;margin-top:0;gap:8px;background-color:#fff;background-color:var(--dsw-alias-surface-l1,#fff)}.sm-migrateDialog .sm-migrateRow>label{color:#444;color:var(--dsw-alias-label-secondary,#444)}.sm-migrateDialog .sm-migrateChip{padding:6px 12px;border-radius:999px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);background-color:#f5f5f5;background-color:var(--dsw-alias-fill-l2,#f5f5f5);color:#111;color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px;cursor:pointer;pointer-events:auto;position:relative;z-index:1;white-space:nowrap}.sm-migrateDialog .sm-migrateChip:hover:not(:disabled){background-color:#e8e8e8;background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-migrateChipOn{background-color:#356ae6;background-color:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:#356ae6;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateDialog .sm-migrateChip.sm-migrateChipOn:hover:not(:disabled){background-color:#4576f0;background-color:var(--dsw-alias-accent-primary-hover,#4576f0);color:#fff;border-color:#4576f0;border-color:var(--dsw-alias-accent-primary-hover,#4576f0);filter:none}.sm-migrateDialog .sm-migrateChipOn:hover:not(:disabled){filter:brightness(.92)}.sm-migrateDialog .sm-migrateChip[disabled]{opacity:.5;cursor:not-allowed}.sm-migrateDialog .sm-migrateEmpty{color:#888;color:var(--dsw-alias-label-tertiary,#888)}.sm-migrateDialog .sm-migratePreview{padding:10px 12px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background-color:#f5f5f5;background-color:var(--dsw-alias-fill-l2,#f5f5f5);color:#111;color:var(--dsw-alias-label-primary,#111);font-size:13px;line-height:18px}.sm-migrateDialog .sm-migrateWarn{padding:10px 12px;border:1px solid rgba(217,119,6,.25);border-radius:8px;background-color:rgba(217,119,6,.08);color:#444;color:var(--dsw-alias-label-secondary,#444);font-size:13px;line-height:18px}.sm-migrateDialog .sm-nativeDialogButton{min-height:28px;padding:3px 14px;font-size:12px;line-height:20px;border:1px solid #d4d4d8;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;cursor:pointer;background-color:#fff;background-color:var(--dsw-alias-fill-l2,#fff);color:#111;color:var(--dsw-alias-label-primary,#111);text-align:center}.sm-migrateDialog .sm-nativeDialogButton:hover:not(:disabled){background-color:#e8e8e8;background-color:var(--dsw-alias-interactive-bg-hover,#e8e8e8)}.sm-migrateDialog .sm-nativeDialogConfirm{background-color:#356ae6;background-color:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:#356ae6;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}",
557
+ ".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:#e53e3e;border:1.5px solid var(--dsw-alias-surface-l1,#fff)}.sm-panelHeaderWhale .sm-updateSpinner{position:absolute;inset:2px;border:2px solid transparent;border-top-color:var(--dsw-alias-accent-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(--dsw-alias-surface-l1,#fff);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-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-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-fill-l2,#f5f5f5);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:#d97706;background:rgba(217,119,6,.08);padding:8px 10px;border-radius:6px;border:1px solid rgba(217,119,6,.2)}.sm-updateStatusBox.sm-error{color:#dc2626;background:rgba(220,38,38,.08);padding:8px 10px;border-radius:6px;border:1px solid rgba(220,38,38,.2)}.sm-updateStatusBox.sm-success{color:#16a34a;background:rgba(22,163,74,.08);padding:8px 10px;border-radius:6px;border:1px solid rgba(22,163,74,.2)}.sm-settingsCard{background:var(--dsw-alias-surface-l1,#fff);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-fill-l2,#f0f0f0);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-accent-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;padding:3px 8px;font-size:12px;line-height:20px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:6px;background:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);cursor:pointer;outline:none}.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-panelHeaderSelect{min-height:26px;padding:2px 9px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary,#555);cursor:pointer;font-size:12px;line-height:18px;display:inline-flex;align-items:center;gap:4px}.sm-panelHeaderSelect:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#eee);color:var(--dsw-alias-label-primary,#111)}.sm-panelHeaderSelect:disabled{opacity:.5;cursor:not-allowed}.sm-panelHeaderSelect.sm-on{background:var(--dsw-alias-accent-primary-bg,rgba(53,106,230,.12));border-color:var(--dsw-alias-accent-primary,#356ae6);color:var(--dsw-alias-accent-primary,#356ae6)}.sm-migrateCurrent{padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;background:var(--dsw-alias-fill-l2,#f5f5f5);font-size:13px;line-height:18px;color:var(--dsw-alias-label-primary,#111)}.sm-migrateConfirmLayer.sm-confirmDialog.sm-nativeDialogLayer{width:360px;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:none;max-height:min(70vh,520px);z-index:auto}.sm-migrateConfirmLayer .sm-migratePanel{min-width:0}.sm-migrateConfirmLayer .sm-nativeDialogButton.sm-nativeDialogConfirm:hover:not(:disabled){background-color:#4576f0;background-color:var(--dsw-alias-accent-primary-hover,#4576f0);color:#fff;border-color:#4576f0;border-color:var(--dsw-alias-accent-primary-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-fill-l2,#f5f5f5);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-accent-primary,#356ae6);border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-settingsBadgeLink svg{flex:none}[data-sm-theme=dark] .sm-settingsBadgeLink{background:#2a2a30!important;color:#b3b3b3!important;border-color:#3a3a40!important}[data-sm-theme=dark] .sm-settingsBadgeLink:hover{background:rgba(255,255,255,.06)!important;color:#5d8aff!important;border-color:#5d8aff!important}.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}",
475
558
 
476
559
  // Theme colors are scoped to the plugin dialogs. DSH exposes its
477
560
  // actual theme through `body[data-ds-dark-theme]` and color-scheme;
478
561
  // keeping these values local avoids changing DSH's global variables.
479
- "[data-sm-theme=light] .sm-panelDialog,[data-sm-theme=light] .sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=light] .sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog{--dsw-alias-surface-l1:#fff;--dsw-alias-label-primary:#1f1f1f;--dsw-alias-label-secondary:#555;--dsw-alias-label-tertiary:#888;--dsw-alias-border-l1:#d4d4d8;--dsw-alias-border-l2:#e5e5e5;--dsw-alias-fill-l2:#f5f5f5;--dsw-alias-interactive-bg-hover:#eee;--dsw-alias-state-error-primary:#d92d20;--dsw-alias-state-warning-primary:#d97706;--dsw-alias-accent-primary:#356ae6;--dsw-alias-accent-primary-bg:rgba(53,106,230,.12);background:#fff!important;background-color:#fff!important;color:#1f1f1f!important;border-color:#e5e5e5!important}",
480
- "[data-sm-theme=dark] .sm-panelDialog,[data-sm-theme=dark] .sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=dark] .sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=dark] .sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialog{--dsw-alias-surface-l1:#1f1f23;--dsw-alias-label-primary:#ececec;--dsw-alias-label-secondary:#b3b3b3;--dsw-alias-label-tertiary:#999;--dsw-alias-border-l1:#555;--dsw-alias-border-l2:#3a3a40;--dsw-alias-fill-l1:#1a1a1e;--dsw-alias-fill-l2:#2a2a30;--dsw-alias-interactive-bg-hover:rgba(255,255,255,.06);--dsw-alias-state-error-primary:#f47171;--dsw-alias-state-warning-primary:#f0a040;--dsw-alias-accent-primary:#5d8aff;--dsw-alias-accent-primary-bg:rgba(93,138,255,.18);background:#1f1f23!important;background-color:#1f1f23!important;color:#ececec!important;border-color:#3a3a40!important}","[data-sm-theme=dark] .sm-header{--dsw-alias-surface-l1:#1f1f23;--dsw-alias-label-primary:#ececec;--dsw-alias-label-secondary:#b3b3b3;--dsw-alias-label-tertiary:#999;--dsw-alias-border-l1:#555;--dsw-alias-border-l2:#3a3a40;--dsw-alias-fill-l1:#1a1a1e;--dsw-alias-fill-l2:#2a2a30;--dsw-alias-interactive-bg-hover:rgba(255,255,255,.06);--dsw-alias-accent-primary:#5d8aff;--dsw-alias-accent-primary-bg:rgba(93,138,255,.18)}",
481
- "[data-sm-theme=light] .sm-panelDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-panelDialog .sm-nativeDialogFooter,[data-sm-theme=light] .sm-confirmDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-confirmDialog .sm-nativeDialogFooter,[data-sm-theme=light] .sm-migrateDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-migrateDialog .sm-nativeDialogBody,[data-sm-theme=light] .sm-migrateDialog .sm-nativeDialogFooter{background:#fff!important;background-color:#fff!important;border-color:#e5e5e5!important}",
482
- "[data-sm-theme=dark] .sm-panelDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-panelDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-confirmDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-confirmDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-migrateDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-migrateDialog .sm-nativeDialogBody,[data-sm-theme=dark] .sm-migrateDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-bulkDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-bulkDialog .sm-nativeDialogBody,[data-sm-theme=dark] .sm-bulkDialog .sm-nativeDialogFooter{background:#1f1f23!important;background-color:#1f1f23!important;border-color:#3a3a40!important}[data-sm-theme=dark] .sm-bulkDialog .sm-bulkSessionList,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkResultList,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkProgressBar{background:#1a1a1e!important;background-color:#1a1a1e!important;border-color:#3a3a40!important;color:var(--dsw-alias-label-primary,#ececec)}[data-sm-theme=dark] .sm-bulkDialog .sm-bulkSessionItem,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkResultItemTitle,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkResultItem{color:var(--dsw-alias-label-primary,#ececec)}",
562
+ "[data-sm-theme=light] .sm-panelDialog,[data-sm-theme=light] .sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=light] .sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=light] .sm-updateDialogLayer .sm-nativeDialog,[data-sm-theme=light] .sm-settingsCard{--dsw-alias-surface-l1:#fff;--dsw-alias-label-primary:#1f1f1f;--dsw-alias-label-secondary:#555;--dsw-alias-label-tertiary:#888;--dsw-alias-border-l1:#d4d4d8;--dsw-alias-border-l2:#e5e5e5;--dsw-alias-fill-l2:#f5f5f5;--dsw-alias-interactive-bg-hover:#eee;--dsw-alias-state-error-primary:#d92d20;--dsw-alias-state-warning-primary:#d97706;--dsw-alias-accent-primary:#356ae6;--dsw-alias-accent-primary-bg:rgba(53,106,230,.12);background:#fff!important;background-color:#fff!important;color:#1f1f1f!important;border-color:#e5e5e5!important}",
563
+ "[data-sm-theme=dark] .sm-panelDialog,[data-sm-theme=dark] .sm-confirmDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=dark] .sm-migrateDialog.sm-nativeDialogLayer .sm-nativeDialog,[data-sm-theme=dark] .sm-updateDialogLayer .sm-nativeDialog,[data-sm-theme=dark] .sm-settingsCard,[data-sm-theme=dark] .sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialog{--dsw-alias-surface-l1:#1f1f23;--dsw-alias-label-primary:#ececec;--dsw-alias-label-secondary:#b3b3b3;--dsw-alias-label-tertiary:#999;--dsw-alias-border-l1:#555;--dsw-alias-border-l2:#3a3a40;--dsw-alias-fill-l1:#1a1a1e;--dsw-alias-fill-l2:#2a2a30;--dsw-alias-interactive-bg-hover:rgba(255,255,255,.06);--dsw-alias-state-error-primary:#f47171;--dsw-alias-state-warning-primary:#f0a040;--dsw-alias-accent-primary:#5d8aff;--dsw-alias-accent-primary-bg:rgba(93,138,255,.18);background:#1f1f23!important;background-color:#1f1f23!important;color:#ececec!important;border-color:#3a3a40!important}","[data-sm-theme=dark] .sm-header{--dsw-alias-surface-l1:#1f1f23;--dsw-alias-label-primary:#ececec;--dsw-alias-label-secondary:#b3b3b3;--dsw-alias-label-tertiary:#999;--dsw-alias-border-l1:#555;--dsw-alias-border-l2:#3a3a40;--dsw-alias-fill-l1:#1a1a1e;--dsw-alias-fill-l2:#2a2a30;--dsw-alias-interactive-bg-hover:rgba(255,255,255,.06);--dsw-alias-state-error-primary:#f47171;--dsw-alias-accent-primary:#5d8aff;--dsw-alias-accent-primary-bg:rgba(93,138,255,.18)}",
564
+ "[data-sm-theme=light] .sm-panelDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-panelDialog .sm-nativeDialogFooter,[data-sm-theme=light] .sm-confirmDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-confirmDialog .sm-nativeDialogFooter,[data-sm-theme=light] .sm-migrateDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-migrateDialog .sm-nativeDialogBody,[data-sm-theme=light] .sm-migrateDialog .sm-nativeDialogFooter,[data-sm-theme=light] .sm-updateDialog .sm-nativeDialogHeader,[data-sm-theme=light] .sm-updateDialog .sm-nativeDialogFooter{background:#fff!important;background-color:#fff!important;border-color:#e5e5e5!important}",
565
+ "[data-sm-theme=dark] .sm-panelDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-panelDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-confirmDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-confirmDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-migrateDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-migrateDialog .sm-nativeDialogBody,[data-sm-theme=dark] .sm-migrateDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-bulkDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-bulkDialog .sm-nativeDialogBody,[data-sm-theme=dark] .sm-bulkDialog .sm-nativeDialogFooter,[data-sm-theme=dark] .sm-updateDialog .sm-nativeDialogHeader,[data-sm-theme=dark] .sm-updateDialog .sm-nativeDialogFooter{background:#1f1f23!important;background-color:#1f1f23!important;border-color:#3a3a40!important}[data-sm-theme=dark] .sm-updateVersionGrid{background:#1a1a1e!important;background-color:#1a1a1e!important;border-color:#3a3a40!important}[data-sm-theme=dark] .sm-updateVersionLabel{color:#b3b3b3!important}[data-sm-theme=dark] .sm-updateVersionValue{color:#ececec!important}[data-sm-theme=dark] .sm-settingsHeader,[data-sm-theme=dark] .sm-settingsSection{border-color:#3a3a40!important}[data-sm-theme=dark] .sm-settingsTag{background:#2a2a30!important;color:#b3b3b3!important}[data-sm-theme=dark] .sm-bulkDialog .sm-bulkSessionList,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkResultList,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkProgressBar{background:#1a1a1e!important;background-color:#1a1a1e!important;border-color:#3a3a40!important;color:var(--dsw-alias-label-primary,#ececec)}[data-sm-theme=dark] .sm-bulkDialog .sm-bulkSessionItem,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkResultItemTitle,[data-sm-theme=dark] .sm-bulkDialog .sm-bulkResultItem{color:var(--dsw-alias-label-primary,#ececec)}[data-sm-theme=dark] .sm-settingsSelect{background:#2a2a30!important;color:#ececec!important;border-color:#3a3a40!important}",
483
566
  ".sm-panelDialog{max-height:min(640px,calc(100vh - 32px))}.sm-panelDialog .sm-panel{min-width:0;overflow:hidden}",
484
567
  ".sm-panelTools{display:flex;flex-direction:column;gap:8px;flex:none;padding:2px 0 6px}",
485
568
  ".sm-queryInput,.sm-viewSelect{box-sizing:border-box;width:100%;min-width:0;height:32px;padding:5px 9px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;background:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);font:inherit;font-size:12px;line-height:20px}",
@@ -491,13 +574,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
491
574
  ".sm-markIcon{min-width:25px;padding-left:5px;padding-right:5px;font-size:15px}.sm-markIcon.sm-markOn{color:var(--dsw-alias-accent-primary,#356ae6)!important;background:var(--dsw-alias-fill-l2,#eee)}.sm-priorityBadge{padding:0 5px;border-radius:4px;background:var(--dsw-alias-fill-l2,#eee);color:var(--dsw-alias-label-secondary,#666)}.sm-priority-1{color:#c2410c;background:rgba(234,88,12,.12)}.sm-priority-2{color:#a16207;background:rgba(202,138,4,.12)}",
492
575
  "[data-sm-theme=dark] .sm-priority-1{color:#fdba74}[data-sm-theme=dark] .sm-priority-2{color:#fde68a}",
493
576
  ".sm-tagChip,.sm-noteBadge{max-width:88px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;border:0;border-radius:4px;background:var(--dsw-alias-fill-l2,#eee);color:var(--dsw-alias-label-secondary,#666);font:inherit;line-height:16px;padding:0 5px;cursor:pointer}.sm-noteBadge{background:transparent}.sm-tagChip:hover,.sm-noteBadge:hover{color:var(--dsw-alias-accent-primary,#356ae6)}",
494
- ".sm-markFilters{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.sm-markFiltersGroup{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.sm-markFiltersSpacer{flex:1 1 auto;min-width:12px}.sm-markFilterToggle{height:28px;padding:3px 10px;white-space:nowrap}.sm-markFilterToggle:disabled{opacity:.5;cursor:not-allowed}.sm-bulkSelectBtn{height:28px;padding:3px 10px;white-space:nowrap}.sm-bulkSelectBtn:disabled{opacity:.5;cursor:not-allowed}.sm-header{flex-wrap:wrap}",
495
- ".sm-annotationDialog.sm-nativeDialogLayer{position:fixed;display:block;pointer-events:none;z-index:10002;background:transparent}.sm-annotationDialog .sm-nativeDialogBackdrop{display:none}.sm-annotationDialog.sm-annotationDialog-anchored.sm-nativeDialogLayer{inset:auto;background:transparent}.sm-annotationDialog.sm-confirmDialog.sm-nativeDialogLayer:not(.sm-annotationDialog-anchored){inset:50% auto auto calc(50vw + 308px);transform:translateY(-50%);max-height:calc(100vh - 32px)}.sm-panelDialog.sm-annotationSurface{position:absolute;width:360px;max-height:min(680px,calc(100vh - 32px));pointer-events:auto;z-index:10003;box-shadow:0 16px 48px rgba(0,0,0,.25)}.sm-panelDialog.sm-annotationSurface.sm-annotationSurface-anchored{position:relative;transform:none;left:auto;top:auto;margin:0}.sm-annotationCloseHint{margin:0 16px 8px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}",
577
+ ".sm-markFilters{display:flex;flex-wrap:wrap;align-items:center;gap:8px}.sm-markFiltersGroup{display:flex;flex-wrap:wrap;align-items:center;gap:6px}.sm-markFiltersSpacer{flex:1 1 auto;min-width:12px}.sm-markFilterToggle{height:28px;padding:3px 10px;white-space:nowrap}.sm-markFilterToggle:disabled{opacity:.5;cursor:not-allowed}.sm-bulkSelectBtn{height:28px;padding:3px 10px;white-space:nowrap}.sm-bulkSelectBtn:disabled{opacity:.5;cursor:not-allowed}",
578
+ "#dsh-session-manager-overlay-root{position:fixed!important;inset:0!important;width:100%!important;height:100%!important;z-index:99999!important;pointer-events:none!important;overflow:visible!important}.sm-annotationDialog.sm-nativeDialogLayer{position:fixed;display:block;pointer-events:none;z-index:100002;background:transparent}.sm-annotationDialog .sm-nativeDialogBackdrop{display:none}.sm-annotationDialog.sm-annotationDialog-anchored.sm-nativeDialogLayer,.sm-confirmDialog.sm-confirmDialog-anchored.sm-nativeDialogLayer{inset:auto;background:transparent}.sm-annotationDialog.sm-confirmDialog.sm-nativeDialogLayer:not(.sm-annotationDialog-anchored){inset:50% auto auto calc(50vw + 308px);transform:translateY(-50%);max-height:calc(100vh - 32px)}.sm-panelDialog.sm-annotationSurface{position:absolute;width:360px;max-height:min(680px,calc(100vh - 32px));pointer-events:auto;z-index:100003;box-shadow:0 16px 48px rgba(0,0,0,.25)}.sm-panelDialog.sm-annotationSurface.sm-annotationSurface-anchored{position:relative;transform:none;left:auto;top:auto;margin:0}.sm-annotationCloseHint{margin:0 16px 8px;font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary)}",
496
579
  ".sm-annotationBody{padding:14px 16px;display:flex;flex-direction:column;gap:12px;min-height:0;overflow:auto;flex:1 1 auto}.sm-annotationTarget{font-size:12px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-secondary,#666)}.sm-annotationChecks{display:grid;grid-template-columns:auto 1fr;column-gap:14px;row-gap:4px;align-items:center;font-size:13px}.sm-annotationChecks>label{display:flex;gap:6px;align-items:center;cursor:pointer}.sm-annotationChecks .sm-annotationPriority{display:inline-flex;align-items:center;gap:6px;font-size:13px;line-height:18px;color:inherit}.sm-annotationChecks .sm-prioritySelectInline{height:24px;padding:2px 6px;font-size:12px;line-height:18px;min-width:104px;width:auto;border-radius:6px;color:var(--dsw-alias-label-primary,#111)}.sm-annotationChecks>small{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888);justify-self:start}.sm-annotationHint,.sm-annotationBody small{font-size:11px;line-height:16px;color:var(--dsw-alias-label-tertiary,#888)}",
497
580
  ".sm-noteInput{box-sizing:border-box;width:100%;min-height:60px;resize:vertical;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:7px;padding:8px;background:var(--dsw-alias-surface-l1,#fff);color:var(--dsw-alias-label-primary,#111);font:inherit;font-size:13px;line-height:19px}.sm-noteInput:focus-visible{outline:2px solid var(--dsw-alias-accent-primary,#356ae6);outline-offset:2px}.sm-markConflict{display:flex;flex-direction:column;gap:5px;font-size:12px;padding:8px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:6px}.sm-fieldWithClear .sm-fieldRow{position:relative;display:flex;align-items:flex-start;gap:4px}.sm-fieldRow .sm-queryInput{flex:1 1 auto;min-width:0}.sm-fieldRowNote{align-items:stretch}.sm-fieldClear{position:absolute;top:5px;right:6px;width:22px;height:22px;border:0;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:4px;font-size:14px;line-height:18px;display:inline-flex;align-items:center;justify-content:center;padding:0}.sm-fieldClear:hover,.sm-fieldClear:focus-visible{color:var(--dsw-alias-accent-primary);background:var(--dsw-alias-interactive-bg-hover);outline:none}.sm-fieldClearNote{top:6px}.sm-importGroup{display:flex;flex-direction:column;gap:8px;padding:10px 16px;border-top:1px solid var(--dsw-alias-border-l2,#eee);background:var(--dsw-alias-fill-l1,#fafbfc)}.sm-importGroupButtons{display:flex;justify-content:space-between;align-items:center;gap:8px}.sm-importBtn{cursor:pointer;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-surface-l1,#fff);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;padding:5px 12px;font-size:12px;line-height:18px}.sm-importBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.sm-importBtn:disabled{opacity:.5;cursor:not-allowed}.sm-importStatus{margin:0 16px;padding:8px 10px;font-size:12px;line-height:18px;background:var(--dsw-alias-accent-primary-bg,rgba(53,106,230,.08));color:var(--dsw-alias-label-secondary);border-radius:6px;white-space:pre-wrap;word-break:break-word}",
498
581
  ".sm-bulkBar{box-sizing:border-box;display:grid;grid-template-columns:repeat(6,minmax(0,1fr));align-items:stretch;gap:6px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:10px;background:var(--dsw-alias-fill-l1,#fafbfc)}.sm-bulkBar .sm-bulkSummary{grid-column:1/-1;color:var(--dsw-alias-label-primary,#111);font-size:12px;line-height:18px;font-weight:500;margin:0 0 2px}",
499
582
  ".sm-bulkSummary{color:var(--dsw-alias-label-primary,#111);font-size:12px;line-height:18px;font-weight:500}",
500
583
  "",
584
+ ".sm-panelDialog button,.sm-panelDialog a,.sm-panelHeaderGithub,.sm-panelHeaderWhale,.sm-panelHeaderClose,.sm-headerBtn,.sm-headerMenuItem,.sm-updateDialog button,.sm-settingsCard button,.sm-settingsCard a,.sm-rowBtn,.sm-bulkBtn{outline:none;box-shadow:none;-webkit-appearance:none;-moz-appearance:none;appearance:none}.sm-panelDialog button:hover,.sm-panelDialog a:hover,.sm-panelHeaderGithub:hover,.sm-panelHeaderWhale:hover,.sm-panelHeaderClose:hover,.sm-headerBtn:hover,.sm-headerMenuItem:hover,.sm-updateDialog button:hover,.sm-settingsCard button:hover,.sm-rowBtn:hover,.sm-bulkBtn:hover{outline:none;box-shadow:none}",
501
585
  ".sm-bulkBar .sm-bulkBtn{cursor:pointer;color:var(--dsw-alias-label-secondary,#666);background:var(--dsw-alias-surface-l1,#fff);border:1px solid var(--dsw-alias-border-l2,#ddd);border-radius:8px;padding:4px 10px;font-size:12px;line-height:18px;display:inline-flex;align-items:center;justify-content:center;gap:4px;white-space:nowrap;text-align:center}",
502
586
  ".sm-bulkBar .sm-bulkBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary,#111)}",
503
587
  ".sm-bulkBar .sm-bulkBtn:disabled{opacity:.5;cursor:not-allowed}",
@@ -508,7 +592,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
508
592
  ".sm-bulkRowCheckbox input{width:14px;height:14px;cursor:pointer;margin:0}",
509
593
  ".sm-bulkRowCheckbox input:disabled{cursor:not-allowed}",
510
594
  ".sm-rowBulkSelected{border-color:var(--dsw-alias-accent-primary,#356ae6);background:var(--dsw-alias-accent-primary-bg,rgba(53,106,230,.06))}",
511
- ".sm-bulkDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px);z-index:10002}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--dsw-alias-surface-l1,#fff);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);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-bulkDialog .sm-nativeDialogHeader{padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;display:flex;align-items:center;gap:8px}.sm-bulkDialog .sm-nativeDialogTitle{margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:100%}.sm-bulkDialog .sm-nativeDialogBody{padding:12px 16px;display:flex;flex-direction:column;gap:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-bulkDialog .sm-nativeDialogFooter{padding:10px 16px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px}.sm-bulkDialog .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-bulkDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-bulkDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-bulkDialog .sm-nativeDialog select.sm-viewSelect{font-size:13px;line-height:20px;height:32px;padding:5px 9px}",
595
+ ".sm-bulkDialog.sm-nativeDialogLayer{position:fixed;left:calc(50vw + 184px);top:calc(50vh - 90px);width:360px;max-width:calc(100vw - 32px);max-height:none;display:block;align-items:initial;justify-content:initial;box-sizing:border-box;background:transparent;border:0;box-shadow:none;padding:0;inset:calc(50vh - 90px) auto auto calc(50vw + 308px);z-index:10002}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialogBackdrop{display:none}.sm-bulkDialog.sm-nativeDialogLayer .sm-nativeDialog{position:relative;left:auto;top:auto;transform:none;width:auto;box-sizing:border-box;background:var(--dsw-alias-surface-l1,#fff);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);padding:0;overflow:hidden;animation:sm-confirmPop .14s ease-out}.sm-bulkDialog .sm-nativeDialogHeader{padding:10px 16px;border-bottom:1px solid var(--dsw-alias-border-l2,#eee);flex:none;position:relative;display:flex;align-items:center;justify-content:center;min-height:44px;box-sizing:border-box}.sm-bulkDialog .sm-nativeDialogTitle{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);margin:0;font-size:14px;line-height:20px;font-weight:600;text-align:center;width:auto;max-width:calc(100% - 32px);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sm-bulkDialog .sm-nativeDialogBody{padding:12px 16px;display:flex;flex-direction:column;gap:10px;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}.sm-bulkDialog .sm-nativeDialogFooter{padding:10px 16px;display:flex;flex-wrap:wrap;justify-content:space-between;gap:6px}.sm-bulkDialog .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-bulkDialog .sm-nativeDialogConfirm{background:var(--dsw-alias-accent-primary,#356ae6);color:#fff;border-color:var(--dsw-alias-accent-primary,#356ae6)}.sm-bulkDialog .sm-nativeDialogConfirm:hover:not(:disabled){filter:brightness(.94)}.sm-bulkDialog .sm-nativeDialogDanger{background:var(--dsw-alias-state-error-primary,#d92d20);color:#fff;border-color:var(--dsw-alias-state-error-primary,#d92d20)}.sm-bulkDialog .sm-nativeDialogDanger:hover:not(:disabled){filter:brightness(.92)}.sm-bulkDialog .sm-nativeDialog select.sm-viewSelect{font-size:13px;line-height:20px;height:32px;padding:5px 9px}",
512
596
  ".sm-bulkDialog .sm-nativeDialog{width:100%;max-height:min(640px,calc(100vh - 32px))}",
513
597
  ".sm-bulkDialogBody{display:flex;flex-direction:column;gap:12px;min-height:0}",
514
598
  ".sm-bulkDialogSummary{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}",
@@ -526,13 +610,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
526
610
  ".sm-bulkResultItemReason{color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px;word-break:break-word}",
527
611
  ".sm-bulkResultItemReasonSkip{color:var(--dsw-alias-label-tertiary,#888)}",
528
612
  ".sm-bulkResultFooter{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}",
529
- ".sm-footerBtn-wide{flex:1 1 auto;min-width:0;min-height:36px;justify-content:flex-start;padding:0 10px;border-radius:12px;font-size:13px;line-height:20px;gap:8px}",
613
+ ".sm-footerBtn-wide{flex:none;display:flex;align-items:center;gap:8px;width:calc(100% + 8px);height:34px;margin:4px -4px 4px;padding:6px 2px 6px 10px;box-sizing:border-box;border:none;border-radius:12px;cursor:pointer;overflow:hidden;font-size:14px;line-height:22px}",
530
614
  ".sm-footerBtn-wide:hover,.sm-footerBtn-wide:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
531
- ".sm-footerBtn-rail{width:36px;height:36px;padding:0;justify-content:center;border-radius:12px;color:var(--dsw-alias-label-secondary)}",
615
+ ".sm-footerBtn-rail{width:36px;height:36px;padding:0;justify-content:center;border-radius:12px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:0 0;border:0;display:inline-flex;align-items:center}",
532
616
  ".sm-footerBtn-rail:hover,.sm-footerBtn-rail:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
533
617
  ".sm-footerBtn-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}",
534
- ".sm-footer-wide{display:flex;width:100%}",
535
- ".sm-footer-rail{display:flex;width:100%;justify-content:center}",
618
+ ".sm-overlayLayer{position:fixed;inset:0;pointer-events:none}",
619
+ ".sm-overlayLayer>*{pointer-events:auto}",
620
+ ".sm-overlayBackdrop{position:fixed;inset:0;background:transparent;pointer-events:auto}",
536
621
  "@media(max-width:720px){.sm-panelSelects{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.sm-panelDialog .sm-row{flex-wrap:wrap}.sm-panelDialog .sm-rowMain{flex-basis:100%}.sm-panelDialog .sm-rowActions{width:100%;min-width:0;flex:1 1 100%;justify-content:flex-start}}@media(max-width:540px){.sm-panelSelects{grid-template-columns:minmax(0,1fr)}}",
537
622
  ].join("");
538
623
 
@@ -656,6 +741,268 @@ function nextDialogZ() { return ++dialogZStackCounter; }
656
741
  try { installAnchor(); } catch (_) {}
657
742
 
658
743
  const h = (type, props, ...children) => React.createElement(type, props, ...children);
744
+
745
+ let overlayRootElement = null;
746
+ function getOverlayRoot() {
747
+ if (typeof document === "undefined" || !document.body) return null;
748
+ if (typeof document.createElement !== "function") return null;
749
+ const contains = typeof document.body.contains === "function" ? (el) => document.body.contains(el) : () => true;
750
+ if (!overlayRootElement || !contains(overlayRootElement)) {
751
+ let el = typeof document.getElementById === "function"
752
+ ? document.getElementById("dsh-session-manager-overlay-root")
753
+ : (typeof document.querySelector === "function" ? document.querySelector("#dsh-session-manager-overlay-root") : null);
754
+ if (!el) {
755
+ el = document.createElement("div");
756
+ el.id = "dsh-session-manager-overlay-root";
757
+ el.style.position = "fixed";
758
+ el.style.top = "0";
759
+ el.style.left = "0";
760
+ el.style.width = "100%";
761
+ el.style.height = "100%";
762
+ el.style.zIndex = "99999";
763
+ el.style.overflow = "visible";
764
+ el.style.pointerEvents = "none";
765
+ if (typeof document.body.appendChild === "function") {
766
+ document.body.appendChild(el);
767
+ }
768
+ }
769
+ overlayRootElement = el;
770
+ }
771
+ try {
772
+ if (document.documentElement && typeof document.documentElement.getAttribute === "function") {
773
+ const currentTheme = document.documentElement.getAttribute(SM_THEME_ATTR);
774
+ if (currentTheme && overlayRootElement && typeof overlayRootElement.setAttribute === "function") {
775
+ if (overlayRootElement.getAttribute(SM_THEME_ATTR) !== currentTheme) {
776
+ overlayRootElement.setAttribute(SM_THEME_ATTR, currentTheme);
777
+ }
778
+ }
779
+ }
780
+ } catch (_) {}
781
+ return overlayRootElement;
782
+ }
783
+
784
+ function getPortalFn() {
785
+ if (typeof React.createPortal === "function") return React.createPortal;
786
+ if (typeof window !== "undefined") {
787
+ if (window.__smReactDOM && typeof window.__smReactDOM.createPortal === "function") return window.__smReactDOM.createPortal;
788
+ if (window.ReactDOM && typeof window.ReactDOM.createPortal === "function") return window.ReactDOM.createPortal;
789
+ if (window.React && typeof window.React.createPortal === "function") return window.React.createPortal;
790
+ }
791
+ try {
792
+ const RDOM = require("react-dom");
793
+ if (RDOM && typeof RDOM.createPortal === "function") return RDOM.createPortal;
794
+ } catch (_) {}
795
+ try {
796
+ const RDOMC = require("react-dom/client");
797
+ if (RDOMC && typeof RDOMC.createPortal === "function") return RDOMC.createPortal;
798
+ } catch (_) {}
799
+ return null;
800
+ }
801
+
802
+ function renderInOverlay(vnode) {
803
+ if (!vnode) return null;
804
+ const root = getOverlayRoot();
805
+ const portal = getPortalFn();
806
+ if (portal && root) {
807
+ return portal(vnode, root);
808
+ }
809
+ return vnode;
810
+ }
811
+
812
+ function OverlayLayer({ children, className, style, onBackdropClick, role = "presentation", onKeyDown }) {
813
+ const zRef = useRef(null);
814
+ if (zRef.current === null) {
815
+ zRef.current = nextDialogZ();
816
+ }
817
+ const root = getOverlayRoot();
818
+ const portal = getPortalFn();
819
+
820
+ const layerStyle = {
821
+ position: "fixed",
822
+ inset: "0",
823
+ zIndex: zRef.current,
824
+ pointerEvents: "none",
825
+ ...(style || {})
826
+ };
827
+
828
+ const content = h("div", {
829
+ className: "sm-overlayLayer " + (className || ""),
830
+ style: layerStyle,
831
+ role: role,
832
+ onKeyDown: onKeyDown
833
+ },
834
+ onBackdropClick ? h("div", {
835
+ className: "sm-nativeDialogBackdrop sm-overlayBackdrop",
836
+ style: {
837
+ position: "fixed",
838
+ inset: "0",
839
+ background: "transparent",
840
+ pointerEvents: "auto",
841
+ zIndex: -1
842
+ },
843
+ onClick: (e) => {
844
+ if (e.target === e.currentTarget && onBackdropClick) {
845
+ onBackdropClick(e);
846
+ }
847
+ }
848
+ }) : null,
849
+ children
850
+ );
851
+
852
+ if (portal && root) {
853
+ return portal(content, root);
854
+ }
855
+ return content;
856
+ }
857
+
858
+ const raf = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 16);
859
+ const caf = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : (id) => clearTimeout(id);
860
+
861
+ function useFloatingPosition(anchor, open, options = {}) {
862
+ const {
863
+ placement = "bottom-end",
864
+ dialogWidth = 360,
865
+ dialogHeight = 220,
866
+ gap = 8,
867
+ margin = 16
868
+ } = options;
869
+
870
+ const [coords, setCoords] = useState(() => {
871
+ if (anchor && typeof anchor.top === "number" && typeof anchor.left === "number") {
872
+ return { top: anchor.top, left: anchor.left };
873
+ }
874
+ return null;
875
+ });
876
+
877
+ const anchorRef = useRef(anchor);
878
+ anchorRef.current = anchor;
879
+
880
+ useEffect(() => {
881
+ if (!open) return;
882
+ const currentAnchor = anchorRef.current;
883
+ if (!currentAnchor) return;
884
+
885
+ if (typeof currentAnchor.top === "number" && typeof currentAnchor.getBoundingClientRect !== "function") {
886
+ setCoords({ top: currentAnchor.top, left: currentAnchor.left });
887
+ return;
888
+ }
889
+
890
+ const getEl = () => {
891
+ const a = anchorRef.current;
892
+ if (!a) return null;
893
+ if (typeof a.getBoundingClientRect === "function") return a;
894
+ if (a.current && typeof a.current.getBoundingClientRect === "function") return a.current;
895
+ if (a.nodeType === 1) return a;
896
+ return null;
897
+ };
898
+
899
+ const targetEl = getEl();
900
+ if (!targetEl) return;
901
+
902
+ let frameId = 0;
903
+ const update = () => {
904
+ caf(frameId);
905
+ frameId = raf(() => {
906
+ const el = getEl();
907
+ if (!el) return;
908
+ const r = el.getBoundingClientRect();
909
+ if (!r || (r.width === 0 && r.height === 0 && r.top === 0 && r.bottom === 0)) {
910
+ return;
911
+ }
912
+ const winW = typeof window !== "undefined" && window.innerWidth ? window.innerWidth : 1024;
913
+ const winH = typeof window !== "undefined" && window.innerHeight ? window.innerHeight : 768;
914
+
915
+ let left;
916
+ if (placement.endsWith("-end")) {
917
+ left = r.right - dialogWidth;
918
+ } else if (placement.endsWith("-start")) {
919
+ left = r.left;
920
+ } else {
921
+ left = r.left + (r.width - dialogWidth) / 2;
922
+ }
923
+ left = Math.max(margin, Math.min(left, winW - dialogWidth - margin));
924
+
925
+ let top;
926
+ const fitsBelow = (r.bottom + gap + dialogHeight) <= (winH - margin);
927
+ const fitsAbove = (r.top - gap - dialogHeight) >= margin;
928
+
929
+ if (placement.startsWith("top")) {
930
+ if (fitsAbove || !fitsBelow) {
931
+ top = r.top - dialogHeight - gap;
932
+ } else {
933
+ top = r.bottom + gap;
934
+ }
935
+ top = Math.max(margin, Math.min(top, winH - dialogHeight - margin));
936
+ } else {
937
+ // For anchors near viewport top (like title bar actions), default to below.
938
+ // Never jump upward over the header when there is insufficient space above.
939
+ if (!fitsBelow && fitsAbove && r.top > dialogHeight + gap + margin) {
940
+ top = r.top - dialogHeight - gap;
941
+ } else {
942
+ top = r.bottom + gap;
943
+ }
944
+ top = Math.max(margin, top);
945
+ }
946
+
947
+ setCoords({ top: Math.round(top), left: Math.round(left) });
948
+ });
949
+ };
950
+
951
+ update();
952
+
953
+ if (typeof window !== "undefined") {
954
+ window.addEventListener("resize", update);
955
+ window.addEventListener("scroll", update, true);
956
+ if (window.visualViewport) {
957
+ window.visualViewport.addEventListener("resize", update);
958
+ window.visualViewport.addEventListener("scroll", update);
959
+ }
960
+ }
961
+
962
+ const pollTimer = setInterval(update, 100);
963
+
964
+ let ro = null;
965
+ const getRealEl = (target) => {
966
+ if (!target) return null;
967
+ if (typeof Element !== "undefined" && target instanceof Element) return target;
968
+ if (target.current && typeof Element !== "undefined" && target.current instanceof Element) return target.current;
969
+ if (typeof target.resolveActiveEl === "function") {
970
+ const resolved = target.resolveActiveEl();
971
+ if (resolved && typeof Element !== "undefined" && resolved instanceof Element) return resolved;
972
+ }
973
+ if (target.nodeType === 1 && typeof target.addEventListener === "function") return target;
974
+ return null;
975
+ };
976
+ const domEl = getRealEl(targetEl);
977
+ if (typeof ResizeObserver === "function" && domEl) {
978
+ try {
979
+ ro = new ResizeObserver(update);
980
+ ro.observe(domEl);
981
+ if (domEl.parentElement) ro.observe(domEl.parentElement);
982
+ const headerAncestor = typeof domEl.closest === "function" ? domEl.closest(".sm-header") : null;
983
+ if (headerAncestor) ro.observe(headerAncestor);
984
+ if (document.body) ro.observe(document.body);
985
+ } catch (_) {}
986
+ }
987
+
988
+ return () => {
989
+ caf(frameId);
990
+ clearInterval(pollTimer);
991
+ if (typeof window !== "undefined") {
992
+ window.removeEventListener("resize", update);
993
+ window.removeEventListener("scroll", update, true);
994
+ if (window.visualViewport) {
995
+ window.visualViewport.removeEventListener("resize", update);
996
+ window.visualViewport.removeEventListener("scroll", update);
997
+ }
998
+ }
999
+ if (ro) ro.disconnect();
1000
+ };
1001
+ }, [open, placement, dialogWidth, dialogHeight, gap, margin]);
1002
+
1003
+ return coords;
1004
+ }
1005
+
659
1006
  const callApi = (path, payload) => fetch(API + path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload || {}) }).then((r) => r.json());
660
1007
  const fetchApi = (path, options) => fetch(API + path, options).then((r) => r.json());
661
1008
  // Run a bulk action across many sessionIds. /batch already does per-id
@@ -743,12 +1090,30 @@ function nextDialogZ() { return ++dialogZStackCounter; }
743
1090
  const annotationButtons = (id, title, t, state, className, onToggle, onEdit, disabled = false, editorOpen = false) => {
744
1091
  const value = annotationOf(state, id);
745
1092
  const busy = disabled || !state.loaded || !!state.error || state.pending.has(id);
746
- const favoriteLabel = t(value.favorite ? "marks.favorite.remove" : "marks.favorite.add") + ": " + title;
747
- const reviewLabel = t(value.reviewLater ? "marks.review.remove" : "marks.review.add") + ": " + title;
1093
+ const favoriteDesc = t(value.favorite ? "marks.favorite.remove" : "marks.favorite.add");
1094
+ const reviewDesc = t(value.reviewLater ? "marks.review.remove" : "marks.review.add");
1095
+ const favoriteLabel = favoriteDesc + ": " + title;
1096
+ const reviewLabel = reviewDesc + ": " + title;
1097
+ const isHeader = className === "sm-headerBtn";
748
1098
  return h(React.Fragment, null,
749
- h("button", { type: "button", className: className + " sm-markIcon" + (value.favorite ? " sm-markOn" : ""), disabled: busy, "aria-label": favoriteLabel, title: favoriteLabel, "aria-pressed": value.favorite, onClick: () => onToggle({ favorite: !value.favorite }) }, value.favorite ? "★" : "☆"),
750
- h("button", { type: "button", className: className + " sm-markIcon" + (value.reviewLater ? " sm-markOn" : ""), disabled: busy, "aria-label": reviewLabel, title: reviewLabel, "aria-pressed": value.reviewLater, onClick: () => onToggle({ reviewLater: !value.reviewLater }) }, "◷"),
751
- h("button", { type: "button", className: className + (editorOpen ? " sm-annotationToggleOpen sm-headerBtnActive" : ""), disabled: busy, "aria-label": t("marks.edit.aria") + ": " + title, title: t("marks.edit.aria"), ...(className === "sm-headerBtn" ? { "aria-expanded": editorOpen } : {}), onClick: e => onEdit(e) }, t(className === "sm-headerBtn" ? "marks.header.edit" : "marks.edit"), className === "sm-headerBtn" ? h("span", { className: "sm-priorityBadge sm-priority-" + (value.priority ?? 3), title: t("marks.priority." + (value.priority ?? 3)) }, "P" + (value.priority ?? 3)) : null)
1099
+ renderTip(favoriteDesc, h("button", { type: "button", className: className + " sm-markIcon" + (value.favorite ? " sm-markOn" : ""), disabled: busy, "aria-label": favoriteLabel, "aria-pressed": value.favorite, onClick: () => onToggle({ favorite: !value.favorite }) },
1100
+ h("span", { className: "sm-headerBtnIcon" }, value.favorite ? "★" : "☆")
1101
+ )),
1102
+ renderTip(reviewDesc, h("button", { type: "button", className: className + " sm-markIcon" + (value.reviewLater ? " sm-markOn" : ""), disabled: busy, "aria-label": reviewLabel, "aria-pressed": value.reviewLater, onClick: () => onToggle({ reviewLater: !value.reviewLater }) },
1103
+ h("span", { className: "sm-headerBtnIcon" }, "◷")
1104
+ )),
1105
+ renderTip(t("marks.edit.aria"), h("button", {
1106
+ type: "button",
1107
+ className: className + (isHeader ? " sm-headerSecondaryAction" : "") + (editorOpen ? " sm-annotationToggleOpen sm-headerBtnActive" : ""),
1108
+ disabled: busy,
1109
+ "aria-label": t("marks.edit.aria") + ": " + title,
1110
+ ...(isHeader ? { "aria-expanded": editorOpen } : {}),
1111
+ onClick: e => onEdit(e)
1112
+ },
1113
+ isHeader ? h("span", { className: "sm-headerBtnIcon" }, "🏷") : null,
1114
+ isHeader ? h("span", { className: "sm-headerBtnLabel" }, t("marks.header.edit")) : t("marks.edit"),
1115
+ isHeader ? h("span", { className: "sm-priorityBadge sm-priority-" + (value.priority ?? 3) }, "P" + (value.priority ?? 3)) : null
1116
+ ))
752
1117
  );
753
1118
  };
754
1119
 
@@ -1239,17 +1604,19 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1239
1604
  return "zh";
1240
1605
  };
1241
1606
  const activeLanguage = detectLanguage(t);
1242
- const hasAnchor = anchor && typeof anchor.top === "number" && typeof anchor.left === "number";
1243
- const layerClass = "sm-nativeDialogLayer sm-annotationDialog sm-confirmDialog" + (hasAnchor ? " sm-annotationDialog-anchored" : "");
1244
- const surfaceClass = "sm-nativeDialog sm-panelDialog sm-annotationSurface" + (hasAnchor ? " sm-annotationSurface-anchored" : "");
1245
- // Default position matches ConfirmDialog / MoveDialog so all inner
1246
- // dialogs line up at top calc(50vh - 90px), left calc(50vw + 308px).
1607
+ const floatingCoords = useFloatingPosition(anchor, true, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 460 });
1608
+ const hasCoords = floatingCoords !== null || (anchor && typeof anchor.top === "number" && typeof anchor.left === "number");
1609
+ const computedTop = floatingCoords ? floatingCoords.top : (anchor && typeof anchor.top === "number" ? anchor.top : null);
1610
+ const computedLeft = floatingCoords ? floatingCoords.left : (anchor && typeof anchor.left === "number" ? anchor.left : null);
1611
+ const layerClass = "sm-nativeDialogLayer sm-annotationDialog sm-confirmDialog" + (hasCoords ? " sm-annotationDialog-anchored" : "");
1612
+ const surfaceClass = "sm-nativeDialog sm-panelDialog sm-annotationSurface" + (hasCoords ? " sm-annotationSurface-anchored" : "");
1247
1613
  const layerStyle = {
1248
1614
  zIndex: zIndex || undefined,
1249
- ...(hasAnchor ? { position: "fixed", top: anchor.top + "px", left: anchor.left + "px" } : {})
1615
+ ...(hasCoords ? { position: "fixed", top: computedTop + "px", left: computedLeft + "px", right: "auto", bottom: "auto", inset: `${computedTop}px auto auto ${computedLeft}px` } : {})
1250
1616
  };
1251
- return h("div", { className: layerClass, style: layerStyle, role: "presentation" },
1252
- h("section", { className: surfaceClass, role: "dialog", "aria-labelledby": "sm-annotation-title", ref: dialogRef, onKeyDown },
1617
+ return renderInOverlay(
1618
+ h("div", { className: layerClass, style: layerStyle, role: "presentation" },
1619
+ h("section", { className: surfaceClass, style: { pointerEvents: "auto" }, role: "dialog", "aria-labelledby": "sm-annotation-title", ref: dialogRef, onKeyDown },
1253
1620
  h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-annotation-title", className: "sm-nativeDialogTitle" }, t("marks.title"))),
1254
1621
  h("div", { className: "sm-annotationBody" },
1255
1622
  h("div", { className: "sm-annotationTarget", title: displayTitle || sessionId }, displayTitle || sessionId),
@@ -1284,7 +1651,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1284
1651
  h("button", { type: "button", className: "sm-nativeDialogButton sm-nativeDialogConfirm", disabled: busy || !annotations.loaded || !!annotations.error || latest.revision !== base.revision, onClick: save }, t(busy ? "marks.saving" : "marks.save"))
1285
1652
  )
1286
1653
  )
1287
- );
1654
+ ));
1288
1655
  }
1289
1656
 
1290
1657
 
@@ -1351,24 +1718,31 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1351
1718
  window.addEventListener("keydown", handler);
1352
1719
  return () => window.removeEventListener("keydown", handler);
1353
1720
  }, [open]);
1354
- // Render inline as a sibling of the panel; createPortal to document.body broke under some hosts. Migrate and AnnotationDialog render inline; do the same here.
1355
1721
 
1722
+ const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 180 });
1356
1723
 
1357
1724
  if (!open) return null;
1358
1725
 
1359
- return h("div", {
1360
- className: "sm-nativeDialogLayer sm-confirmDialog",
1361
- style: {
1362
- zIndex: zIndex || undefined,
1363
- ...(props.anchor && typeof props.anchor.top === "number"
1364
- ? { position: "fixed", top: props.anchor.top + "px", left: props.anchor.left + "px" }
1365
- : {})
1366
- },
1367
- role: "presentation"
1368
- },
1726
+ const topPx = floatingCoords ? floatingCoords.top : (props.anchor && typeof props.anchor.top === "number" ? props.anchor.top : null);
1727
+ const leftPx = floatingCoords ? floatingCoords.left : (props.anchor && typeof props.anchor.left === "number" ? props.anchor.left : null);
1728
+ const hasCoords = topPx !== null && leftPx !== null;
1369
1729
 
1370
- h("section", {
1371
- className: "sm-nativeDialog",
1730
+ const layerStyle = {
1731
+ zIndex: zIndex || undefined,
1732
+ ...(hasCoords
1733
+ ? { position: "fixed", top: topPx + "px", left: leftPx + "px", right: "auto", bottom: "auto", inset: `${topPx}px auto auto ${leftPx}px` }
1734
+ : {})
1735
+ };
1736
+
1737
+ return renderInOverlay(
1738
+ h("div", {
1739
+ className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
1740
+ style: layerStyle,
1741
+ role: "presentation"
1742
+ },
1743
+ h("section", {
1744
+ className: "sm-nativeDialog",
1745
+ style: { pointerEvents: "auto" },
1372
1746
  role: "dialog",
1373
1747
  "aria-modal": "true",
1374
1748
  "aria-labelledby": "sm-confirm-dialog-title"
@@ -1395,7 +1769,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1395
1769
  }, confirmLabel)
1396
1770
  )
1397
1771
  )
1398
- );
1772
+ ));
1399
1773
  }
1400
1774
 
1401
1775
  function MoveDialog(props) {
@@ -1476,20 +1850,27 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1476
1850
  onConfirm(selectedWorkspaceId);
1477
1851
  }
1478
1852
  };
1479
- return h("div", {
1480
- className: "sm-nativeDialogLayer sm-confirmDialog",
1481
- style: {
1482
- zIndex: zIndex || undefined,
1483
- ...(props.anchor && typeof props.anchor.top === "number"
1484
- ? { position: "fixed", top: props.anchor.top + "px", left: props.anchor.left + "px" }
1485
- : {})
1486
- },
1487
- role: "presentation",
1488
- onKeyDown
1489
- },
1853
+ const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 320 });
1854
+ const topPx = floatingCoords ? floatingCoords.top : (props.anchor && typeof props.anchor.top === "number" ? props.anchor.top : null);
1855
+ const leftPx = floatingCoords ? floatingCoords.left : (props.anchor && typeof props.anchor.left === "number" ? props.anchor.left : null);
1856
+ const hasCoords = topPx !== null && leftPx !== null;
1490
1857
 
1491
- h("section", {
1492
- className: "sm-nativeDialog",
1858
+ const layerStyle = {
1859
+ zIndex: zIndex || undefined,
1860
+ ...(hasCoords
1861
+ ? { position: "fixed", top: topPx + "px", left: leftPx + "px", right: "auto", bottom: "auto", inset: `${topPx}px auto auto ${leftPx}px` }
1862
+ : {})
1863
+ };
1864
+ return renderInOverlay(
1865
+ h("div", {
1866
+ className: "sm-nativeDialogLayer sm-confirmDialog" + (hasCoords ? " sm-confirmDialog-anchored" : ""),
1867
+ style: layerStyle,
1868
+ role: "presentation",
1869
+ onKeyDown
1870
+ },
1871
+ h("section", {
1872
+ className: "sm-nativeDialog",
1873
+ style: { pointerEvents: "auto" },
1493
1874
  role: "dialog",
1494
1875
  "aria-modal": "true",
1495
1876
  "aria-labelledby": "sm-move-dialog-title"
@@ -1513,7 +1894,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1513
1894
  }, confirmLabel)
1514
1895
  )
1515
1896
  )
1516
- );
1897
+ ));
1517
1898
  }
1518
1899
 
1519
1900
  function MigratePresetDialog(props) {
@@ -1610,14 +1991,15 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1610
1991
  target === currentPreset ? h("div", { className: "sm-migrateWarn" }, t("migrate.same")) : null
1611
1992
  )
1612
1993
  );
1613
- return h("div", {
1614
- className: "sm-nativeDialogLayer sm-confirmDialog sm-migrateConfirmLayer",
1615
- role: "presentation",
1616
- style: { zIndex: zIndex || undefined }
1617
- },
1618
-
1619
- h("section", {
1620
- className: "sm-nativeDialog sm-migrateDialog",
1994
+ return renderInOverlay(
1995
+ h("div", {
1996
+ className: "sm-nativeDialogLayer sm-confirmDialog sm-migrateConfirmLayer",
1997
+ role: "presentation",
1998
+ style: { zIndex: zIndex || undefined }
1999
+ },
2000
+ h("section", {
2001
+ className: "sm-nativeDialog sm-migrateDialog",
2002
+ style: { pointerEvents: "auto" },
1621
2003
  role: "dialog",
1622
2004
  "aria-modal": "true",
1623
2005
  "aria-labelledby": "sm-migrate-dialog-title"
@@ -1641,9 +2023,274 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1641
2023
  }, busy ? t("busy.processing") : t("migrate.confirm"))
1642
2024
  )
1643
2025
  )
1644
- );
2026
+ ));
2027
+ }
2028
+
2029
+ const CURRENT_VERSION = "0.6.2";
2030
+
2031
+ function compareSemver(v1, v2) {
2032
+ if (typeof v1 !== "string" || typeof v2 !== "string") return 0;
2033
+ const parse = (v) => {
2034
+ // Strip build metadata (+...)
2035
+ const noBuild = v.trim().replace(/^[vV]/, "").split("+")[0];
2036
+ const hyphenIdx = noBuild.indexOf("-");
2037
+ const core = hyphenIdx === -1 ? noBuild : noBuild.slice(0, hyphenIdx);
2038
+ const prerelease = hyphenIdx === -1 ? undefined : noBuild.slice(hyphenIdx + 1);
2039
+ const parts = (core || "").split(".").map(n => parseInt(n, 10) || 0);
2040
+ while (parts.length < 3) parts.push(0);
2041
+ return { parts, prerelease: prerelease !== undefined ? prerelease.trim() : undefined };
2042
+ };
2043
+ const p1 = parse(v1);
2044
+ const p2 = parse(v2);
2045
+ for (let i = 0; i < 3; i++) {
2046
+ if (p1.parts[i] > p2.parts[i]) return 1;
2047
+ if (p1.parts[i] < p2.parts[i]) return -1;
2048
+ }
2049
+ // When major, minor, patch match: version without prerelease is higher
2050
+ if (p1.prerelease && !p2.prerelease) return -1;
2051
+ if (!p1.prerelease && p2.prerelease) return 1;
2052
+ if (p1.prerelease && p2.prerelease) {
2053
+ if (p1.prerelease === p2.prerelease) return 0;
2054
+ const id1 = p1.prerelease.split(".");
2055
+ const id2 = p2.prerelease.split(".");
2056
+ const maxLen = Math.max(id1.length, id2.length);
2057
+ for (let i = 0; i < maxLen; i++) {
2058
+ if (i >= id1.length) return -1;
2059
+ if (i >= id2.length) return 1;
2060
+ const part1 = id1[i];
2061
+ const part2 = id2[i];
2062
+ if (part1 === part2) continue;
2063
+ const num1 = /^\d+$/.test(part1) ? parseInt(part1, 10) : null;
2064
+ const num2 = /^\d+$/.test(part2) ? parseInt(part2, 10) : null;
2065
+ if (num1 !== null && num2 !== null) {
2066
+ if (num1 > num2) return 1;
2067
+ if (num1 < num2) return -1;
2068
+ } else if (num1 !== null && num2 === null) {
2069
+ return -1;
2070
+ } else if (num1 === null && num2 !== null) {
2071
+ return 1;
2072
+ } else {
2073
+ if (part1 > part2) return 1;
2074
+ if (part1 < part2) return -1;
2075
+ }
2076
+ }
2077
+ }
2078
+ return 0;
1645
2079
  }
1646
2080
 
2081
+ let activeClientCtx = null;
2082
+
2083
+ const updateStore = {
2084
+ state: {
2085
+ status: "idle",
2086
+ currentVersion: CURRENT_VERSION,
2087
+ latestVersion: null,
2088
+ error: null,
2089
+ application: null,
2090
+ dialogOpen: false,
2091
+ checkedAt: null,
2092
+ },
2093
+ listeners: new Set(),
2094
+ getSnapshot() { return this.state; },
2095
+ subscribe(cb) {
2096
+ this.listeners.add(cb);
2097
+ return () => this.listeners.delete(cb);
2098
+ },
2099
+ _notify() {
2100
+ this.state = { ...this.state };
2101
+ for (const fn of [...this.listeners]) fn();
2102
+ },
2103
+ openDialog() {
2104
+ this.state.dialogOpen = true;
2105
+ this._notify();
2106
+ },
2107
+ closeDialog() {
2108
+ this.state.dialogOpen = false;
2109
+ this._notify();
2110
+ },
2111
+ getAutoCheck() {
2112
+ try {
2113
+ if (typeof localStorage !== "undefined") {
2114
+ return localStorage.getItem("dsh-session-manager-auto-check") !== "false";
2115
+ }
2116
+ } catch (_) {}
2117
+ return true;
2118
+ },
2119
+ setAutoCheck(enabled) {
2120
+ try {
2121
+ if (typeof localStorage !== "undefined") {
2122
+ localStorage.setItem("dsh-session-manager-auto-check", enabled ? "true" : "false");
2123
+ }
2124
+ } catch (_) {}
2125
+ this._notify();
2126
+ },
2127
+ REGISTRY_OPTIONS: {
2128
+ "registry.npmjs.org": "https://registry.npmjs.org",
2129
+ "registry.npmmirror.com": "https://registry.npmmirror.com",
2130
+ },
2131
+ DEFAULT_REGISTRY: "registry.npmjs.org",
2132
+ getRegistry() {
2133
+ try {
2134
+ if (typeof localStorage !== "undefined") {
2135
+ const v = localStorage.getItem("dsh-session-manager-registry");
2136
+ if (v && this.REGISTRY_OPTIONS[v]) return v;
2137
+ }
2138
+ } catch (_) {}
2139
+ return this.DEFAULT_REGISTRY;
2140
+ },
2141
+ setRegistry(key) {
2142
+ try {
2143
+ if (typeof localStorage !== "undefined") {
2144
+ if (this.REGISTRY_OPTIONS[key]) {
2145
+ localStorage.setItem("dsh-session-manager-registry", key);
2146
+ } else {
2147
+ localStorage.setItem("dsh-session-manager-registry", this.DEFAULT_REGISTRY);
2148
+ }
2149
+ }
2150
+ } catch (_) {}
2151
+ this._notify();
2152
+ },
2153
+ getRegistryUrl() {
2154
+ return this.REGISTRY_OPTIONS[this.getRegistry()] || this.REGISTRY_OPTIONS[this.DEFAULT_REGISTRY];
2155
+ },
2156
+ async checkForUpdate(options = {}) {
2157
+ const { silent = false, openOnFound = true, manual = false } = options;
2158
+ const shouldOpenDialog = options.openDialog ?? (manual && !silent && options.openOnFound !== false);
2159
+ if (this.state.status === "checking" || this.state.status === "updating") return this.state;
2160
+
2161
+ this.state.status = "checking";
2162
+ this.state.error = null;
2163
+ if (shouldOpenDialog) {
2164
+ this.state.dialogOpen = true;
2165
+ }
2166
+ this._notify();
2167
+
2168
+ try {
2169
+ let res = null;
2170
+ if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
2171
+ const testOverride = window.__DSH_SM_TEST_UPDATE__;
2172
+ if (testOverride.error) {
2173
+ throw new Error(testOverride.error);
2174
+ }
2175
+ const cur = testOverride.currentVersion || this.state.currentVersion;
2176
+ const lat = testOverride.latestVersion || "9.9.9";
2177
+ const hasUpdate = compareSemver(lat, cur) > 0;
2178
+ res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
2179
+ } else {
2180
+ const registryUrl = this.getRegistryUrl();
2181
+ const registryParam = encodeURIComponent(registryUrl);
2182
+ try {
2183
+ res = await fetchApi("/update/check?registry=" + registryParam);
2184
+ } catch (fetchErr) {
2185
+ try {
2186
+ const base = registryUrl.endsWith("/") ? registryUrl : registryUrl + "/";
2187
+ const npmRes = await fetch(base + "dsh-session-manager/latest");
2188
+ if (npmRes.ok) {
2189
+ const npmData = await npmRes.json();
2190
+ if (npmData && npmData.version) {
2191
+ const cur = this.state.currentVersion;
2192
+ const lat = npmData.version;
2193
+ const hasUpdate = compareSemver(lat, cur) > 0;
2194
+ res = { ok: true, result: { currentVersion: cur, latestVersion: lat, hasUpdate } };
2195
+ }
2196
+ }
2197
+ } catch (_) {}
2198
+ if (!res) throw fetchErr;
2199
+ }
2200
+ }
2201
+
2202
+ if (!res || !res.ok) {
2203
+ throw new Error(res?.error || "检查更新失败");
2204
+ }
2205
+
2206
+ const result = res.result || {};
2207
+ const currentVersion = result.currentVersion || this.state.currentVersion;
2208
+ const latestVersion = result.latestVersion || currentVersion;
2209
+ const hasUpdate = !!result.hasUpdate || compareSemver(latestVersion, currentVersion) > 0;
2210
+
2211
+ this.state.currentVersion = currentVersion;
2212
+ this.state.latestVersion = latestVersion;
2213
+ this.state.checkedAt = Date.now();
2214
+
2215
+ if (hasUpdate) {
2216
+ this.state.status = "available";
2217
+ if (openOnFound && !silent) {
2218
+ this.state.dialogOpen = true;
2219
+ }
2220
+ } else {
2221
+ this.state.status = "idle";
2222
+ if (shouldOpenDialog) {
2223
+ this.state.dialogOpen = true;
2224
+ }
2225
+ }
2226
+ this._notify();
2227
+ return this.state;
2228
+ } catch (err) {
2229
+ this.state.status = "error";
2230
+ this.state.error = err.message || "检查更新失败";
2231
+ if (shouldOpenDialog) {
2232
+ this.state.dialogOpen = true;
2233
+ }
2234
+ this._notify();
2235
+ return this.state;
2236
+ }
2237
+ },
2238
+ async startUpdate(options = {}) {
2239
+ const { openDialog = false } = options;
2240
+ if (this.state.status === "updating") return this.state;
2241
+ this.state.status = "updating";
2242
+ this.state.error = null;
2243
+ if (openDialog) {
2244
+ this.state.dialogOpen = true;
2245
+ }
2246
+ this._notify();
2247
+
2248
+ const targetVersion = this.state.latestVersion || "latest";
2249
+ const spec = "dsh-session-manager@" + targetVersion;
2250
+
2251
+ try {
2252
+ let outcome = null;
2253
+ if (typeof window !== "undefined" && window.__DSH_SM_TEST_UPDATE__) {
2254
+ const testOverride = window.__DSH_SM_TEST_UPDATE__;
2255
+ if (testOverride.error) {
2256
+ throw new Error(testOverride.error);
2257
+ }
2258
+ if (typeof testOverride.installBundle === "function") {
2259
+ outcome = await testOverride.installBundle(spec);
2260
+ } else {
2261
+ await new Promise(r => setTimeout(r, 100));
2262
+ outcome = { application: testOverride.application || "restart-required" };
2263
+ }
2264
+ } else {
2265
+ const remotePm = activeClientCtx?.remote?.pluginManager || activeClientCtx?.pluginManager;
2266
+ if (remotePm && typeof remotePm.installBundle === "function") {
2267
+ outcome = await remotePm.installBundle(spec);
2268
+ } else {
2269
+ const res = await callApi("/update/install", { version: targetVersion, registry: this.getRegistryUrl() });
2270
+ if (!res || !res.ok) {
2271
+ throw new Error(res?.error || "安装更新失败");
2272
+ }
2273
+ outcome = res.result;
2274
+ }
2275
+ }
2276
+
2277
+ const application = outcome?.application || "restart-required";
2278
+ this.state.status = "done";
2279
+ this.state.application = application;
2280
+ this._notify();
2281
+ return outcome;
2282
+ } catch (err) {
2283
+ this.state.status = "error";
2284
+ this.state.error = err.message || "更新安装失败";
2285
+ if (openDialog) {
2286
+ this.state.dialogOpen = true;
2287
+ }
2288
+ this._notify();
2289
+ return { ok: false, error: this.state.error };
2290
+ }
2291
+ }
2292
+ };
2293
+
1647
2294
  const panelStore = {
1648
2295
  open: false,
1649
2296
  listeners: new Set(),
@@ -1661,6 +2308,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1661
2308
  setPendingMove(v) { this.pendingMove = v; this._emitPending(); },
1662
2309
  consumePendingMove() { const v = this.pendingMove; this.pendingMove = null; return v; }
1663
2310
  };
2311
+ const lastBatchContext = { action: null, ids: [] };
1664
2312
 
1665
2313
  const DEFAULT_SORT = "updated-desc";
1666
2314
  const SORT_ORDERS = ["updated-desc", "updated-asc", "created-desc", "created-asc", "priority"];
@@ -1716,6 +2364,11 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1716
2364
  const onMigrate = props.onMigrate;
1717
2365
  const annotations = useAnnotations(true);
1718
2366
  const marksReady = annotations.loaded && !annotations.error;
2367
+ const updateState = useSyncExternalStore(
2368
+ (cb) => updateStore.subscribe(cb),
2369
+ () => updateStore.getSnapshot(),
2370
+ () => updateStore.getSnapshot()
2371
+ );
1719
2372
  const [onlyFavorite, setOnlyFavorite] = useState(false);
1720
2373
  const [onlyReview, setOnlyReview] = useState(false);
1721
2374
  const [tagFilter, setTagFilter] = useState("all");
@@ -1839,6 +2492,8 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1839
2492
  setBulkProgress(null);
1840
2493
  setBulkResult({ action, actionLabel, items });
1841
2494
  setBulkBusy(false);
2495
+ lastBatchContext.action = action;
2496
+ lastBatchContext.ids = ids;
1842
2497
  try { await annotationStore.load(true); } catch (_) { /* ignore */ }
1843
2498
  if (typeof props.onRefreshAfterBulk === "function") {
1844
2499
  try { await props.onRefreshAfterBulk(action); } catch (_) { /* ignore */ }
@@ -1890,16 +2545,16 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1890
2545
  const onBulkTagApply = (tags) => {
1891
2546
  const mode = bulkTagDraft && bulkTagDraft.mode;
1892
2547
  setBulkTagDraft(null);
1893
- if (mode === "add") onBulkAction("add-tags", { tags }, true);
2548
+ if (mode === "add") onBulkAction("add-tags", { tags }, false);
1894
2549
  };
1895
2550
  const onBulkPriorityApply = (value) => {
1896
2551
  const priority = Number(value);
1897
2552
  setBulkTagDraft(null);
1898
- if (Number.isInteger(priority) && priority >= 1 && priority <= 5) onBulkAction("set-priority", { priority }, true);
2553
+ if (Number.isInteger(priority) && priority >= 1 && priority <= 5) onBulkAction("set-priority", { priority }, false);
1899
2554
  };
1900
2555
  const onBulkMoveApply = (value) => {
1901
2556
  setBulkTagDraft(null);
1902
- if (value) onBulkAction("move", { targetWorkspaceId: value }, true);
2557
+ if (value) onBulkAction("move", { targetWorkspaceId: value }, false);
1903
2558
  };
1904
2559
  const [bulkPresetDraft, setBulkPresetDraft] = useState(null);
1905
2560
  const [bulkPresetOptions, setBulkPresetOptions] = useState([]);
@@ -1925,7 +2580,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1925
2580
  };
1926
2581
  const onBulkPresetApply = (value) => {
1927
2582
  setBulkPresetDraft(null);
1928
- if (value) onBulkAction("preset-migrate", { toPreset: value }, true);
2583
+ if (value) onBulkAction("preset-migrate", { toPreset: value }, false);
1929
2584
  };
1930
2585
  const bulkMoveOptions = useMemo(() => workspaces.map(ws => ({ value: ws.id, label: ws.title || ws.name || ws.id })), [workspaces]);
1931
2586
  const bulkPriorityOptions = useMemo(() => [1, 2, 3, 4, 5].map(value => ({ value: String(value), label: t("marks.priority." + value) })), [t]);
@@ -2158,29 +2813,74 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2158
2813
  "aria-labelledby": "sm-panel-dialog-title"
2159
2814
  },
2160
2815
  h("div", { className: "sm-nativeDialogHeader" },
2161
- h("a", {
2162
- href: "https://github.com/hkkz9522/dsh-session-manager",
2163
- target: "_blank",
2164
- rel: "noopener noreferrer",
2165
- className: "sm-panelHeaderGithub",
2166
- title: t("panel.github.title"),
2167
- "aria-label": t("panel.github.title")
2168
- },
2169
- h("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": "true" },
2170
- h("path", {
2171
- fill: "currentColor",
2172
- d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"
2173
- })
2174
- )
2816
+ h("div", { className: "sm-panelHeaderLeft" },
2817
+ renderTip(t("panel.github.title"), h("a", {
2818
+ href: "https://github.com/hkkz9522/dsh-session-manager",
2819
+ target: "_blank",
2820
+ rel: "noopener noreferrer",
2821
+ className: "sm-panelHeaderGithub",
2822
+ "aria-label": t("panel.github.title")
2823
+ },
2824
+ h("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": "true" },
2825
+ h("path", {
2826
+ fill: "currentColor",
2827
+ d: "M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0 0 16 8c0-4.42-3.58-8-8-8z"
2828
+ })
2829
+ )
2830
+ )),
2831
+ renderTip(updateState.status === "available"
2832
+ ? t("panel.update.badge")
2833
+ : updateState.status === "checking"
2834
+ ? t("update.checking")
2835
+ : updateState.status === "done"
2836
+ ? t("update.done.applied")
2837
+ : updateState.status === "error"
2838
+ ? (updateState.error || t("update.error"))
2839
+ : t("panel.update.title"),
2840
+ h("a", {
2841
+ role: "button",
2842
+ tabIndex: 0,
2843
+ className: "sm-panelHeaderGithub sm-panelHeaderWhale" + (updateState.status === "available" ? " sm-hasUpdate" : ""),
2844
+ "aria-label": updateState.status === "available"
2845
+ ? t("panel.update.badge")
2846
+ : updateState.status === "checking"
2847
+ ? t("update.checking")
2848
+ : t("panel.update.title"),
2849
+ onClick: (e) => {
2850
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
2851
+ if (updateState.status === "available" || updateState.status === "done" || updateState.status === "updating") {
2852
+ updateStore.openDialog();
2853
+ } else {
2854
+ updateStore.openDialog();
2855
+ updateStore.checkForUpdate({ manual: true, silent: false, openDialog: true });
2856
+ }
2857
+ },
2858
+ onKeyDown: (e) => {
2859
+ if (e.key === "Enter" || e.key === " ") {
2860
+ if (e && typeof e.preventDefault === "function") e.preventDefault();
2861
+ if (updateState.status === "available" || updateState.status === "done" || updateState.status === "updating") {
2862
+ updateStore.openDialog();
2863
+ } else {
2864
+ updateStore.openDialog();
2865
+ updateStore.checkForUpdate({ manual: true, silent: false, openDialog: true });
2866
+ }
2867
+ }
2868
+ }
2869
+ },
2870
+ h(NpmIcon, { size: 16 }),
2871
+ updateState.status === "available" ? h("span", { className: "sm-updateDot", "aria-hidden": "true" }) : null,
2872
+ updateState.status === "checking" ? h("span", { className: "sm-updateSpinner", "aria-hidden": "true" }) : null
2873
+ )),
2175
2874
  ),
2176
2875
  h("h2", { id: "sm-panel-dialog-title", className: "sm-nativeDialogTitle" }, t("panel.title")),
2177
2876
  h("div", { className: "sm-nativeDialogHeaderActions" },
2178
- h("button", {
2877
+ renderTip(t("panel.close") || "关闭", h("button", {
2179
2878
  type: "button",
2180
2879
  className: "sm-panelHeaderClose",
2181
2880
  disabled: busyId !== null || migrating,
2182
- onClick: onPanelClose
2183
- }, t("panel.close"))
2881
+ onClick: onPanelClose,
2882
+ "aria-label": t("panel.close")
2883
+ }, h(CloseIcon, { size: 14 })))
2184
2884
  )
2185
2885
  ),
2186
2886
  h("div", { className: "sm-panel" },
@@ -2494,30 +3194,119 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2494
3194
  });
2495
3195
  return () => { alive = false; };
2496
3196
  }, [moveFor ? (moveFor.id || "x") : null]);
2497
- // All three HeaderAction dialogs (annotation / move / delete)
2498
- // share a 360px width. Anchor the dialog's right edge to the
2499
- // trigger button's right edge, with 8px screen-edge padding.
2500
- const anchorFor = (el) => {
2501
- if (!el || typeof el.getBoundingClientRect !== "function") return null;
2502
- const r = el.getBoundingClientRect();
3197
+ const [moreOpen, setMoreOpen] = useState(false);
3198
+ const headerRef = useRef(null);
3199
+ const moreBtnRef = useRef(null);
3200
+ const moreBtnElRef = useRef(null);
3201
+ useEffect(() => {
3202
+ if (!moreOpen) return;
3203
+ const onDocClick = (e) => {
3204
+ if (moreBtnRef.current && moreBtnRef.current.contains(e.target)) return;
3205
+ setMoreOpen(false);
3206
+ };
3207
+ const onKey = (e) => {
3208
+ if (e.key === "Escape") setMoreOpen(false);
3209
+ };
3210
+ window.addEventListener("click", onDocClick, true);
3211
+ window.addEventListener("keydown", onKey, true);
3212
+ return () => {
3213
+ window.removeEventListener("click", onDocClick, true);
3214
+ window.removeEventListener("keydown", onKey, true);
3215
+ };
3216
+ }, [moreOpen]);
3217
+
3218
+ const getMoreBtn = () => {
3219
+ if (moreBtnElRef.current && moreBtnElRef.current.nodeType === 1) return moreBtnElRef.current;
3220
+ if (moreBtnRef.current) {
3221
+ const btn = moreBtnRef.current.querySelector(".sm-headerCompactMenuBtn");
3222
+ if (btn) return btn;
3223
+ }
3224
+ if (headerRef.current) {
3225
+ const btn = headerRef.current.querySelector(".sm-headerCompactMenuBtn");
3226
+ if (btn) return btn;
3227
+ }
3228
+ return null;
3229
+ };
3230
+
3231
+ const isVisible = (element) => {
3232
+ if (!element || typeof element.getBoundingClientRect !== "function") return false;
3233
+ if (typeof element.isConnected === "boolean" && !element.isConnected) return false;
3234
+ const rect = element.getBoundingClientRect();
3235
+ if (rect.width === 0 && rect.height === 0) return false;
3236
+ if (typeof element.offsetParent !== "undefined" && element.offsetParent === null && element.style?.position !== "fixed") return false;
3237
+ return true;
3238
+ };
3239
+
3240
+ const resolveActiveAnchorEl = (targetEl, actionType) => {
3241
+ if (isVisible(targetEl)) return targetEl;
3242
+ const moreBtn = getMoreBtn();
3243
+ if (isVisible(moreBtn)) return moreBtn;
3244
+ if (headerRef.current) {
3245
+ if (actionType === "annotation") {
3246
+ const btn = headerRef.current.querySelector(".sm-headerSecondaryAction")
3247
+ || headerRef.current.querySelector(".sm-annotationToggleOpen")
3248
+ || headerRef.current.querySelector("[aria-label*='marks']")
3249
+ || headerRef.current.querySelector("[aria-label*='标签']");
3250
+ if (isVisible(btn)) return btn;
3251
+ } else if (actionType === "move") {
3252
+ const btn = headerRef.current.querySelector(".sm-headerSecondaryActions button:first-child")
3253
+ || headerRef.current.querySelector("[aria-label*='move']")
3254
+ || headerRef.current.querySelector("[aria-label*='移动']");
3255
+ if (isVisible(btn)) return btn;
3256
+ } else if (actionType === "delete") {
3257
+ const btn = headerRef.current.querySelector(".sm-headerSecondaryActions button:last-child")
3258
+ || headerRef.current.querySelector(".sm-headerBtnDanger");
3259
+ if (isVisible(btn)) return btn;
3260
+ }
3261
+ if (isVisible(headerRef.current)) return headerRef.current;
3262
+ }
3263
+ return moreBtn || targetEl || null;
3264
+ };
3265
+
3266
+ // Anchor dialogs to the trigger button with dynamic tracking (issue #19 / #20).
3267
+ const anchorFor = (el, actionType) => {
3268
+ const domEl = el?.nodeType === 1 ? el : (el?.currentTarget || el?.target || el?.current || el);
3269
+ if (!domEl || typeof domEl.getBoundingClientRect !== "function") return domEl || null;
3270
+
3271
+ const activeEl = resolveActiveAnchorEl(domEl, actionType);
3272
+ const r = (activeEl && isVisible(activeEl) ? activeEl : domEl).getBoundingClientRect();
3273
+
2503
3274
  return {
2504
3275
  top: Math.round(r.top + r.height + 6),
2505
- left: Math.max(8, Math.round(r.right - 360))
3276
+ left: Math.max(8, Math.round(r.right - 360)),
3277
+ current: domEl,
3278
+ nodeType: domEl.nodeType,
3279
+ actionType: actionType,
3280
+ resolveActiveEl: () => resolveActiveAnchorEl(domEl, actionType),
3281
+ getBoundingClientRect: () => {
3282
+ const currentEl = resolveActiveAnchorEl(domEl, actionType);
3283
+ if (currentEl && typeof currentEl.getBoundingClientRect === "function") {
3284
+ const curR = currentEl.getBoundingClientRect();
3285
+ if (curR.width > 0 || curR.height > 0) return curR;
3286
+ }
3287
+ if (headerRef.current && typeof headerRef.current.getBoundingClientRect === "function") {
3288
+ const hr = headerRef.current.getBoundingClientRect();
3289
+ if (hr.width > 0 || hr.height > 0) return hr;
3290
+ }
3291
+ return r;
3292
+ }
2506
3293
  };
2507
3294
  };
2508
3295
  const archiveLabelKey = isArchived ? "row.unarchive" : "row.archive";
2509
3296
  return h(React.Fragment, null,
2510
3297
  annotationFor ? h(AnnotationDialog, { key: annotationFor.id, sessionId: annotationFor.id, displayTitle: annotationFor.displayTitle, t, anchor: annotationAnchor, onClose: () => { setAnnotationFor(null); setAnnotationAnchor(null); } }) : null,
2511
- h("div", { className: "sm-header" },
2512
- h("button", {
3298
+ h("div", { className: "sm-header", ref: headerRef },
3299
+ (onArchive || onUnarchive) ? renderTip(t ? t(archiveLabelKey) : (isArchived ? "移出归档" : "归档会话"), h("button", {
2513
3300
  type: "button",
2514
3301
  className: "sm-headerBtn" + (isArchived ? " sm-headerBtnActive" : ""),
2515
3302
  "aria-label": t ? t(archiveLabelKey) : (isArchived ? "移出归档" : "归档会话"),
2516
3303
  onClick: () => runWithAlert("archive", () =>
2517
3304
  isArchived ? onUnarchive(sessionId) : onArchive(sessionId)
2518
3305
  )
2519
- }, isArchived ? (t ? t("row.unarchive") : "移出归档") : (t ? t("row.archive") : "归档")),
2520
-
3306
+ },
3307
+ h("span", { className: "sm-headerBtnIcon" }, isArchived ? "📤" : "📥"),
3308
+ h("span", { className: "sm-headerBtnLabel" }, isArchived ? (t ? t("row.unarchive") : "移出归档") : (t ? t("row.archive") : "归档"))
3309
+ )) : null,
2521
3310
  annotationButtons(sessionId, props.displayTitle || sessionId, t, annotations, "sm-headerBtn", patch => runWithAlert("annotations", () => annotationStore.save(sessionId, patch)), (e) => {
2522
3311
  const nextOpen = !(annotationFor && annotationFor.id === sessionId);
2523
3312
  // Do NOT clear moveFor / confirmFor here: the z-index counter
@@ -2525,51 +3314,143 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2525
3314
  // popup must not silently dismiss a previously opened move or
2526
3315
  // delete popup on the same session.
2527
3316
  if (nextOpen && e && e.currentTarget) {
2528
- const r = e.currentTarget.getBoundingClientRect();
2529
- setAnnotationAnchor({ top: Math.round(r.top + r.height + 6), left: Math.max(8, Math.round(r.right - 360)) });
3317
+ setAnnotationAnchor(anchorFor(e.currentTarget, "annotation"));
2530
3318
  } else setAnnotationAnchor(null);
2531
3319
  setAnnotationFor(current => current?.id === sessionId ? null : { id: sessionId, displayTitle });
2532
3320
  }, false, annotationFor?.id === sessionId),
2533
- annotations.error ? h("button", { type: "button", className: "sm-headerBtn", title: t("marks.error", { message: annotations.error }), "aria-label": t("marks.retry"), onClick: () => annotationStore.load(true) }, "!") : null,
3321
+ annotations.error ? renderTip(t("marks.error", { message: annotations.error }), h("button", { type: "button", className: "sm-headerBtn", "aria-label": t("marks.retry"), onClick: () => annotationStore.load(true) }, "!")) : null,
2534
3322
 
2535
- h("button", {
2536
- type: "button",
2537
- className: "sm-headerBtn" + (moveFor ? " sm-headerBtnActive" : ""),
2538
- "aria-label": t ? t("row.move") : "移动至工作区",
2539
- onClick: (e) => {
2540
- e.stopPropagation();
2541
- // Do NOT clear confirmFor / confirmAnchor here: opening the
2542
- // move popup must not silently dismiss a previously opened
2543
- // delete popup on the same session. The z-index counter
2544
- // (see nextDialogZ) handles stacking.
2545
- if (moveFor && moveFor.id === sessionId) {
2546
- setMoveFor(null);
2547
- setMoveAnchor(null);
2548
- } else {
2549
- setMoveAnchor(anchorFor(e.currentTarget));
2550
- setMoveFor({ id: sessionId, displayTitle, workspaceId: "" });
3323
+ h("div", { className: "sm-headerSecondaryActions" },
3324
+ renderTip(t ? t("row.move") : "移动至工作区", h("button", {
3325
+ type: "button",
3326
+ className: "sm-headerBtn" + (moveFor ? " sm-headerBtnActive" : ""),
3327
+ "aria-label": t ? t("row.move") : "移动至工作区",
3328
+ onClick: (e) => {
3329
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3330
+ // Do NOT clear confirmFor / confirmAnchor here: opening the
3331
+ // move popup must not silently dismiss a previously opened
3332
+ // delete popup on the same session. The z-index counter
3333
+ // (see nextDialogZ) handles stacking.
3334
+ if (moveFor && moveFor.id === sessionId) {
3335
+ setMoveFor(null);
3336
+ setMoveAnchor(null);
3337
+ } else {
3338
+ setMoveAnchor(anchorFor(e?.currentTarget, "move"));
3339
+ setMoveFor({ id: sessionId, displayTitle, workspaceId: "" });
3340
+ }
2551
3341
  }
2552
- }
2553
- }, t ? t("row.move") : "移动至工作区"),
2554
- h("button", {
2555
- type: "button",
2556
- className: "sm-headerBtn sm-headerBtnDanger" + (confirmFor ? " sm-headerBtnActive" : ""),
2557
- "aria-label": t ? t("row.delete") : "删除会话",
2558
- onClick: (e) => {
2559
- e.stopPropagation();
2560
- // Do NOT clear moveFor / moveAnchor here: opening the delete
2561
- // popup must not silently dismiss a previously opened move
2562
- // popup on the same session. The z-index counter (see
2563
- // nextDialogZ) handles stacking.
2564
- if (confirmFor && confirmFor.id === sessionId) {
2565
- setConfirmFor(null);
2566
- setConfirmAnchor(null);
2567
- } else {
2568
- setConfirmAnchor(anchorFor(e.currentTarget));
2569
- setConfirmFor({ id: sessionId, displayTitle });
3342
+ },
3343
+ h("span", { className: "sm-headerBtnIcon" }, "↔"),
3344
+ h("span", { className: "sm-headerBtnLabel" }, t ? t("row.move") : "移动至工作区")
3345
+ )),
3346
+ renderTip(t ? t("row.delete") : "删除会话", h("button", {
3347
+ type: "button",
3348
+ className: "sm-headerBtn sm-headerBtnDanger" + (confirmFor ? " sm-headerBtnActive" : ""),
3349
+ "aria-label": t ? t("row.delete") : "删除会话",
3350
+ onClick: (e) => {
3351
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3352
+ // Do NOT clear moveFor / moveAnchor here: opening the delete
3353
+ // popup must not silently dismiss a previously opened move
3354
+ // popup on the same session. The z-index counter (see
3355
+ // nextDialogZ) handles stacking.
3356
+ if (confirmFor && confirmFor.id === sessionId) {
3357
+ setConfirmFor(null);
3358
+ setConfirmAnchor(null);
3359
+ } else {
3360
+ setConfirmAnchor(anchorFor(e?.currentTarget, "delete"));
3361
+ setConfirmFor({ id: sessionId, displayTitle });
3362
+ }
2570
3363
  }
2571
- }
2572
- }, t ? t("row.delete") : "删除会话")
3364
+ },
3365
+ h("span", { className: "sm-headerBtnIcon" }, "🗑"),
3366
+ h("span", { className: "sm-headerBtnLabel" }, t ? t("row.delete") : "删除会话")
3367
+ ))
3368
+ ),
3369
+ h("div", { className: "sm-headerCompactMenu", ref: moreBtnRef },
3370
+ renderTip((t && t("header.more")) || "更多操作", h("button", {
3371
+ ref: moreBtnElRef,
3372
+ type: "button",
3373
+ className: "sm-headerBtn sm-headerCompactMenuBtn" + (moreOpen ? " sm-headerBtnActive" : ""),
3374
+ "aria-label": (t && t("header.more")) || "更多操作",
3375
+ "aria-haspopup": "menu",
3376
+ "aria-expanded": moreOpen,
3377
+ onClick: (e) => {
3378
+ if (e && typeof e.stopPropagation === "function") e.stopPropagation();
3379
+ setMoreOpen(v => !v);
3380
+ }
3381
+ },
3382
+ h("span", { className: "sm-headerBtnIcon" }, "⋯")
3383
+ )),
3384
+ moreOpen ? h("div", { className: "sm-headerMenu", role: "menu" },
3385
+ h("button", {
3386
+ type: "button",
3387
+ className: "sm-headerMenuItem",
3388
+ role: "menuitem",
3389
+ onClick: () => {
3390
+ const anchorEl = getMoreBtn() || moreBtnRef.current;
3391
+ setMoreOpen(false);
3392
+ const nextOpen = !(annotationFor && annotationFor.id === sessionId);
3393
+ if (nextOpen && anchorEl) {
3394
+ setAnnotationAnchor(anchorFor(anchorEl, "annotation"));
3395
+ } else setAnnotationAnchor(null);
3396
+ setAnnotationFor(curr => (curr?.id === sessionId ? null : { id: sessionId, displayTitle }));
3397
+ }
3398
+ },
3399
+ h("span", { className: "sm-headerBtnIcon" }, "🏷"),
3400
+ h("span", null, t ? t("marks.header.edit") : "标签/备注")
3401
+ ),
3402
+ h("button", {
3403
+ type: "button",
3404
+ className: "sm-headerMenuItem",
3405
+ role: "menuitem",
3406
+ onClick: () => {
3407
+ const anchorEl = getMoreBtn() || moreBtnRef.current;
3408
+ setMoreOpen(false);
3409
+ if (moveFor && moveFor.id === sessionId) {
3410
+ setMoveFor(null);
3411
+ setMoveAnchor(null);
3412
+ } else {
3413
+ setMoveAnchor(anchorFor(anchorEl, "move"));
3414
+ setMoveFor({ id: sessionId, displayTitle, workspaceId: "" });
3415
+ }
3416
+ }
3417
+ },
3418
+ h("span", { className: "sm-headerBtnIcon" }, "↔"),
3419
+ h("span", null, t ? t("row.move") : "移动至工作区")
3420
+ ),
3421
+ (onArchive || onUnarchive) ? h("button", {
3422
+ type: "button",
3423
+ className: "sm-headerMenuItem",
3424
+ role: "menuitem",
3425
+ onClick: () => {
3426
+ setMoreOpen(false);
3427
+ runWithAlert("archive", () => isArchived ? onUnarchive(sessionId) : onArchive(sessionId));
3428
+ }
3429
+ },
3430
+ h("span", { className: "sm-headerBtnIcon" }, isArchived ? "📤" : "📥"),
3431
+ h("span", null, isArchived ? (t ? t("row.unarchive") : "移出归档") : (t ? t("row.archive") : "归档"))
3432
+ ) : null,
3433
+ h("button", {
3434
+ type: "button",
3435
+ className: "sm-headerMenuItem sm-headerMenuItemDanger",
3436
+ role: "menuitem",
3437
+ onClick: () => {
3438
+ const anchorEl = getMoreBtn() || moreBtnRef.current;
3439
+ setMoreOpen(false);
3440
+ if (confirmFor && confirmFor.id === sessionId) {
3441
+ setConfirmFor(null);
3442
+ setConfirmAnchor(null);
3443
+ } else {
3444
+ setConfirmAnchor(anchorFor(anchorEl, "delete"));
3445
+ setConfirmFor({ id: sessionId, displayTitle });
3446
+ }
3447
+ }
3448
+ },
3449
+ h("span", { className: "sm-headerBtnIcon" }, "🗑"),
3450
+ h("span", null, t ? t("row.delete") : "删除会话")
3451
+ )
3452
+ ) : null
3453
+ )
2573
3454
  ),
2574
3455
  confirmFor === null ? null : h(ConfirmDialog, {
2575
3456
  open: true,
@@ -2626,8 +3507,8 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2626
3507
  // Bulk operations need to refresh ctx.sessions.list and the
2627
3508
  // workspace projection after /batch mutates disk state so the
2628
3509
  // panel reflects the new layout.
2629
- onRefreshAfterBulk: async () => {
2630
- try { await this.props.props.onBulkRefresh(); } catch (_) { /* ignore */ }
3510
+ onRefreshAfterBulk: async (...args) => {
3511
+ try { await this.props.props.onBulkRefresh?.(...args); } catch (_) { /* ignore */ }
2631
3512
  },
2632
3513
  onOpen: (id) => { try { this.props.panelStore.set(false); this.props.props.onOpen(id); } catch (_) {} },
2633
3514
  onArchive: this.props.props.onArchive,
@@ -2653,10 +3534,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2653
3534
  () => panelStore.getSnapshot(),
2654
3535
  () => panelStore.getSnapshot()
2655
3536
  );
2656
- const footerClass = "sm-footer" + (wide ? " sm-footer-wide" : " sm-footer-rail");
3537
+ const updateState = useSyncExternalStore(
3538
+ (cb) => updateStore.subscribe(cb),
3539
+ () => updateStore.getSnapshot(),
3540
+ () => updateStore.getSnapshot()
3541
+ );
2657
3542
  const btnClass = "sm-footerBtn" + (wide ? " sm-footerBtn-wide" : " sm-footerBtn-rail");
2658
3543
  const btnLabel = t("footer.aria");
2659
- return h("div", { className: footerClass },
3544
+ return h(React.Fragment, null,
2660
3545
  h("button", {
2661
3546
  type: "button",
2662
3547
  className: btnClass,
@@ -2673,11 +3558,344 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2673
3558
  t: t,
2674
3559
  useSessions: props.useSessions,
2675
3560
  useWorkspaces: props.useWorkspaces,
2676
- }) : null
3561
+ }) : null,
3562
+ updateState.dialogOpen ? h(UpdateDialog, { t: t }) : null
3563
+ );
3564
+ }
3565
+
3566
+ function NpmIcon(props) {
3567
+ const size = props.size || 16;
3568
+ return h("svg", {
3569
+ viewBox: "0 0 16 16",
3570
+ width: size,
3571
+ height: size,
3572
+ fill: "currentColor",
3573
+ "aria-hidden": "true",
3574
+ style: { display: "block" }
3575
+ },
3576
+ h("path", {
3577
+ fillRule: "evenodd",
3578
+ d: "M0 0v16h16V0H0zm13 13h-2V5H8v8H3V3h10v10z"
3579
+ })
3580
+ );
3581
+ }
3582
+ const WhaleIcon = NpmIcon;
3583
+
3584
+ function CloseIcon(props) {
3585
+ const size = props.size || 14;
3586
+ return h("svg", {
3587
+ viewBox: "0 0 16 16",
3588
+ width: size,
3589
+ height: size,
3590
+ fill: "none",
3591
+ stroke: "currentColor",
3592
+ strokeWidth: "1.8",
3593
+ strokeLinecap: "round",
3594
+ strokeLinejoin: "round",
3595
+ "aria-hidden": "true",
3596
+ style: { display: "block" }
3597
+ },
3598
+ h("path", { d: "M3.5 3.5l9 9M12.5 3.5l-9 9" })
3599
+ );
3600
+ }
3601
+
3602
+ function StarIcon(props) {
3603
+ const size = props.size || 14;
3604
+ return h("svg", {
3605
+ viewBox: "0 0 16 16",
3606
+ width: size,
3607
+ height: size,
3608
+ fill: "#eac54f",
3609
+ "aria-hidden": "true",
3610
+ style: { display: "block" }
3611
+ },
3612
+ h("path", {
3613
+ d: "M8 .25a.75.75 0 0 1 .673.418l1.882 3.815 4.21.612a.75.75 0 0 1 .416 1.279l-3.046 2.97.719 4.192a.75.75 0 0 1-1.088.791L8 12.347l-3.766 1.98a.75.75 0 0 1-1.088-.79l.72-4.194L.818 6.374a.75.75 0 0 1 .416-1.28l4.21-.611L7.327.668A.75.75 0 0 1 8 .25z"
3614
+ })
3615
+ );
3616
+ }
3617
+
3618
+ function IssueIcon(props) {
3619
+ const size = props.size || 14;
3620
+ return h("svg", {
3621
+ viewBox: "0 0 16 16",
3622
+ width: size,
3623
+ height: size,
3624
+ fill: "currentColor",
3625
+ "aria-hidden": "true",
3626
+ style: { display: "block" }
3627
+ },
3628
+ h("path", {
3629
+ fillRule: "evenodd",
3630
+ d: "M8 1.5a6.5 6.5 0 1 0 0 13 6.5 6.5 0 0 0 0-13zM0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm9 3a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-.25-6.25a.75.75 0 0 0-1.5 0v3.5a.75.75 0 0 0 1.5 0v-3.5z"
3631
+ })
3632
+ );
3633
+ }
3634
+
3635
+ function UpdateDialog(props) {
3636
+ const t = props.t || ((k) => k);
3637
+ const updateState = useSyncExternalStore(
3638
+ (cb) => updateStore.subscribe(cb),
3639
+ () => updateStore.getSnapshot(),
3640
+ () => updateStore.getSnapshot()
3641
+ );
3642
+
3643
+ const status = updateState.status;
3644
+ const isUpdating = status === "updating";
3645
+ const isDone = status === "done";
3646
+ const isError = status === "error";
3647
+ const isAvailable = status === "available";
3648
+ const isChecking = status === "checking";
3649
+ const isIdle = status === "idle";
3650
+
3651
+ let dialogTitle = t("update.title");
3652
+ if (isAvailable) dialogTitle = t("update.newVersion");
3653
+ else if (isUpdating) dialogTitle = t("update.installing");
3654
+ else if (isDone) dialogTitle = t("update.title");
3655
+ else if (isError) dialogTitle = t("update.error");
3656
+
3657
+ const handleClose = () => {
3658
+ if (!isUpdating) {
3659
+ updateStore.closeDialog();
3660
+ }
3661
+ };
3662
+
3663
+ return h(OverlayLayer, {
3664
+ className: "sm-updateDialogLayer",
3665
+ onBackdropClick: handleClose,
3666
+ onKeyDown: (e) => {
3667
+ if (e.key === "Escape" && !isUpdating) handleClose();
3668
+ }
3669
+ },
3670
+ h("section", {
3671
+ className: "sm-nativeDialog sm-updateDialog",
3672
+ style: { pointerEvents: "auto" },
3673
+ role: "dialog",
3674
+ "aria-modal": "true",
3675
+ "aria-labelledby": "sm-update-dialog-title"
3676
+ },
3677
+ h("div", { className: "sm-nativeDialogHeader" },
3678
+ h("h3", { id: "sm-update-dialog-title", className: "sm-nativeDialogTitle" }, dialogTitle),
3679
+ !isUpdating ? renderTip(t("update.btn.close"), h("button", {
3680
+ type: "button",
3681
+ className: "sm-panelHeaderClose",
3682
+ "aria-label": t("update.btn.close"),
3683
+ onClick: handleClose
3684
+ }, h(CloseIcon, { size: 14 }))) : null
3685
+ ),
3686
+ h("div", { className: "sm-nativeDialogBody" },
3687
+ h("div", { className: "sm-updateVersionGrid" },
3688
+ h("span", { className: "sm-updateVersionLabel" }, t("update.currentVersion")),
3689
+ h("span", { className: "sm-updateVersionValue" }, "v" + updateState.currentVersion),
3690
+ h("span", { className: "sm-updateVersionLabel" }, t("update.latestVersion")),
3691
+ h("span", { className: "sm-updateVersionValue" }, updateState.latestVersion ? "v" + updateState.latestVersion : (isChecking ? t("update.checking") : "-"))
3692
+ ),
3693
+ isChecking ? h("div", { className: "sm-updateStatusBox" }, t("update.checking")) : null,
3694
+ isAvailable ? h("div", { className: "sm-updateStatusBox sm-warn" }, t("update.newVersion") + " (v" + updateState.latestVersion + ")") : null,
3695
+ isUpdating ? h("div", { className: "sm-updateStatusBox sm-warn" }, t("update.installing")) : null,
3696
+ isDone ? h("div", { className: "sm-updateStatusBox sm-success" },
3697
+ updateState.application === "applied"
3698
+ ? t("update.done.applied")
3699
+ : t("update.done.restart", { from: updateState.currentVersion, to: updateState.latestVersion || updateState.currentVersion })
3700
+ ) : null,
3701
+ isError ? h("div", { className: "sm-updateStatusBox sm-error" }, (updateState.error || t("update.error"))) : null,
3702
+ (isIdle && updateState.latestVersion && !isAvailable) ? h("div", { className: "sm-updateStatusBox sm-success" }, t("update.isLatest")) : null
3703
+ ),
3704
+ h("div", { className: "sm-nativeDialogFooter" },
3705
+ isAvailable ? h(React.Fragment, null,
3706
+ h("button", {
3707
+ type: "button",
3708
+ className: "sm-nativeDialogButton sm-nativeDialogCancel",
3709
+ onClick: handleClose
3710
+ }, t("update.btn.later")),
3711
+ h("button", {
3712
+ type: "button",
3713
+ className: "sm-nativeDialogButton sm-nativeDialogConfirm",
3714
+ onClick: () => updateStore.startUpdate()
3715
+ }, t("update.btn.update", { version: updateState.latestVersion }))
3716
+ ) : null,
3717
+ isUpdating ? h("button", {
3718
+ type: "button",
3719
+ className: "sm-nativeDialogButton sm-nativeDialogConfirm",
3720
+ disabled: true
3721
+ }, t("update.btn.updating")) : null,
3722
+ isDone ? h("button", {
3723
+ type: "button",
3724
+ className: "sm-nativeDialogButton sm-nativeDialogConfirm",
3725
+ onClick: handleClose
3726
+ }, t("update.btn.done")) : null,
3727
+ isError ? h(React.Fragment, null,
3728
+ h("button", {
3729
+ type: "button",
3730
+ className: "sm-nativeDialogButton sm-nativeDialogCancel",
3731
+ onClick: handleClose
3732
+ }, t("update.btn.close")),
3733
+ h("button", {
3734
+ type: "button",
3735
+ className: "sm-nativeDialogButton sm-nativeDialogConfirm",
3736
+ onClick: () => {
3737
+ if (updateState.latestVersion && compareSemver(updateState.latestVersion, updateState.currentVersion) > 0) {
3738
+ updateStore.startUpdate();
3739
+ } else {
3740
+ updateStore.checkForUpdate({ manual: true, openDialog: true });
3741
+ }
3742
+ }
3743
+ }, t("update.btn.retry"))
3744
+ ) : null,
3745
+ (isIdle || isChecking) ? h(React.Fragment, null,
3746
+ h("button", {
3747
+ type: "button",
3748
+ className: "sm-nativeDialogButton sm-nativeDialogCancel",
3749
+ onClick: handleClose
3750
+ }, t("update.btn.close")),
3751
+ !isChecking ? h("button", {
3752
+ type: "button",
3753
+ className: "sm-nativeDialogButton",
3754
+ onClick: () => updateStore.checkForUpdate({ manual: true, openDialog: true })
3755
+ }, t("update.btn.check")) : null
3756
+ ) : null
3757
+ )
3758
+ )
3759
+ );
3760
+ }
3761
+
3762
+ function SessionManagerSettingsCard(props) {
3763
+ const t = props.t || ((k, v) => {
3764
+ const dict = zh[k] || en[k] || k;
3765
+ return dict.replace(/\{(\w+)\}/g, (_, name) => String(v?.[name] ?? ""));
3766
+ });
3767
+ const updateState = useSyncExternalStore(
3768
+ (cb) => updateStore.subscribe(cb),
3769
+ () => updateStore.getSnapshot(),
3770
+ () => updateStore.getSnapshot()
3771
+ );
3772
+ const autoCheck = updateStore.getAutoCheck();
3773
+
3774
+ const isChecking = updateState.status === "checking";
3775
+ const isUpdating = updateState.status === "updating";
3776
+ const isAvailable = updateState.status === "available";
3777
+
3778
+ const onToggleAutoCheck = (e) => {
3779
+ updateStore.setAutoCheck(e.target.checked);
3780
+ };
3781
+ const currentRegistry = updateStore.getRegistry();
3782
+ const onRegistryChange = (e) => {
3783
+ updateStore.setRegistry(e.target.value);
3784
+ };
3785
+
3786
+ return h("div", { className: "sm-settingsCard" },
3787
+ h("div", { className: "sm-settingsHeader" },
3788
+ h("h3", { className: "sm-settingsTitle" },
3789
+ h(NpmIcon, { size: 18 }),
3790
+ h("span", null, t("settings.title")),
3791
+ h("span", { className: "sm-settingsTag" }, "v" + updateState.currentVersion)
3792
+ )
3793
+ ),
3794
+ h("div", { className: "sm-settingsSection" },
3795
+ h("div", { className: "sm-settingsSectionHeader" },
3796
+ h("div", { className: "sm-settingsSectionTitle" }, t("settings.versionSection")),
3797
+ h("div", { className: "sm-settingsVersionActions" },
3798
+ h("button", {
3799
+ type: "button",
3800
+ className: "sm-nativeDialogButton sm-settingsCheckBtn",
3801
+ disabled: isChecking || isUpdating,
3802
+ onClick: () => updateStore.checkForUpdate({ manual: true, openOnFound: false, openDialog: false })
3803
+ }, isChecking ? t("update.checking") : t("update.btn.check")),
3804
+ isAvailable ? h("button", {
3805
+ type: "button",
3806
+ className: "sm-nativeDialogButton sm-nativeDialogConfirm sm-settingsCheckBtn",
3807
+ disabled: isUpdating,
3808
+ onClick: () => updateStore.startUpdate({ openDialog: false })
3809
+ }, isUpdating ? t("update.btn.updating") : t("update.btn.update", { version: updateState.latestVersion })) : null
3810
+ )
3811
+ ),
3812
+ h("div", { className: "sm-settingsRow" },
3813
+ h("span", null, t("update.currentVersion")),
3814
+ h("span", { style: { fontFamily: "monospace" } }, "v" + updateState.currentVersion)
3815
+ ),
3816
+ h("div", { className: "sm-settingsRow" },
3817
+ h("span", null, t("update.latestVersion")),
3818
+ h("span", { style: { fontFamily: "monospace" } },
3819
+ updateState.latestVersion ? "v" + updateState.latestVersion : (isChecking ? t("update.checking") : "-")
3820
+ )
3821
+ ),
3822
+ updateState.status === "available" ? h("div", { className: "sm-updateStatusBox sm-warn" },
3823
+ t("update.newVersion") + " (v" + updateState.latestVersion + ")"
3824
+ ) : null,
3825
+ updateState.status === "updating" ? h("div", { className: "sm-updateStatusBox sm-warn" },
3826
+ t("update.installing")
3827
+ ) : null,
3828
+ updateState.status === "done" ? h("div", { className: "sm-updateStatusBox sm-success" },
3829
+ updateState.application === "applied" ? t("update.done.applied") : t("update.done.restart", { from: updateState.currentVersion, to: updateState.latestVersion || updateState.currentVersion })
3830
+ ) : null,
3831
+ updateState.status === "error" ? h("div", { className: "sm-updateStatusBox sm-error" },
3832
+ updateState.error || t("update.error")
3833
+ ) : null
3834
+ ),
3835
+ h("div", { className: "sm-settingsSection" },
3836
+ h("div", { className: "sm-settingsSectionTitle" }, t("settings.prefSection")),
3837
+ h("div", { className: "sm-settingsRow" },
3838
+ h("span", null, t("settings.registry")),
3839
+ h("select", {
3840
+ className: "sm-settingsSelect",
3841
+ value: currentRegistry,
3842
+ onChange: onRegistryChange,
3843
+ "aria-label": t("settings.registry")
3844
+ },
3845
+ h("option", { value: "registry.npmjs.org" }, t("settings.registry.npm")),
3846
+ h("option", { value: "registry.npmmirror.com" }, t("settings.registry.china"))
3847
+ )
3848
+ ),
3849
+ h("div", { className: "sm-settingsRow" },
3850
+ h("span", null, t("update.autoCheck")),
3851
+ h("label", { className: "sm-settingsCheckbox" },
3852
+ h("input", {
3853
+ type: "checkbox",
3854
+ checked: autoCheck,
3855
+ onChange: onToggleAutoCheck,
3856
+ "aria-label": t("update.autoCheck")
3857
+ }),
3858
+ h("span", null, t("update.autoCheck.enable"))
3859
+ )
3860
+ )
3861
+ ),
3862
+ h("div", { className: "sm-settingsSection" },
3863
+ h("div", { className: "sm-settingsSectionTitle" }, t("settings.projectSection")),
3864
+ h("div", { className: "sm-settingsRow sm-settingsRowInline" },
3865
+ h("span", null, t("settings.github")),
3866
+ h("a", {
3867
+ href: "https://github.com/hkkz9522/dsh-session-manager",
3868
+ target: "_blank",
3869
+ rel: "noopener noreferrer",
3870
+ className: "sm-settingsLink"
3871
+ }, "hkkz9522/dsh-session-manager"),
3872
+ h("a", {
3873
+ href: "https://github.com/hkkz9522/dsh-session-manager",
3874
+ target: "_blank",
3875
+ rel: "noopener noreferrer",
3876
+ className: "sm-settingsBadgeLink",
3877
+ title: "Star on GitHub"
3878
+ },
3879
+ h(StarIcon, { size: 14 }),
3880
+ h("span", null, t("settings.star"))
3881
+ ),
3882
+ h("a", {
3883
+ href: "https://github.com/hkkz9522/dsh-session-manager/issues",
3884
+ target: "_blank",
3885
+ rel: "noopener noreferrer",
3886
+ className: "sm-settingsBadgeLink",
3887
+ title: "GitHub Issues"
3888
+ },
3889
+ h(IssueIcon, { size: 14 }),
3890
+ h("span", null, t("settings.feedback"))
3891
+ )
3892
+ )
3893
+ )
2677
3894
  );
2678
3895
  }
2679
3896
 
2680
3897
  function apply(ctx) {
3898
+ activeClientCtx = ctx;
2681
3899
  ctx.effect(() => {
2682
3900
  const refresh = () => { if (annotationStore.hasSubscribers()) void annotationStore.load(true); };
2683
3901
  window.addEventListener("focus", refresh);
@@ -2692,6 +3910,34 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2692
3910
  return () => { window.removeEventListener("focus", refresh); channel?.close(); annotationStore.notify = null; };
2693
3911
  }, "session-manager: annotation synchronization");
2694
3912
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), "session-manager: dictionaries");
3913
+ const getCurrentSessionId = () => {
3914
+ try {
3915
+ const id = ctx.uiWorkspace?.mainReference?.sessionId
3916
+ || ctx.uiWorkspace?.selection?.getSnapshot?.()?.sessionId
3917
+ || ctx.sessions?.list?.getSnapshot?.()?.current;
3918
+ return typeof id === "string" && id ? id : null;
3919
+ } catch (_) {
3920
+ return null;
3921
+ }
3922
+ };
3923
+
3924
+ const isCurrentSession = (id) => {
3925
+ if (!id) return false;
3926
+ return getCurrentSessionId() === id;
3927
+ };
3928
+
3929
+ const clearCurrentSession = () => {
3930
+ const uiWorkspace = ctx.uiWorkspace;
3931
+ if (uiWorkspace && typeof uiWorkspace.clearMain === "function") {
3932
+ try { uiWorkspace.clearMain(); } catch (_) {}
3933
+ } else if (uiWorkspace && typeof uiWorkspace.startSession === "function") {
3934
+ try { uiWorkspace.startSession(); } catch (_) {}
3935
+ }
3936
+ if (ctx.sessions && typeof ctx.sessions.clear === "function") {
3937
+ try { ctx.sessions.clear(); } catch (_) {}
3938
+ }
3939
+ };
3940
+
2695
3941
  const actions = () => ({
2696
3942
  // DSH 0.1.6+ removed ctx.sessions.open(); the navigation owner is
2697
3943
  // `ctx.uiWorkspace.openSession()`, and the bare SessionController only
@@ -2713,18 +3959,28 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2713
3959
  }
2714
3960
  throw new Error("session-manager: no Session open API on this DSH host");
2715
3961
  },
2716
- onArchive: async (sessionId) => { await ctx.workspaces.archiveSession(sessionId); },
3962
+ onArchive: async (sessionId) => {
3963
+ if (ctx.uiWorkspace && typeof ctx.uiWorkspace.archiveSession === "function") {
3964
+ await ctx.uiWorkspace.archiveSession(sessionId);
3965
+ } else {
3966
+ await ctx.workspaces.archiveSession(sessionId);
3967
+ }
3968
+ },
2717
3969
  onUnarchive: async (sessionId) => {
2718
3970
  const response = await callApi("/unarchive", { sessionId });
2719
3971
  if (!response.ok) throw new Error(response.error || "unarchive failed");
2720
3972
  },
2721
3973
  onRemove: async (sessionId) => {
3974
+ const wasCurrent = isCurrentSession(sessionId);
2722
3975
  const response = await callApi("/delete", { sessionId });
2723
3976
  if (!response.ok) throw new Error(response.error || "delete failed");
2724
3977
  await annotationStore.load(true);
2725
3978
  if (response.result?.warning) window.alert(response.result.warning);
2726
- const current = ctx.sessions.list.getSnapshot().current;
2727
- if (current === sessionId) ctx.sessions.clear();
3979
+ if (wasCurrent || isCurrentSession(sessionId)) {
3980
+ clearCurrentSession();
3981
+ }
3982
+ try { await ctx.sessions?.refresh?.(); } catch (_) {}
3983
+ try { await ctx.workspaces?.refresh?.(); } catch (_) {}
2728
3984
  },
2729
3985
  onMove: async (sessionId, targetWorkspaceId) => {
2730
3986
  const wasCurrent = ctx.sessions.list.getSnapshot().current === sessionId;
@@ -2754,7 +4010,6 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2754
4010
  if (!response.ok) throw new Error(response.error || "preset migration failed");
2755
4011
  // The current DSH client session store derives agentPreset from
2756
4012
  // the refreshed projection; older builds exposed noteAgentPreset,
2757
- onOpenPanel: () => panelStore.toggle(),
2758
4013
  await ctx.sessions.refresh();
2759
4014
  // The migrate rewrite happens in-process on the live session, so
2760
4015
  // we just need a delayed baseline to let the api-gateway's projection
@@ -2766,7 +4021,31 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2766
4021
  }, 250);
2767
4022
  },
2768
4023
  onOpenPanel: () => panelStore.toggle(),
2769
- onBulkRefresh: async () => { try { await ctx.sessions.refresh(); } catch (_) { /* ignore */ } try { await ctx.workspaces.refresh(); } catch (_) { /* ignore */ } },
4024
+ onBulkRefresh: async (action, meta) => {
4025
+ const currentBefore = getCurrentSessionId();
4026
+ if (action === "delete" || action === "archive") {
4027
+ const items = meta?.items || meta?.result?.items || [];
4028
+ const successIds = items
4029
+ .filter(item => item && (item.status === "success" || item.ok === true))
4030
+ .map(item => item.sessionId);
4031
+ const batchIds = (lastBatchContext.action === action && Array.isArray(lastBatchContext.ids)) ? lastBatchContext.ids : [];
4032
+ const candidateIds = successIds.length > 0 ? successIds : (meta?.ids || batchIds);
4033
+ if (candidateIds.some(isCurrentSession)) {
4034
+ clearCurrentSession();
4035
+ }
4036
+ }
4037
+ try { await ctx.sessions?.refresh?.(); } catch (_) { /* ignore */ }
4038
+ try { await ctx.workspaces?.refresh?.(); } catch (_) { /* ignore */ }
4039
+ if (currentBefore && (action === "delete" || action === "archive")) {
4040
+ const sessionsSnapshot = ctx.sessions?.list?.getSnapshot?.();
4041
+ const workspacesSnapshot = ctx.workspaces?.list?.getSnapshot?.();
4042
+ const deleted = sessionsSnapshot?.byId && sessionsSnapshot.byId[currentBefore] === undefined;
4043
+ const archived = Array.isArray(workspacesSnapshot?.archivedSessionIds) && workspacesSnapshot.archivedSessionIds.includes(currentBefore);
4044
+ if (deleted || archived) {
4045
+ clearCurrentSession();
4046
+ }
4047
+ }
4048
+ },
2770
4049
  });
2771
4050
  ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
2772
4051
  name: "conversation.session.header.actions",
@@ -2782,12 +4061,66 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2782
4061
  locale: NS,
2783
4062
  inject: () => actions()
2784
4063
  }, FooterAction));
4064
+ ctx.slots.inject("plugins.bundle.config", () => ctx.slots.register({
4065
+ name: "plugins.bundle.config",
4066
+ id: "dsh-session-manager-bundle-config",
4067
+ key: "dsh-session-manager",
4068
+ locale: NS,
4069
+ inject: () => actions()
4070
+ }, (ownerProps = {}) => (ownerProps?.view === "summary" ? null : h(SessionManagerSettingsCard, ownerProps))));
4071
+
4072
+ try {
4073
+ if (typeof ctx.inject === "function") {
4074
+ ctx.inject(["settingsScope"], (scoped) => {
4075
+ if (scoped && scoped.slots) {
4076
+ scoped.slots.inject("settings.plugin.item", () => scoped.slots.register({
4077
+ name: "settings.plugin.item",
4078
+ id: "session-manager-settings-scoped",
4079
+ key: "dsh-session-manager",
4080
+ locale: NS,
4081
+ inject: () => actions()
4082
+ }, SessionManagerSettingsCard));
4083
+ }
4084
+ });
4085
+ }
4086
+ } catch (_) {}
4087
+
4088
+ ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
4089
+ name: "settings.plugin.item",
4090
+ id: "session-manager-settings",
4091
+ key: "dsh-session-manager",
4092
+ order: 50,
4093
+ locale: NS,
4094
+ inject: () => actions()
4095
+ }, SessionManagerSettingsCard));
4096
+
4097
+ ctx.effect(() => {
4098
+ if (!updateStore.getAutoCheck()) return;
4099
+ const timer = setTimeout(() => {
4100
+ updateStore.checkForUpdate({ silent: true, openOnFound: false, openDialog: false }).catch(() => {});
4101
+ }, 1500);
4102
+ return () => {
4103
+ try {
4104
+ if (typeof clearTimeout === "function") clearTimeout(timer);
4105
+ else if (typeof window !== "undefined" && typeof window.clearTimeout === "function") window.clearTimeout(timer);
4106
+ } catch (_) {}
4107
+ };
4108
+ }, "session-manager: auto update check");
2785
4109
  }
2786
4110
 
2787
4111
  const inject = ["slots", "sessions", "workspaces", "locale", "uiWorkspace"];
2788
4112
 
2789
4113
  exports.apply = apply;
2790
4114
  exports.inject = inject;
4115
+ exports.updateStore = updateStore;
4116
+ exports.compareSemver = compareSemver;
4117
+ exports.UpdateDialog = UpdateDialog;
4118
+ exports.SessionManagerSettingsCard = SessionManagerSettingsCard;
4119
+ exports.WhaleIcon = WhaleIcon;
4120
+ exports.NpmIcon = NpmIcon;
4121
+ exports.CloseIcon = CloseIcon;
4122
+ exports.StarIcon = StarIcon;
4123
+ exports.IssueIcon = IssueIcon;
2791
4124
  return module.exports;
2792
4125
  }
2793
4126
  });