dsh-plugin-standalone-session 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -14,7 +14,7 @@ DeepSeek Harness 的独立会话:**不隶属于任何工作区**,但完整
14
14
 
15
15
  - 侧边栏顶部点击 **新建独立会话**,直接创建并打开会话。
16
16
  - 上一次由该入口创建的空白会话会复用,避免连点产生大量空会话;管理面板空状态可强制新建。
17
- - 侧边栏底部 **管理独立会话**:点击行打开,`⋯` 菜单重命名/删除。
17
+ - 侧边栏底部 **管理独立会话**:点击行打开,`⋯` 菜单重命名/删除,支持多选批量删除。
18
18
  - 原生输入区可用:模型选择、附件、`/` 指令、发送。
19
19
  - 重启 DSH 后仍保持独立状态。
20
20
  - 不替换原生新建会话、工作区浏览器、会话菜单或聊天 UI。
@@ -55,7 +55,7 @@ dsh plugin --profile web add /absolute/path/to/dsh-plugin-standalone-session-0.1
55
55
  - **命令**:输入 `/`,选择 `独立会话:新建` / `独立会话:管理`。
56
56
  - **删除**:使用 DSH 原生归档,不是物理删除;已删除会话可在归档视图中恢复。
57
57
 
58
- 管理面板点击整行打开会话;行尾 `⋯` 提供重命名和删除。删除最后一条后会停留在空状态,不会跳回新会话页。
58
+ 管理面板点击整行打开会话;行尾 `⋯` 提供重命名和删除。点击右上角 `选择` 进入批量模式,可全选/半选后一次删除;部分失败会保留失败项。删除最后一条后会停留在空状态,不会跳回新会话页。
59
59
 
60
60
  ## 与普通会话的区别
61
61
 
@@ -102,7 +102,7 @@ dsh plugin --profile web add /absolute/path/to/dsh-plugin-standalone-session-0.1
102
102
 
103
103
  ```bash
104
104
  npm ci
105
- npm run check # typecheck + build + 51 个单元测试
105
+ npm run check # typecheck + build + 59 个单元测试
106
106
  npm test
107
107
  ```
108
108
 
package/lib/client.js CHANGED
@@ -311,6 +311,20 @@ async function renameStandalone(ctx, sessionId, title) {
311
311
  async function archiveStandalone(ctx, sessionId) {
312
312
  await ctx.workspaces.archiveSession(sessionId, { stopActivity: true });
313
313
  }
314
+ async function archiveStandalones(ctx, sessionIds, onProgress) {
315
+ const archived = [];
316
+ const failed = [];
317
+ for (const [index, sessionId] of sessionIds.entries()) {
318
+ try {
319
+ await archiveStandalone(ctx, sessionId);
320
+ archived.push(sessionId);
321
+ } catch (reason) {
322
+ failed.push({ sessionId, message: messageOf(reason) });
323
+ }
324
+ onProgress?.(index + 1, sessionIds.length);
325
+ }
326
+ return { archived, failed };
327
+ }
314
328
  function messageOf(error) {
315
329
  return error instanceof Error ? error.message : String(error);
316
330
  }
@@ -462,6 +476,19 @@ var zh = {
462
476
  "panel.deleteTitle": "\u5220\u9664\u72EC\u7ACB\u4F1A\u8BDD\uFF1F",
463
477
  "panel.deleteBody": "\u4F1A\u8BDD\u5C06\u4ECE\u5217\u8868\u548C\u539F\u751F\u4F1A\u8BDD\u89C6\u56FE\u4E2D\u79FB\u9664\uFF08DSH \u4EE5\u5F52\u6863\u5B9E\u73B0\u5220\u9664\uFF09\uFF0C\u4F46\u4ECD\u53EF\u5728\u5F52\u6863\u89C6\u56FE\u4E2D\u6062\u590D\u3002\u7A7A\u767D\u4F1A\u8BDD\u7684\u4E34\u65F6\u76EE\u5F55\u4F1A\u88AB\u6E05\u7406\uFF1B\u5DF2\u7ECF\u4EA7\u751F\u8FC7\u6D88\u606F\u7684\u4F1A\u8BDD\u4F1A\u4FDD\u7559\u5176\u76EE\u5F55\u3002",
464
478
  "panel.deleteConfirm": "\u5220\u9664",
479
+ "panel.select": "\u9009\u62E9",
480
+ "panel.selectToolbar": "\u6279\u91CF\u9009\u62E9",
481
+ "panel.selectAll": "\u5168\u9009",
482
+ "panel.selectAllLabel": "\u5168\u9009\u72EC\u7ACB\u4F1A\u8BDD",
483
+ "panel.selectedCount": "\u5DF2\u9009 {n} / {total}",
484
+ "panel.selectRow": "\u9009\u62E9\u201C{title}\u201D",
485
+ "panel.batchDelete": "\u5220\u9664",
486
+ "panel.batchDeleteTitle": "\u5220\u9664 {n} \u4E2A\u72EC\u7ACB\u4F1A\u8BDD\uFF1F",
487
+ "panel.batchDeleteBody": "\u5C06\u5F52\u6863\u8FD9 {n} \u4E2A\u4F1A\u8BDD\uFF0C\u53EF\u5728\u5F52\u6863\u89C6\u56FE\u4E2D\u6062\u590D\u3002",
488
+ "panel.batchDeleteRunning": "\u5176\u4E2D {n} \u4E2A\u6B63\u5728\u8FD0\u884C\uFF0C\u5F52\u6863\u4F1A\u505C\u6B62\u5B83\u4EEC\u3002",
489
+ "panel.batchDeleteDirs": "\u7A7A\u767D\u4E14\u76EE\u5F55\u4E3A\u7A7A\u7684\u4F1A\u8BDD\u4F1A\u6E05\u7406\u5DE5\u4F5C\u76EE\u5F55\uFF1B\u5DF2\u6709\u6D88\u606F\u6216\u76EE\u5F55\u975E\u7A7A\u7684\u4F1A\u8BDD\u4F1A\u4FDD\u7559\u76EE\u5F55\u3002",
490
+ "panel.batchDeleting": "\u5F52\u6863\u4E2D {done}/{total}\u2026",
491
+ "panel.batchPartial": "{n} \u4E2A\u4F1A\u8BDD\u5F52\u6863\u5931\u8D25\uFF0C\u5DF2\u4FDD\u7559\u9009\u4E2D\u72B6\u6001\u3002",
465
492
  "panel.deleteKeepDir": "\u8BE5\u4F1A\u8BDD\u5DF2\u6709\u6D88\u606F\uFF0C\u76EE\u5F55\u4F1A\u88AB\u4FDD\u7559\u3002",
466
493
  "panel.cancel": "\u53D6\u6D88",
467
494
  "panel.renameTitle": "\u91CD\u547D\u540D\u72EC\u7ACB\u4F1A\u8BDD",
@@ -524,6 +551,19 @@ var en = {
524
551
  "panel.deleteTitle": "Delete standalone session?",
525
552
  "panel.deleteBody": "The session leaves the list and the native session view (DSH implements deletion as archive), and remains recoverable from the archived view. The directory of an unused session is removed; a session that already carried messages keeps its directory.",
526
553
  "panel.deleteConfirm": "Delete",
554
+ "panel.select": "Select",
555
+ "panel.selectToolbar": "Bulk selection",
556
+ "panel.selectAll": "Select all",
557
+ "panel.selectAllLabel": "Select all standalone sessions",
558
+ "panel.selectedCount": "{n} / {total} selected",
559
+ "panel.selectRow": 'Select "{title}"',
560
+ "panel.batchDelete": "Delete",
561
+ "panel.batchDeleteTitle": "Delete {n} standalone session(s)?",
562
+ "panel.batchDeleteBody": "The {n} selected session(s) will be archived and can be restored from the archived view.",
563
+ "panel.batchDeleteRunning": "{n} session(s) are running; archiving will stop them.",
564
+ "panel.batchDeleteDirs": "Blank sessions with empty directories lose their working directory; sessions with messages or non-empty directories keep theirs.",
565
+ "panel.batchDeleting": "Archiving {done}/{total}\u2026",
566
+ "panel.batchPartial": "Failed to archive {n} session(s); selection was kept.",
527
567
  "panel.deleteKeepDir": "This session already carried messages; its directory is retained.",
528
568
  "panel.cancel": "Cancel",
529
569
  "panel.renameTitle": "Rename standalone session",
@@ -568,6 +608,39 @@ var en = {
568
608
  "error.noSession": "No session is available"
569
609
  };
570
610
 
611
+ // src/client/selection.ts
612
+ function toggleSelection(selected, sessionId) {
613
+ const next = new Set(selected);
614
+ if (next.has(sessionId)) next.delete(sessionId);
615
+ else next.add(sessionId);
616
+ return next;
617
+ }
618
+ function selectAllRows(rows) {
619
+ return new Set(rows.map((row) => row.id));
620
+ }
621
+ function selectedRows(rows, selected) {
622
+ return rows.filter((row) => selected.has(row.id));
623
+ }
624
+ function pruneSelection(rows, selected) {
625
+ if (selected.size === 0) return selected;
626
+ const live = new Set(rows.map((row) => row.id));
627
+ let changed = false;
628
+ const next = /* @__PURE__ */ new Set();
629
+ for (const id of selected) {
630
+ if (live.has(id)) next.add(id);
631
+ else changed = true;
632
+ }
633
+ return changed ? next : selected;
634
+ }
635
+ function selectionState(rows, selected) {
636
+ const count = selectedRows(rows, selected).length;
637
+ return {
638
+ count,
639
+ all: rows.length > 0 && count === rows.length,
640
+ some: count > 0 && count < rows.length
641
+ };
642
+ }
643
+
571
644
  // src/client/components.tsx
572
645
  var import_jsx_runtime = require("react/jsx-runtime");
573
646
  function StandaloneIcon({
@@ -1031,6 +1104,72 @@ function DeleteDialog({
1031
1104
  }
1032
1105
  );
1033
1106
  }
1107
+ function BatchDeleteDialog({
1108
+ targets,
1109
+ t,
1110
+ progress,
1111
+ onCancel,
1112
+ onConfirm
1113
+ }) {
1114
+ const [submitting, setSubmitting] = (0, import_react3.useState)(false);
1115
+ const [error, setError] = (0, import_react3.useState)(null);
1116
+ const busy = submitting || progress !== null;
1117
+ const running = targets.filter((row) => row.running).length;
1118
+ const hasBlank = targets.some((row) => row.blank);
1119
+ const confirm = async () => {
1120
+ if (busy) return;
1121
+ setSubmitting(true);
1122
+ setError(null);
1123
+ try {
1124
+ await onConfirm();
1125
+ } catch (reason) {
1126
+ setError(messageOf(reason));
1127
+ setSubmitting(false);
1128
+ }
1129
+ };
1130
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1131
+ DialogFrame,
1132
+ {
1133
+ title: t("panel.batchDeleteTitle", { n: targets.length }),
1134
+ busy,
1135
+ onCancel,
1136
+ footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1137
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1138
+ "button",
1139
+ {
1140
+ type: "button",
1141
+ className: "ss-button ss-buttonQuiet",
1142
+ disabled: busy,
1143
+ onClick: onCancel,
1144
+ children: t("panel.cancel")
1145
+ }
1146
+ ),
1147
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1148
+ "button",
1149
+ {
1150
+ type: "button",
1151
+ className: "ss-button ss-buttonDanger",
1152
+ disabled: busy,
1153
+ "aria-busy": progress !== null,
1154
+ onClick: () => {
1155
+ void confirm();
1156
+ },
1157
+ children: progress === null ? t("panel.batchDelete") : t("panel.batchDeleting", {
1158
+ done: progress.done,
1159
+ total: progress.total
1160
+ })
1161
+ }
1162
+ )
1163
+ ] }),
1164
+ children: [
1165
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-dialogBody", children: t("panel.batchDeleteBody", { n: targets.length }) }),
1166
+ running > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-batchWarning", children: t("panel.batchDeleteRunning", { n: running }) }) : null,
1167
+ hasBlank ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-batchDirs", children: t("panel.batchDeleteDirs") }) : null,
1168
+ error !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-error", children: error }) : null
1169
+ ]
1170
+ }
1171
+ );
1172
+ }
1034
1173
  function createStandalonePanel(ctx) {
1035
1174
  const fallbackT = ctx.locale.bind(NS);
1036
1175
  return function StandalonePanel(props) {
@@ -1041,8 +1180,30 @@ function createStandalonePanel(ctx) {
1041
1180
  const [renameTarget, setRenameTarget] = (0, import_react3.useState)(null);
1042
1181
  const [deleteTarget, setDeleteTarget] = (0, import_react3.useState)(null);
1043
1182
  const [menuTarget, setMenuTarget] = (0, import_react3.useState)(null);
1183
+ const [selectionMode, setSelectionMode] = (0, import_react3.useState)(false);
1184
+ const [selectedIds, setSelectedIds] = (0, import_react3.useState)(() => /* @__PURE__ */ new Set());
1185
+ const [batchTargets, setBatchTargets] = (0, import_react3.useState)(null);
1186
+ const [batchProgress, setBatchProgress] = (0, import_react3.useState)(null);
1044
1187
  const menuRef = (0, import_react3.useRef)(null);
1045
1188
  const menuButtonRef = (0, import_react3.useRef)(null);
1189
+ const selectAllRef = (0, import_react3.useRef)(null);
1190
+ const selectButtonRef = (0, import_react3.useRef)(null);
1191
+ const selected = (0, import_react3.useMemo)(() => selectedRows(rows, selectedIds), [rows, selectedIds]);
1192
+ const state = (0, import_react3.useMemo)(() => selectionState(rows, selectedIds), [rows, selectedIds]);
1193
+ const locked = busy !== null || batchProgress !== null;
1194
+ const exitSelection = () => {
1195
+ setSelectionMode(false);
1196
+ setSelectedIds(/* @__PURE__ */ new Set());
1197
+ setMenuTarget(null);
1198
+ setError(null);
1199
+ selectButtonRef.current?.focus();
1200
+ };
1201
+ const enterSelection = () => {
1202
+ if (locked) return;
1203
+ setMenuTarget(null);
1204
+ setSelectedIds(/* @__PURE__ */ new Set());
1205
+ setSelectionMode(true);
1206
+ };
1046
1207
  (0, import_react3.useEffect)(() => {
1047
1208
  if (menuTarget === null) return;
1048
1209
  menuRef.current?.querySelector("button")?.focus();
@@ -1063,8 +1224,36 @@ function createStandalonePanel(ctx) {
1063
1224
  document.removeEventListener("keydown", onKeyDown);
1064
1225
  };
1065
1226
  }, [menuTarget]);
1227
+ (0, import_react3.useEffect)(() => {
1228
+ const pruned = pruneSelection(rows, selectedIds);
1229
+ if (pruned !== selectedIds) setSelectedIds(pruned);
1230
+ if (rows.length === 0 && selectionMode) {
1231
+ setSelectionMode(false);
1232
+ setSelectedIds(/* @__PURE__ */ new Set());
1233
+ }
1234
+ }, [rows, selectedIds, selectionMode]);
1235
+ (0, import_react3.useEffect)(() => {
1236
+ if (selectionMode) selectAllRef.current?.focus();
1237
+ }, [selectionMode]);
1238
+ (0, import_react3.useEffect)(() => {
1239
+ if (selectAllRef.current !== null) selectAllRef.current.indeterminate = state.some;
1240
+ }, [state.some, selectionMode]);
1241
+ (0, import_react3.useEffect)(() => {
1242
+ if (!selectionMode) return;
1243
+ const onKey = (event) => {
1244
+ if (batchTargets !== null || renameTarget !== null || deleteTarget !== null || menuTarget !== null) {
1245
+ return;
1246
+ }
1247
+ if (event.key === "Escape") {
1248
+ event.preventDefault();
1249
+ exitSelection();
1250
+ }
1251
+ };
1252
+ document.addEventListener("keydown", onKey);
1253
+ return () => document.removeEventListener("keydown", onKey);
1254
+ }, [selectionMode, batchTargets, renameTarget, deleteTarget, menuTarget]);
1066
1255
  const create = async () => {
1067
- if (busy !== null) return;
1256
+ if (locked) return;
1068
1257
  setBusy("new");
1069
1258
  setError(null);
1070
1259
  try {
@@ -1076,7 +1265,7 @@ function createStandalonePanel(ctx) {
1076
1265
  }
1077
1266
  };
1078
1267
  const open = (row) => {
1079
- if (busy !== null) return;
1268
+ if (locked) return;
1080
1269
  setMenuTarget(null);
1081
1270
  try {
1082
1271
  ctx.uiWorkspace.openSession(row.id);
@@ -1084,6 +1273,14 @@ function createStandalonePanel(ctx) {
1084
1273
  setError(t("panel.actionFailed", { message: messageOf(reason) }));
1085
1274
  }
1086
1275
  };
1276
+ const toggleRow = (sessionId) => {
1277
+ if (locked) return;
1278
+ setSelectedIds((current2) => toggleSelection(current2, sessionId));
1279
+ };
1280
+ const toggleAll = () => {
1281
+ if (locked) return;
1282
+ setSelectedIds(state.all ? /* @__PURE__ */ new Set() : selectAllRows(rows));
1283
+ };
1087
1284
  const rename = async (row, title) => {
1088
1285
  setBusy(row.id);
1089
1286
  setError(null);
@@ -1109,16 +1306,109 @@ function createStandalonePanel(ctx) {
1109
1306
  setBusy(null);
1110
1307
  }
1111
1308
  };
1309
+ const beginBatch = () => {
1310
+ if (locked || selected.length === 0) return;
1311
+ setMenuTarget(null);
1312
+ setError(null);
1313
+ setBatchProgress(null);
1314
+ setBatchTargets([...selected]);
1315
+ };
1316
+ const runBatch = async (targets) => {
1317
+ setBatchProgress({ done: 0, total: targets.length });
1318
+ setError(null);
1319
+ try {
1320
+ const result = await archiveStandalones(
1321
+ ctx,
1322
+ targets.map((row) => row.id),
1323
+ (done, total) => setBatchProgress({ done, total })
1324
+ );
1325
+ setBatchTargets(null);
1326
+ setSelectedIds(new Set(result.failed.map((failure) => failure.sessionId)));
1327
+ if (result.failed.length === 0) {
1328
+ setSelectionMode(false);
1329
+ } else {
1330
+ const message = t("panel.batchPartial", { n: result.failed.length });
1331
+ setError(message);
1332
+ showNotice("error", message);
1333
+ }
1334
+ openManagementPanel(ctx, t);
1335
+ } catch (reason) {
1336
+ setBatchTargets(null);
1337
+ const message = t("panel.actionFailed", { message: messageOf(reason) });
1338
+ setError(message);
1339
+ showNotice("error", message);
1340
+ openManagementPanel(ctx, t);
1341
+ } finally {
1342
+ setBatchProgress(null);
1343
+ }
1344
+ };
1112
1345
  const count = t("panel.count", { n: rows.length });
1113
1346
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "ss-panel", "aria-label": t("panel.title"), children: [
1114
1347
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-shell", children: [
1115
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("header", { className: "ss-header", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
1116
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-titleRow", children: [
1117
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "ss-title", children: t("panel.title") }),
1118
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-count ss-countInline", children: count })
1119
- ] }),
1120
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-description", children: t("panel.description") })
1121
- ] }) }),
1348
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1349
+ "header",
1350
+ {
1351
+ className: `ss-header${selectionMode ? " ss-headerSelection" : ""}`,
1352
+ role: selectionMode ? "toolbar" : void 0,
1353
+ "aria-label": selectionMode ? t("panel.selectToolbar") : void 0,
1354
+ children: [
1355
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-headerMain", children: [
1356
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-titleRow", children: [
1357
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "ss-title", children: t("panel.title") }),
1358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-count ss-countInline", children: selectionMode ? t("panel.selectedCount", { n: state.count, total: rows.length }) : count })
1359
+ ] }),
1360
+ !selectionMode ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-description", children: t("panel.description") }) : null
1361
+ ] }),
1362
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-headerActions", children: selectionMode ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1363
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { className: "ss-selectAll", children: [
1364
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1365
+ "input",
1366
+ {
1367
+ ref: selectAllRef,
1368
+ type: "checkbox",
1369
+ className: "ss-checkbox",
1370
+ checked: state.all,
1371
+ disabled: locked,
1372
+ "aria-label": t("panel.selectAllLabel"),
1373
+ onChange: toggleAll
1374
+ }
1375
+ ),
1376
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: t("panel.selectAll") })
1377
+ ] }),
1378
+ state.count > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1379
+ "button",
1380
+ {
1381
+ type: "button",
1382
+ className: "ss-button ss-buttonDanger",
1383
+ disabled: locked,
1384
+ onClick: beginBatch,
1385
+ children: t("panel.batchDelete")
1386
+ }
1387
+ ) : null,
1388
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1389
+ "button",
1390
+ {
1391
+ type: "button",
1392
+ className: "ss-selectButton",
1393
+ disabled: locked,
1394
+ onClick: exitSelection,
1395
+ children: t("panel.cancel")
1396
+ }
1397
+ )
1398
+ ] }) : rows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1399
+ "button",
1400
+ {
1401
+ ref: selectButtonRef,
1402
+ type: "button",
1403
+ className: "ss-selectButton",
1404
+ disabled: locked,
1405
+ onClick: enterSelection,
1406
+ children: t("panel.select")
1407
+ }
1408
+ ) : null })
1409
+ ]
1410
+ }
1411
+ ),
1122
1412
  error !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-error", role: "alert", children: error }) : null,
1123
1413
  loading && rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-empty", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-emptyHint", children: t("panel.loading") }) }) : rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-empty", children: [
1124
1414
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-emptyTitle", children: t("panel.empty") }),
@@ -1128,7 +1418,7 @@ function createStandalonePanel(ctx) {
1128
1418
  {
1129
1419
  type: "button",
1130
1420
  className: "ss-button ss-buttonPrimary",
1131
- disabled: busy !== null,
1421
+ disabled: locked,
1132
1422
  onClick: () => {
1133
1423
  void create();
1134
1424
  },
@@ -1142,6 +1432,7 @@ function createStandalonePanel(ctx) {
1142
1432
  const title = row.title?.trim() || t("panel.untitled");
1143
1433
  const updated = relativeTimeLabel(t, row.updatedAt);
1144
1434
  const openMenu = menuTarget === row.id;
1435
+ const checked = selectedIds.has(row.id);
1145
1436
  const metaItems = [];
1146
1437
  if (updated !== "") metaItems.push(/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: updated }, "time"));
1147
1438
  if (row.running) {
@@ -1160,30 +1451,46 @@ function createStandalonePanel(ctx) {
1160
1451
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1161
1452
  "li",
1162
1453
  {
1163
- className: `ss-row${openMenu ? " ss-rowMenuOpen" : ""}`,
1164
- role: "button",
1165
- tabIndex: 0,
1166
- "aria-disabled": busy !== null,
1167
- onClick: () => open(row),
1168
- onKeyDown: (event) => {
1169
- if (event.target !== event.currentTarget) return;
1170
- if (event.key === "Enter" || event.key === " ") {
1171
- event.preventDefault();
1172
- open(row);
1173
- } else if (event.key === "ArrowDown") {
1174
- event.preventDefault();
1175
- setMenuTarget(row.id);
1176
- }
1177
- },
1454
+ className: `ss-row${openMenu ? " ss-rowMenuOpen" : ""}${selectionMode && checked ? " ss-rowSelected" : ""}`,
1178
1455
  children: [
1179
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-rowMain", children: [
1180
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-rowTitleRow", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-rowTitle", title, children: title }) }),
1181
- metaItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-rowMeta", children: metaItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react3.Fragment, { children: [
1182
- index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-dotSep", children: "\xB7" }) : null,
1183
- item
1184
- ] }, index)) }) : null
1185
- ] }),
1186
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-rowActions", children: [
1456
+ selectionMode ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1457
+ "input",
1458
+ {
1459
+ type: "checkbox",
1460
+ className: "ss-checkbox",
1461
+ checked,
1462
+ disabled: locked,
1463
+ "aria-label": t("panel.selectRow", { title }),
1464
+ onChange: () => toggleRow(row.id)
1465
+ }
1466
+ ) : null,
1467
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1468
+ "button",
1469
+ {
1470
+ type: "button",
1471
+ className: "ss-rowMain",
1472
+ disabled: locked,
1473
+ "aria-pressed": selectionMode ? checked : void 0,
1474
+ onClick: () => {
1475
+ if (selectionMode) toggleRow(row.id);
1476
+ else open(row);
1477
+ },
1478
+ onKeyDown: (event) => {
1479
+ if (!selectionMode && event.key === "ArrowDown") {
1480
+ event.preventDefault();
1481
+ setMenuTarget(row.id);
1482
+ }
1483
+ },
1484
+ children: [
1485
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-rowTitleRow", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-rowTitle", title, children: title }) }),
1486
+ metaItems.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "ss-rowMeta", children: metaItems.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react3.Fragment, { children: [
1487
+ index > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ss-dotSep", children: "\xB7" }) : null,
1488
+ item
1489
+ ] }, index)) }) : null
1490
+ ]
1491
+ }
1492
+ ),
1493
+ !selectionMode ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "ss-rowActions", children: [
1187
1494
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1188
1495
  "button",
1189
1496
  {
@@ -1192,7 +1499,7 @@ function createStandalonePanel(ctx) {
1192
1499
  "aria-label": t("panel.more"),
1193
1500
  "aria-haspopup": "menu",
1194
1501
  "aria-expanded": openMenu,
1195
- disabled: busy !== null,
1502
+ disabled: locked,
1196
1503
  ref: openMenu ? menuButtonRef : void 0,
1197
1504
  onClick: (event) => {
1198
1505
  event.stopPropagation();
@@ -1215,7 +1522,7 @@ function createStandalonePanel(ctx) {
1215
1522
  {
1216
1523
  type: "button",
1217
1524
  role: "menuitem",
1218
- disabled: busy !== null,
1525
+ disabled: locked,
1219
1526
  onClick: () => {
1220
1527
  setMenuTarget(null);
1221
1528
  setRenameTarget(row);
@@ -1229,7 +1536,7 @@ function createStandalonePanel(ctx) {
1229
1536
  type: "button",
1230
1537
  role: "menuitem",
1231
1538
  className: "ss-rowMenuDanger",
1232
- disabled: busy !== null,
1539
+ disabled: locked,
1233
1540
  onClick: () => {
1234
1541
  setMenuTarget(null);
1235
1542
  setDeleteTarget(row);
@@ -1240,14 +1547,26 @@ function createStandalonePanel(ctx) {
1240
1547
  ]
1241
1548
  }
1242
1549
  ) : null
1243
- ] })
1550
+ ] }) : null
1244
1551
  ]
1245
1552
  },
1246
1553
  row.id
1247
1554
  );
1248
1555
  }) }),
1249
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-panelHint", children: t("panel.archivedHint") })
1556
+ !selectionMode ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "ss-panelHint", children: t("panel.archivedHint") }) : null
1250
1557
  ] }),
1558
+ batchTargets !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1559
+ BatchDeleteDialog,
1560
+ {
1561
+ targets: batchTargets,
1562
+ t,
1563
+ progress: batchProgress,
1564
+ onCancel: () => {
1565
+ if (batchProgress === null) setBatchTargets(null);
1566
+ },
1567
+ onConfirm: () => runBatch(batchTargets)
1568
+ }
1569
+ ) : null,
1251
1570
  renameTarget !== null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1252
1571
  RenameDialog,
1253
1572
  {
@@ -1323,6 +1642,46 @@ var CSS = `
1323
1642
  margin-top: 0;
1324
1643
  align-self: center;
1325
1644
  }
1645
+ .ss-headerActions {
1646
+ display: flex;
1647
+ align-items: center;
1648
+ justify-content: flex-end;
1649
+ flex-wrap: wrap;
1650
+ gap: 8px;
1651
+ }
1652
+ .ss-headerSelection {
1653
+ position: sticky;
1654
+ top: 0;
1655
+ z-index: 6;
1656
+ align-items: center;
1657
+ padding: 8px 0;
1658
+ background: var(--dsw-specific-main-fill, var(--dsw-alias-bg-elevated, #fff));
1659
+ }
1660
+ .ss-selectButton {
1661
+ min-height: 30px;
1662
+ padding: 3px 8px;
1663
+ border: 0;
1664
+ border-radius: var(--dsw-radius-md, 10px);
1665
+ background: transparent;
1666
+ color: var(--dsw-alias-label-secondary, #59636e);
1667
+ font: inherit;
1668
+ font-size: 13px;
1669
+ line-height: 20px;
1670
+ cursor: pointer;
1671
+ }
1672
+ .ss-selectButton:hover:not(:disabled) {
1673
+ color: var(--dsw-alias-label-primary, #1f2328);
1674
+ background: var(--dsw-alias-interactive-bg-hover, #e9ebee);
1675
+ }
1676
+ .ss-selectButton:focus-visible {
1677
+ outline: var(--dsw-focus-ring-width, 2px) solid
1678
+ var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));
1679
+ outline-offset: 1px;
1680
+ }
1681
+ .ss-selectButton:disabled {
1682
+ cursor: default;
1683
+ opacity: 0.55;
1684
+ }
1326
1685
  .ss-button {
1327
1686
  font: inherit;
1328
1687
  display: inline-flex;
@@ -1384,6 +1743,28 @@ var CSS = `
1384
1743
  background: var(--dsw-alias-state-business-tertiary, rgba(59, 130, 246, 0.12));
1385
1744
  border: 0.5px solid var(--dsw-alias-interactive-bg-hover, rgba(59, 130, 246, 0.18));
1386
1745
  }
1746
+ .ss-selectAll {
1747
+ display: inline-flex;
1748
+ align-items: center;
1749
+ gap: 7px;
1750
+ color: var(--dsw-alias-label-secondary, #59636e);
1751
+ font-size: 13px;
1752
+ line-height: 20px;
1753
+ cursor: pointer;
1754
+ user-select: none;
1755
+ }
1756
+ .ss-checkbox {
1757
+ width: 18px;
1758
+ height: 18px;
1759
+ margin: 0;
1760
+ flex: none;
1761
+ accent-color: var(--dsw-alias-state-business-primary, #2563eb);
1762
+ cursor: pointer;
1763
+ }
1764
+ .ss-checkbox:disabled {
1765
+ cursor: default;
1766
+ opacity: 0.55;
1767
+ }
1387
1768
  .ss-list {
1388
1769
  display: flex;
1389
1770
  flex-direction: column;
@@ -1410,10 +1791,10 @@ var CSS = `
1410
1791
  border-color: var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));
1411
1792
  background: var(--dsw-alias-interactive-bg-hover, #e9ebee);
1412
1793
  }
1413
- .ss-row:focus-visible {
1414
- outline: var(--dsw-focus-ring-width, 2px) solid
1415
- var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));
1416
- outline-offset: 1px;
1794
+ .ss-rowSelected,
1795
+ .ss-rowSelected:hover,
1796
+ .ss-rowSelected:focus-within {
1797
+ border-color: var(--dsw-alias-state-business-primary, #3b82f6);
1417
1798
  }
1418
1799
  .ss-row[aria-disabled="true"] {
1419
1800
  cursor: default;
@@ -1425,6 +1806,23 @@ var CSS = `
1425
1806
  display: flex;
1426
1807
  flex-direction: column;
1427
1808
  gap: 3px;
1809
+ padding: 0;
1810
+ border: 0;
1811
+ background: transparent;
1812
+ color: inherit;
1813
+ font: inherit;
1814
+ text-align: left;
1815
+ cursor: pointer;
1816
+ }
1817
+ .ss-rowMain:disabled {
1818
+ cursor: default;
1819
+ opacity: 0.7;
1820
+ }
1821
+ .ss-rowMain:focus-visible {
1822
+ outline: var(--dsw-focus-ring-width, 2px) solid
1823
+ var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));
1824
+ outline-offset: 2px;
1825
+ border-radius: 6px;
1428
1826
  }
1429
1827
  .ss-rowTitleRow {
1430
1828
  display: flex;
@@ -1613,6 +2011,8 @@ var CSS = `
1613
2011
  .ss-dialog {
1614
2012
  width: 100%;
1615
2013
  max-width: 440px;
2014
+ max-height: calc(100vh - 48px);
2015
+ overflow: auto;
1616
2016
  box-sizing: border-box;
1617
2017
  border-radius: var(--dsw-radius-lg, 14px);
1618
2018
  border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));
@@ -1649,6 +2049,19 @@ var CSS = `
1649
2049
  gap: 8px;
1650
2050
  margin-top: 18px;
1651
2051
  }
2052
+ .ss-batchWarning {
2053
+ margin: 0 0 10px;
2054
+ color: var(--dsw-alias-label-primary, #1f2328);
2055
+ font-size: 12px;
2056
+ line-height: 18px;
2057
+ font-weight: 600;
2058
+ }
2059
+ .ss-batchDirs {
2060
+ margin: 0 0 10px;
2061
+ color: var(--dsw-alias-label-tertiary, #818b98);
2062
+ font-size: 12px;
2063
+ line-height: 18px;
2064
+ }
1652
2065
  .ss-footerAction {
1653
2066
  box-sizing: border-box;
1654
2067
  width: 100%;
@@ -1804,8 +2217,12 @@ var CSS = `
1804
2217
  }
1805
2218
  @media (max-width: 640px) {
1806
2219
  .ss-panel { padding: 20px 14px 40px; }
1807
- .ss-row { flex-wrap: wrap; }
1808
- .ss-rowActions { width: 100%; justify-content: flex-end; }
2220
+ .ss-row { flex-wrap: nowrap; gap: 10px; }
2221
+ .ss-headerSelection { align-items: flex-start; }
2222
+ .ss-headerSelection .ss-headerActions {
2223
+ width: 100%;
2224
+ justify-content: flex-end;
2225
+ }
1809
2226
  }
1810
2227
  `;
1811
2228
  function insertStyles() {
@@ -36,5 +36,24 @@ export declare function renameStandalone(ctx: ClientContext, sessionId: string,
36
36
  * @param sessionId - target session.
37
37
  */
38
38
  export declare function archiveStandalone(ctx: ClientContext, sessionId: string): Promise<void>;
39
+ /** One failed session in a batch archive operation. */
40
+ export interface BatchArchiveFailure {
41
+ readonly sessionId: string;
42
+ readonly message: string;
43
+ }
44
+ /** Result of archiving a snapshot of selected sessions. */
45
+ export interface BatchArchiveResult {
46
+ readonly archived: readonly string[];
47
+ readonly failed: readonly BatchArchiveFailure[];
48
+ }
49
+ /**
50
+ * Archive sessions one at a time. A failure is recorded and the remaining
51
+ * sessions continue, so one stale row cannot strand the rest of the batch.
52
+ * @param ctx - client root context.
53
+ * @param sessionIds - frozen snapshot of the selected session ids.
54
+ * @param onProgress - called after every attempt with 1-based progress.
55
+ * @returns successfully archived ids and per-session failures.
56
+ */
57
+ export declare function archiveStandalones(ctx: ClientContext, sessionIds: readonly string[], onProgress?: (done: number, total: number) => void): Promise<BatchArchiveResult>;
39
58
  /** Human-readable error text. */
40
59
  export declare function messageOf(error: unknown): string;
@@ -3,7 +3,7 @@
3
3
  * keeps `en` complete, and both shipped languages are registered together.
4
4
  */
5
5
  export declare const NS = "standaloneSession";
6
- export type StandaloneKey = 'panel.label' | 'panel.title' | 'panel.description' | 'panel.new' | 'panel.empty' | 'panel.emptyHint' | 'panel.badge' | 'panel.open' | 'panel.rename' | 'panel.delete' | 'panel.untitled' | 'panel.blank' | 'panel.running' | 'panel.cwd' | 'panel.count' | 'panel.deleteTitle' | 'panel.deleteBody' | 'panel.deleteConfirm' | 'panel.deleteKeepDir' | 'panel.cancel' | 'panel.renameTitle' | 'panel.renameLabel' | 'panel.more' | 'panel.save' | 'panel.titleRequired' | 'panel.actionFailed' | 'panel.retry' | 'panel.archivedHint' | 'panel.loading' | 'entry.label' | 'launcher.creating' | 'launcher.failedTitle' | 'launcher.retry' | 'launcher.manage' | 'launcher.hint' | 'command.label' | 'command.description' | 'command.manageLabel' | 'command.manageDescription' | 'footer.manage' | 'footer.manageCount' | 'footer.manageTooltip' | 'time.now' | 'time.minutes' | 'time.hours' | 'time.days' | 'toast.manageFailed' | 'hero.badge' | 'hero.hint' | 'row.mark' | 'row.hover' | 'composer.placeholder' | 'toast.created' | 'toast.createFailed' | 'toast.deleteFailed' | 'toast.deleted' | 'toast.renamed' | 'toast.renameFailed' | 'error.noHome' | 'error.noSession';
6
+ export type StandaloneKey = 'panel.label' | 'panel.title' | 'panel.description' | 'panel.new' | 'panel.empty' | 'panel.emptyHint' | 'panel.badge' | 'panel.open' | 'panel.rename' | 'panel.delete' | 'panel.untitled' | 'panel.blank' | 'panel.running' | 'panel.cwd' | 'panel.count' | 'panel.deleteTitle' | 'panel.deleteBody' | 'panel.deleteConfirm' | 'panel.select' | 'panel.selectToolbar' | 'panel.selectAll' | 'panel.selectAllLabel' | 'panel.selectedCount' | 'panel.selectRow' | 'panel.batchDelete' | 'panel.batchDeleteTitle' | 'panel.batchDeleteBody' | 'panel.batchDeleteRunning' | 'panel.batchDeleteDirs' | 'panel.batchDeleting' | 'panel.batchPartial' | 'panel.deleteKeepDir' | 'panel.cancel' | 'panel.renameTitle' | 'panel.renameLabel' | 'panel.more' | 'panel.save' | 'panel.titleRequired' | 'panel.actionFailed' | 'panel.retry' | 'panel.archivedHint' | 'panel.loading' | 'entry.label' | 'launcher.creating' | 'launcher.failedTitle' | 'launcher.retry' | 'launcher.manage' | 'launcher.hint' | 'command.label' | 'command.description' | 'command.manageLabel' | 'command.manageDescription' | 'footer.manage' | 'footer.manageCount' | 'footer.manageTooltip' | 'time.now' | 'time.minutes' | 'time.hours' | 'time.days' | 'toast.manageFailed' | 'hero.badge' | 'hero.hint' | 'row.mark' | 'row.hover' | 'composer.placeholder' | 'toast.created' | 'toast.createFailed' | 'toast.deleteFailed' | 'toast.deleted' | 'toast.renamed' | 'toast.renameFailed' | 'error.noHome' | 'error.noSession';
7
7
  export type StandaloneDict = Readonly<Record<StandaloneKey, string>>;
8
8
  export declare const zh: StandaloneDict;
9
9
  export declare const en: StandaloneDict;
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Pure selection helpers for the standalone-session manager. Keeping these out
3
+ * of the panel makes bulk-selection edge cases (pruning, select-all, partial
4
+ * state) directly unit-testable.
5
+ */
6
+ import type { SessionRow } from './dsh.js';
7
+ /** Toggle one session id without mutating the caller's set. */
8
+ export declare function toggleSelection(selected: ReadonlySet<string>, sessionId: string): ReadonlySet<string>;
9
+ /** Select every row in the current view. */
10
+ export declare function selectAllRows(rows: readonly SessionRow[]): ReadonlySet<string>;
11
+ /** Rows that are still present in the current view and selected. */
12
+ export declare function selectedRows(rows: readonly SessionRow[], selected: ReadonlySet<string>): SessionRow[];
13
+ /**
14
+ * Drop ids that disappeared from the view. Returns the original set when
15
+ * nothing changed so callers can avoid a redundant state update.
16
+ */
17
+ export declare function pruneSelection(rows: readonly SessionRow[], selected: ReadonlySet<string>): ReadonlySet<string>;
18
+ /** Select-all checkbox state for the current view. */
19
+ export declare function selectionState(rows: readonly SessionRow[], selected: ReadonlySet<string>): {
20
+ readonly count: number;
21
+ readonly all: boolean;
22
+ readonly some: boolean;
23
+ };
24
+ /** Counts used by the batch confirmation copy. */
25
+ export declare function batchSummary(rows: readonly SessionRow[], selected: ReadonlySet<string>): {
26
+ readonly count: number;
27
+ readonly running: number;
28
+ readonly blank: number;
29
+ };
@@ -2,7 +2,7 @@
2
2
  * One namespaced stylesheet. DSH theme variables carry the palette, so the
3
3
  * plugin follows light/dark themes without owning color tokens.
4
4
  */
5
- export declare const CSS = "\n.ss-panel {\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n overflow: auto;\n padding: 32px clamp(20px, 5vw, 56px) 56px;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-specific-main-fill, transparent);\n}\n.ss-shell {\n width: 100%;\n max-width: 880px;\n margin: 0 auto;\n}\n.ss-header {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n justify-content: space-between;\n flex-wrap: wrap;\n margin-bottom: 8px;\n}\n.ss-titleRow {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n.ss-title {\n font-size: 24px;\n line-height: 32px;\n font-weight: 600;\n margin: 0;\n}\n.ss-description {\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n margin: 6px 0 0;\n max-width: 560px;\n}\n.ss-count {\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 20px;\n margin-top: 6px;\n}\n.ss-countInline {\n margin-top: 0;\n align-self: center;\n}\n.ss-button {\n font: inherit;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n box-sizing: border-box;\n min-height: 32px;\n padding: 5px 12px;\n border-radius: var(--dsw-radius-md, 10px);\n border: 0.5px solid transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-button-elevated-fill, #f3f4f6);\n transition: background 120ms ease, border-color 120ms ease;\n}\n.ss-button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-button:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 1px;\n}\n.ss-button:disabled {\n cursor: default;\n opacity: 0.55;\n}\n.ss-buttonPrimary {\n color: #fff;\n background: var(--dsw-alias-state-business-primary, #2563eb);\n border-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n.ss-buttonPrimary:hover:not(:disabled) {\n background: var(--dsw-alias-state-business-primary, #2563eb);\n filter: brightness(1.05);\n}\n.ss-buttonQuiet {\n background: transparent;\n border-color: var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));\n}\n.ss-buttonDanger {\n color: var(--dsw-alias-state-error-primary, #d1242f);\n background: transparent;\n border-color: var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));\n}\n.ss-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex: none;\n border-radius: 999px;\n padding: 1px 8px 2px;\n font-size: 11px;\n line-height: 16px;\n font-weight: 600;\n letter-spacing: 0.01em;\n color: var(--dsw-alias-label-primary-bluish, #1f4f8f);\n background: var(--dsw-alias-state-business-tertiary, rgba(59, 130, 246, 0.12));\n border: 0.5px solid var(--dsw-alias-interactive-bg-hover, rgba(59, 130, 246, 0.18));\n}\n.ss-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 20px 0 0;\n padding: 0;\n list-style: none;\n}\n.ss-row {\n position: relative;\n display: flex;\n align-items: center;\n gap: 14px;\n box-sizing: border-box;\n padding: 12px 14px;\n border-radius: var(--dsw-radius-lg, 14px);\n border: 0.5px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.2));\n background: var(--dsw-alias-bg-elevated, rgba(255, 255, 255, 0.02));\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n.ss-row:hover,\n.ss-row:focus-within {\n border-color: var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-row:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 1px;\n}\n.ss-row[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.7;\n}\n.ss-rowMain {\n min-width: 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 3px;\n}\n.ss-rowTitleRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n.ss-rowTitle {\n font-size: 14px;\n line-height: 20px;\n font-weight: 600;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ss-rowMeta {\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 18px;\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex-wrap: wrap;\n}\n.ss-dotSep {\n opacity: 0.5;\n}\n.ss-rowActions {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n flex: none;\n}\n.ss-rowMenuButton {\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: var(--dsw-radius-md, 10px);\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #818b98);\n font: inherit;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n opacity: 0;\n transition: background 120ms ease, color 120ms ease, opacity 120ms ease;\n}\n.ss-row:hover .ss-rowMenuButton,\n.ss-row:focus-within .ss-rowMenuButton,\n.ss-rowMenuOpen .ss-rowMenuButton {\n opacity: 1;\n}\n.ss-rowMenuButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-rowMenuButton:focus-visible {\n opacity: 1;\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 1px;\n}\n.ss-rowMenuButton:disabled {\n cursor: default;\n opacity: 0.35;\n}\n.ss-rowMenu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n z-index: 20;\n min-width: 136px;\n padding: 4px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n border-radius: var(--dsw-radius-md, 10px);\n background: var(--dsw-alias-bg-elevated, #fff);\n box-shadow: 0 10px 28px rgba(0, 0, 0, 0.16);\n}\n.ss-rowMenu button {\n box-sizing: border-box;\n width: 100%;\n padding: 6px 9px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-primary, #1f2328);\n font: inherit;\n font-size: 13px;\n line-height: 20px;\n text-align: left;\n cursor: pointer;\n}\n.ss-rowMenu button:hover:not(:disabled),\n.ss-rowMenu button:focus-visible {\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n outline: none;\n}\n.ss-rowMenu button:disabled {\n cursor: default;\n opacity: 0.5;\n}\n.ss-rowMenuDanger {\n color: var(--dsw-alias-state-error-primary, #d1242f) !important;\n}\n.ss-status {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n.ss-statusDot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: currentColor;\n opacity: 0.55;\n}\n.ss-stateRunning {\n color: var(--dsw-alias-state-business-primary, #2563eb);\n font-weight: 600;\n}\n.ss-empty {\n margin-top: 28px;\n padding: 44px 24px;\n text-align: center;\n border: 0.5px dashed var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));\n border-radius: var(--dsw-radius-lg, 14px);\n}\n.ss-emptyTitle {\n font-size: 15px;\n font-weight: 600;\n line-height: 22px;\n margin: 0 0 6px;\n}\n.ss-emptyHint {\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n margin: 0 auto;\n max-width: 460px;\n}\n.ss-emptyAction {\n margin-top: 18px;\n}\n.ss-panelHint {\n margin: 18px 0 0;\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 20px;\n}\n.ss-fieldLabel {\n display: block;\n margin: 12px 0 6px;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 12px;\n line-height: 18px;\n}\n.ss-error {\n margin-top: 16px;\n padding: 8px 10px;\n border-radius: var(--dsw-radius-sm, 8px);\n color: var(--dsw-alias-state-error-primary, #d1242f);\n background: var(--dsw-alias-state-error-tertiary, rgba(209, 36, 47, 0.08));\n font-size: 12px;\n line-height: 18px;\n}\n.ss-dialogBackdrop {\n position: fixed;\n inset: 0;\n z-index: 80;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.28);\n padding: 24px;\n}\n.ss-dialog {\n width: 100%;\n max-width: 440px;\n box-sizing: border-box;\n border-radius: var(--dsw-radius-lg, 14px);\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: var(--dsw-alias-bg-elevated, #fff);\n padding: 20px;\n box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22);\n}\n.ss-dialogTitle {\n margin: 0 0 6px;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n}\n.ss-dialogBody {\n margin: 0 0 14px;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n}\n.ss-input {\n box-sizing: border-box;\n width: 100%;\n height: 36px;\n border-radius: var(--dsw-radius-sm, 8px);\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: transparent;\n color: inherit;\n font: inherit;\n padding: 0 10px;\n}\n.ss-dialogFooter {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 18px;\n}\n.ss-footerAction {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 30px;\n padding: 4px 8px;\n border: 0;\n border-radius: var(--dsw-radius-md, 10px);\n background: transparent;\n color: var(--dsw-alias-label-secondary, #59636e);\n font: inherit;\n cursor: pointer;\n text-align: left;\n}\n.ss-footerAction:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-footerAction:disabled {\n cursor: default;\n opacity: 0.55;\n}\n.ss-footerLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n}\n.ss-footerRail {\n width: 36px;\n height: 36px;\n justify-content: center;\n padding: 0;\n}\n.ss-panelIcon {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n.ss-launcher {\n box-sizing: border-box;\n min-height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 32px;\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n.ss-launcherCard {\n box-sizing: border-box;\n width: 100%;\n max-width: 430px;\n padding: 30px 28px;\n text-align: center;\n border: 0.5px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));\n border-radius: var(--dsw-radius-lg, 14px);\n background: var(--dsw-alias-bg-elevated, rgba(255, 255, 255, 0.02));\n}\n.ss-launcherSpinner {\n width: 22px;\n height: 22px;\n margin: 0 auto 14px;\n border-radius: 50%;\n border: 2px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n border-top-color: var(--dsw-alias-state-business-primary, #2563eb);\n animation: ss-spin 900ms linear infinite;\n}\n@keyframes ss-spin {\n to { transform: rotate(360deg); }\n}\n.ss-launcherTitle {\n margin: 0;\n font-size: 15px;\n line-height: 22px;\n font-weight: 600;\n}\n.ss-launcherHint {\n margin: 6px 0 0;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n}\n.ss-launcherActions {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 8px;\n margin-top: 18px;\n}\n.ss-heroBadge {\n margin-right: 4px;\n}\n.ss-rowMark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n border-radius: 4px;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n color: var(--dsw-alias-label-primary-bluish, #1f4f8f);\n background: var(--dsw-alias-state-business-tertiary, rgba(59, 130, 246, 0.14));\n flex: none;\n}\n.ss-rowHover {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #cfd3d6;\n font-size: 12px;\n line-height: 16px;\n}\n.ss-toast {\n position: fixed;\n left: 50%;\n bottom: 28px;\n transform: translateX(-50%);\n z-index: 90;\n max-width: min(520px, calc(100vw - 40px));\n box-sizing: border-box;\n padding: 9px 14px;\n border-radius: var(--dsw-radius-md, 10px);\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: var(--dsw-alias-bg-elevated, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);\n font-size: 13px;\n line-height: 19px;\n pointer-events: auto;\n}\n.ss-toastError {\n color: var(--dsw-alias-state-error-primary, #d1242f);\n}\n.ss-visuallyHidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n@media (hover: none) {\n .ss-rowMenuButton { opacity: 1; }\n}\n@media (max-width: 640px) {\n .ss-panel { padding: 20px 14px 40px; }\n .ss-row { flex-wrap: wrap; }\n .ss-rowActions { width: 100%; justify-content: flex-end; }\n}\n";
5
+ export declare const CSS = "\n.ss-panel {\n box-sizing: border-box;\n height: 100%;\n min-height: 0;\n overflow: auto;\n padding: 32px clamp(20px, 5vw, 56px) 56px;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-specific-main-fill, transparent);\n}\n.ss-shell {\n width: 100%;\n max-width: 880px;\n margin: 0 auto;\n}\n.ss-header {\n display: flex;\n align-items: flex-start;\n gap: 16px;\n justify-content: space-between;\n flex-wrap: wrap;\n margin-bottom: 8px;\n}\n.ss-titleRow {\n display: flex;\n align-items: center;\n gap: 10px;\n min-width: 0;\n}\n.ss-title {\n font-size: 24px;\n line-height: 32px;\n font-weight: 600;\n margin: 0;\n}\n.ss-description {\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n margin: 6px 0 0;\n max-width: 560px;\n}\n.ss-count {\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 20px;\n margin-top: 6px;\n}\n.ss-countInline {\n margin-top: 0;\n align-self: center;\n}\n.ss-headerActions {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n flex-wrap: wrap;\n gap: 8px;\n}\n.ss-headerSelection {\n position: sticky;\n top: 0;\n z-index: 6;\n align-items: center;\n padding: 8px 0;\n background: var(--dsw-specific-main-fill, var(--dsw-alias-bg-elevated, #fff));\n}\n.ss-selectButton {\n min-height: 30px;\n padding: 3px 8px;\n border: 0;\n border-radius: var(--dsw-radius-md, 10px);\n background: transparent;\n color: var(--dsw-alias-label-secondary, #59636e);\n font: inherit;\n font-size: 13px;\n line-height: 20px;\n cursor: pointer;\n}\n.ss-selectButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-selectButton:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 1px;\n}\n.ss-selectButton:disabled {\n cursor: default;\n opacity: 0.55;\n}\n.ss-button {\n font: inherit;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n box-sizing: border-box;\n min-height: 32px;\n padding: 5px 12px;\n border-radius: var(--dsw-radius-md, 10px);\n border: 0.5px solid transparent;\n cursor: pointer;\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-button-elevated-fill, #f3f4f6);\n transition: background 120ms ease, border-color 120ms ease;\n}\n.ss-button:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-button:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 1px;\n}\n.ss-button:disabled {\n cursor: default;\n opacity: 0.55;\n}\n.ss-buttonPrimary {\n color: #fff;\n background: var(--dsw-alias-state-business-primary, #2563eb);\n border-color: var(--dsw-alias-state-business-primary, #2563eb);\n}\n.ss-buttonPrimary:hover:not(:disabled) {\n background: var(--dsw-alias-state-business-primary, #2563eb);\n filter: brightness(1.05);\n}\n.ss-buttonQuiet {\n background: transparent;\n border-color: var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));\n}\n.ss-buttonDanger {\n color: var(--dsw-alias-state-error-primary, #d1242f);\n background: transparent;\n border-color: var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));\n}\n.ss-badge {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n flex: none;\n border-radius: 999px;\n padding: 1px 8px 2px;\n font-size: 11px;\n line-height: 16px;\n font-weight: 600;\n letter-spacing: 0.01em;\n color: var(--dsw-alias-label-primary-bluish, #1f4f8f);\n background: var(--dsw-alias-state-business-tertiary, rgba(59, 130, 246, 0.12));\n border: 0.5px solid var(--dsw-alias-interactive-bg-hover, rgba(59, 130, 246, 0.18));\n}\n.ss-selectAll {\n display: inline-flex;\n align-items: center;\n gap: 7px;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n cursor: pointer;\n user-select: none;\n}\n.ss-checkbox {\n width: 18px;\n height: 18px;\n margin: 0;\n flex: none;\n accent-color: var(--dsw-alias-state-business-primary, #2563eb);\n cursor: pointer;\n}\n.ss-checkbox:disabled {\n cursor: default;\n opacity: 0.55;\n}\n.ss-list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin: 20px 0 0;\n padding: 0;\n list-style: none;\n}\n.ss-row {\n position: relative;\n display: flex;\n align-items: center;\n gap: 14px;\n box-sizing: border-box;\n padding: 12px 14px;\n border-radius: var(--dsw-radius-lg, 14px);\n border: 0.5px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.2));\n background: var(--dsw-alias-bg-elevated, rgba(255, 255, 255, 0.02));\n cursor: pointer;\n transition: background 120ms ease, border-color 120ms ease;\n}\n.ss-row:hover,\n.ss-row:focus-within {\n border-color: var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-rowSelected,\n.ss-rowSelected:hover,\n.ss-rowSelected:focus-within {\n border-color: var(--dsw-alias-state-business-primary, #3b82f6);\n}\n.ss-row[aria-disabled=\"true\"] {\n cursor: default;\n opacity: 0.7;\n}\n.ss-rowMain {\n min-width: 0;\n flex: 1;\n display: flex;\n flex-direction: column;\n gap: 3px;\n padding: 0;\n border: 0;\n background: transparent;\n color: inherit;\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.ss-rowMain:disabled {\n cursor: default;\n opacity: 0.7;\n}\n.ss-rowMain:focus-visible {\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 2px;\n border-radius: 6px;\n}\n.ss-rowTitleRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n.ss-rowTitle {\n font-size: 14px;\n line-height: 20px;\n font-weight: 600;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ss-rowMeta {\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 18px;\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n flex-wrap: wrap;\n}\n.ss-dotSep {\n opacity: 0.5;\n}\n.ss-rowActions {\n position: relative;\n display: flex;\n align-items: center;\n gap: 6px;\n flex: none;\n}\n.ss-rowMenuButton {\n width: 28px;\n height: 28px;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n border: 0;\n border-radius: var(--dsw-radius-md, 10px);\n background: transparent;\n color: var(--dsw-alias-label-tertiary, #818b98);\n font: inherit;\n font-size: 18px;\n line-height: 1;\n cursor: pointer;\n opacity: 0;\n transition: background 120ms ease, color 120ms ease, opacity 120ms ease;\n}\n.ss-row:hover .ss-rowMenuButton,\n.ss-row:focus-within .ss-rowMenuButton,\n.ss-rowMenuOpen .ss-rowMenuButton {\n opacity: 1;\n}\n.ss-rowMenuButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-rowMenuButton:focus-visible {\n opacity: 1;\n outline: var(--dsw-focus-ring-width, 2px) solid\n var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary, #3b82f6));\n outline-offset: 1px;\n}\n.ss-rowMenuButton:disabled {\n cursor: default;\n opacity: 0.35;\n}\n.ss-rowMenu {\n position: absolute;\n top: calc(100% + 4px);\n right: 0;\n z-index: 20;\n min-width: 136px;\n padding: 4px;\n display: flex;\n flex-direction: column;\n gap: 2px;\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n border-radius: var(--dsw-radius-md, 10px);\n background: var(--dsw-alias-bg-elevated, #fff);\n box-shadow: 0 10px 28px rgba(0, 0, 0, 0.16);\n}\n.ss-rowMenu button {\n box-sizing: border-box;\n width: 100%;\n padding: 6px 9px;\n border: 0;\n border-radius: 6px;\n background: transparent;\n color: var(--dsw-alias-label-primary, #1f2328);\n font: inherit;\n font-size: 13px;\n line-height: 20px;\n text-align: left;\n cursor: pointer;\n}\n.ss-rowMenu button:hover:not(:disabled),\n.ss-rowMenu button:focus-visible {\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n outline: none;\n}\n.ss-rowMenu button:disabled {\n cursor: default;\n opacity: 0.5;\n}\n.ss-rowMenuDanger {\n color: var(--dsw-alias-state-error-primary, #d1242f) !important;\n}\n.ss-status {\n display: inline-flex;\n align-items: center;\n gap: 5px;\n}\n.ss-statusDot {\n width: 5px;\n height: 5px;\n border-radius: 50%;\n background: currentColor;\n opacity: 0.55;\n}\n.ss-stateRunning {\n color: var(--dsw-alias-state-business-primary, #2563eb);\n font-weight: 600;\n}\n.ss-empty {\n margin-top: 28px;\n padding: 44px 24px;\n text-align: center;\n border: 0.5px dashed var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.3));\n border-radius: var(--dsw-radius-lg, 14px);\n}\n.ss-emptyTitle {\n font-size: 15px;\n font-weight: 600;\n line-height: 22px;\n margin: 0 0 6px;\n}\n.ss-emptyHint {\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n margin: 0 auto;\n max-width: 460px;\n}\n.ss-emptyAction {\n margin-top: 18px;\n}\n.ss-panelHint {\n margin: 18px 0 0;\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 20px;\n}\n.ss-fieldLabel {\n display: block;\n margin: 12px 0 6px;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 12px;\n line-height: 18px;\n}\n.ss-error {\n margin-top: 16px;\n padding: 8px 10px;\n border-radius: var(--dsw-radius-sm, 8px);\n color: var(--dsw-alias-state-error-primary, #d1242f);\n background: var(--dsw-alias-state-error-tertiary, rgba(209, 36, 47, 0.08));\n font-size: 12px;\n line-height: 18px;\n}\n.ss-dialogBackdrop {\n position: fixed;\n inset: 0;\n z-index: 80;\n display: flex;\n align-items: center;\n justify-content: center;\n background: rgba(0, 0, 0, 0.28);\n padding: 24px;\n}\n.ss-dialog {\n width: 100%;\n max-width: 440px;\n max-height: calc(100vh - 48px);\n overflow: auto;\n box-sizing: border-box;\n border-radius: var(--dsw-radius-lg, 14px);\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: var(--dsw-alias-bg-elevated, #fff);\n padding: 20px;\n box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22);\n}\n.ss-dialogTitle {\n margin: 0 0 6px;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n}\n.ss-dialogBody {\n margin: 0 0 14px;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n}\n.ss-input {\n box-sizing: border-box;\n width: 100%;\n height: 36px;\n border-radius: var(--dsw-radius-sm, 8px);\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: transparent;\n color: inherit;\n font: inherit;\n padding: 0 10px;\n}\n.ss-dialogFooter {\n display: flex;\n justify-content: flex-end;\n gap: 8px;\n margin-top: 18px;\n}\n.ss-batchWarning {\n margin: 0 0 10px;\n color: var(--dsw-alias-label-primary, #1f2328);\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n}\n.ss-batchDirs {\n margin: 0 0 10px;\n color: var(--dsw-alias-label-tertiary, #818b98);\n font-size: 12px;\n line-height: 18px;\n}\n.ss-footerAction {\n box-sizing: border-box;\n width: 100%;\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 30px;\n padding: 4px 8px;\n border: 0;\n border-radius: var(--dsw-radius-md, 10px);\n background: transparent;\n color: var(--dsw-alias-label-secondary, #59636e);\n font: inherit;\n cursor: pointer;\n text-align: left;\n}\n.ss-footerAction:hover {\n color: var(--dsw-alias-label-primary, #1f2328);\n background: var(--dsw-alias-interactive-bg-hover, #e9ebee);\n}\n.ss-footerAction:disabled {\n cursor: default;\n opacity: 0.55;\n}\n.ss-footerLabel {\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 13px;\n}\n.ss-footerRail {\n width: 36px;\n height: 36px;\n justify-content: center;\n padding: 0;\n}\n.ss-panelIcon {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n}\n.ss-launcher {\n box-sizing: border-box;\n min-height: 100%;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 32px;\n color: var(--dsw-alias-label-primary, #1f2328);\n}\n.ss-launcherCard {\n box-sizing: border-box;\n width: 100%;\n max-width: 430px;\n padding: 30px 28px;\n text-align: center;\n border: 0.5px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.22));\n border-radius: var(--dsw-radius-lg, 14px);\n background: var(--dsw-alias-bg-elevated, rgba(255, 255, 255, 0.02));\n}\n.ss-launcherSpinner {\n width: 22px;\n height: 22px;\n margin: 0 auto 14px;\n border-radius: 50%;\n border: 2px solid var(--dsw-alias-border-l2, rgba(128, 128, 128, 0.25));\n border-top-color: var(--dsw-alias-state-business-primary, #2563eb);\n animation: ss-spin 900ms linear infinite;\n}\n@keyframes ss-spin {\n to { transform: rotate(360deg); }\n}\n.ss-launcherTitle {\n margin: 0;\n font-size: 15px;\n line-height: 22px;\n font-weight: 600;\n}\n.ss-launcherHint {\n margin: 6px 0 0;\n color: var(--dsw-alias-label-secondary, #59636e);\n font-size: 13px;\n line-height: 20px;\n}\n.ss-launcherActions {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n gap: 8px;\n margin-top: 18px;\n}\n.ss-heroBadge {\n margin-right: 4px;\n}\n.ss-rowMark {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 14px;\n height: 14px;\n border-radius: 4px;\n font-size: 10px;\n line-height: 1;\n font-weight: 700;\n color: var(--dsw-alias-label-primary-bluish, #1f4f8f);\n background: var(--dsw-alias-state-business-tertiary, rgba(59, 130, 246, 0.14));\n flex: none;\n}\n.ss-rowHover {\n display: flex;\n align-items: center;\n gap: 6px;\n color: #cfd3d6;\n font-size: 12px;\n line-height: 16px;\n}\n.ss-toast {\n position: fixed;\n left: 50%;\n bottom: 28px;\n transform: translateX(-50%);\n z-index: 90;\n max-width: min(520px, calc(100vw - 40px));\n box-sizing: border-box;\n padding: 9px 14px;\n border-radius: var(--dsw-radius-md, 10px);\n border: 0.5px solid var(--dsw-alias-border-l4, rgba(128, 128, 128, 0.35));\n background: var(--dsw-alias-bg-elevated, #fff);\n color: var(--dsw-alias-label-primary, #1f2328);\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.18);\n font-size: 13px;\n line-height: 19px;\n pointer-events: auto;\n}\n.ss-toastError {\n color: var(--dsw-alias-state-error-primary, #d1242f);\n}\n.ss-visuallyHidden {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n margin: -1px;\n overflow: hidden;\n clip: rect(0, 0, 0, 0);\n white-space: nowrap;\n border: 0;\n}\n@media (hover: none) {\n .ss-rowMenuButton { opacity: 1; }\n}\n@media (max-width: 640px) {\n .ss-panel { padding: 20px 14px 40px; }\n .ss-row { flex-wrap: nowrap; gap: 10px; }\n .ss-headerSelection { align-items: flex-start; }\n .ss-headerSelection .ss-headerActions {\n width: 100%;\n justify-content: flex-end;\n }\n}\n";
6
6
  /**
7
7
  * Insert (or replace) the plugin's one style element.
8
8
  * @returns a disposer that removes the element.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-standalone-session",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "displayName": "Standalone Session",
5
5
  "description": "Create and manage standalone DSH sessions that are not attached to any workspace.",
6
6
  "type": "module",