dsh-session-manager 0.5.3 → 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": "移出归档",
@@ -128,7 +146,39 @@ function nextDialogZ() { return ++dialogZStackCounter; }
128
146
  "footer.aria": "会话管理",
129
147
  "footer.label": "会话管理",
130
148
  "panel.title": "会话管理",
131
- "panel.github.title": "欢迎Star和Issue",
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": "全部工作区",
@@ -285,7 +335,6 @@ function nextDialogZ() { return ++dialogZStackCounter; }
285
335
  "marks.discard": "Discard unsaved annotation changes?",
286
336
  "marks.note.exists": "Has note",
287
337
  "marks.sort": "Priority (1 → 5)",
288
- "marks.note.exists": "Has note",
289
338
  "marks.import.copy": "Copy Prompt",
290
339
  "marks.import.copy.copied": "Copied. Paste it into the current conversation to generate the result.",
291
340
  "marks.import.copy.failed": "Copy failed: {message}",
@@ -304,6 +353,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
304
353
  "marks.tags.clear": "Clear tags",
305
354
  "marks.note.clear": "Clear note",
306
355
  "header.aria": "Session actions",
356
+ "header.more": "More actions",
307
357
  "menu.open": "Open",
308
358
  "menu.archive": "Archive session",
309
359
  "menu.unarchive": "Unarchive session",
@@ -313,7 +363,39 @@ function nextDialogZ() { return ++dialogZStackCounter; }
313
363
  "footer.aria": "Session manager",
314
364
  "footer.label": "Sessions",
315
365
  "panel.title": "Session manager",
316
- "panel.github.title": "Star or open an issue",
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",
317
399
  "panel.search": "Search title, ID, tags or notes",
318
400
  "panel.workspace": "Workspace",
319
401
  "panel.workspace.all": "All workspaces",
@@ -470,17 +552,17 @@ function nextDialogZ() { return ++dialogZStackCounter; }
470
552
  ".sm-moveItem:hover{background:var(--dsw-alias-interactive-bg-hover)}",
471
553
  ".sm-moveItemSelected{border-color:var(--dsw-alias-accent-primary);background:var(--dsw-alias-accent-primary-bg)}",
472
554
  ".sm-moveItemName{color:var(--dsw-alias-label-primary);font-size:13px;line-height:18px}",
473
- ".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)}",
474
- ".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)}",
475
- ".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}",
476
558
 
477
559
  // Theme colors are scoped to the plugin dialogs. DSH exposes its
478
560
  // actual theme through `body[data-ds-dark-theme]` and color-scheme;
479
561
  // keeping these values local avoids changing DSH's global variables.
480
- "[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}",
481
- "[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)}",
482
- "[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}",
483
- "[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}",
484
566
  ".sm-panelDialog{max-height:min(640px,calc(100vh - 32px))}.sm-panelDialog .sm-panel{min-width:0;overflow:hidden}",
485
567
  ".sm-panelTools{display:flex;flex-direction:column;gap:8px;flex:none;padding:2px 0 6px}",
486
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}",
@@ -492,13 +574,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
492
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)}",
493
575
  "[data-sm-theme=dark] .sm-priority-1{color:#fdba74}[data-sm-theme=dark] .sm-priority-2{color:#fde68a}",
494
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)}",
495
- ".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}",
496
- ".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)}",
497
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)}",
498
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}",
499
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}",
500
582
  ".sm-bulkSummary{color:var(--dsw-alias-label-primary,#111);font-size:12px;line-height:18px;font-weight:500}",
501
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}",
502
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}",
503
586
  ".sm-bulkBar .sm-bulkBtn:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary,#111)}",
504
587
  ".sm-bulkBar .sm-bulkBtn:disabled{opacity:.5;cursor:not-allowed}",
@@ -509,7 +592,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
509
592
  ".sm-bulkRowCheckbox input{width:14px;height:14px;cursor:pointer;margin:0}",
510
593
  ".sm-bulkRowCheckbox input:disabled{cursor:not-allowed}",
511
594
  ".sm-rowBulkSelected{border-color:var(--dsw-alias-accent-primary,#356ae6);background:var(--dsw-alias-accent-primary-bg,rgba(53,106,230,.06))}",
512
- ".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}",
513
596
  ".sm-bulkDialog .sm-nativeDialog{width:100%;max-height:min(640px,calc(100vh - 32px))}",
514
597
  ".sm-bulkDialogBody{display:flex;flex-direction:column;gap:12px;min-height:0}",
515
598
  ".sm-bulkDialogSummary{font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary,#111)}",
@@ -527,13 +610,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
527
610
  ".sm-bulkResultItemReason{color:var(--dsw-alias-state-error-primary);font-size:11px;line-height:16px;word-break:break-word}",
528
611
  ".sm-bulkResultItemReasonSkip{color:var(--dsw-alias-label-tertiary,#888)}",
529
612
  ".sm-bulkResultFooter{display:flex;justify-content:space-between;align-items:center;gap:8px;flex-wrap:wrap}",
530
- ".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}",
531
614
  ".sm-footerBtn-wide:hover,.sm-footerBtn-wide:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
532
- ".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}",
533
616
  ".sm-footerBtn-rail:hover,.sm-footerBtn-rail:focus-visible{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
534
617
  ".sm-footerBtn-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;max-width:100%}",
535
- ".sm-footer-wide{display:flex;width:100%}",
536
- ".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}",
537
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)}}",
538
622
  ].join("");
539
623
 
@@ -657,6 +741,268 @@ function nextDialogZ() { return ++dialogZStackCounter; }
657
741
  try { installAnchor(); } catch (_) {}
658
742
 
659
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
+
660
1006
  const callApi = (path, payload) => fetch(API + path, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(payload || {}) }).then((r) => r.json());
661
1007
  const fetchApi = (path, options) => fetch(API + path, options).then((r) => r.json());
662
1008
  // Run a bulk action across many sessionIds. /batch already does per-id
@@ -744,12 +1090,30 @@ function nextDialogZ() { return ++dialogZStackCounter; }
744
1090
  const annotationButtons = (id, title, t, state, className, onToggle, onEdit, disabled = false, editorOpen = false) => {
745
1091
  const value = annotationOf(state, id);
746
1092
  const busy = disabled || !state.loaded || !!state.error || state.pending.has(id);
747
- const favoriteLabel = t(value.favorite ? "marks.favorite.remove" : "marks.favorite.add") + ": " + title;
748
- 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";
749
1098
  return h(React.Fragment, null,
750
- 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 ? "★" : "☆"),
751
- 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 }) }, "◷"),
752
- 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
+ ))
753
1117
  );
754
1118
  };
755
1119
 
@@ -1240,17 +1604,19 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1240
1604
  return "zh";
1241
1605
  };
1242
1606
  const activeLanguage = detectLanguage(t);
1243
- const hasAnchor = anchor && typeof anchor.top === "number" && typeof anchor.left === "number";
1244
- const layerClass = "sm-nativeDialogLayer sm-annotationDialog sm-confirmDialog" + (hasAnchor ? " sm-annotationDialog-anchored" : "");
1245
- const surfaceClass = "sm-nativeDialog sm-panelDialog sm-annotationSurface" + (hasAnchor ? " sm-annotationSurface-anchored" : "");
1246
- // Default position matches ConfirmDialog / MoveDialog so all inner
1247
- // 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" : "");
1248
1613
  const layerStyle = {
1249
1614
  zIndex: zIndex || undefined,
1250
- ...(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` } : {})
1251
1616
  };
1252
- return h("div", { className: layerClass, style: layerStyle, role: "presentation" },
1253
- 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 },
1254
1620
  h("div", { className: "sm-nativeDialogHeader" }, h("h2", { id: "sm-annotation-title", className: "sm-nativeDialogTitle" }, t("marks.title"))),
1255
1621
  h("div", { className: "sm-annotationBody" },
1256
1622
  h("div", { className: "sm-annotationTarget", title: displayTitle || sessionId }, displayTitle || sessionId),
@@ -1285,7 +1651,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1285
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"))
1286
1652
  )
1287
1653
  )
1288
- );
1654
+ ));
1289
1655
  }
1290
1656
 
1291
1657
 
@@ -1352,24 +1718,31 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1352
1718
  window.addEventListener("keydown", handler);
1353
1719
  return () => window.removeEventListener("keydown", handler);
1354
1720
  }, [open]);
1355
- // 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.
1356
1721
 
1722
+ const floatingCoords = useFloatingPosition(props.anchor, open, { placement: "bottom-end", dialogWidth: 360, dialogHeight: 180 });
1357
1723
 
1358
1724
  if (!open) return null;
1359
1725
 
1360
- return h("div", {
1361
- className: "sm-nativeDialogLayer sm-confirmDialog",
1362
- style: {
1363
- zIndex: zIndex || undefined,
1364
- ...(props.anchor && typeof props.anchor.top === "number"
1365
- ? { position: "fixed", top: props.anchor.top + "px", left: props.anchor.left + "px" }
1366
- : {})
1367
- },
1368
- role: "presentation"
1369
- },
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;
1370
1729
 
1371
- h("section", {
1372
- 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" },
1373
1746
  role: "dialog",
1374
1747
  "aria-modal": "true",
1375
1748
  "aria-labelledby": "sm-confirm-dialog-title"
@@ -1396,7 +1769,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1396
1769
  }, confirmLabel)
1397
1770
  )
1398
1771
  )
1399
- );
1772
+ ));
1400
1773
  }
1401
1774
 
1402
1775
  function MoveDialog(props) {
@@ -1477,20 +1850,27 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1477
1850
  onConfirm(selectedWorkspaceId);
1478
1851
  }
1479
1852
  };
1480
- return h("div", {
1481
- className: "sm-nativeDialogLayer sm-confirmDialog",
1482
- style: {
1483
- zIndex: zIndex || undefined,
1484
- ...(props.anchor && typeof props.anchor.top === "number"
1485
- ? { position: "fixed", top: props.anchor.top + "px", left: props.anchor.left + "px" }
1486
- : {})
1487
- },
1488
- role: "presentation",
1489
- onKeyDown
1490
- },
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;
1491
1857
 
1492
- h("section", {
1493
- 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" },
1494
1874
  role: "dialog",
1495
1875
  "aria-modal": "true",
1496
1876
  "aria-labelledby": "sm-move-dialog-title"
@@ -1514,7 +1894,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1514
1894
  }, confirmLabel)
1515
1895
  )
1516
1896
  )
1517
- );
1897
+ ));
1518
1898
  }
1519
1899
 
1520
1900
  function MigratePresetDialog(props) {
@@ -1611,14 +1991,15 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1611
1991
  target === currentPreset ? h("div", { className: "sm-migrateWarn" }, t("migrate.same")) : null
1612
1992
  )
1613
1993
  );
1614
- return h("div", {
1615
- className: "sm-nativeDialogLayer sm-confirmDialog sm-migrateConfirmLayer",
1616
- role: "presentation",
1617
- style: { zIndex: zIndex || undefined }
1618
- },
1619
-
1620
- h("section", {
1621
- 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" },
1622
2003
  role: "dialog",
1623
2004
  "aria-modal": "true",
1624
2005
  "aria-labelledby": "sm-migrate-dialog-title"
@@ -1642,9 +2023,274 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1642
2023
  }, busy ? t("busy.processing") : t("migrate.confirm"))
1643
2024
  )
1644
2025
  )
1645
- );
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;
1646
2079
  }
1647
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
+
1648
2294
  const panelStore = {
1649
2295
  open: false,
1650
2296
  listeners: new Set(),
@@ -1662,6 +2308,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1662
2308
  setPendingMove(v) { this.pendingMove = v; this._emitPending(); },
1663
2309
  consumePendingMove() { const v = this.pendingMove; this.pendingMove = null; return v; }
1664
2310
  };
2311
+ const lastBatchContext = { action: null, ids: [] };
1665
2312
 
1666
2313
  const DEFAULT_SORT = "updated-desc";
1667
2314
  const SORT_ORDERS = ["updated-desc", "updated-asc", "created-desc", "created-asc", "priority"];
@@ -1717,6 +2364,11 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1717
2364
  const onMigrate = props.onMigrate;
1718
2365
  const annotations = useAnnotations(true);
1719
2366
  const marksReady = annotations.loaded && !annotations.error;
2367
+ const updateState = useSyncExternalStore(
2368
+ (cb) => updateStore.subscribe(cb),
2369
+ () => updateStore.getSnapshot(),
2370
+ () => updateStore.getSnapshot()
2371
+ );
1720
2372
  const [onlyFavorite, setOnlyFavorite] = useState(false);
1721
2373
  const [onlyReview, setOnlyReview] = useState(false);
1722
2374
  const [tagFilter, setTagFilter] = useState("all");
@@ -1840,6 +2492,8 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1840
2492
  setBulkProgress(null);
1841
2493
  setBulkResult({ action, actionLabel, items });
1842
2494
  setBulkBusy(false);
2495
+ lastBatchContext.action = action;
2496
+ lastBatchContext.ids = ids;
1843
2497
  try { await annotationStore.load(true); } catch (_) { /* ignore */ }
1844
2498
  if (typeof props.onRefreshAfterBulk === "function") {
1845
2499
  try { await props.onRefreshAfterBulk(action); } catch (_) { /* ignore */ }
@@ -1891,16 +2545,16 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1891
2545
  const onBulkTagApply = (tags) => {
1892
2546
  const mode = bulkTagDraft && bulkTagDraft.mode;
1893
2547
  setBulkTagDraft(null);
1894
- if (mode === "add") onBulkAction("add-tags", { tags }, true);
2548
+ if (mode === "add") onBulkAction("add-tags", { tags }, false);
1895
2549
  };
1896
2550
  const onBulkPriorityApply = (value) => {
1897
2551
  const priority = Number(value);
1898
2552
  setBulkTagDraft(null);
1899
- 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);
1900
2554
  };
1901
2555
  const onBulkMoveApply = (value) => {
1902
2556
  setBulkTagDraft(null);
1903
- if (value) onBulkAction("move", { targetWorkspaceId: value }, true);
2557
+ if (value) onBulkAction("move", { targetWorkspaceId: value }, false);
1904
2558
  };
1905
2559
  const [bulkPresetDraft, setBulkPresetDraft] = useState(null);
1906
2560
  const [bulkPresetOptions, setBulkPresetOptions] = useState([]);
@@ -1926,7 +2580,7 @@ function nextDialogZ() { return ++dialogZStackCounter; }
1926
2580
  };
1927
2581
  const onBulkPresetApply = (value) => {
1928
2582
  setBulkPresetDraft(null);
1929
- if (value) onBulkAction("preset-migrate", { toPreset: value }, true);
2583
+ if (value) onBulkAction("preset-migrate", { toPreset: value }, false);
1930
2584
  };
1931
2585
  const bulkMoveOptions = useMemo(() => workspaces.map(ws => ({ value: ws.id, label: ws.title || ws.name || ws.id })), [workspaces]);
1932
2586
  const bulkPriorityOptions = useMemo(() => [1, 2, 3, 4, 5].map(value => ({ value: String(value), label: t("marks.priority." + value) })), [t]);
@@ -2159,29 +2813,74 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2159
2813
  "aria-labelledby": "sm-panel-dialog-title"
2160
2814
  },
2161
2815
  h("div", { className: "sm-nativeDialogHeader" },
2162
- h("a", {
2163
- href: "https://github.com/hkkz9522/dsh-session-manager",
2164
- target: "_blank",
2165
- rel: "noopener noreferrer",
2166
- className: "sm-panelHeaderGithub",
2167
- title: t("panel.github.title"),
2168
- "aria-label": t("panel.github.title")
2169
- },
2170
- h("svg", { viewBox: "0 0 16 16", width: 16, height: 16, "aria-hidden": "true" },
2171
- h("path", {
2172
- fill: "currentColor",
2173
- 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"
2174
- })
2175
- )
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
+ )),
2176
2874
  ),
2177
2875
  h("h2", { id: "sm-panel-dialog-title", className: "sm-nativeDialogTitle" }, t("panel.title")),
2178
2876
  h("div", { className: "sm-nativeDialogHeaderActions" },
2179
- h("button", {
2877
+ renderTip(t("panel.close") || "关闭", h("button", {
2180
2878
  type: "button",
2181
2879
  className: "sm-panelHeaderClose",
2182
2880
  disabled: busyId !== null || migrating,
2183
- onClick: onPanelClose
2184
- }, t("panel.close"))
2881
+ onClick: onPanelClose,
2882
+ "aria-label": t("panel.close")
2883
+ }, h(CloseIcon, { size: 14 })))
2185
2884
  )
2186
2885
  ),
2187
2886
  h("div", { className: "sm-panel" },
@@ -2495,30 +3194,119 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2495
3194
  });
2496
3195
  return () => { alive = false; };
2497
3196
  }, [moveFor ? (moveFor.id || "x") : null]);
2498
- // All three HeaderAction dialogs (annotation / move / delete)
2499
- // share a 360px width. Anchor the dialog's right edge to the
2500
- // trigger button's right edge, with 8px screen-edge padding.
2501
- const anchorFor = (el) => {
2502
- if (!el || typeof el.getBoundingClientRect !== "function") return null;
2503
- 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
+
2504
3274
  return {
2505
3275
  top: Math.round(r.top + r.height + 6),
2506
- 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
+ }
2507
3293
  };
2508
3294
  };
2509
3295
  const archiveLabelKey = isArchived ? "row.unarchive" : "row.archive";
2510
3296
  return h(React.Fragment, null,
2511
3297
  annotationFor ? h(AnnotationDialog, { key: annotationFor.id, sessionId: annotationFor.id, displayTitle: annotationFor.displayTitle, t, anchor: annotationAnchor, onClose: () => { setAnnotationFor(null); setAnnotationAnchor(null); } }) : null,
2512
- h("div", { className: "sm-header" },
2513
- h("button", {
3298
+ h("div", { className: "sm-header", ref: headerRef },
3299
+ (onArchive || onUnarchive) ? renderTip(t ? t(archiveLabelKey) : (isArchived ? "移出归档" : "归档会话"), h("button", {
2514
3300
  type: "button",
2515
3301
  className: "sm-headerBtn" + (isArchived ? " sm-headerBtnActive" : ""),
2516
3302
  "aria-label": t ? t(archiveLabelKey) : (isArchived ? "移出归档" : "归档会话"),
2517
3303
  onClick: () => runWithAlert("archive", () =>
2518
3304
  isArchived ? onUnarchive(sessionId) : onArchive(sessionId)
2519
3305
  )
2520
- }, isArchived ? (t ? t("row.unarchive") : "移出归档") : (t ? t("row.archive") : "归档")),
2521
-
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,
2522
3310
  annotationButtons(sessionId, props.displayTitle || sessionId, t, annotations, "sm-headerBtn", patch => runWithAlert("annotations", () => annotationStore.save(sessionId, patch)), (e) => {
2523
3311
  const nextOpen = !(annotationFor && annotationFor.id === sessionId);
2524
3312
  // Do NOT clear moveFor / confirmFor here: the z-index counter
@@ -2526,51 +3314,143 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2526
3314
  // popup must not silently dismiss a previously opened move or
2527
3315
  // delete popup on the same session.
2528
3316
  if (nextOpen && e && e.currentTarget) {
2529
- const r = e.currentTarget.getBoundingClientRect();
2530
- setAnnotationAnchor({ top: Math.round(r.top + r.height + 6), left: Math.max(8, Math.round(r.right - 360)) });
3317
+ setAnnotationAnchor(anchorFor(e.currentTarget, "annotation"));
2531
3318
  } else setAnnotationAnchor(null);
2532
3319
  setAnnotationFor(current => current?.id === sessionId ? null : { id: sessionId, displayTitle });
2533
3320
  }, false, annotationFor?.id === sessionId),
2534
- 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,
2535
3322
 
2536
- h("button", {
2537
- type: "button",
2538
- className: "sm-headerBtn" + (moveFor ? " sm-headerBtnActive" : ""),
2539
- "aria-label": t ? t("row.move") : "移动至工作区",
2540
- onClick: (e) => {
2541
- e.stopPropagation();
2542
- // Do NOT clear confirmFor / confirmAnchor here: opening the
2543
- // move popup must not silently dismiss a previously opened
2544
- // delete popup on the same session. The z-index counter
2545
- // (see nextDialogZ) handles stacking.
2546
- if (moveFor && moveFor.id === sessionId) {
2547
- setMoveFor(null);
2548
- setMoveAnchor(null);
2549
- } else {
2550
- setMoveAnchor(anchorFor(e.currentTarget));
2551
- 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
+ }
2552
3341
  }
2553
- }
2554
- }, t ? t("row.move") : "移动至工作区"),
2555
- h("button", {
2556
- type: "button",
2557
- className: "sm-headerBtn sm-headerBtnDanger" + (confirmFor ? " sm-headerBtnActive" : ""),
2558
- "aria-label": t ? t("row.delete") : "删除会话",
2559
- onClick: (e) => {
2560
- e.stopPropagation();
2561
- // Do NOT clear moveFor / moveAnchor here: opening the delete
2562
- // popup must not silently dismiss a previously opened move
2563
- // popup on the same session. The z-index counter (see
2564
- // nextDialogZ) handles stacking.
2565
- if (confirmFor && confirmFor.id === sessionId) {
2566
- setConfirmFor(null);
2567
- setConfirmAnchor(null);
2568
- } else {
2569
- setConfirmAnchor(anchorFor(e.currentTarget));
2570
- 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
+ }
2571
3363
  }
2572
- }
2573
- }, 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
+ )
2574
3454
  ),
2575
3455
  confirmFor === null ? null : h(ConfirmDialog, {
2576
3456
  open: true,
@@ -2627,8 +3507,8 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2627
3507
  // Bulk operations need to refresh ctx.sessions.list and the
2628
3508
  // workspace projection after /batch mutates disk state so the
2629
3509
  // panel reflects the new layout.
2630
- onRefreshAfterBulk: async () => {
2631
- try { await this.props.props.onBulkRefresh(); } catch (_) { /* ignore */ }
3510
+ onRefreshAfterBulk: async (...args) => {
3511
+ try { await this.props.props.onBulkRefresh?.(...args); } catch (_) { /* ignore */ }
2632
3512
  },
2633
3513
  onOpen: (id) => { try { this.props.panelStore.set(false); this.props.props.onOpen(id); } catch (_) {} },
2634
3514
  onArchive: this.props.props.onArchive,
@@ -2654,10 +3534,14 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2654
3534
  () => panelStore.getSnapshot(),
2655
3535
  () => panelStore.getSnapshot()
2656
3536
  );
2657
- 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
+ );
2658
3542
  const btnClass = "sm-footerBtn" + (wide ? " sm-footerBtn-wide" : " sm-footerBtn-rail");
2659
3543
  const btnLabel = t("footer.aria");
2660
- return h("div", { className: footerClass },
3544
+ return h(React.Fragment, null,
2661
3545
  h("button", {
2662
3546
  type: "button",
2663
3547
  className: btnClass,
@@ -2674,11 +3558,344 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2674
3558
  t: t,
2675
3559
  useSessions: props.useSessions,
2676
3560
  useWorkspaces: props.useWorkspaces,
2677
- }) : 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
+ )
2678
3894
  );
2679
3895
  }
2680
3896
 
2681
3897
  function apply(ctx) {
3898
+ activeClientCtx = ctx;
2682
3899
  ctx.effect(() => {
2683
3900
  const refresh = () => { if (annotationStore.hasSubscribers()) void annotationStore.load(true); };
2684
3901
  window.addEventListener("focus", refresh);
@@ -2693,6 +3910,34 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2693
3910
  return () => { window.removeEventListener("focus", refresh); channel?.close(); annotationStore.notify = null; };
2694
3911
  }, "session-manager: annotation synchronization");
2695
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
+
2696
3941
  const actions = () => ({
2697
3942
  // DSH 0.1.6+ removed ctx.sessions.open(); the navigation owner is
2698
3943
  // `ctx.uiWorkspace.openSession()`, and the bare SessionController only
@@ -2714,18 +3959,28 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2714
3959
  }
2715
3960
  throw new Error("session-manager: no Session open API on this DSH host");
2716
3961
  },
2717
- 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
+ },
2718
3969
  onUnarchive: async (sessionId) => {
2719
3970
  const response = await callApi("/unarchive", { sessionId });
2720
3971
  if (!response.ok) throw new Error(response.error || "unarchive failed");
2721
3972
  },
2722
3973
  onRemove: async (sessionId) => {
3974
+ const wasCurrent = isCurrentSession(sessionId);
2723
3975
  const response = await callApi("/delete", { sessionId });
2724
3976
  if (!response.ok) throw new Error(response.error || "delete failed");
2725
3977
  await annotationStore.load(true);
2726
3978
  if (response.result?.warning) window.alert(response.result.warning);
2727
- const current = ctx.sessions.list.getSnapshot().current;
2728
- 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 (_) {}
2729
3984
  },
2730
3985
  onMove: async (sessionId, targetWorkspaceId) => {
2731
3986
  const wasCurrent = ctx.sessions.list.getSnapshot().current === sessionId;
@@ -2755,7 +4010,6 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2755
4010
  if (!response.ok) throw new Error(response.error || "preset migration failed");
2756
4011
  // The current DSH client session store derives agentPreset from
2757
4012
  // the refreshed projection; older builds exposed noteAgentPreset,
2758
- onOpenPanel: () => panelStore.toggle(),
2759
4013
  await ctx.sessions.refresh();
2760
4014
  // The migrate rewrite happens in-process on the live session, so
2761
4015
  // we just need a delayed baseline to let the api-gateway's projection
@@ -2767,7 +4021,31 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2767
4021
  }, 250);
2768
4022
  },
2769
4023
  onOpenPanel: () => panelStore.toggle(),
2770
- 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
+ },
2771
4049
  });
2772
4050
  ctx.slots.inject("conversation.session.header.actions", () => ctx.slots.register({
2773
4051
  name: "conversation.session.header.actions",
@@ -2783,12 +4061,66 @@ function nextDialogZ() { return ++dialogZStackCounter; }
2783
4061
  locale: NS,
2784
4062
  inject: () => actions()
2785
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");
2786
4109
  }
2787
4110
 
2788
4111
  const inject = ["slots", "sessions", "workspaces", "locale", "uiWorkspace"];
2789
4112
 
2790
4113
  exports.apply = apply;
2791
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;
2792
4124
  return module.exports;
2793
4125
  }
2794
4126
  });