@michengai/dsh-automation 0.1.18 → 0.1.20

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
@@ -27,10 +27,10 @@ __export(index_exports, {
27
27
  name: () => name
28
28
  });
29
29
  module.exports = __toCommonJS(index_exports);
30
- var import_react7 = require("react");
30
+ var import_react11 = require("react");
31
31
 
32
32
  // src/client/AutomationView.tsx
33
- var import_react3 = require("react");
33
+ var import_react6 = require("react");
34
34
 
35
35
  // src/client/helpers.ts
36
36
  var AutomationFormError = class extends Error {
@@ -70,6 +70,7 @@ function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], def
70
70
  scheduleKind: "daily",
71
71
  onceAt: localDateTimeValue(now),
72
72
  everyMinutes: "60",
73
+ intervalAnchor: "",
73
74
  time: "09:00",
74
75
  weekdays: [1, 2, 3, 4, 5],
75
76
  hourlyMinute: "00",
@@ -105,7 +106,12 @@ function buildCreateInput(form, workspaces, models, now = /* @__PURE__ */ new Da
105
106
  if (!Number.isInteger(everyMinutes) || everyMinutes < 5 || everyMinutes > 43200) {
106
107
  throw new AutomationFormError("form.error.interval");
107
108
  }
108
- schedule = { kind: "interval", everyMinutes, anchor: now.toISOString(), timeZone: form.timeZone };
109
+ schedule = {
110
+ kind: "interval",
111
+ everyMinutes,
112
+ anchor: form.intervalAnchor.trim() || now.toISOString(),
113
+ timeZone: form.timeZone
114
+ };
109
115
  break;
110
116
  }
111
117
  case "daily":
@@ -187,6 +193,15 @@ function clockTime(iso) {
187
193
  if (Number.isNaN(value.getTime())) return iso;
188
194
  return value.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
189
195
  }
196
+ var HISTORY_STATUS_OPTIONS = [
197
+ "succeeded",
198
+ "failed",
199
+ "interrupted",
200
+ "running",
201
+ "queued",
202
+ "skipped",
203
+ "cancelled"
204
+ ];
190
205
  function sortStamp(value) {
191
206
  const parsed = Date.parse(value);
192
207
  return Number.isFinite(parsed) ? parsed : 0;
@@ -212,6 +227,24 @@ function sortAutomations(items, key, direction) {
212
227
  return left.id.localeCompare(right.id);
213
228
  });
214
229
  }
230
+ var SETTINGS_SORT_DEFAULT_KEY = "dsh-automation.sort-default.settings";
231
+ var OVERVIEW_SORT_DEFAULT_KEY = "dsh-automation.sort-default.overview";
232
+ function readSortDefault(storage, storageKey) {
233
+ if (storage === void 0) return void 0;
234
+ try {
235
+ const raw = storage.getItem(storageKey);
236
+ if (raw === null) return void 0;
237
+ const parsed = JSON.parse(raw);
238
+ if (parsed.key !== "created" && parsed.key !== "planned") return void 0;
239
+ if (parsed.direction !== "asc" && parsed.direction !== "desc") return void 0;
240
+ return { key: parsed.key, direction: parsed.direction };
241
+ } catch {
242
+ return void 0;
243
+ }
244
+ }
245
+ function writeSortDefault(storage, storageKey, key, direction) {
246
+ storage.setItem(storageKey, JSON.stringify({ key, direction }));
247
+ }
215
248
  function groupHistory(runs, range, now, t) {
216
249
  const buckets = /* @__PURE__ */ new Map();
217
250
  for (const run of runs) {
@@ -258,13 +291,19 @@ function formFromAutomation(item, workspaces = [], defaultModel, defaultPermissi
258
291
  permission: item.permission,
259
292
  workspaceId: item.workspaceId ?? base.workspaceId,
260
293
  modelKey,
261
- reasoningEffort: item.reasoningEffort ?? "none"
294
+ reasoningEffort: item.reasoningEffort ?? "none",
295
+ timeZone: item.timeZone || schedule.timeZone || base.timeZone
262
296
  };
263
297
  switch (schedule.kind) {
264
298
  case "once":
265
299
  return { ...common, scheduleKind: "once", onceAt: toLocalInput(schedule.at) };
266
300
  case "interval":
267
- return { ...common, scheduleKind: "interval", everyMinutes: String(schedule.everyMinutes) };
301
+ return {
302
+ ...common,
303
+ scheduleKind: "interval",
304
+ everyMinutes: String(schedule.everyMinutes),
305
+ intervalAnchor: schedule.anchor ?? ""
306
+ };
268
307
  case "hourly":
269
308
  return { ...common, scheduleKind: "hourly", hourlyMinute: String(schedule.minute).padStart(2, "0") };
270
309
  case "daily":
@@ -301,6 +340,9 @@ function RefreshIcon(props) {
301
340
  function PlayIcon(props) {
302
341
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", width: 16, height: 16, fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4.6 3.4 11.7 8l-7.1 4.6V3.4Z", fill: "currentColor", stroke: "currentColor", strokeWidth: "1.6", strokeLinejoin: "round" }) });
303
342
  }
343
+ function PauseIcon(props) {
344
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 7v10M15 7v10" }) });
345
+ }
304
346
  function TrashIcon(props) {
305
347
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FillIcon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M14.478 4.841 14.214 10.115c-.104 2.072-.147 2.896-.827 3.846a3.53 3.53 0 0 1-1.044.993c-.519.333-1.101.478-1.784.546-.671.067-1.509.066-2.559.066s-1.887.001-2.558-.066c-.683-.068-1.266-.213-1.784-.546a3.53 3.53 0 0 1-1.044-.993c-.681-.95-.724-1.774-.828-3.846L1.522 4.841l1.368-.068.263 5.273c.109 2.176.171 2.556.573 3.117a2.16 2.16 0 0 0 .673.64c.263.169.603.277 1.179.334.587.059 1.345.06 2.422.06s1.834-.001 2.422-.06c.575-.057.916-.165 1.179-.335.262-.168.49-.386.672-.64.402-.56.464-.94.573-3.116l.263-5.273 1.369.068ZM5.43 6.228h1.37v5.163H5.43V6.228Zm3.77 0h1.37v5.163H9.2V6.228ZM8.536.434c.644 0 1.116-.007 1.56.137.14.045.276.101.406.168.416.212.745.552 1.2 1.007l.796.795h2.876v1.37H.626V2.541h2.876l.796-.795c.456-.455.784-.795 1.2-1.007.13-.067.266-.123.405-.168C6.348.427 6.82.434 7.464.434h1.072Zm-1.072 1.37c-.732 0-.948.008-1.138.07a2.2 2.2 0 0 0-.206.085c-.156.08-.296.204-.678.583h5.117c-.382-.379-.522-.503-.679-.583a2.2 2.2 0 0 0-.205-.085c-.191-.062-.406-.07-1.138-.07H7.464Z" }) });
306
348
  }
@@ -310,6 +352,15 @@ function ShieldIcon(props) {
310
352
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9.4 12 1.7 1.7 3.7-4" })
311
353
  ] });
312
354
  }
355
+ function CalendarIcon(props) {
356
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
357
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("rect", { x: "4", y: "5.5", width: "16", height: "14", rx: "2" }),
358
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 3.8v3.4M16 3.8v3.4M4 9.5h16" })
359
+ ] });
360
+ }
361
+ function CheckIcon(props) {
362
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m5.5 12.5 4 4 9-9" }) });
363
+ }
313
364
  function MoreIcon(props) {
314
365
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
315
366
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "12", r: "1.2", fill: "currentColor" }),
@@ -1101,6 +1152,176 @@ function clampOnceAt(value) {
1101
1152
  return new Date(next.getTime() - offset).toISOString().slice(0, 16);
1102
1153
  }
1103
1154
 
1155
+ // src/client/delete-confirmation.tsx
1156
+ var import_react3 = require("react");
1157
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1158
+ function DeleteConfirmation({
1159
+ target,
1160
+ t,
1161
+ busy,
1162
+ onCancel,
1163
+ onConfirm
1164
+ }) {
1165
+ (0, import_react3.useEffect)(() => {
1166
+ if (target === void 0 || busy) return;
1167
+ const onKeyDown = (event) => {
1168
+ if (event.key !== "Escape") return;
1169
+ event.preventDefault();
1170
+ onCancel();
1171
+ };
1172
+ document.addEventListener("keydown", onKeyDown);
1173
+ return () => {
1174
+ document.removeEventListener("keydown", onKeyDown);
1175
+ };
1176
+ }, [busy, onCancel, target]);
1177
+ if (target === void 0) return null;
1178
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-mask", onMouseDown: (event) => event.stopPropagation(), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1179
+ "section",
1180
+ {
1181
+ className: "dsh-st-confirm-modal",
1182
+ role: "alertdialog",
1183
+ "aria-modal": "true",
1184
+ "aria-labelledby": "dsh-st-confirm-delete-title",
1185
+ "aria-describedby": "dsh-st-confirm-delete-description",
1186
+ onMouseDown: (event) => event.stopPropagation(),
1187
+ children: [
1188
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { id: "dsh-st-confirm-delete-title", children: t("card.confirmDelete") }),
1189
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-st-confirm-target", children: target.name }),
1190
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { id: "dsh-st-confirm-delete-description", children: t("card.confirmDeleteHint") }),
1191
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-modal-actions", children: [
1192
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-btn", autoFocus: true, disabled: busy, onClick: onCancel, children: t("card.cancel") }),
1193
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--danger", disabled: busy, onClick: onConfirm, children: t("card.confirm") })
1194
+ ] })
1195
+ ]
1196
+ }
1197
+ ) });
1198
+ }
1199
+
1200
+ // src/client/dropdown-menu.tsx
1201
+ var import_react4 = require("react");
1202
+ var import_react_dom2 = require("react-dom");
1203
+ var import_jsx_runtime5 = require("react/jsx-runtime");
1204
+ function DropdownMenu({
1205
+ ariaLabel,
1206
+ className,
1207
+ buttonClassName,
1208
+ menuClassName,
1209
+ options,
1210
+ trigger
1211
+ }) {
1212
+ const [open, setOpen] = (0, import_react4.useState)(false);
1213
+ const root = (0, import_react4.useRef)(null);
1214
+ const menuRef = (0, import_react4.useRef)(null);
1215
+ const [menuStyle, setMenuStyle] = (0, import_react4.useState)({});
1216
+ const selectedLabel = options.find((option) => option.selected)?.label ?? options[0]?.label ?? ariaLabel;
1217
+ (0, import_react4.useEffect)(() => {
1218
+ if (!open) return;
1219
+ const close = (event) => {
1220
+ if (root.current !== null && root.current.contains(event.target)) return;
1221
+ if (menuRef.current?.contains(event.target) === true) return;
1222
+ setOpen(false);
1223
+ };
1224
+ const closeOnEscape = (event) => {
1225
+ if (event.key === "Escape") setOpen(false);
1226
+ };
1227
+ document.addEventListener("mousedown", close);
1228
+ document.addEventListener("keydown", closeOnEscape);
1229
+ return () => {
1230
+ document.removeEventListener("mousedown", close);
1231
+ document.removeEventListener("keydown", closeOnEscape);
1232
+ };
1233
+ }, [open]);
1234
+ (0, import_react4.useLayoutEffect)(() => {
1235
+ if (!open) return;
1236
+ const update = () => {
1237
+ const button = root.current?.querySelector(".dsh-st-dropdown-btn");
1238
+ const rect = button?.getBoundingClientRect();
1239
+ if (rect === void 0) return;
1240
+ const height = menuRef.current?.offsetHeight ?? 220;
1241
+ const margin = 8;
1242
+ let top = rect.bottom + 6;
1243
+ if (top + height > window.innerHeight - margin) top = Math.max(margin, rect.top - height - 6);
1244
+ const right = Math.max(margin, window.innerWidth - rect.right);
1245
+ setMenuStyle((current) => current.top === top && current.right === right ? current : { position: "fixed", top, right });
1246
+ };
1247
+ const onScroll = (event) => {
1248
+ if (event.target instanceof Node && menuRef.current?.contains(event.target)) return;
1249
+ update();
1250
+ };
1251
+ update();
1252
+ window.addEventListener("resize", update);
1253
+ document.addEventListener("scroll", onScroll, true);
1254
+ return () => {
1255
+ window.removeEventListener("resize", update);
1256
+ document.removeEventListener("scroll", onScroll, true);
1257
+ };
1258
+ }, [open, selectedLabel]);
1259
+ const menu = open && typeof document !== "undefined" ? (0, import_react_dom2.createPortal)(
1260
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { ref: menuRef, className: `dsh-st-dropdown-menu is-float${menuClassName === void 0 ? "" : ` ${menuClassName}`}`, style: menuStyle, children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1261
+ DropdownRow,
1262
+ {
1263
+ label: option.label,
1264
+ selected: option.selected,
1265
+ trailing: option.trailing,
1266
+ onSelect: () => {
1267
+ if (option.keepOpen !== true) setOpen(false);
1268
+ option.onSelect();
1269
+ }
1270
+ },
1271
+ option.key
1272
+ )) }),
1273
+ document.body
1274
+ ) : null;
1275
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: `dsh-st-dropdown${className === void 0 ? "" : ` ${className}`}`, ref: root, children: [
1276
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: `dsh-st-dropdown-btn${buttonClassName === void 0 ? "" : ` ${buttonClassName}`}${open ? " is-open" : ""}`, "aria-label": ariaLabel, "aria-expanded": open, onClick: () => setOpen((value) => !value), children: trigger ?? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
1277
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-label", children: selectedLabel }),
1278
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronIcon, { width: 10, height: 10, className: "dsh-st-dropdown-chevron" })
1279
+ ] }) }),
1280
+ menu
1281
+ ] });
1282
+ }
1283
+ function DropdownRow({
1284
+ label,
1285
+ selected,
1286
+ trailing,
1287
+ onSelect
1288
+ }) {
1289
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1290
+ "div",
1291
+ {
1292
+ className: `dsh-st-dropdown-row${selected ? " is-selected" : ""}${trailing === void 0 ? "" : " has-trailing"}`,
1293
+ role: "menuitemradio",
1294
+ "aria-checked": selected,
1295
+ tabIndex: 0,
1296
+ onClick: onSelect,
1297
+ onKeyDown: (event) => {
1298
+ if (event.key === "Enter" || event.key === " ") {
1299
+ event.preventDefault();
1300
+ onSelect();
1301
+ }
1302
+ },
1303
+ children: [
1304
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-label-cell", children: label }),
1305
+ trailing !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1306
+ "button",
1307
+ {
1308
+ type: "button",
1309
+ className: `dsh-st-dropdown-default${trailing.active ? " is-on" : ""}`,
1310
+ disabled: trailing.active,
1311
+ onClick: (event) => {
1312
+ event.stopPropagation();
1313
+ trailing.onSelect();
1314
+ },
1315
+ children: trailing.label
1316
+ }
1317
+ ),
1318
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-spacer" }),
1319
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-dropdown-check", children: selected ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-sort-tick" }) })
1320
+ ]
1321
+ }
1322
+ );
1323
+ }
1324
+
1104
1325
  // src/client/prefill.ts
1105
1326
  var pending = null;
1106
1327
  var listeners = /* @__PURE__ */ new Set();
@@ -1283,28 +1504,136 @@ function createAutomationRuntime(rpc) {
1283
1504
  };
1284
1505
  }
1285
1506
 
1507
+ // src/client/sort-menu.tsx
1508
+ var import_react5 = require("react");
1509
+ var import_jsx_runtime6 = require("react/jsx-runtime");
1510
+ var SORT_OPTIONS = [
1511
+ ["created", "desc"],
1512
+ ["created", "asc"],
1513
+ ["planned", "asc"],
1514
+ ["planned", "desc"]
1515
+ ];
1516
+ function SortMenu({
1517
+ t,
1518
+ storage,
1519
+ storageKey,
1520
+ sortKey,
1521
+ sortDirection,
1522
+ onSelect,
1523
+ compact = false,
1524
+ iconOnly = false,
1525
+ className
1526
+ }) {
1527
+ const [saved, setSaved] = (0, import_react5.useState)(() => readSortDefault(storage, storageKey));
1528
+ const options = SORT_OPTIONS.map(([key, direction]) => {
1529
+ const selected = sortKey === key && sortDirection === direction;
1530
+ const isDefault = saved?.key === key && saved.direction === direction;
1531
+ return {
1532
+ key: `${key}-${direction}`,
1533
+ label: t(key === "planned" ? `sort.planned.${direction}` : `sort.created.${direction}`),
1534
+ selected,
1535
+ keepOpen: true,
1536
+ onSelect: () => onSelect(key, direction),
1537
+ ...selected && storage !== void 0 ? {
1538
+ trailing: {
1539
+ label: t("sort.default.saved"),
1540
+ active: isDefault,
1541
+ onSelect: () => {
1542
+ writeSortDefault(storage, storageKey, key, direction);
1543
+ setSaved({ key, direction });
1544
+ }
1545
+ }
1546
+ } : {}
1547
+ };
1548
+ });
1549
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1550
+ DropdownMenu,
1551
+ {
1552
+ ariaLabel: t("sort.by"),
1553
+ ...compact || className !== void 0 ? { className: [compact ? "dsh-st-dropdown-compact" : "", className ?? ""].filter(Boolean).join(" ") } : {},
1554
+ ...iconOnly ? { buttonClassName: "dsh-st-n-head-btn", trigger: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(SlidersIcon, { width: 16, height: 16 }) } : {},
1555
+ menuClassName: compact ? "dsh-st-dropdown-sort dsh-st-dropdown-compact" : "dsh-st-dropdown-sort",
1556
+ options
1557
+ }
1558
+ );
1559
+ }
1560
+
1561
+ // src/client/task-settings-request.ts
1562
+ var AUTOMATION_TASK_SETTINGS_EVENT = "dsh-automation:open-task-settings";
1563
+ var AUTOMATION_TASK_SETTINGS_STORAGE_KEY = "dsh-automation:pending-task-settings";
1564
+ function parseAutomationTaskSettingsRequest(value) {
1565
+ if (typeof value !== "object" || value === null) return void 0;
1566
+ const record = value;
1567
+ if (typeof record.name !== "string" || record.name.trim() === "" || !Array.isArray(record.sessionIds) || record.sessionIds.some((id) => typeof id !== "string")) return void 0;
1568
+ if (record.automationId !== void 0 && (typeof record.automationId !== "string" || record.automationId.trim() === "")) return void 0;
1569
+ return {
1570
+ ...typeof record.automationId === "string" ? { automationId: record.automationId } : {},
1571
+ name: record.name,
1572
+ sessionIds: [...record.sessionIds]
1573
+ };
1574
+ }
1575
+ function writeAutomationTaskSettingsRequest(storage, request) {
1576
+ try {
1577
+ storage?.setItem(AUTOMATION_TASK_SETTINGS_STORAGE_KEY, JSON.stringify(request));
1578
+ } catch {
1579
+ }
1580
+ }
1581
+ function requestAutomationTaskSettings(request) {
1582
+ if (typeof window === "undefined") return;
1583
+ writeAutomationTaskSettingsRequest(window.sessionStorage, request);
1584
+ window.dispatchEvent(new CustomEvent(AUTOMATION_TASK_SETTINGS_EVENT, { detail: request }));
1585
+ }
1586
+ function readAutomationTaskSettingsRequest(storage) {
1587
+ if (storage === void 0) return void 0;
1588
+ try {
1589
+ const raw = storage.getItem(AUTOMATION_TASK_SETTINGS_STORAGE_KEY);
1590
+ return raw === null ? void 0 : parseAutomationTaskSettingsRequest(JSON.parse(raw));
1591
+ } catch {
1592
+ return void 0;
1593
+ }
1594
+ }
1595
+ function clearAutomationTaskSettingsRequest(storage) {
1596
+ try {
1597
+ storage?.removeItem(AUTOMATION_TASK_SETTINGS_STORAGE_KEY);
1598
+ } catch {
1599
+ }
1600
+ }
1601
+ function resolveAutomationTaskSettings(request, automations, runs) {
1602
+ if (request.automationId !== void 0) {
1603
+ const exact = automations.find((item) => item.id === request.automationId);
1604
+ if (exact !== void 0) return exact;
1605
+ }
1606
+ const sessionIds = new Set(request.sessionIds);
1607
+ const automationId = runs.find((run) => run.sessionId !== void 0 && sessionIds.has(run.sessionId))?.automationId;
1608
+ return automations.find((item) => item.id === automationId) ?? automations.find((item) => item.name === request.name);
1609
+ }
1610
+
1286
1611
  // src/client/AutomationView.tsx
1287
- var import_jsx_runtime4 = require("react/jsx-runtime");
1612
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1613
+ var SORT_STORAGE = typeof window === "undefined" ? void 0 : window.localStorage;
1614
+ var TASK_SETTINGS_STORAGE = typeof window === "undefined" ? void 0 : window.sessionStorage;
1288
1615
  var EXAMPLES = [
1289
1616
  { name: "\u6BCF\u65E5\u56DE\u5F52\u68C0\u67E5", scheduleKind: "daily", time: "09:00", weekdays: [1, 2, 3, 4, 5] },
1290
1617
  { name: "\u6BCF\u5468\u4F9D\u8D56\u5DE1\u68C0", scheduleKind: "weekly", time: "10:00", weekdays: [1] },
1291
1618
  { name: "\u5DE5\u4F5C\u65E5\u65E9\u62A5", scheduleKind: "weekly", time: "08:00", weekdays: [1, 2, 3, 4, 5] }
1292
1619
  ];
1293
1620
  function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1294
- const state = (0, import_react3.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
1295
- const [tab, setTab] = (0, import_react3.useState)("mine");
1296
- const [query, setQuery] = (0, import_react3.useState)("");
1297
- const [creating, setCreating] = (0, import_react3.useState)(false);
1298
- const [editingId, setEditingId] = (0, import_react3.useState)();
1299
- const [draft, setDraft] = (0, import_react3.useState)();
1300
- const [busy, setBusy] = (0, import_react3.useState)(false);
1301
- const [error, setError] = (0, import_react3.useState)();
1302
- const [historyRange, setHistoryRange] = (0, import_react3.useState)("day");
1303
- const [historyTask, setHistoryTask] = (0, import_react3.useState)("all");
1304
- const [historyStatus, setHistoryStatus] = (0, import_react3.useState)("all");
1305
- const [sortKey, setSortKey] = (0, import_react3.useState)("created");
1306
- const [sortDirection, setSortDirection] = (0, import_react3.useState)("desc");
1307
- const now = (0, import_react3.useMemo)(() => new Date(state.snapshot?.serverNow ?? Date.now()), [state.snapshot?.serverNow, state.refreshedAt]);
1621
+ const state = (0, import_react6.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
1622
+ const [tab, setTab] = (0, import_react6.useState)("mine");
1623
+ const [query, setQuery] = (0, import_react6.useState)("");
1624
+ const [creating, setCreating] = (0, import_react6.useState)(false);
1625
+ const [editingId, setEditingId] = (0, import_react6.useState)();
1626
+ const [deleteTarget, setDeleteTarget] = (0, import_react6.useState)();
1627
+ const [draft, setDraft] = (0, import_react6.useState)();
1628
+ const [busy, setBusy] = (0, import_react6.useState)(false);
1629
+ const [error, setError] = (0, import_react6.useState)();
1630
+ const [historyRange, setHistoryRange] = (0, import_react6.useState)("day");
1631
+ const [historyTask, setHistoryTask] = (0, import_react6.useState)("all");
1632
+ const [historyStatus, setHistoryStatus] = (0, import_react6.useState)("all");
1633
+ const [sortKey, setSortKey] = (0, import_react6.useState)(() => readSortDefault(SORT_STORAGE, SETTINGS_SORT_DEFAULT_KEY)?.key ?? "created");
1634
+ const [sortDirection, setSortDirection] = (0, import_react6.useState)(() => readSortDefault(SORT_STORAGE, SETTINGS_SORT_DEFAULT_KEY)?.direction ?? "desc");
1635
+ const [taskSettingsRequest, setTaskSettingsRequest] = (0, import_react6.useState)(() => readAutomationTaskSettingsRequest(TASK_SETTINGS_STORAGE));
1636
+ const now = (0, import_react6.useMemo)(() => new Date(state.snapshot?.serverNow ?? Date.now()), [state.snapshot?.serverNow, state.refreshedAt]);
1308
1637
  const snapshot = state.snapshot;
1309
1638
  const workspaces = snapshot?.workspaces ?? [];
1310
1639
  const models = snapshot?.models ?? [];
@@ -1348,37 +1677,61 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1348
1677
  setDraft(formFromAutomation(item, workspaces, snapshot?.defaultModel ?? null, snapshot?.defaultPermission ?? item.permission));
1349
1678
  setCreating(true);
1350
1679
  };
1351
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-shell", children: [
1352
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "dsh-st-top", children: [
1353
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-heading", children: [
1354
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { children: t("tab") }),
1355
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t("header.lead") })
1680
+ (0, import_react6.useEffect)(() => {
1681
+ if (typeof window === "undefined") return;
1682
+ const onTaskSettings = (event) => {
1683
+ const request = parseAutomationTaskSettingsRequest(event.detail);
1684
+ if (request !== void 0) setTaskSettingsRequest(request);
1685
+ };
1686
+ window.addEventListener(AUTOMATION_TASK_SETTINGS_EVENT, onTaskSettings);
1687
+ return () => {
1688
+ window.removeEventListener(AUTOMATION_TASK_SETTINGS_EVENT, onTaskSettings);
1689
+ };
1690
+ }, []);
1691
+ (0, import_react6.useEffect)(() => {
1692
+ if (taskSettingsRequest === void 0 || snapshot === void 0) return;
1693
+ const item = resolveAutomationTaskSettings(taskSettingsRequest, snapshot.automations, snapshot.runs);
1694
+ clearAutomationTaskSettingsRequest(TASK_SETTINGS_STORAGE);
1695
+ setTaskSettingsRequest(void 0);
1696
+ setTab("mine");
1697
+ setQuery("");
1698
+ if (item === void 0) {
1699
+ setError(t("error.taskMissing"));
1700
+ return;
1701
+ }
1702
+ openEdit(item);
1703
+ }, [snapshot, taskSettingsRequest, t]);
1704
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-shell", children: [
1705
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("header", { className: "dsh-st-top", children: [
1706
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-heading", children: [
1707
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h1", { children: t("tab") }),
1708
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: t("header.lead") })
1356
1709
  ] }),
1357
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-toolbar", children: [
1358
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { className: "dsh-st-search", value: query, placeholder: t("search.placeholder"), onChange: (event) => setQuery(event.target.value) }),
1359
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "dsh-st-btn", onClick: () => {
1710
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-toolbar", children: [
1711
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { className: "dsh-st-search", value: query, placeholder: t("search.placeholder"), onChange: (event) => setQuery(event.target.value) }),
1712
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "dsh-st-btn", onClick: () => {
1360
1713
  setChatPrefill(t("chat.prompt"));
1361
1714
  closeSettings?.();
1362
1715
  }, children: [
1363
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChatIcon, {}),
1716
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChatIcon, {}),
1364
1717
  t("action.chatCreate")
1365
1718
  ] }),
1366
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", disabled: defaultPermission === "" || permissions.length === 0, onClick: () => openCreate(), children: [
1367
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlusIcon, {}),
1719
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", disabled: defaultPermission === "" || permissions.length === 0, onClick: () => openCreate(), children: [
1720
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlusIcon, {}),
1368
1721
  t("action.create")
1369
1722
  ] }),
1370
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-icon", onClick: () => {
1723
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-icon", onClick: () => {
1371
1724
  void runtime.refresh();
1372
- }, "aria-label": t("section.refresh"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RefreshIcon, {}) })
1725
+ }, "aria-label": t("section.refresh"), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RefreshIcon, {}) })
1373
1726
  ] })
1374
1727
  ] }),
1375
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-banner", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1376
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(InfoIcon, {}),
1728
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-banner", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
1729
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(InfoIcon, {}),
1377
1730
  t("banner.wake")
1378
1731
  ] }) }),
1379
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "dsh-st-examples", children: [
1380
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-examples-head", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { children: t("examples.title") }) }),
1381
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-example-row", children: EXAMPLES.map((example, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1732
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-st-examples", children: [
1733
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-examples-head", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h2", { children: t("examples.title") }) }),
1734
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-example-row", children: EXAMPLES.map((example, index) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1382
1735
  "button",
1383
1736
  {
1384
1737
  type: "button",
@@ -1392,10 +1745,10 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1392
1745
  weekdays: example.weekdays
1393
1746
  }),
1394
1747
  children: [
1395
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t(`examples.${index + 1}.title`) }),
1396
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t(`examples.${index + 1}.body`) }),
1397
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "dsh-st-chip", children: [
1398
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ClockIcon, {}),
1748
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: t(`examples.${index + 1}.title`) }),
1749
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: t(`examples.${index + 1}.body`) }),
1750
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-st-chip", children: [
1751
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ClockIcon, {}),
1399
1752
  t(`examples.${index + 1}.chip`)
1400
1753
  ] })
1401
1754
  ]
@@ -1403,22 +1756,24 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1403
1756
  example.name
1404
1757
  )) })
1405
1758
  ] }),
1406
- error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-st-error", children: error }),
1407
- (state.phase === "idle" || state.phase === "loading" && snapshot === void 0) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-st-muted", children: t("loading") }),
1408
- state.phase === "error" && snapshot === void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-empty", children: [
1409
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: t("error.title") }),
1410
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: state.error }),
1411
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => {
1759
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dsh-st-error", children: error }),
1760
+ (state.phase === "idle" || state.phase === "loading" && snapshot === void 0) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "dsh-st-muted", children: t("loading") }),
1761
+ state.phase === "error" && snapshot === void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-empty", children: [
1762
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: t("error.title") }),
1763
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: state.error }),
1764
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => {
1412
1765
  void runtime.refresh();
1413
1766
  }, children: t("error.retry") })
1414
1767
  ] }),
1415
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-tabs", children: [
1416
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: tab === "mine" ? "is-on" : "", onClick: () => setTab("mine"), children: t("tabs.mine") }),
1417
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: tab === "runs" ? "is-on" : "", onClick: () => setTab("runs"), children: t("tabs.runs") }),
1418
- tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1768
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-tabs", children: [
1769
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: tab === "mine" ? "is-on" : "", onClick: () => setTab("mine"), children: t("tabs.mine") }),
1770
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: tab === "runs" ? "is-on" : "", onClick: () => setTab("runs"), children: t("tabs.runs") }),
1771
+ tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-sort-wrap", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1419
1772
  SortMenu,
1420
1773
  {
1421
1774
  t,
1775
+ ...SORT_STORAGE === void 0 ? {} : { storage: SORT_STORAGE },
1776
+ storageKey: SETTINGS_SORT_DEFAULT_KEY,
1422
1777
  sortKey,
1423
1778
  sortDirection,
1424
1779
  onSelect: (key, direction) => {
@@ -1426,10 +1781,10 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1426
1781
  setSortDirection(direction);
1427
1782
  }
1428
1783
  }
1429
- ),
1430
- tab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-filters", children: [
1431
- ["day", "week", "month"].map((range) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: historyRange === range ? "is-on" : "", onClick: () => setHistoryRange(range), children: t(`history.range.${range}`) }, range)),
1432
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1784
+ ) }),
1785
+ tab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-filters", children: [
1786
+ ["day", "week", "month"].map((range) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: historyRange === range ? "is-on" : "", onClick: () => setHistoryRange(range), children: t(`history.range.${range}`) }, range)),
1787
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1433
1788
  DropdownMenu,
1434
1789
  {
1435
1790
  ariaLabel: t("history.allTasks"),
@@ -1444,13 +1799,13 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1444
1799
  ]
1445
1800
  }
1446
1801
  ),
1447
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1802
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1448
1803
  DropdownMenu,
1449
1804
  {
1450
1805
  ariaLabel: t("history.allStatus"),
1451
1806
  options: [
1452
1807
  { key: "all", label: t("history.allStatus"), selected: historyStatus === "all", onSelect: () => setHistoryStatus("all") },
1453
- ...["succeeded", "failed", "running", "queued", "skipped", "cancelled"].map((status) => ({
1808
+ ...HISTORY_STATUS_OPTIONS.map((status) => ({
1454
1809
  key: status,
1455
1810
  label: t(`status.${status}`),
1456
1811
  selected: historyStatus === status,
@@ -1461,10 +1816,10 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1461
1816
  )
1462
1817
  ] })
1463
1818
  ] }),
1464
- tab === "mine" && (automations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-empty", children: [
1465
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: t("empty.title") }),
1466
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t("empty.body") })
1467
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-grid", children: automations.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1819
+ tab === "mine" && (automations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-empty", children: [
1820
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: t("empty.title") }),
1821
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: t("empty.body") })
1822
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-grid", children: automations.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1468
1823
  TaskCard,
1469
1824
  {
1470
1825
  item,
@@ -1478,17 +1833,15 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1478
1833
  onRun: () => {
1479
1834
  void runAction(() => runtime.runNow(item.id));
1480
1835
  },
1481
- onDelete: () => {
1482
- void runAction(() => runtime.mutateAutomation(item.id, "delete"));
1483
- }
1836
+ onDelete: () => setDeleteTarget(item)
1484
1837
  },
1485
1838
  item.id
1486
1839
  )) })),
1487
- tab === "runs" && (groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-empty", children: t("runs.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-timeline", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "dsh-st-group", children: [
1488
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: group.label }),
1489
- group.items.map((run) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RunRow, { run, t }, run.id))
1840
+ tab === "runs" && (groups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-empty", children: t("runs.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-timeline", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-st-group", children: [
1841
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: group.label }),
1842
+ group.items.map((run) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RunRow, { run, t }, run.id))
1490
1843
  ] }, group.key)) })),
1491
- creating && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1844
+ creating && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1492
1845
  CreateModal,
1493
1846
  {
1494
1847
  t,
@@ -1517,6 +1870,23 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1517
1870
  }
1518
1871
  },
1519
1872
  editingId ?? "create"
1873
+ ),
1874
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1875
+ DeleteConfirmation,
1876
+ {
1877
+ target: deleteTarget,
1878
+ t,
1879
+ busy,
1880
+ onCancel: () => setDeleteTarget(void 0),
1881
+ onConfirm: () => {
1882
+ const target = deleteTarget;
1883
+ if (target === void 0) return;
1884
+ void runAction(async () => {
1885
+ await runtime.mutateAutomation(target.id, "delete");
1886
+ setDeleteTarget(void 0);
1887
+ });
1888
+ }
1889
+ }
1520
1890
  )
1521
1891
  ] });
1522
1892
  }
@@ -1530,9 +1900,9 @@ function TaskCard({
1530
1900
  onRun,
1531
1901
  onDelete
1532
1902
  }) {
1533
- const [menu, setMenu] = (0, import_react3.useState)(false);
1534
- const root = (0, import_react3.useRef)(null);
1535
- (0, import_react3.useEffect)(() => {
1903
+ const [menu, setMenu] = (0, import_react6.useState)(false);
1904
+ const root = (0, import_react6.useRef)(null);
1905
+ (0, import_react6.useEffect)(() => {
1536
1906
  if (!menu) return;
1537
1907
  const close = (event) => {
1538
1908
  if (root.current !== null && !root.current.contains(event.target)) setMenu(false);
@@ -1542,131 +1912,59 @@ function TaskCard({
1542
1912
  document.removeEventListener("mousedown", close);
1543
1913
  };
1544
1914
  }, [menu]);
1545
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("article", { className: "dsh-st-card", ref: root, onClick: onEdit, children: [
1546
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-card-head", children: [
1547
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: `dsh-st-switch ${item.status === "active" ? "is-on" : ""}`, role: "switch", "aria-checked": item.status === "active", disabled: busy, onClick: (event) => {
1915
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: "dsh-st-card", ref: root, onClick: onEdit, children: [
1916
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-card-head", children: [
1917
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: `dsh-st-switch ${item.status === "active" ? "is-on" : ""}`, role: "switch", "aria-checked": item.status === "active", disabled: busy, onClick: (event) => {
1548
1918
  event.stopPropagation();
1549
1919
  onToggle();
1550
1920
  } }),
1551
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-more", onClick: (event) => {
1921
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", className: "dsh-st-more", onClick: (event) => {
1552
1922
  event.stopPropagation();
1553
1923
  setMenu((value) => !value);
1554
- }, "aria-label": t("card.more"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) }),
1555
- menu && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-menu", onClick: (event) => event.stopPropagation(), children: [
1556
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1924
+ }, "aria-label": t("card.more"), children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MoreIcon, {}) }),
1925
+ menu && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-menu", onClick: (event) => event.stopPropagation(), children: [
1926
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1557
1927
  setMenu(false);
1558
1928
  onRun();
1559
1929
  }, children: [
1560
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, { width: 16, height: 16 }),
1930
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PlayIcon, { width: 16, height: 16 }),
1561
1931
  t("menu.run")
1562
1932
  ] }),
1563
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1933
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1564
1934
  setMenu(false);
1565
1935
  onEdit();
1566
1936
  }, children: [
1567
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PencilIcon, { width: 16, height: 16 }),
1937
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(PencilIcon, { width: 16, height: 16 }),
1568
1938
  t("menu.edit")
1569
1939
  ] }),
1570
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "is-danger", disabled: busy, onClick: () => {
1940
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { type: "button", className: "is-danger", disabled: busy, onClick: () => {
1571
1941
  setMenu(false);
1572
1942
  onDelete();
1573
1943
  }, children: [
1574
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrashIcon, { width: 16, height: 16 }),
1944
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TrashIcon, { width: 16, height: 16 }),
1575
1945
  t("menu.delete")
1576
1946
  ] })
1577
1947
  ] })
1578
1948
  ] }),
1579
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: item.name }),
1580
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: item.prompt }),
1581
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-card-foot", children: [
1582
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "dsh-st-chip", children: [
1583
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ClockIcon, {}),
1949
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("h3", { children: item.name }),
1950
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { children: item.prompt }),
1951
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-card-foot", children: [
1952
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "dsh-st-chip", children: [
1953
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ClockIcon, {}),
1584
1954
  formatSchedule(item.schedule, t)
1585
1955
  ] }),
1586
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: item.nextRunAt === void 0 ? t("stats.noneScheduled") : t("history.nextApprox", { when: formatWithin(item.nextRunAt, now, t) }) })
1956
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: item.nextRunAt === void 0 ? t("stats.noneScheduled") : t("history.nextApprox", { when: formatWithin(item.nextRunAt, now, t) }) })
1587
1957
  ] })
1588
1958
  ] });
1589
1959
  }
1590
- function SortMenu({
1591
- t,
1592
- sortKey,
1593
- sortDirection,
1594
- onSelect
1595
- }) {
1596
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1597
- DropdownMenu,
1598
- {
1599
- className: "dsh-st-sort",
1600
- ariaLabel: t("sort.by"),
1601
- options: [
1602
- { key: "created-desc", label: t("sort.created.desc"), selected: sortKey === "created" && sortDirection === "desc", onSelect: () => onSelect("created", "desc") },
1603
- { key: "created-asc", label: t("sort.created.asc"), selected: sortKey === "created" && sortDirection === "asc", onSelect: () => onSelect("created", "asc") },
1604
- { key: "planned-asc", label: t("sort.planned.asc"), selected: sortKey === "planned" && sortDirection === "asc", onSelect: () => onSelect("planned", "asc") },
1605
- { key: "planned-desc", label: t("sort.planned.desc"), selected: sortKey === "planned" && sortDirection === "desc", onSelect: () => onSelect("planned", "desc") }
1606
- ]
1607
- }
1608
- );
1609
- }
1610
- function DropdownMenu({
1611
- ariaLabel,
1612
- className,
1613
- options
1614
- }) {
1615
- const [open, setOpen] = (0, import_react3.useState)(false);
1616
- const root = (0, import_react3.useRef)(null);
1617
- (0, import_react3.useEffect)(() => {
1618
- if (!open) return;
1619
- const close = (event) => {
1620
- if (root.current !== null && !root.current.contains(event.target)) setOpen(false);
1621
- };
1622
- const closeOnEscape = (event) => {
1623
- if (event.key === "Escape") setOpen(false);
1624
- };
1625
- document.addEventListener("mousedown", close);
1626
- document.addEventListener("keydown", closeOnEscape);
1627
- return () => {
1628
- document.removeEventListener("mousedown", close);
1629
- document.removeEventListener("keydown", closeOnEscape);
1630
- };
1631
- }, [open]);
1632
- const selectedLabel = options.find((option) => option.selected)?.label ?? options[0]?.label ?? ariaLabel;
1633
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `dsh-st-dropdown${className === void 0 ? "" : ` ${className}`}`, ref: root, children: [
1634
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: `dsh-st-dropdown-btn${open ? " is-open" : ""}`, "aria-label": ariaLabel, "aria-expanded": open, onClick: () => setOpen((value) => !value), children: [
1635
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-st-dropdown-label", children: selectedLabel }),
1636
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronIcon, { width: 10, height: 10, className: "dsh-st-dropdown-chevron" })
1637
- ] }),
1638
- open && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-dropdown-menu", children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1639
- DropdownRow,
1640
- {
1641
- label: option.label,
1642
- selected: option.selected,
1643
- onSelect: () => {
1644
- setOpen(false);
1645
- option.onSelect();
1646
- }
1647
- },
1648
- option.key
1649
- )) })
1650
- ] });
1651
- }
1652
- function DropdownRow({
1653
- label,
1654
- selected,
1655
- onSelect
1656
- }) {
1657
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", "aria-pressed": selected, className: selected ? "is-selected" : void 0, onClick: onSelect, children: [
1658
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: label }),
1659
- selected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-st-sort-tick" })
1660
- ] });
1661
- }
1662
1960
  function RunRow({ run, t }) {
1663
1961
  const duration = formatDuration(run.startedAt, run.finishedAt);
1664
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("article", { className: `dsh-st-run is-${run.status}`, children: [
1665
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: run.automationName }),
1666
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { children: [
1667
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: clockTime(run.startedAt ?? run.scheduledFor) }),
1668
- duration !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: duration }),
1669
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("history.trigger") })
1962
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("article", { className: `dsh-st-run is-${run.status}`, children: [
1963
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("strong", { children: run.automationName }),
1964
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("p", { children: [
1965
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: clockTime(run.startedAt ?? run.scheduledFor) }),
1966
+ duration !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: duration }),
1967
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: t("history.trigger") })
1670
1968
  ] })
1671
1969
  ] });
1672
1970
  }
@@ -1679,6 +1977,8 @@ var en = {
1679
1977
  "sidebar.tabs": "Workspace views",
1680
1978
  "sidebar.tasksTab": "Tasks",
1681
1979
  "sidebar.channelsTab": "Channels",
1980
+ "sidebar.views": "Scheduled views",
1981
+ "sidebar.viewOverview": "Task overview",
1682
1982
  "sidebar.empty": "No scheduled runs yet.",
1683
1983
  "sidebar.tasksEmpty": "No web tasks yet.",
1684
1984
  "sidebar.ungrouped": "Ungrouped",
@@ -1713,6 +2013,15 @@ var en = {
1713
2013
  "session.rename": "Rename",
1714
2014
  "session.fork": "Fork session",
1715
2015
  "session.archive": "Archive session",
2016
+ "session.groupActions": "Actions for {name}",
2017
+ "session.taskSettings": "Task settings",
2018
+ "session.archiveGroup": "Archive all conversations",
2019
+ "session.archiveGroupConfirm": "Archive all",
2020
+ "session.archiveGroupDescription": "Archive all {count} conversations for \u201C{name}\u201D. You can restore them later in Settings \u2192 Archived.",
2021
+ "session.archiveGroupPending": "Archiving conversations\u2026",
2022
+ "session.archiveGroupFailed": "Some conversations could not be archived: {message}",
2023
+ "session.archiveGroupClose": "Close",
2024
+ "session.archiveGroupCancel": "Cancel",
1716
2025
  "session.idle": "Idle",
1717
2026
  "session.runningStatus": "Running",
1718
2027
  "session.delete": "Remove from Scheduled",
@@ -1746,6 +2055,7 @@ var en = {
1746
2055
  "sort.created.desc": "Created time descending",
1747
2056
  "sort.planned.asc": "Planned time ascending",
1748
2057
  "sort.planned.desc": "Planned time descending",
2058
+ "sort.default.saved": "Default",
1749
2059
  "form.workspace": "Workspace",
1750
2060
  "form.workspacePath": "Folder path",
1751
2061
  "form.workspacePathPlaceholder": "D:\\work\\project",
@@ -1782,6 +2092,7 @@ var en = {
1782
2092
  "empty.body": "Save a self-contained task, a schedule, and a permission boundary. Every run starts in a new Session.",
1783
2093
  "empty.action": "Create the first automation",
1784
2094
  "runs.empty": "No runs yet. Run one now, or wait for the next scheduled occurrence.",
2095
+ "overview.empty": "No scheduled tasks yet. Create one in Settings.",
1785
2096
  "form.title": "Create automation",
1786
2097
  "form.subtitle": "Write a complete, standalone task. Scheduled runs do not inherit this conversation.",
1787
2098
  "form.name": "Name",
@@ -1864,6 +2175,7 @@ var en = {
1864
2175
  "error.title": "Automations could not be loaded",
1865
2176
  "error.retry": "Try again",
1866
2177
  "error.action": "The action failed. Please try again.",
2178
+ "error.taskMissing": "This scheduled task no longer exists.",
1867
2179
  "error.offline": "Could not reach the local automation service. Check that DSH is still running and try again.",
1868
2180
  "time.now": "now",
1869
2181
  "time.minuteAgo": "{count}m ago",
@@ -1879,6 +2191,8 @@ var zh = {
1879
2191
  "sidebar.tabs": "\u5DE5\u4F5C\u533A\u5206\u7C7B",
1880
2192
  "sidebar.tasksTab": "\u4EFB\u52A1",
1881
2193
  "sidebar.channelsTab": "\u9891\u9053",
2194
+ "sidebar.views": "\u5B9A\u65F6\u9875\u89C6\u56FE",
2195
+ "sidebar.viewOverview": "\u4EFB\u52A1\u603B\u89C8",
1882
2196
  "sidebar.empty": "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1\u6267\u884C\u8BB0\u5F55\u3002",
1883
2197
  "sidebar.tasksEmpty": "\u6682\u65E0\u7F51\u9875\u4EFB\u52A1",
1884
2198
  "sidebar.ungrouped": "\u672A\u5206\u7EC4",
@@ -1913,6 +2227,15 @@ var zh = {
1913
2227
  "session.rename": "\u91CD\u547D\u540D",
1914
2228
  "session.fork": "\u5206\u53C9\u4F1A\u8BDD",
1915
2229
  "session.archive": "\u5F52\u6863\u4F1A\u8BDD",
2230
+ "session.groupActions": "\u201C{name}\u201D\u7684\u4EFB\u52A1\u64CD\u4F5C",
2231
+ "session.taskSettings": "\u4EFB\u52A1\u8BBE\u7F6E",
2232
+ "session.archiveGroup": "\u5F52\u6863\u6574\u7EC4\u4F1A\u8BDD",
2233
+ "session.archiveGroupConfirm": "\u786E\u8BA4\u5F52\u6863",
2234
+ "session.archiveGroupDescription": "\u5C06\u5F52\u6863\u201C{name}\u201D\u4E0B\u7684 {count} \u4E2A\u4F1A\u8BDD\u3002\u5F52\u6863\u540E\u53EF\u4EE5\u5728\u201C\u8BBE\u7F6E \u2192 \u5DF2\u5F52\u6863\u201D\u4E2D\u6062\u590D\u3002",
2235
+ "session.archiveGroupPending": "\u6B63\u5728\u5F52\u6863\u6574\u7EC4\u4F1A\u8BDD\u2026",
2236
+ "session.archiveGroupFailed": "\u90E8\u5206\u4F1A\u8BDD\u5F52\u6863\u5931\u8D25\uFF1A{message}",
2237
+ "session.archiveGroupClose": "\u5173\u95ED",
2238
+ "session.archiveGroupCancel": "\u53D6\u6D88",
1916
2239
  "session.idle": "\u7A7A\u95F2",
1917
2240
  "session.runningStatus": "\u8FD0\u884C\u4E2D",
1918
2241
  "session.delete": "\u4ECE\u5B9A\u65F6\u9875\u79FB\u9664",
@@ -1946,6 +2269,7 @@ var zh = {
1946
2269
  "sort.created.desc": "\u6309\u521B\u5EFA\u65F6\u95F4\u5012\u5E8F",
1947
2270
  "sort.planned.asc": "\u6309\u8BA1\u5212\u65F6\u95F4\u5347\u5E8F",
1948
2271
  "sort.planned.desc": "\u6309\u8BA1\u5212\u65F6\u95F4\u5012\u5E8F",
2272
+ "sort.default.saved": "\u9ED8\u8BA4",
1949
2273
  "form.workspace": "\u5DE5\u4F5C\u76EE\u5F55",
1950
2274
  "form.workspacePath": "\u76EE\u5F55\u8DEF\u5F84",
1951
2275
  "form.workspacePathPlaceholder": "D:\\work\\project",
@@ -1982,6 +2306,7 @@ var zh = {
1982
2306
  "empty.body": "\u8BBE\u7F6E\u4E00\u4E2A\u76EE\u6807\u660E\u786E\u7684\u4EFB\u52A1\u3001\u8FD0\u884C\u65F6\u95F4\u548C\u6743\u9650\u8FB9\u754C\u3002\u6BCF\u6B21\u8FD0\u884C\u90FD\u4ECE\u5168\u65B0 Session \u5F00\u59CB\u3002",
1983
2307
  "empty.action": "\u521B\u5EFA\u7B2C\u4E00\u4E2A\u81EA\u52A8\u5316",
1984
2308
  "runs.empty": "\u8FD8\u6CA1\u6709\u8FD0\u884C\u8BB0\u5F55\u3002\u4F60\u53EF\u4EE5\u7ACB\u5373\u8FD0\u884C\u4E00\u6B21\uFF0C\u6216\u7B49\u5F85\u8BA1\u5212\u89E6\u53D1\u3002",
2309
+ "overview.empty": "\u6682\u65E0\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u53EF\u5230\u8BBE\u7F6E\u9875\u521B\u5EFA\u3002",
1985
2310
  "form.title": "\u521B\u5EFA\u81EA\u52A8\u5316",
1986
2311
  "form.subtitle": "\u8BF7\u5199\u5B8C\u6574\u3001\u72EC\u7ACB\u7684\u4EFB\u52A1\u8BF4\u660E\uFF1A\u5B9A\u65F6\u8FD0\u884C\u4E0D\u4F1A\u7EE7\u627F\u5F53\u524D\u5BF9\u8BDD\u3002",
1987
2312
  "form.name": "\u540D\u79F0",
@@ -2064,6 +2389,7 @@ var zh = {
2064
2389
  "error.title": "\u65E0\u6CD5\u52A0\u8F7D\u81EA\u52A8\u5316",
2065
2390
  "error.retry": "\u91CD\u8BD5",
2066
2391
  "error.action": "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
2392
+ "error.taskMissing": "\u8BE5\u5B9A\u65F6\u4EFB\u52A1\u5DF2\u4E0D\u5B58\u5728\u3002",
2067
2393
  "error.offline": "\u65E0\u6CD5\u8FDE\u63A5\u672C\u673A\u81EA\u52A8\u5316\u670D\u52A1\uFF0C\u8BF7\u786E\u8BA4 DSH \u4ECD\u5728\u8FD0\u884C\u540E\u91CD\u8BD5\u3002",
2068
2394
  "time.now": "\u521A\u521A",
2069
2395
  "time.minuteAgo": "{count} \u5206\u949F\u524D",
@@ -2151,8 +2477,9 @@ function isForeignSidebarHost(component) {
2151
2477
  }
2152
2478
 
2153
2479
  // src/client/native-session-list.tsx
2154
- var import_react5 = require("react");
2155
- var import_react_dom2 = require("react-dom");
2480
+ var import_react9 = require("react");
2481
+ var import_react_dom3 = require("react-dom");
2482
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
2156
2483
 
2157
2484
  // src/client/native-session-menu.ts
2158
2485
  function resolveEventElement(target) {
@@ -2214,16 +2541,28 @@ function nativeSessionHoverStyle(row, card, viewport) {
2214
2541
  top: `${Math.round(top)}px`
2215
2542
  };
2216
2543
  }
2217
- function relativeTime(value) {
2544
+ function relativeTime(value, t, now = Date.now()) {
2218
2545
  const ts = Date.parse(value || "");
2219
2546
  if (!Number.isFinite(ts)) return "";
2220
- const delta = Math.max(0, Date.now() - ts);
2547
+ const delta = Math.max(0, now - ts);
2221
2548
  const min = Math.floor(delta / 6e4);
2222
- if (min < 1) return "\u521A\u521A";
2223
- if (min < 60) return String(min) + "\u5206\u949F\u524D";
2549
+ if (min < 1) return t("time.now");
2550
+ if (min < 60) return t("time.minuteAgo", { count: min });
2224
2551
  const hour = Math.floor(min / 60);
2225
- if (hour < 24) return String(hour) + "\u5C0F\u65F6\u524D";
2226
- return String(Math.floor(hour / 24)) + "\u5929\u524D";
2552
+ if (hour < 24) return t("time.hourAgo", { count: hour });
2553
+ return t("time.dayAgo", { count: Math.floor(hour / 24) });
2554
+ }
2555
+
2556
+ // src/client/native-group-actions.ts
2557
+ var ARCHIVE_MANAGER_PLUGIN = "@michengai/dsh-archive-manager";
2558
+ function hasArchiveManagerPlugin(root) {
2559
+ return root?.querySelector(`[data-plugin="${ARCHIVE_MANAGER_PLUGIN}"]`) != null;
2560
+ }
2561
+ function scheduledGroupShowsActiveFolder(expanded, sessionIds, selectedId) {
2562
+ return expanded && selectedId !== null && sessionIds.includes(selectedId);
2563
+ }
2564
+ async function archiveScheduledGroup(sessionIds, archiveSession) {
2565
+ for (const sessionId of sessionIds) await archiveSession(sessionId);
2227
2566
  }
2228
2567
 
2229
2568
  // src/run-title.ts
@@ -2272,6 +2611,26 @@ function groupScheduledSessions(automations, runs) {
2272
2611
  };
2273
2612
  }).filter((group) => group.sessions.length > 0);
2274
2613
  }
2614
+ function deriveTaskOverviewRows(automations, runs) {
2615
+ const lastByAutomation = /* @__PURE__ */ new Map();
2616
+ for (const run of runs) {
2617
+ if (run.sessionId === void 0 || run.sessionId === "") continue;
2618
+ const current = lastByAutomation.get(run.automationId);
2619
+ const stamp = Date.parse(run.startedAt ?? run.scheduledFor);
2620
+ const currentStamp = current === void 0 ? Number.NaN : Date.parse(current.startedAt ?? current.scheduledFor);
2621
+ if (current === void 0 || stamp >= currentStamp) lastByAutomation.set(run.automationId, run);
2622
+ }
2623
+ return automations.map((item) => {
2624
+ const last = lastByAutomation.get(item.id);
2625
+ return {
2626
+ id: item.id,
2627
+ name: item.name,
2628
+ status: item.status,
2629
+ ...item.nextRunAt === void 0 ? {} : { nextRunAt: item.nextRunAt },
2630
+ ...last === void 0 ? {} : { lastSessionId: last.sessionId }
2631
+ };
2632
+ });
2633
+ }
2275
2634
  function keepScheduledSessionLink(sessionId, archived, presentIds) {
2276
2635
  if (sessionId === void 0 || sessionId === "") return false;
2277
2636
  if (archived.has(sessionId)) return false;
@@ -2503,9 +2862,116 @@ function latestSessionTime(group) {
2503
2862
  return latest;
2504
2863
  }
2505
2864
 
2865
+ // src/client/schedule-overview.tsx
2866
+ var import_react7 = require("react");
2867
+ var import_jsx_runtime8 = require("react/jsx-runtime");
2868
+ var EMPTY_SET = /* @__PURE__ */ new Set();
2869
+ var SORT_STORAGE2 = typeof window === "undefined" ? void 0 : window.localStorage;
2870
+ function ScheduleViewSwitch({
2871
+ t,
2872
+ view,
2873
+ onChange
2874
+ }) {
2875
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-rail-views", role: "tablist", "aria-label": t("sidebar.views"), children: [
2876
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": view === "runs", className: view === "runs" ? "is-on" : void 0, onClick: () => onChange("runs"), children: t("tabs.runs") }),
2877
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { type: "button", role: "tab", "aria-selected": view === "overview", className: view === "overview" ? "is-on" : void 0, onClick: () => onChange("overview"), children: t("sidebar.viewOverview") })
2878
+ ] });
2879
+ }
2880
+ function ScheduleOverview({
2881
+ t,
2882
+ automations,
2883
+ runs,
2884
+ openSession,
2885
+ serverNow,
2886
+ archived,
2887
+ presentIds
2888
+ }) {
2889
+ const [sortKey, setSortKey] = (0, import_react7.useState)(() => readSortDefault(SORT_STORAGE2, OVERVIEW_SORT_DEFAULT_KEY)?.key ?? "planned");
2890
+ const [sortDirection, setSortDirection] = (0, import_react7.useState)(() => readSortDefault(SORT_STORAGE2, OVERVIEW_SORT_DEFAULT_KEY)?.direction ?? "asc");
2891
+ const now = (0, import_react7.useMemo)(() => new Date(serverNow ?? Date.now()), [serverNow]);
2892
+ const rows = (0, import_react7.useMemo)(() => {
2893
+ const sorted = sortAutomations(automations, sortKey, sortDirection);
2894
+ return deriveTaskOverviewRows(sorted, runs).map((row) => {
2895
+ if (row.lastSessionId === void 0 || !keepScheduledSessionLink(row.lastSessionId, archived ?? EMPTY_SET, presentIds)) {
2896
+ const { lastSessionId: _dropped, ...rest } = row;
2897
+ return rest;
2898
+ }
2899
+ return row;
2900
+ });
2901
+ }, [archived, automations, presentIds, runs, sortDirection, sortKey]);
2902
+ const scheduleSummaries = (0, import_react7.useMemo)(() => new Map(automations.map((item) => [item.id, formatSchedule(item.schedule, t)])), [automations, t]);
2903
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview", children: [
2904
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview-head", children: [
2905
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview-title", children: [
2906
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: t("sidebar.viewOverview") }),
2907
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-label": `${rows.length}`, children: rows.length })
2908
+ ] }),
2909
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
2910
+ SortMenu,
2911
+ {
2912
+ t,
2913
+ compact: true,
2914
+ iconOnly: true,
2915
+ className: "dsh-st-overview-sort",
2916
+ ...SORT_STORAGE2 === void 0 ? {} : { storage: SORT_STORAGE2 },
2917
+ storageKey: OVERVIEW_SORT_DEFAULT_KEY,
2918
+ sortKey,
2919
+ sortDirection,
2920
+ onSelect: (key, direction) => {
2921
+ setSortKey(key);
2922
+ setSortDirection(direction);
2923
+ }
2924
+ }
2925
+ )
2926
+ ] }),
2927
+ rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "dsh-st-rail-empty", children: t("overview.empty") }) : rows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(OverviewRow, { t, row, now, scheduleSummary: scheduleSummaries.get(row.id) ?? "", ...openSession === void 0 ? {} : { openSession } }, row.id))
2928
+ ] });
2929
+ }
2930
+ function OverviewRow({
2931
+ t,
2932
+ row,
2933
+ now,
2934
+ scheduleSummary,
2935
+ openSession
2936
+ }) {
2937
+ const paused = row.status !== "active";
2938
+ const nextRun = row.nextRunAt === void 0 ? t("stats.noneScheduled") : formatWithin(row.nextRunAt, now, t);
2939
+ const status = paused ? t("status.paused") : t("status.active");
2940
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
2941
+ "button",
2942
+ {
2943
+ type: "button",
2944
+ className: `dsh-st-overview-row${paused ? " is-paused" : ""}`,
2945
+ disabled: row.lastSessionId === void 0,
2946
+ title: paused ? t("status.paused") : t("status.active"),
2947
+ onClick: () => {
2948
+ if (row.lastSessionId !== void 0) openSession?.(row.lastSessionId);
2949
+ },
2950
+ children: [
2951
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-copy", children: [
2952
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-status", children: [
2953
+ paused ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PauseIcon, { width: 14, height: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, { width: 14, height: 14 }),
2954
+ status
2955
+ ] }),
2956
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-overview-name", children: row.name }),
2957
+ scheduleSummary !== "" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-schedule", children: [
2958
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CalendarIcon, { width: 14, height: 14 }),
2959
+ scheduleSummary
2960
+ ] })
2961
+ ] }),
2962
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-next", children: [
2963
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: t("stats.next") }),
2964
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: nextRun })
2965
+ ] }),
2966
+ row.lastSessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChevronIcon, { width: 12, height: 12, className: "dsh-st-overview-chevron" })
2967
+ ]
2968
+ }
2969
+ );
2970
+ }
2971
+
2506
2972
  // src/client/workspace-toolbar.tsx
2507
- var import_react4 = require("react");
2508
- var import_jsx_runtime5 = require("react/jsx-runtime");
2973
+ var import_react8 = require("react");
2974
+ var import_jsx_runtime9 = require("react/jsx-runtime");
2509
2975
  function officialSearchIconSize(expanded) {
2510
2976
  return expanded ? 11 : 14;
2511
2977
  }
@@ -2518,15 +2984,15 @@ function WorkspaceToolbar({
2518
2984
  onSortChange,
2519
2985
  onGroupModeChange
2520
2986
  }) {
2521
- const [searching, setSearching] = (0, import_react4.useState)(query.trim() !== "");
2522
- const [filterOpen, setFilterOpen] = (0, import_react4.useState)(false);
2523
- const inputRef = (0, import_react4.useRef)(null);
2524
- const rootRef = (0, import_react4.useRef)(null);
2987
+ const [searching, setSearching] = (0, import_react8.useState)(query.trim() !== "");
2988
+ const [filterOpen, setFilterOpen] = (0, import_react8.useState)(false);
2989
+ const inputRef = (0, import_react8.useRef)(null);
2990
+ const rootRef = (0, import_react8.useRef)(null);
2525
2991
  const searchSize = officialSearchIconSize(searching);
2526
- (0, import_react4.useEffect)(() => {
2992
+ (0, import_react8.useEffect)(() => {
2527
2993
  if (searching) inputRef.current?.focus();
2528
2994
  }, [searching]);
2529
- (0, import_react4.useEffect)(() => {
2995
+ (0, import_react8.useEffect)(() => {
2530
2996
  if (!filterOpen) return;
2531
2997
  const close = (event) => {
2532
2998
  const target = event.target;
@@ -2544,37 +3010,37 @@ function WorkspaceToolbar({
2544
3010
  onQueryChange("");
2545
3011
  setSearching(false);
2546
3012
  };
2547
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: searching ? "dsh-st-n-toolbar is-search" : "dsh-st-n-toolbar", ref: rootRef, children: [
2548
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-head-label", children: t("sidebar.workspaces") }),
2549
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-search-slot", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-n-search", onClick: openSearch, children: [
2550
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "dsh-st-n-search-btn", "aria-label": t("sidebar.search"), "aria-expanded": searching, onClick: openSearch, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SearchOutlineIcon, { width: searchSize, height: searchSize }) }),
2551
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("input", { ref: inputRef, className: "dsh-st-n-search-input", value: query, placeholder: t("sidebar.searchSessions"), "aria-label": t("sidebar.searchSessions"), tabIndex: searching ? 0 : -1, "aria-hidden": !searching, onChange: (event) => onQueryChange(event.target.value), onKeyDown: (event) => {
3013
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: searching ? "dsh-st-n-toolbar is-search" : "dsh-st-n-toolbar", ref: rootRef, children: [
3014
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-st-n-head-label", children: t("sidebar.workspaces") }),
3015
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-search-slot", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-st-n-search", onClick: openSearch, children: [
3016
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "dsh-st-n-search-btn", "aria-label": t("sidebar.search"), "aria-expanded": searching, onClick: openSearch, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SearchOutlineIcon, { width: searchSize, height: searchSize }) }),
3017
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("input", { ref: inputRef, className: "dsh-st-n-search-input", value: query, placeholder: t("sidebar.searchSessions"), "aria-label": t("sidebar.searchSessions"), tabIndex: searching ? 0 : -1, "aria-hidden": !searching, onChange: (event) => onQueryChange(event.target.value), onKeyDown: (event) => {
2552
3018
  if (event.key === "Escape") closeSearch();
2553
3019
  } }),
2554
- searching && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "dsh-st-n-search-clear", "aria-label": t("sidebar.clearSearch"), onClick: (event) => {
3020
+ searching && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: "dsh-st-n-search-clear", "aria-label": t("sidebar.clearSearch"), onClick: (event) => {
2555
3021
  event.stopPropagation();
2556
3022
  closeSearch();
2557
- }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CloseOutlineIcon, { width: 14, height: 14 }) })
3023
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CloseOutlineIcon, { width: 14, height: 14 }) })
2558
3024
  ] }) }),
2559
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-head-acts", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-n-head-filter", children: [
2560
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: filterOpen ? "dsh-st-n-head-btn is-on" : "dsh-st-n-head-btn", "aria-label": t("sidebar.filter"), "aria-expanded": filterOpen, onClick: () => setFilterOpen((open) => !open), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(SlidersIcon, { width: 16, height: 16 }) }),
2561
- filterOpen && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-n-filter-menu", role: "menu", children: [
2562
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.groupBy") }),
2563
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FilterRow, { label: t("sidebar.groupWorkspace"), selected: groupMode === "workspace", onSelect: () => {
3025
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-head-acts", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-st-n-head-filter", children: [
3026
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("button", { type: "button", className: filterOpen ? "dsh-st-n-head-btn is-on" : "dsh-st-n-head-btn", "aria-label": t("sidebar.filter"), "aria-expanded": filterOpen, onClick: () => setFilterOpen((open) => !open), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(SlidersIcon, { width: 16, height: 16 }) }),
3027
+ filterOpen && /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "dsh-st-n-filter-menu", role: "menu", children: [
3028
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.groupBy") }),
3029
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.groupWorkspace"), selected: groupMode === "workspace", onSelect: () => {
2564
3030
  onGroupModeChange("workspace");
2565
3031
  setFilterOpen(false);
2566
3032
  } }),
2567
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FilterRow, { label: t("sidebar.groupList"), selected: groupMode === "list", onSelect: () => {
3033
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.groupList"), selected: groupMode === "list", onSelect: () => {
2568
3034
  onGroupModeChange("list");
2569
3035
  setFilterOpen(false);
2570
3036
  } }),
2571
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-filter-split" }),
2572
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.sortBy") }),
2573
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FilterRow, { label: t("sidebar.sortManual"), selected: sort === "manual", onSelect: () => {
3037
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-filter-split" }),
3038
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "dsh-st-n-filter-label", children: t("sidebar.sortBy") }),
3039
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.sortManual"), selected: sort === "manual", onSelect: () => {
2574
3040
  onSortChange("manual");
2575
3041
  setFilterOpen(false);
2576
3042
  } }),
2577
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FilterRow, { label: t("sidebar.sortTime"), selected: sort === "time", onSelect: () => {
3043
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(FilterRow, { label: t("sidebar.sortTime"), selected: sort === "time", onSelect: () => {
2578
3044
  onSortChange("time");
2579
3045
  setFilterOpen(false);
2580
3046
  } })
@@ -2587,34 +3053,40 @@ function FilterRow({
2587
3053
  selected,
2588
3054
  onSelect
2589
3055
  }) {
2590
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", role: "menuitemradio", "aria-checked": selected, className: selected ? "is-on" : void 0, onClick: onSelect, children: [
2591
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { children: label }),
2592
- selected ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-filter-tick" })
3056
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("button", { type: "button", role: "menuitemradio", "aria-checked": selected, className: selected ? "is-on" : void 0, onClick: onSelect, children: [
3057
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { children: label }),
3058
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "dsh-st-n-filter-tick" })
2593
3059
  ] });
2594
3060
  }
2595
3061
 
2596
3062
  // src/client/native-session-list.tsx
2597
- var import_jsx_runtime6 = require("react/jsx-runtime");
3063
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2598
3064
  var EMPTY_SESSION_BY_ID = {};
2599
3065
  function NativeScheduleSessionList(props) {
2600
- const { t, runtime, openSession, useSessions, useWorkspaces, renameSession, archiveSession, forkSession } = props;
2601
- const state = (0, import_react5.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3066
+ const { t, runtime, openSession, useSessions, useWorkspaces, renameSession, archiveSession, forkSession, openTaskSettings } = props;
3067
+ const state = (0, import_react9.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2602
3068
  const selectedId = useSessions ? useSessions((snap) => snap?.current ?? null) : null;
2603
3069
  const sessionById = useSessions ? useSessions((snap) => snap?.byId ?? EMPTY_SESSION_BY_ID) : EMPTY_SESSION_BY_ID;
2604
3070
  const archivedIds = useWorkspaces ? useWorkspaces((snap) => snap?.archivedSessionIds ?? []) : [];
2605
- const [folded, setFolded] = (0, import_react5.useState)({});
2606
- const [openMenu, setOpenMenu] = (0, import_react5.useState)(null);
2607
- const [query, setQuery] = (0, import_react5.useState)("");
2608
- const [sort, setSort] = (0, import_react5.useState)("time");
2609
- const [groupMode, setGroupMode] = (0, import_react5.useState)("workspace");
2610
- const archived = (0, import_react5.useMemo)(() => new Set(archivedIds), [archivedIds]);
3071
+ const [folded, setFolded] = (0, import_react9.useState)({});
3072
+ const [openMenu, setOpenMenu] = (0, import_react9.useState)(null);
3073
+ const [openGroupMenu, setOpenGroupMenu] = (0, import_react9.useState)();
3074
+ const [archiveGroupTarget, setArchiveGroupTarget] = (0, import_react9.useState)();
3075
+ const [archiveGroupBusy, setArchiveGroupBusy] = (0, import_react9.useState)(false);
3076
+ const [archiveGroupError, setArchiveGroupError] = (0, import_react9.useState)();
3077
+ const [archiveManagerInstalled, setArchiveManagerInstalled] = (0, import_react9.useState)(() => typeof document !== "undefined" && hasArchiveManagerPlugin(document));
3078
+ const [query, setQuery] = (0, import_react9.useState)("");
3079
+ const [sort, setSort] = (0, import_react9.useState)("time");
3080
+ const [groupMode, setGroupMode] = (0, import_react9.useState)("workspace");
3081
+ const [view, setView] = (0, import_react9.useState)("runs");
3082
+ const archived = (0, import_react9.useMemo)(() => new Set(archivedIds), [archivedIds]);
2611
3083
  const listedIds = useSessions ? useSessions((snap) => Array.isArray(snap?.ids) ? snap.ids : void 0) : void 0;
2612
- const presentIds = (0, import_react5.useMemo)(() => {
3084
+ const presentIds = (0, import_react9.useMemo)(() => {
2613
3085
  if (listedIds !== void 0) return new Set(listedIds);
2614
3086
  const keys = Object.keys(sessionById);
2615
3087
  return keys.length > 0 ? new Set(keys) : void 0;
2616
3088
  }, [listedIds, sessionById]);
2617
- const groups = (0, import_react5.useMemo)(() => {
3089
+ const groups = (0, import_react9.useMemo)(() => {
2618
3090
  const snapshot = state.snapshot;
2619
3091
  if (snapshot === void 0) return [];
2620
3092
  return groupScheduledSessions(snapshot.automations, snapshot.runs).map((group) => ({
@@ -2630,63 +3102,212 @@ function NativeScheduleSessionList(props) {
2630
3102
  })
2631
3103
  })).filter((group) => group.sessions.length > 0);
2632
3104
  }, [archived, presentIds, sessionById, state.snapshot]);
2633
- const visibleGroups = (0, import_react5.useMemo)(() => applyWorkspaceBrowserQuery(groups.map((group) => ({ ...group, name: group.name })), query, sort, groupMode), [groups, query, sort, groupMode]);
2634
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n", children: [
2635
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(WorkspaceToolbar, { t, query, sort, groupMode, onQueryChange: setQuery, onSortChange: setSort, onGroupModeChange: setGroupMode }),
2636
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-tree", role: "tree", children: [
2637
- state.phase === "loading" && visibleGroups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-empty", children: t("loading") }),
2638
- visibleGroups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-empty", children: t("sidebar.empty") }),
2639
- visibleGroups.map((group) => {
2640
- const expanded = folded[group.id] !== true;
2641
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-group", children: [
2642
- groupMode === "workspace" && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-row", role: "treeitem", "aria-expanded": expanded, onClick: () => setFolded((current) => ({ ...current, [group.id]: expanded })), children: [
2643
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-slot dsh-st-n-folder", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FolderOpenIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(FolderClosedIcon, { width: 16, height: 16 }) }),
2644
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-title", children: group.name })
2645
- ] }),
2646
- (groupMode === "list" || expanded) && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2647
- NativeSessionRow,
2648
- {
2649
- t,
2650
- id: session.id,
2651
- title: session.title,
2652
- hoverTitle: String(sessionById[session.id]?.displayTitle ?? sessionById[session.id]?.title ?? group.name),
2653
- updatedAt: session.updatedAt,
2654
- running: session.running,
2655
- selected: selectedId === session.id,
2656
- menuOpen: openMenu?.id === session.id,
2657
- menuPoint: openMenu === null || openMenu.id !== session.id ? { x: 8, y: 8 } : { x: openMenu.x, y: openMenu.y },
2658
- onToggleMenu: (event) => setOpenMenu((current) => nextOpenSessionMenu(current, session.id, pointerPoint(event))),
2659
- onCloseMenu: () => setOpenMenu((current) => current?.id === session.id ? null : current),
2660
- onOpen: () => {
2661
- setOpenMenu(null);
2662
- openSession?.(session.id);
3105
+ const visibleGroups = (0, import_react9.useMemo)(() => applyWorkspaceBrowserQuery(groups.map((group) => ({ ...group, name: group.name })), query, sort, groupMode), [groups, query, sort, groupMode]);
3106
+ (0, import_react9.useEffect)(() => {
3107
+ if (typeof document === "undefined" || typeof MutationObserver === "undefined") return;
3108
+ const refresh = () => {
3109
+ setArchiveManagerInstalled(hasArchiveManagerPlugin(document));
3110
+ };
3111
+ refresh();
3112
+ const observer = new MutationObserver(refresh);
3113
+ observer.observe(document.documentElement, { childList: true, subtree: true });
3114
+ return () => {
3115
+ observer.disconnect();
3116
+ };
3117
+ }, []);
3118
+ const canArchiveGroup = archiveManagerInstalled && archiveSession !== void 0;
3119
+ const confirmArchiveGroup = () => {
3120
+ if (archiveGroupTarget === void 0 || archiveSession === void 0 || archiveGroupBusy) return;
3121
+ const target = archiveGroupTarget;
3122
+ setArchiveGroupBusy(true);
3123
+ setArchiveGroupError(void 0);
3124
+ void archiveScheduledGroup(target.sessionIds, archiveSession).then(() => {
3125
+ setArchiveGroupTarget(void 0);
3126
+ }).catch((caught) => {
3127
+ setArchiveGroupError(caught instanceof Error ? caught.message : t("error.action"));
3128
+ }).finally(() => {
3129
+ setArchiveGroupBusy(false);
3130
+ });
3131
+ };
3132
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n", children: [
3133
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ScheduleViewSwitch, { t, view, onChange: setView }),
3134
+ view === "overview" ? state.snapshot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-empty", children: state.phase === "loading" ? t("loading") : t("overview.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3135
+ ScheduleOverview,
3136
+ {
3137
+ t,
3138
+ automations: state.snapshot.automations,
3139
+ runs: state.snapshot.runs,
3140
+ ...openSession === void 0 ? {} : { openSession },
3141
+ ...state.snapshot.serverNow === void 0 ? {} : { serverNow: state.snapshot.serverNow },
3142
+ archived,
3143
+ ...presentIds === void 0 ? {} : { presentIds }
3144
+ }
3145
+ ) : /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
3146
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WorkspaceToolbar, { t, query, sort, groupMode, onQueryChange: setQuery, onSortChange: setSort, onGroupModeChange: setGroupMode }),
3147
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-tree", role: "tree", children: [
3148
+ state.phase === "loading" && visibleGroups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-empty", children: t("loading") }),
3149
+ visibleGroups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-empty", children: t("sidebar.empty") }),
3150
+ visibleGroups.map((group) => {
3151
+ const expanded = folded[group.id] !== true;
3152
+ const hasCurrentSession = scheduledGroupShowsActiveFolder(expanded, group.sessions.map((session) => session.id), selectedId);
3153
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-group", children: [
3154
+ groupMode === "workspace" && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3155
+ NativeScheduleGroupRow,
3156
+ {
3157
+ t,
3158
+ id: group.id,
3159
+ name: group.name,
3160
+ sessionIds: group.sessions.map((session) => session.id),
3161
+ expanded,
3162
+ hasCurrentSession,
3163
+ menuOpen: openGroupMenu === group.id,
3164
+ canArchiveGroup,
3165
+ onToggle: () => setFolded((current) => ({ ...current, [group.id]: expanded })),
3166
+ onMenuChange: (open) => {
3167
+ setOpenMenu(null);
3168
+ setOpenGroupMenu(open ? group.id : void 0);
3169
+ },
3170
+ onTaskSettings: () => {
3171
+ openTaskSettings?.({ automationId: group.id, name: group.name, sessionIds: group.sessions.map((session) => session.id) });
3172
+ },
3173
+ onArchiveGroup: () => {
3174
+ setArchiveGroupError(void 0);
3175
+ setArchiveGroupTarget({ id: group.id, name: group.name, sessionIds: group.sessions.map((session) => session.id) });
3176
+ }
3177
+ }
3178
+ ),
3179
+ (groupMode === "list" || expanded) && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3180
+ NativeSessionRow,
3181
+ {
3182
+ t,
3183
+ id: session.id,
3184
+ title: session.title,
3185
+ hoverTitle: String(sessionById[session.id]?.displayTitle ?? sessionById[session.id]?.title ?? group.name),
3186
+ updatedAt: session.updatedAt,
3187
+ running: session.running,
3188
+ selected: selectedId === session.id,
3189
+ menuOpen: openMenu?.id === session.id,
3190
+ menuPoint: openMenu === null || openMenu.id !== session.id ? { x: 8, y: 8 } : { x: openMenu.x, y: openMenu.y },
3191
+ onToggleMenu: (event) => {
3192
+ setOpenGroupMenu(void 0);
3193
+ setOpenMenu((current) => nextOpenSessionMenu(current, session.id, pointerPoint(event)));
3194
+ },
3195
+ onCloseMenu: () => setOpenMenu((current) => current?.id === session.id ? null : current),
3196
+ onOpen: () => {
3197
+ setOpenMenu(null);
3198
+ openSession?.(session.id);
3199
+ },
3200
+ ...renameSession === void 0 ? {} : { renameSession },
3201
+ ...archiveSession === void 0 ? {} : { archiveSession },
3202
+ ...forkSession === void 0 ? {} : { forkSession }
2663
3203
  },
2664
- ...renameSession === void 0 ? {} : { renameSession },
2665
- ...archiveSession === void 0 ? {} : { archiveSession },
2666
- ...forkSession === void 0 ? {} : { forkSession }
2667
- },
2668
- session.id
2669
- ))
2670
- ] }, group.id);
2671
- })
2672
- ] })
3204
+ session.id
3205
+ ))
3206
+ ] }, group.id);
3207
+ })
3208
+ ] })
3209
+ ] }),
3210
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3211
+ import_dsh_client_ui_primitives2.Modal,
3212
+ {
3213
+ open: archiveGroupTarget !== void 0,
3214
+ onClose: () => {
3215
+ if (archiveGroupBusy) return;
3216
+ setArchiveGroupTarget(void 0);
3217
+ setArchiveGroupError(void 0);
3218
+ },
3219
+ closeLabel: t("session.archiveGroupClose"),
3220
+ title: t("session.archiveGroup"),
3221
+ footer: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-dialog-actions", children: [
3222
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", disabled: archiveGroupBusy, onClick: () => {
3223
+ setArchiveGroupTarget(void 0);
3224
+ setArchiveGroupError(void 0);
3225
+ }, children: t("session.archiveGroupCancel") }),
3226
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", className: "dsh-st-n-danger-button", disabled: archiveGroupBusy, onClick: confirmArchiveGroup, children: t("session.archiveGroupConfirm") })
3227
+ ] }),
3228
+ children: [
3229
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("p", { className: "dsh-st-n-dialog-copy", children: archiveGroupTarget === void 0 ? "" : t("session.archiveGroupDescription", { name: archiveGroupTarget.name, count: archiveGroupTarget.sessionIds.length }) }),
3230
+ archiveGroupBusy && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-dialog-status", role: "status", children: t("session.archiveGroupPending") }),
3231
+ archiveGroupError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-dialog-error", role: "alert", children: t("session.archiveGroupFailed", { message: archiveGroupError }) })
3232
+ ]
3233
+ }
3234
+ )
2673
3235
  ] });
2674
3236
  }
3237
+ function NativeScheduleGroupRow(props) {
3238
+ const { t, id, name: name2, expanded, hasCurrentSession, menuOpen, canArchiveGroup, onToggle, onMenuChange, onTaskSettings, onArchiveGroup } = props;
3239
+ const items = [
3240
+ { id: "task-settings", label: t("session.taskSettings"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.IconSettingsOutline16, { size: 16 }) },
3241
+ ...canArchiveGroup ? [
3242
+ { type: "separator", id: "archive-separator" },
3243
+ { id: "archive-group", label: t("session.archiveGroup"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.IconArchiveOutline20, { size: 16 }), danger: true }
3244
+ ] : []
3245
+ ];
3246
+ const rowClass = "dsh-st-n-row" + (hasCurrentSession ? " has-current-session" : "") + (menuOpen ? " is-menu" : "");
3247
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
3248
+ "div",
3249
+ {
3250
+ className: rowClass,
3251
+ role: "treeitem",
3252
+ "aria-expanded": expanded,
3253
+ "data-n-group": id,
3254
+ onClick: onToggle,
3255
+ children: [
3256
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-slot dsh-st-n-folder", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FolderOpenIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(FolderClosedIcon, { width: 16, height: 16 }) }),
3257
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-title", children: name2 }),
3258
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3259
+ import_dsh_client_ui_primitives2.Menu,
3260
+ {
3261
+ open: menuOpen,
3262
+ onClose: () => {
3263
+ onMenuChange(false);
3264
+ },
3265
+ items,
3266
+ onSelect: (action) => {
3267
+ onMenuChange(false);
3268
+ if (action === "task-settings") onTaskSettings();
3269
+ if (action === "archive-group") onArchiveGroup();
3270
+ },
3271
+ portal: true,
3272
+ dense: true,
3273
+ compact: true,
3274
+ anchor: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
3275
+ "button",
3276
+ {
3277
+ type: "button",
3278
+ className: "dsh-st-n-ico",
3279
+ "aria-label": t("session.groupActions", { name: name2 }),
3280
+ onMouseDown: (event) => {
3281
+ event.stopPropagation();
3282
+ },
3283
+ onClick: (event) => {
3284
+ event.stopPropagation();
3285
+ onMenuChange(!menuOpen);
3286
+ },
3287
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_dsh_client_ui_primitives2.IconEllipsisOutline16, { size: 16 })
3288
+ }
3289
+ )
3290
+ }
3291
+ ) })
3292
+ ]
3293
+ }
3294
+ );
3295
+ }
2675
3296
  function NativeSessionRow(props) {
2676
3297
  const { t, id, title, hoverTitle, updatedAt, running, selected, menuOpen, menuPoint, onToggleMenu, onCloseMenu, onOpen, renameSession, archiveSession, forkSession } = props;
2677
- const rowRef = (0, import_react5.useRef)(null);
2678
- const menuRef = (0, import_react5.useRef)(null);
2679
- const hoverRef = (0, import_react5.useRef)(null);
2680
- const [hoverOpen, setHoverOpen] = (0, import_react5.useState)(false);
2681
- const [hoverStyle, setHoverStyle] = (0, import_react5.useState)({});
2682
- const hoverTimer = (0, import_react5.useRef)(void 0);
2683
- const [renaming, setRenaming] = (0, import_react5.useState)(false);
2684
- const [draft, setDraft] = (0, import_react5.useState)(title);
2685
- const [menuStyle, setMenuStyle] = (0, import_react5.useState)({});
2686
- (0, import_react5.useEffect)(() => {
3298
+ const rowRef = (0, import_react9.useRef)(null);
3299
+ const menuRef = (0, import_react9.useRef)(null);
3300
+ const hoverRef = (0, import_react9.useRef)(null);
3301
+ const [hoverOpen, setHoverOpen] = (0, import_react9.useState)(false);
3302
+ const [hoverStyle, setHoverStyle] = (0, import_react9.useState)({});
3303
+ const hoverTimer = (0, import_react9.useRef)(void 0);
3304
+ const [renaming, setRenaming] = (0, import_react9.useState)(false);
3305
+ const [draft, setDraft] = (0, import_react9.useState)(title);
3306
+ const [menuStyle, setMenuStyle] = (0, import_react9.useState)({});
3307
+ (0, import_react9.useEffect)(() => {
2687
3308
  setDraft(title);
2688
3309
  }, [title]);
2689
- (0, import_react5.useEffect)(() => {
3310
+ (0, import_react9.useEffect)(() => {
2690
3311
  if (!menuOpen) return;
2691
3312
  const close = (event) => {
2692
3313
  if (!shouldCloseNativeSessionMenu(event.target, [rowRef.current, menuRef.current])) return;
@@ -2702,7 +3323,7 @@ function NativeSessionRow(props) {
2702
3323
  document.removeEventListener("keydown", onKey);
2703
3324
  };
2704
3325
  }, [menuOpen, onCloseMenu]);
2705
- (0, import_react5.useLayoutEffect)(() => {
3326
+ (0, import_react9.useLayoutEffect)(() => {
2706
3327
  if (!menuOpen) return;
2707
3328
  const update = () => {
2708
3329
  const el = menuRef.current;
@@ -2717,7 +3338,7 @@ function NativeSessionRow(props) {
2717
3338
  document.removeEventListener("scroll", update, true);
2718
3339
  };
2719
3340
  }, [menuOpen, menuPoint]);
2720
- (0, import_react5.useEffect)(() => {
3341
+ (0, import_react9.useEffect)(() => {
2721
3342
  if (!hoverOpen || menuOpen) return;
2722
3343
  const update = () => {
2723
3344
  const row = rowRef.current?.getBoundingClientRect();
@@ -2734,7 +3355,7 @@ function NativeSessionRow(props) {
2734
3355
  document.removeEventListener("scroll", update, true);
2735
3356
  };
2736
3357
  }, [hoverOpen, menuOpen, title, updatedAt, running]);
2737
- (0, import_react5.useEffect)(() => () => {
3358
+ (0, import_react9.useEffect)(() => () => {
2738
3359
  if (hoverTimer.current !== void 0) window.clearTimeout(hoverTimer.current);
2739
3360
  }, []);
2740
3361
  const run = (action) => {
@@ -2751,7 +3372,7 @@ function NativeSessionRow(props) {
2751
3372
  };
2752
3373
  const rowClass = "dsh-st-n-sess" + (selected ? " is-on" : "") + (menuOpen ? " is-menu" : "");
2753
3374
  if (renaming) {
2754
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: rowClass, ref: rowRef, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("input", { className: "dsh-st-n-rename", value: draft, autoFocus: true, "aria-label": t("session.rename"), onChange: (event) => setDraft(event.target.value), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => {
3375
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: rowClass, ref: rowRef, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("input", { className: "dsh-st-n-rename", value: draft, autoFocus: true, "aria-label": t("session.rename"), onChange: (event) => setDraft(event.target.value), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => {
2755
3376
  if (event.key === "Enter") {
2756
3377
  event.preventDefault();
2757
3378
  setRenaming(false);
@@ -2768,23 +3389,23 @@ function NativeSessionRow(props) {
2768
3389
  } }) });
2769
3390
  }
2770
3391
  const menuItems = [
2771
- { id: "rename", label: t("session.rename"), icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PencilIcon, { width: 16, height: 16 }), go: () => {
3392
+ { id: "rename", label: t("session.rename"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PencilIcon, { width: 16, height: 16 }), go: () => {
2772
3393
  setRenaming(true);
2773
3394
  } },
2774
- { id: "fork", label: t("session.fork"), icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(BranchIcon, { width: 16, height: 16 }), go: () => run(() => forkSession?.(id)) },
2775
- { id: "archive", label: t("session.archive"), icon: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ArchiveIcon, { width: 16, height: 16 }), go: () => run(() => archiveSession?.(id)) }
3395
+ { id: "fork", label: t("session.fork"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(BranchIcon, { width: 16, height: 16 }), go: () => run(() => forkSession?.(id)) },
3396
+ { id: "archive", label: t("session.archive"), icon: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ArchiveIcon, { width: 16, height: 16 }), go: () => run(() => archiveSession?.(id)) }
2776
3397
  ];
2777
- const menu = menuOpen && typeof document !== "undefined" ? (0, import_react_dom2.createPortal)(
2778
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { ref: menuRef, className: "dsh-st-n-menu is-float", "data-n-menu": id, style: menuStyle, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("button", { type: "button", className: void 0, onClick: () => {
3398
+ const menu = menuOpen && typeof document !== "undefined" ? (0, import_react_dom3.createPortal)(
3399
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: menuRef, className: "dsh-st-n-menu is-float", "data-n-menu": id, style: menuStyle, onMouseDown: (event) => event.stopPropagation(), onClick: (event) => event.stopPropagation(), children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("button", { type: "button", className: void 0, onClick: () => {
2779
3400
  onCloseMenu();
2780
3401
  item.go();
2781
3402
  }, children: [
2782
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-mi", children: item.icon }),
3403
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-mi", children: item.icon }),
2783
3404
  item.label
2784
3405
  ] }, item.id)) }),
2785
3406
  document.body
2786
3407
  ) : null;
2787
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: rowClass, ref: rowRef, role: "treeitem", tabIndex: 0, "aria-selected": selected, "data-n-menu-root": id, onClick: onOpen, onMouseEnter: showHover, onMouseLeave: hideHover, onKeyDown: (event) => {
3408
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: rowClass, ref: rowRef, role: "treeitem", tabIndex: 0, "aria-selected": selected, "data-n-menu-root": id, onClick: onOpen, onMouseEnter: showHover, onMouseLeave: hideHover, onKeyDown: (event) => {
2788
3409
  if (event.key === "Enter" || event.key === " ") {
2789
3410
  event.preventDefault();
2790
3411
  onOpen();
@@ -2794,21 +3415,21 @@ function NativeSessionRow(props) {
2794
3415
  event.stopPropagation();
2795
3416
  onToggleMenu(event);
2796
3417
  }, children: [
2797
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-slot", children: running ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RunningStateDot, {}) : null }),
2798
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-title", children: title }),
2799
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-time", children: relativeTime(updatedAt) }),
2800
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", className: "dsh-st-n-ico", "aria-label": title + " \u66F4\u591A", onMouseDown: (event) => event.stopPropagation(), onClick: (event) => {
3418
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-slot", children: running ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RunningStateDot, {}) : null }),
3419
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-title", children: title }),
3420
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-time", children: relativeTime(updatedAt, t) }),
3421
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("button", { type: "button", className: "dsh-st-n-ico", "aria-label": title + " \u66F4\u591A", onMouseDown: (event) => event.stopPropagation(), onClick: (event) => {
2801
3422
  event.stopPropagation();
2802
3423
  hideHover();
2803
3424
  onToggleMenu(event);
2804
- }, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(EllipsisIcon, { width: 16, height: 16 }) }) }),
3425
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(EllipsisIcon, { width: 16, height: 16 }) }) }),
2805
3426
  menu,
2806
- hoverOpen && !menuOpen && typeof document !== "undefined" && (0, import_react_dom2.createPortal)(
2807
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { ref: hoverRef, className: "dsh-st-n-hover", style: hoverStyle, onMouseEnter: showHover, onMouseLeave: hideHover, children: [
2808
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-hover-title", children: (hoverTitle ?? title).trim() || title }),
2809
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-n-hover-time", children: relativeTime(updatedAt) }),
2810
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-n-hover-state", children: [
2811
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: running ? "dsh-st-n-hover-dot is-run" : "dsh-st-n-hover-dot" }),
3427
+ hoverOpen && !menuOpen && typeof document !== "undefined" && (0, import_react_dom3.createPortal)(
3428
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { ref: hoverRef, className: "dsh-st-n-hover", style: hoverStyle, onMouseEnter: showHover, onMouseLeave: hideHover, children: [
3429
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-hover-title", children: (hoverTitle ?? title).trim() || title }),
3430
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "dsh-st-n-hover-time", children: relativeTime(updatedAt, t) }),
3431
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "dsh-st-n-hover-state", children: [
3432
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: running ? "dsh-st-n-hover-dot is-run" : "dsh-st-n-hover-dot" }),
2812
3433
  running ? t("session.runningStatus") : t("session.idle")
2813
3434
  ] })
2814
3435
  ] }),
@@ -2818,11 +3439,11 @@ function NativeSessionRow(props) {
2818
3439
  }
2819
3440
 
2820
3441
  // src/client/ScheduleRail.tsx
2821
- var import_react6 = require("react");
2822
- var import_jsx_runtime7 = require("react/jsx-runtime");
3442
+ var import_react10 = require("react");
3443
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2823
3444
  var EMPTY_EXTRA_TABS = [];
2824
3445
  var noopSubscribe = (_listener) => () => void 0;
2825
- var OfficialTreeGuard = class extends import_react6.Component {
3446
+ var OfficialTreeGuard = class extends import_react10.Component {
2826
3447
  state = { failed: false };
2827
3448
  static getDerivedStateFromError() {
2828
3449
  return { failed: true };
@@ -2837,45 +3458,61 @@ var OfficialTreeGuard = class extends import_react6.Component {
2837
3458
  function ScheduleRail({
2838
3459
  t,
2839
3460
  runtime,
2840
- openSession
3461
+ openSession,
3462
+ view: controlledView,
3463
+ showViewSwitch = true
2841
3464
  }) {
2842
- const state = (0, import_react6.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2843
- const [folded, setFolded] = (0, import_react6.useState)({});
2844
- const groups = (0, import_react6.useMemo)(() => {
2845
- const snapshot = state.snapshot;
3465
+ const state = (0, import_react10.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3466
+ const [folded, setFolded] = (0, import_react10.useState)({});
3467
+ const [localView, setLocalView] = (0, import_react10.useState)("runs");
3468
+ const view = controlledView ?? localView;
3469
+ const snapshot = state.snapshot;
3470
+ const groups = (0, import_react10.useMemo)(() => {
2846
3471
  if (snapshot === void 0) return [];
2847
3472
  return groupScheduledSessions(snapshot.automations, snapshot.runs);
2848
- }, [state.snapshot]);
2849
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-rail", children: [
2850
- state.phase === "loading" && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-rail-empty", children: t("loading") }),
2851
- groups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.empty") }),
2852
- groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-st-rail-group", children: [
2853
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2854
- "button",
2855
- {
2856
- type: "button",
2857
- className: "dsh-st-rail-head",
2858
- onClick: () => setFolded((current) => ({ ...current, [group.id]: !current[group.id] })),
2859
- children: [
2860
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-rail-folder", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ClockIcon, { width: 16, height: 16 }) }),
2861
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-rail-title", children: group.name })
2862
- ]
2863
- }
2864
- ),
2865
- folded[group.id] !== true && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
2866
- "button",
2867
- {
2868
- type: "button",
2869
- className: "dsh-st-rail-session",
2870
- onClick: () => openSession?.(session.id),
2871
- children: [
2872
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: session.label }),
2873
- session.running && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RunningStateDot, {})
2874
- ]
2875
- },
2876
- session.id
2877
- ))
2878
- ] }, group.id))
3473
+ }, [snapshot]);
3474
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-st-rail", children: [
3475
+ showViewSwitch && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScheduleViewSwitch, { t, view, onChange: setLocalView }),
3476
+ view === "overview" ? snapshot === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: state.phase === "loading" ? t("loading") : t("overview.empty") }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3477
+ ScheduleOverview,
3478
+ {
3479
+ t,
3480
+ automations: snapshot.automations,
3481
+ runs: snapshot.runs,
3482
+ ...openSession === void 0 ? {} : { openSession },
3483
+ ...snapshot.serverNow === void 0 ? {} : { serverNow: snapshot.serverNow }
3484
+ }
3485
+ ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
3486
+ state.phase === "loading" && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: t("loading") }),
3487
+ groups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.empty") }),
3488
+ groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: "dsh-st-rail-group", children: [
3489
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3490
+ "button",
3491
+ {
3492
+ type: "button",
3493
+ className: "dsh-st-rail-head",
3494
+ onClick: () => setFolded((current) => ({ ...current, [group.id]: !current[group.id] })),
3495
+ children: [
3496
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-st-rail-folder", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ClockIcon, { width: 16, height: 16 }) }),
3497
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-st-rail-title", children: group.name })
3498
+ ]
3499
+ }
3500
+ ),
3501
+ folded[group.id] !== true && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
3502
+ "button",
3503
+ {
3504
+ type: "button",
3505
+ className: "dsh-st-rail-session",
3506
+ onClick: () => openSession?.(session.id),
3507
+ children: [
3508
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: session.label }),
3509
+ session.running && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RunningStateDot, {})
3510
+ ]
3511
+ },
3512
+ session.id
3513
+ ))
3514
+ ] }, group.id))
3515
+ ] })
2879
3516
  ] });
2880
3517
  }
2881
3518
  function NativeScheduleShell({
@@ -2893,19 +3530,19 @@ function NativeScheduleShell({
2893
3530
  wide
2894
3531
  }) {
2895
3532
  const Official = officialTree;
2896
- const [tab, setTab] = (0, import_react6.useState)(() => {
3533
+ const [tab, setTab] = (0, import_react10.useState)(() => {
2897
3534
  try {
2898
3535
  return readNativeSidebarTab(window.localStorage.getItem(NATIVE_SIDEBAR_TAB_KEY));
2899
3536
  } catch {
2900
3537
  return "tasks";
2901
3538
  }
2902
3539
  });
2903
- const extraTabs = (0, import_react6.useSyncExternalStore)(
3540
+ const extraTabs = (0, import_react10.useSyncExternalStore)(
2904
3541
  tabRegistry?.subscribe ?? noopSubscribe,
2905
3542
  () => tabRegistry?.getTabs() ?? EMPTY_EXTRA_TABS,
2906
3543
  () => EMPTY_EXTRA_TABS
2907
3544
  );
2908
- const channelsReady = (0, import_react6.useSyncExternalStore)(
3545
+ const channelsReady = (0, import_react10.useSyncExternalStore)(
2909
3546
  subscribeChannels ?? noopSubscribe,
2910
3547
  () => {
2911
3548
  try {
@@ -2917,25 +3554,25 @@ function NativeScheduleShell({
2917
3554
  () => false
2918
3555
  );
2919
3556
  const currentId = useSessions?.((state) => state?.current ?? null);
2920
- const automationState = (0, import_react6.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2921
- const scheduledIds = (0, import_react6.useMemo)(() => collectScheduledSessionIds(automationState.snapshot?.runs), [automationState.snapshot]);
2922
- const useFilteredSessions = (0, import_react6.useCallback)((selector, eq) => {
3557
+ const automationState = (0, import_react10.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
3558
+ const scheduledIds = (0, import_react10.useMemo)(() => collectScheduledSessionIds(automationState.snapshot?.runs), [automationState.snapshot]);
3559
+ const useFilteredSessions = (0, import_react10.useCallback)((selector, eq) => {
2923
3560
  if (useSessions === void 0) return selector({ ids: [], byId: {}, current: null });
2924
3561
  return useSessions((state) => selector(filterTaskSessionState(state, scheduledIds)), eq);
2925
3562
  }, [useSessions, scheduledIds]);
2926
- const useFilteredWorkspaces = (0, import_react6.useCallback)((selector, eq) => {
3563
+ const useFilteredWorkspaces = (0, import_react10.useCallback)((selector, eq) => {
2927
3564
  if (useWorkspaces === void 0) return selector({ items: [], archivedSessionIds: [] });
2928
3565
  return useWorkspaces((state) => selector(filterWorkspaceListState(state, scheduledIds)), eq);
2929
3566
  }, [useWorkspaces, scheduledIds]);
2930
- (0, import_react6.useEffect)(() => {
3567
+ (0, import_react10.useEffect)(() => {
2931
3568
  try {
2932
3569
  window.localStorage.setItem(NATIVE_SIDEBAR_TAB_KEY, tab);
2933
3570
  } catch {
2934
3571
  }
2935
3572
  }, [tab]);
2936
- const previousCurrentId = (0, import_react6.useRef)(currentId);
2937
- const tabFollowReady = (0, import_react6.useRef)(false);
2938
- (0, import_react6.useEffect)(() => {
3573
+ const previousCurrentId = (0, import_react10.useRef)(currentId);
3574
+ const tabFollowReady = (0, import_react10.useRef)(false);
3575
+ (0, import_react10.useEffect)(() => {
2939
3576
  if (!tabFollowReady.current) {
2940
3577
  tabFollowReady.current = true;
2941
3578
  previousCurrentId.current = currentId;
@@ -2958,11 +3595,11 @@ function NativeScheduleShell({
2958
3595
  };
2959
3596
  const renderOfficial = (props) => {
2960
3597
  if (Official === void 0) {
2961
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NativeTaskRail, { t, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions: useFilteredSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } });
3598
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NativeTaskRail, { t, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions: useFilteredSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } });
2962
3599
  }
2963
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(OfficialTreeGuard, { fallback: (0, import_react6.createElement)(Official, rawOfficialProps), children: (0, import_react6.createElement)(Official, props) });
3600
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(OfficialTreeGuard, { fallback: (0, import_react10.createElement)(Official, rawOfficialProps), children: (0, import_react10.createElement)(Official, props) });
2964
3601
  };
2965
- if (wide === false) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: renderOfficial(filteredOfficialProps) });
3602
+ if (wide === false) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: renderOfficial(filteredOfficialProps) });
2966
3603
  const foreignTabs = extraTabs.filter((item) => item.id !== "schedule");
2967
3604
  const visibleTab = resolveVisibleSidebarTab({
2968
3605
  tab,
@@ -2970,15 +3607,15 @@ function NativeScheduleShell({
2970
3607
  extraTabIds: ownedSidebarTabIds({ extraTabIds: foreignTabs.map((item) => item.id), channelsReady })
2971
3608
  });
2972
3609
  const hostedSchedule = extraTabs.find((item) => item.id === "schedule");
2973
- const scheduleBody = hostedSchedule === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(NativeScheduleSessionList, { t, runtime, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } }) : hostedSchedule.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true });
2974
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-shell-rail", children: [
2975
- /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "dsh-st-shell-tabs", role: "tablist", "aria-label": t("sidebar.tabs"), children: [
2976
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "tasks", className: visibleTab === "tasks" ? "is-on" : void 0, onClick: () => setTab("tasks"), children: t("sidebar.tasksTab") }),
2977
- foreignTabs.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === item.id, className: visibleTab === item.id ? "is-on" : void 0, onClick: () => setTab(item.id), children: item.label }, item.id)),
2978
- channelsReady && foreignTabs.every((item) => item.id !== "channels") && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "channels", className: visibleTab === "channels" ? "is-on" : void 0, onClick: () => setTab("channels"), children: t("sidebar.channelsTab") }),
2979
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "schedule", className: visibleTab === "schedule" ? "is-on" : void 0, onClick: () => setTab("schedule"), children: t("sidebar.tab") })
3610
+ const scheduleBody = hostedSchedule === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NativeScheduleSessionList, { t, runtime, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } }) : hostedSchedule.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true });
3611
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-st-shell-rail", children: [
3612
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "dsh-st-shell-tabs", role: "tablist", "aria-label": t("sidebar.tabs"), children: [
3613
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "tasks", className: visibleTab === "tasks" ? "is-on" : void 0, onClick: () => setTab("tasks"), children: t("sidebar.tasksTab") }),
3614
+ foreignTabs.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === item.id, className: visibleTab === item.id ? "is-on" : void 0, onClick: () => setTab(item.id), children: item.label }, item.id)),
3615
+ channelsReady && foreignTabs.every((item) => item.id !== "channels") && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "channels", className: visibleTab === "channels" ? "is-on" : void 0, onClick: () => setTab("channels"), children: t("sidebar.channelsTab") }),
3616
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "schedule", className: visibleTab === "schedule" ? "is-on" : void 0, onClick: () => setTab("schedule"), children: t("sidebar.tab") })
2980
3617
  ] }),
2981
- visibleTab === "schedule" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-shell-body", children: scheduleBody }) : foreignTabs.find((item) => item.id === visibleTab) !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-shell-body", children: foreignTabs.find((item) => item.id === visibleTab)?.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true }) }) : visibleTab === "channels" ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-shell-body", children: renderSlot?.("sidebar.channels", { ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true, skin: "native" }) }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-official-tree", children: renderOfficial(filteredOfficialProps) })
3618
+ visibleTab === "schedule" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-shell-body", children: scheduleBody }) : foreignTabs.find((item) => item.id === visibleTab) !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-shell-body", children: foreignTabs.find((item) => item.id === visibleTab)?.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true }) }) : visibleTab === "channels" ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-shell-body", children: renderSlot?.("sidebar.channels", { ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true, skin: "native" }) }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-official-tree", children: renderOfficial(filteredOfficialProps) })
2982
3619
  ] });
2983
3620
  }
2984
3621
  function NativeTaskRail({
@@ -2990,10 +3627,10 @@ function NativeTaskRail({
2990
3627
  const snap = useSessions === void 0 ? { ids: [], byId: {}, current: null } : useSessions((state) => state ?? { ids: [], byId: {}, current: null });
2991
3628
  const workspaces = useWorkspaces === void 0 ? void 0 : useWorkspaces((state) => state ?? { items: [], archivedSessionIds: [] });
2992
3629
  const groups = groupNativeTaskSessions(snap, workspaces, t("sidebar.ungrouped"));
2993
- if (groups.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.tasksEmpty") });
2994
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-rail", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "dsh-st-rail-group", children: [
2995
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "dsh-st-rail-head is-static", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "dsh-st-rail-title", children: group.label }) }),
2996
- group.sessions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
3630
+ if (groups.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.tasksEmpty") });
3631
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("section", { className: "dsh-st-rail-group", children: [
3632
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "dsh-st-rail-head is-static", children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { className: "dsh-st-rail-title", children: group.label }) }),
3633
+ group.sessions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
2997
3634
  "button",
2998
3635
  {
2999
3636
  type: "button",
@@ -3001,7 +3638,7 @@ function NativeTaskRail({
3001
3638
  onClick: () => {
3002
3639
  if (item.id !== void 0) openSession?.(item.id);
3003
3640
  },
3004
- children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: item.title || item.id })
3641
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("span", { children: item.title || item.id })
3005
3642
  },
3006
3643
  item.id
3007
3644
  ))
@@ -3020,6 +3657,7 @@ var CSS_TEXT = `
3020
3657
  .dsh-st-btn,.dsh-st-icon{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:inherit;font:inherit;font-size:13px;cursor:pointer;white-space:nowrap}
3021
3658
  .dsh-st-icon{width:32px;padding:0;flex:none}
3022
3659
  .dsh-st-btn--primary{border-color:transparent;background:var(--dsw-alias-button-primary-fill,#fff);color:var(--dsw-alias-label-primary-foreground,#111)}
3660
+ .dsh-st-btn--danger{border-color:var(--dsw-alias-state-error-primary,#f85149);background:var(--dsw-alias-state-error-primary,#f85149);color:#fff}
3023
3661
  .dsh-st-hint{margin:-6px 0 14px;padding:10px 12px;border-radius:12px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font-size:12px}
3024
3662
  .dsh-st-banner{display:flex;align-items:flex-start;gap:8px;margin-bottom:16px;padding:10px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}
3025
3663
  .dsh-st-banner>span{display:inline-flex;align-items:flex-start;gap:8px}
@@ -3038,16 +3676,33 @@ var CSS_TEXT = `
3038
3676
  .dsh-st-tabs>button{padding:8px 0;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}
3039
3677
  .dsh-st-tabs>button.is-on{border-bottom-color:currentColor;color:var(--dsw-alias-label-primary);font-weight:650}
3040
3678
  .dsh-st-dropdown{position:relative;min-width:0}
3041
- .dsh-st-sort{margin-left:auto}
3042
- .dsh-st-dropdown-btn{display:inline-flex;align-items:center;gap:4px;max-width:220px;height:28px;padding:0 10px;border:0;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));color:var(--dsw-alias-label-primary,inherit);font:13px/20px inherit;cursor:pointer;white-space:nowrap}
3679
+ .dsh-st-sort-wrap{display:flex;align-items:center;gap:6px;margin-left:auto}
3680
+ .dsh-st-dropdown-btn{display:inline-flex;align-items:center;gap:4px;max-width:220px;height:28px;padding:0 10px;border:0;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));color:var(--dsw-alias-label-primary,inherit);font-family:inherit;font-size:13px;line-height:20px;cursor:pointer;white-space:nowrap}
3043
3681
  .dsh-st-dropdown-btn:hover,.dsh-st-dropdown-btn.is-open{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.18))}
3044
3682
  .dsh-st-dropdown-label{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3045
3683
  .dsh-st-dropdown-chevron{flex:none;transition:transform .16s ease;transform:rotate(90deg)}
3046
3684
  .dsh-st-dropdown-btn.is-open .dsh-st-dropdown-chevron{transform:rotate(-90deg)}
3047
- .dsh-st-dropdown-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:180px;max-height:260px;overflow:auto;padding:6px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-alias-bg-layer-3,#303033);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.32))}
3048
- .dsh-st-dropdown-menu button{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-height:36px;padding:6px 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,inherit);font:13px/20px inherit;cursor:pointer;text-align:left}
3049
- .dsh-st-dropdown-menu button>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3050
- .dsh-st-dropdown-menu button:hover,.dsh-st-dropdown-menu button.is-selected{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-primary,inherit)}
3685
+ .dsh-st-dropdown-menu{box-sizing:border-box;position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:max-content;min-width:180px;max-width:calc(100vw - 16px);max-height:260px;overflow-x:hidden;overflow-y:auto;padding:6px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-alias-bg-layer-3,#303033);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.32))}
3686
+ .dsh-st-dropdown-menu.is-float{position:fixed;right:auto;top:auto;z-index:1200}
3687
+ .dsh-st-dropdown-menu.dsh-st-dropdown-sort{min-width:0;transition:width .12s ease}
3688
+ .dsh-st-dropdown-row{box-sizing:border-box;display:flex;align-items:center;justify-content:flex-start;gap:8px;width:100%;min-height:36px;padding:6px 10px;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,inherit);font-family:inherit;font-size:13px;line-height:20px;cursor:pointer;text-align:left}
3689
+ .dsh-st-dropdown-label-cell{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3690
+ .dsh-st-dropdown-row:not(.has-trailing) .dsh-st-dropdown-label-cell{flex:1}
3691
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-label-cell{flex:none}
3692
+ .dsh-st-dropdown-spacer{min-width:0}
3693
+ .dsh-st-dropdown-row:not(.has-trailing) .dsh-st-dropdown-spacer{flex:0 0 0}
3694
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-spacer{flex:1 1 auto}
3695
+ .dsh-st-dropdown-row.has-trailing{gap:0}
3696
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-label-cell{margin-right:8px}
3697
+ .dsh-st-dropdown-row.has-trailing .dsh-st-dropdown-default{margin-right:4px}
3698
+ .dsh-st-dropdown-check{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;flex:none}
3699
+ .dsh-st-dropdown-row:hover,.dsh-st-dropdown-row.is-selected{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-primary,inherit)}
3700
+ .dsh-st-dropdown-default{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;width:auto;min-width:0;height:22px;padding:0 6px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.14));border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));color:var(--dsw-alias-label-primary,inherit);font-family:inherit;font-size:12px;line-height:18px;cursor:pointer;white-space:nowrap;overflow:hidden}
3701
+ .dsh-st-dropdown-default:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.2))}
3702
+ .dsh-st-dropdown-default:disabled,.dsh-st-dropdown-default.is-on{background:rgba(255,255,255,.05);border-color:rgba(255,255,255,.08);color:var(--dsw-alias-label-tertiary,#8b8f98);cursor:default}
3703
+ .dsh-st-dropdown.dsh-st-dropdown-compact .dsh-st-dropdown-btn{font-size:12px;line-height:18px}
3704
+ .dsh-st-dropdown-menu.dsh-st-dropdown-compact .dsh-st-dropdown-row{font-size:12px;line-height:18px}
3705
+ .dsh-st-dropdown-menu.dsh-st-dropdown-compact .dsh-st-dropdown-default{font-size:11px;line-height:16px}
3051
3706
  .dsh-st-sort-tick{width:16px;height:16px;flex:none}
3052
3707
  .dsh-st-filters{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-left:auto}
3053
3708
  .dsh-st-filters>button{height:28px;padding:0 10px;border:0;border-radius:999px;background:rgba(255,255,255,.06);color:inherit;font-size:12px}
@@ -3081,6 +3736,7 @@ var CSS_TEXT = `
3081
3736
  .dsh-st-muted{color:var(--dsw-alias-label-secondary)}
3082
3737
  .dsh-st-mask{position:fixed;inset:0;z-index:40;display:flex;align-items:center;justify-content:center;padding:24px;overflow:auto;background:rgba(0,0,0,.45)}.dsh-st-flyout-root{position:absolute;inset:0;z-index:1200;overflow:visible;pointer-events:none}.dsh-st-flyout-root .dsh-st-select-menu,.dsh-st-flyout-root .dsh-st-model-select-menu{pointer-events:auto}
3083
3738
  .dsh-st-modal,.dsh-st-modal *{box-sizing:border-box}.dsh-st-modal{display:flex;flex-direction:column;width:min(760px,calc(100vw - 48px));max-width:100%;max-height:min(92vh,900px);overflow:hidden;padding:24px;border:1px solid var(--dsw-alias-border-l2);border-radius:20px;background:var(--dsw-alias-bg-base)}
3739
+ .dsh-st-confirm-modal,.dsh-st-confirm-modal *{box-sizing:border-box}.dsh-st-confirm-modal{width:min(420px,calc(100vw - 48px));padding:24px;border:1px solid var(--dsw-alias-border-l2);border-radius:18px;background:var(--dsw-alias-bg-base);box-shadow:var(--dsw-shadow-lv3,0 12px 36px rgba(0,0,0,.36))}.dsh-st-confirm-modal h2{margin:0 0 10px;font-size:18px}.dsh-st-confirm-modal p{margin:0 0 8px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5}.dsh-st-confirm-modal .dsh-st-confirm-target{color:var(--dsw-alias-label-primary);font-weight:600;overflow-wrap:anywhere}
3084
3740
  .dsh-st-modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}
3085
3741
  .dsh-st-modal-head h2{margin:0 0 4px;font-size:20px}
3086
3742
  .dsh-st-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px;min-width:0;max-width:100%;font-size:13px}.dsh-st-field:has(.dsh-st-prompt-card){flex:1;min-height:0;margin-bottom:10px}
@@ -3142,6 +3798,29 @@ var CSS_TEXT = `
3142
3798
  .dsh-st-menu-split{height:1px;margin:6px 8px;background:rgba(255,255,255,.08)}
3143
3799
  .dsh-st-subdialog{margin:0 0 12px;padding:12px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:rgba(255,255,255,.03)}
3144
3800
  .dsh-st-subdialog>strong{display:block;margin:0 0 8px;font-size:13px}
3801
+ .dsh-st-rail-views{display:flex;flex:none;gap:3px;margin:16px 8px 10px;padding:2px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));border-radius:9px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.035))}
3802
+ .dsh-st-rail-views button{flex:1;appearance:none;border:1px solid transparent;border-radius:6px;background:transparent;color:var(--dsw-alias-label-secondary,#9ca3af);padding:3px 7px;font-size:12px;line-height:18px;cursor:pointer;transition:background .16s ease,border-color .16s ease,color .16s ease,box-shadow .16s ease}
3803
+ .dsh-st-rail-views button:hover{color:var(--dsw-alias-label-primary,inherit)}
3804
+ .dsh-st-rail-views button.is-on{border-color:var(--dsw-alias-border-l2,rgba(255,255,255,.18));background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.15));color:var(--dsw-alias-label-primary,#fff);font-weight:650;box-shadow:0 1px 3px rgba(0,0,0,.34),inset 0 1px rgba(255,255,255,.06)}
3805
+ .dsh-st-overview{display:flex;flex-direction:column;flex:1;min-height:0;overflow-y:auto;padding:2px 8px 14px}
3806
+ .dsh-st-overview-head{display:flex;flex:none;align-items:center;justify-content:space-between;gap:8px;height:36px;min-height:36px;margin-bottom:4px;padding:6px 0}
3807
+ .dsh-st-overview-title{display:flex;align-items:baseline;min-width:0;gap:6px;color:var(--dsw-alias-label-tertiary,#81858C)}
3808
+ .dsh-st-overview-title strong{font-size:14px;font-weight:400;line-height:20px}
3809
+ .dsh-st-overview-title span{display:inline-grid;place-items:center;min-width:18px;height:18px;padding:0 5px;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.1));color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:11px;line-height:18px}
3810
+ .dsh-st-overview-sort{display:flex;align-items:center}
3811
+ .dsh-st-overview-row{position:relative;display:grid;grid-template-columns:minmax(0,1fr) auto 12px;align-items:center;gap:8px;width:100%;min-height:88px;margin:0 0 8px;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.1));border-radius:9px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.035));color:var(--dsw-alias-label-primary,inherit);text-align:left;cursor:pointer;box-shadow:inset 0 1px rgba(255,255,255,.025);transition:background .14s ease,border-color .14s ease}
3812
+ .dsh-st-overview-row:hover:not(:disabled){border-color:var(--dsw-alias-border-inverted,rgba(255,255,255,.18));background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.06))}
3813
+ .dsh-st-overview-row:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4c8dff);outline-offset:2px}
3814
+ .dsh-st-overview-row:disabled{cursor:default}
3815
+ .dsh-st-overview-copy{display:flex;flex:1;min-width:0;flex-direction:column;gap:4px}
3816
+ .dsh-st-overview-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:18px;font-weight:580}
3817
+ .dsh-st-overview-status{display:inline-flex;align-self:flex-start;align-items:center;gap:4px;padding:2px 6px;border-radius:999px;background:rgba(50,205,143,.12);color:#45d483;font-size:11px;line-height:16px}
3818
+ .dsh-st-overview-row.is-paused .dsh-st-overview-status{background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.08));color:var(--dsw-alias-label-secondary,#aeb3bd)}
3819
+ .dsh-st-overview-schedule{display:inline-flex;align-items:center;gap:5px;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px;line-height:16px}
3820
+ .dsh-st-overview-next{display:flex;flex:none;min-width:50px;flex-direction:column;align-items:flex-end;gap:2px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:10px;line-height:14px}
3821
+ .dsh-st-overview-next strong{color:var(--dsw-alias-label-secondary,#b6bac2);font-size:12px;font-weight:600;line-height:16px;white-space:nowrap}
3822
+ .dsh-st-overview-row:not(.is-paused) .dsh-st-overview-next strong{color:#45d483}
3823
+ .dsh-st-overview-chevron{flex:none;color:var(--dsw-alias-label-tertiary,#8b8f98)}
3145
3824
  .dsh-st-rail{box-sizing:border-box;height:100%;overflow:auto;padding:4px var(--dsh-sidebar-inline-padding,12px) 18px 8px;color:inherit;scrollbar-gutter:stable}
3146
3825
  .dsh-st-rail-empty{padding:16px 10px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px}
3147
3826
  .dsh-st-rail-group{margin:0 0 8px}
@@ -3154,14 +3833,26 @@ var CSS_TEXT = `
3154
3833
  .dsh-st-rail-session span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3155
3834
  .dsh-st-rail-dot{width:6px;height:6px;margin-left:auto;border-radius:50%;background:#34c759;flex:none}.dsh-st-run-dot{flex:none;color:var(--dsw-static-deepseek-450,#4c8dff)}.dsh-st-run-dot-cell{fill:currentColor;opacity:.15;animation:dsh-st-run-chase 1s infinite}@keyframes dsh-st-run-chase{0%,12.4%{opacity:1}12.5%,24.9%{opacity:.6}25%,37.4%{opacity:.35}37.5%,100%{opacity:.15}}
3156
3835
  .dsh-st-shell-rail{display:flex;flex-direction:column;min-height:0;flex:1;height:100%;overflow:hidden}
3157
- .dsh-st-shell-tabs{display:flex;flex:none;gap:18px;padding:4px 12px 0;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.08))}
3158
- .dsh-st-shell-tabs button{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-secondary,#8b8f98);padding:8px 0;font-size:13px;cursor:pointer}
3836
+ .dsh-st-shell-tabs{display:flex;flex:none;gap:18px;padding:6px 12px 0;border-bottom:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.08))}
3837
+ .dsh-st-shell-tabs button{appearance:none;border:0;background:transparent;color:var(--dsw-alias-label-secondary,#8b8f98);padding:8px 0 9px;font-size:13px;cursor:pointer}
3159
3838
  .dsh-st-shell-tabs button.is-on{color:var(--dsw-alias-label-primary,inherit);box-shadow:inset 0 -2px 0 currentColor}
3160
3839
  .dsh-st-shell-body{display:flex;min-height:0;flex:1;overflow:hidden}
3161
3840
  .dsh-st-shell-body>*{min-width:0;flex:1}.dsh-st-official-tree{display:flex;min-height:0;flex:1;overflow:hidden}.dsh-st-official-tree>*{min-width:0;flex:1}
3162
3841
  .dsh-st-rail-head.is-static{cursor:default;font-weight:600}
3163
3842
  .dsh-st-rail-session.is-on{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
3164
3843
  .dsh-st-n,.dsh-st-n *{box-sizing:border-box}.dsh-st-n{box-sizing:border-box;display:flex;flex:1;min-width:0;max-width:100%;min-height:0;flex-direction:column;padding:0;padding-right:var(--dsh-sidebar-inline-padding,12px);color:var(--dsw-alias-label-primary,inherit);font:14px/20px inherit;overflow:hidden}.dsh-st-n-toolbar{box-sizing:border-box;flex:none;height:36px;margin:2px -4px 4px 0;padding-left:4px;display:flex;justify-content:flex-end;align-items:center;gap:4px;overflow:visible;position:relative;z-index:2;color:var(--dsw-alias-label-tertiary,#81858C);border-radius:12px}.dsh-st-n-head-label{white-space:nowrap;min-width:0;max-width:45%;flex:none;line-height:20px;font-size:14px;overflow:hidden;transition:max-width .18s var(--ds-ease-in-out,ease),margin-right .18s var(--ds-ease-in-out,ease),opacity .12s var(--ds-ease-in-out,ease),transform .18s var(--ds-ease-in-out,ease),visibility 0s linear}.dsh-st-n-toolbar.is-search .dsh-st-n-head-label{opacity:0;visibility:hidden;max-width:0;margin-right:-4px;transform:translate(-4px);transition-delay:0s,0s,0s,0s,.18s}.dsh-st-n-search-slot{box-sizing:border-box;min-width:28px;max-width:28px;transition:max-width .18s var(--ds-ease-in-out,ease);flex:none;align-items:center;margin-left:auto;display:flex;position:relative;z-index:2}.dsh-st-n-toolbar.is-search .dsh-st-n-search-slot{flex:1;min-width:0;max-width:100%}.dsh-st-n-search{box-sizing:border-box;cursor:text;width:100%;height:28px;color:var(--dsw-alias-label-secondary);transition:width .18s var(--ds-ease-in-out,ease),padding .18s var(--ds-ease-in-out,ease),border-color .18s var(--ds-ease-in-out,ease);background:transparent;border:none;border-radius:50%;flex:none;align-items:center;margin:0;padding:0;display:flex;overflow:hidden}.dsh-st-n-toolbar.is-search .dsh-st-n-search{border:1px solid var(--dsw-alias-border-l2,rgba(255,255,255,.10));width:calc(100% + 4px);height:30px;border-radius:10px;margin-inline:-2px;padding:0 4px 0 0}.dsh-st-n-search-btn,.dsh-st-n-head-btn{cursor:pointer;width:28px;height:28px;min-width:28px;min-height:28px;position:relative;z-index:1;color:var(--dsw-alias-label-secondary);background:transparent;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.dsh-st-n-toolbar.is-search .dsh-st-n-search-btn{width:28px;height:30px}.dsh-st-n-search-btn:hover,.dsh-st-n-head-btn:hover,.dsh-st-n-head-btn.is-on{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06));color:var(--dsw-alias-label-primary,inherit)}.dsh-st-n-toolbar.is-search .dsh-st-n-search-btn:hover{background:transparent}.dsh-st-n-head-acts{opacity:1;visibility:visible;max-width:32px;transition:max-width .18s var(--ds-ease-in-out,ease),opacity .12s var(--ds-ease-in-out,ease),transform .18s var(--ds-ease-in-out,ease),visibility 0s linear;flex:none;align-items:center;gap:4px;display:flex;overflow:visible;position:relative}.dsh-st-n-toolbar.is-search .dsh-st-n-head-acts{opacity:0;visibility:hidden;pointer-events:none;max-width:0;transform:translate(4px);transition-delay:0s,0s,0s,.18s}.dsh-st-n-head-filter{position:relative}.dsh-st-n-search-input{display:none;opacity:0;pointer-events:none;width:0;min-width:0;flex:none;color:var(--dsw-alias-label-primary,inherit);transition:opacity .12s var(--ds-ease-in-out,ease);background:transparent;border:none;outline:none;flex:1;font-size:13px;line-height:18px}.dsh-st-n-toolbar.is-search .dsh-st-n-search-input{display:block;opacity:1;pointer-events:auto;margin-left:-2px;width:auto;flex:1;min-width:0}.dsh-st-n-search-input::placeholder{color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-search-clear{cursor:pointer;width:24px;height:24px;color:var(--dsw-alias-label-secondary);background:transparent;border:none;border-radius:50%;flex:none;justify-content:center;align-items:center;padding:0;display:inline-flex}.dsh-st-n-search-clear:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}@media (prefers-reduced-motion:reduce){.dsh-st-n-head-label,.dsh-st-n-search-slot,.dsh-st-n-search,.dsh-st-n-head-acts,.dsh-st-n-search-input{transition:none}}.dsh-st-n-filter-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;min-width:196px;padding:8px 6px;border:1px solid var(--dsw-alias-border-inverted,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-specific-menu,#1c2128);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.36))}.dsh-st-n-filter-label{padding:6px 10px 4px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-filter-split{height:1px;margin:6px 8px;background:var(--dsw-alias-border-l2,rgba(255,255,255,.1))}.dsh-st-n-filter-menu button{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;min-height:36px;padding:6px 10px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-primary,inherit);font:14px/20px inherit;cursor:pointer;text-align:left}.dsh-st-n-filter-menu button:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}.dsh-st-n-filter-tick{width:16px;height:16px;flex:none}.dsh-st-n-tree{flex:1;min-width:0;max-width:100%;min-height:0;overflow-x:hidden;overflow-y:auto;padding:0 0 16px;user-select:none}.dsh-st-n-empty{padding:14px 8px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px}.dsh-st-n-group{min-width:0;max-width:100%}.dsh-st-n-row,.dsh-st-n-sess{display:flex;align-items:center;max-width:100%;border-radius:8px;padding:0 8px 0 12px;cursor:pointer;border:0;background:transparent;color:var(--dsw-alias-label-primary,inherit);text-align:left;font:14px/20px inherit}.dsh-st-n-row{height:34px;gap:6px}.dsh-st-n-sess{height:32px;gap:0;position:relative;width:100%;appearance:none}.dsh-st-n-row:hover,.dsh-st-n-sess:hover,.dsh-st-n-sess.is-on,.dsh-st-n-sess.is-menu{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}.dsh-st-n-slot{flex:none;width:16px;height:20px;display:inline-flex;align-items:center;justify-content:center}.dsh-st-n-folder{color:var(--dsw-alias-label-secondary,#9ca39f)}.dsh-st-n-lead{color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-corner{color:var(--dsw-alias-label-caption,#ADB2B8);width:8px}.dsh-st-n-title{min-width:0;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}.dsh-st-n-sess .dsh-st-n-title{margin:0 6px 0 4px}.dsh-st-n-time{flex:none;font-size:12px;line-height:20px;color:var(--dsw-alias-label-tertiary,#81858C);white-space:nowrap}.dsh-st-n-acts{flex:none;display:none;align-items:center;gap:12px}.dsh-st-n-row:hover .dsh-st-n-acts,.dsh-st-n-sess:hover .dsh-st-n-acts,.dsh-st-n-row.is-menu .dsh-st-n-acts,.dsh-st-n-sess.is-menu .dsh-st-n-acts{display:inline-flex}.dsh-st-n-sess:hover .dsh-st-n-time,.dsh-st-n-sess.is-menu .dsh-st-n-time{display:none}.dsh-st-n-ico{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border:0;border-radius:4px;background:transparent;color:var(--dsw-alias-label-tertiary,#81858C);padding:0;cursor:pointer}.dsh-st-n-ico:hover{color:var(--dsw-alias-label-primary,inherit)}.dsh-st-n-menu.is-float{position:fixed;z-index:4000;right:auto;top:auto}.dsh-st-n-menu{position:absolute;right:8px;top:calc(100% + 4px);z-index:1100;min-width:218px;max-width:360px;box-sizing:border-box;padding:4px;display:flex;flex-direction:column;border:1px solid var(--dsw-alias-border-inverted,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-specific-menu,#1c2128);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.36))}.dsh-st-n-menu button{display:flex;align-items:center;gap:8px;width:100%;min-height:40px;padding:8px 10px;border:0;border-radius:10px;background:transparent;cursor:pointer;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary,inherit);text-align:left}.dsh-st-n-menu button:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}.dsh-st-n-mi{display:inline-flex;flex:none;width:16px;height:16px;align-items:center;justify-content:center;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-menu button.danger{color:var(--dsw-alias-state-error-primary,#f85149)}.dsh-st-n-menu button.danger .dsh-st-n-mi{color:inherit}.dsh-st-n-menu button.danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgba(248,81,73,.12))}.dsh-st-n-hover{position:fixed;z-index:4100;min-width:188px;max-width:280px;padding:12px 14px;border:1px solid var(--dsw-alias-border-inverted,rgba(255,255,255,.12));border-radius:12px;background:var(--dsw-specific-menu,#1c2128);box-shadow:var(--dsw-shadow-lv3,0 8px 24px rgba(0,0,0,.36));color:var(--dsw-alias-label-primary,inherit)}.dsh-st-n-hover-title{font-size:14px;line-height:20px;font-weight:500}.dsh-st-n-hover-time{margin-top:4px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-hover-state{display:flex;align-items:center;gap:6px;margin-top:8px;font-size:12px;line-height:18px;color:var(--dsw-alias-label-secondary,#9ca39f)}.dsh-st-n-hover-dot{width:8px;height:8px;border-radius:50%;background:#34c759;flex:none}.dsh-st-n-hover-dot.is-run{background:#4c8dff}.dsh-st-n-rename{flex:1;min-width:0;margin:0 6px 0 4px;border:1px solid var(--dsw-alias-border-l2);border-radius:4px;background:var(--dsw-alias-button-elevated-fill,rgba(255,255,255,.04));color:inherit;font:inherit;padding:0 2px}
3844
+ .dsh-st-n-row.is-menu{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
3845
+ .dsh-st-overview-sort .dsh-st-n-head-btn.is-open{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06));color:var(--dsw-alias-label-primary,inherit)}
3846
+ .dsh-st-n-row[aria-expanded="true"].has-current-session .dsh-st-n-folder{color:var(--dsw-static-deepseek-450,#4c8dff)}
3847
+ .dsh-st-n-sess:focus{outline:none}.dsh-st-n-sess:focus-visible:not(.is-on){box-shadow:inset 0 0 0 2px var(--dsw-alias-state-business-primary,#4c8dff)}
3848
+ .dsh-st-n-row>.dsh-st-n-acts{display:inline-flex;opacity:0;visibility:hidden;pointer-events:none}
3849
+ .dsh-st-n-row:hover>.dsh-st-n-acts,.dsh-st-n-row:focus-within>.dsh-st-n-acts,.dsh-st-n-row.is-menu>.dsh-st-n-acts{opacity:1;visibility:visible;pointer-events:auto}
3850
+ .dsh-st-n-dialog-actions{display:flex;justify-content:flex-end;gap:8px}
3851
+ .dsh-st-n-dialog-copy{margin:0;color:var(--dsw-alias-label-secondary);font-size:14px;line-height:22px}
3852
+ .dsh-st-n-dialog-status{margin-top:12px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px}
3853
+ .dsh-st-n-dialog-error{margin-top:12px;color:var(--dsw-alias-state-error-primary,#f85149);font-size:13px;line-height:20px}
3854
+ .dsh-st-n-danger-button{color:var(--dsw-alias-state-error-primary,#f85149)!important}
3855
+ .dsh-st-n-danger-button:hover{background:var(--dsw-alias-interactive-bg-hover-danger,rgba(248,81,73,.12))!important}
3165
3856
  `;
3166
3857
  function installStyles() {
3167
3858
  const existing = document.getElementById(STYLE_ID);
@@ -3178,6 +3869,77 @@ function installStyles() {
3178
3869
  };
3179
3870
  }
3180
3871
 
3872
+ // src/client/settings-navigation.ts
3873
+ function pickSettingsSectionButton(buttons, labels) {
3874
+ for (const label of labels) {
3875
+ const target = label.trim();
3876
+ if (target === "") continue;
3877
+ const match = buttons.find((button) => button.textContent?.replace(/\s+/g, " ").trim() === target);
3878
+ if (match !== void 0) return match;
3879
+ }
3880
+ return void 0;
3881
+ }
3882
+ function pickSettingsLauncher(buttons) {
3883
+ const named = buttons.find((button) => {
3884
+ const label = `${button.textContent ?? ""} ${button.getAttribute("aria-label") ?? ""}`.trim();
3885
+ return /(^|\s)(设置|settings)(\s|$)/i.test(label);
3886
+ });
3887
+ return named ?? (buttons.length === 1 ? buttons[0] : void 0);
3888
+ }
3889
+ var cancelPendingNavigation;
3890
+ function openSettingsSection(labels, onSelected, onMissing) {
3891
+ if (typeof document === "undefined" || typeof window === "undefined") {
3892
+ onMissing?.();
3893
+ return;
3894
+ }
3895
+ const launchers = [...document.querySelectorAll('button[aria-haspopup="dialog"]')];
3896
+ const launcher = pickSettingsLauncher(launchers);
3897
+ const dialogOpen = document.querySelector('[role="dialog"]') !== null;
3898
+ if (!dialogOpen && launcher === void 0) {
3899
+ onMissing?.();
3900
+ return;
3901
+ }
3902
+ cancelPendingNavigation?.();
3903
+ if (!dialogOpen) launcher?.click();
3904
+ let frame;
3905
+ let finished = false;
3906
+ const observer = new MutationObserver(() => {
3907
+ schedule();
3908
+ });
3909
+ const cleanup = () => {
3910
+ if (finished) return;
3911
+ finished = true;
3912
+ observer.disconnect();
3913
+ window.clearTimeout(timeout);
3914
+ if (frame !== void 0) window.cancelAnimationFrame(frame);
3915
+ if (cancelPendingNavigation === cleanup) cancelPendingNavigation = void 0;
3916
+ };
3917
+ const select = () => {
3918
+ const buttons = [...document.querySelectorAll('[role="dialog"] nav button')];
3919
+ const target = pickSettingsSectionButton(buttons, labels);
3920
+ if (target === void 0) return false;
3921
+ cleanup();
3922
+ target.click();
3923
+ onSelected?.();
3924
+ return true;
3925
+ };
3926
+ const schedule = () => {
3927
+ if (finished || frame !== void 0) return;
3928
+ frame = window.requestAnimationFrame(() => {
3929
+ frame = void 0;
3930
+ select();
3931
+ });
3932
+ };
3933
+ const timeout = window.setTimeout(() => {
3934
+ if (select()) return;
3935
+ cleanup();
3936
+ onMissing?.();
3937
+ }, 1500);
3938
+ observer.observe(document.body, { childList: true, subtree: true });
3939
+ cancelPendingNavigation = cleanup;
3940
+ schedule();
3941
+ }
3942
+
3181
3943
  // src/client/index.ts
3182
3944
  var name = "dsh-automation-client";
3183
3945
  var inject = ["slots", "locale", "connection", "sessions"];
@@ -3227,7 +3989,7 @@ function apply(ctx) {
3227
3989
  label: () => t("tab"),
3228
3990
  icon: "schedule"
3229
3991
  }, function ScheduledTasksSettings(props) {
3230
- return (0, import_react7.createElement)(AutomationView, { t, permissionT, modelT, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close } });
3992
+ return (0, import_react11.createElement)(AutomationView, { t, permissionT, modelT, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close } });
3231
3993
  }));
3232
3994
  ctx.slots.inject("sidebar.schedule", () => ctx.slots.register({
3233
3995
  name: "sidebar.schedule",
@@ -3236,10 +3998,12 @@ function apply(ctx) {
3236
3998
  locale: NS,
3237
3999
  label: () => t("sidebar.tab")
3238
4000
  }, function AutomationScheduleRail(props) {
3239
- return (0, import_react7.createElement)(ScheduleRail, {
4001
+ return (0, import_react11.createElement)(ScheduleRail, {
3240
4002
  t,
3241
4003
  runtime,
3242
- openSession: createScheduledSessionOpener(ctx, runtime, props.openSession)
4004
+ openSession: createScheduledSessionOpener(ctx, runtime, props.openSession),
4005
+ ...props.view === void 0 ? {} : { view: props.view },
4006
+ ...props.showViewSwitch === void 0 ? {} : { showViewSwitch: props.showViewSwitch }
3243
4007
  });
3244
4008
  }));
3245
4009
  ctx.slots.inject("sidebar.workspaces", () => {
@@ -3282,7 +4046,7 @@ function apply(ctx) {
3282
4046
  render: (props) => {
3283
4047
  const hostOpen = typeof props.openSession === "function" ? props.openSession : typeof props.open === "function" ? props.open : openSession;
3284
4048
  const opener = createScheduledSessionOpener(ctx, runtime, hostOpen);
3285
- return (0, import_react7.createElement)(NativeScheduleSessionList, {
4049
+ return (0, import_react11.createElement)(NativeScheduleSessionList, {
3286
4050
  t,
3287
4051
  runtime,
3288
4052
  openSession: opener,
@@ -3291,7 +4055,16 @@ function apply(ctx) {
3291
4055
  ...typeof props.renameSession === "function" ? { renameSession: props.renameSession } : {},
3292
4056
  ...typeof props.archiveSession === "function" ? { archiveSession: props.archiveSession } : {},
3293
4057
  ...typeof props.deleteSession === "function" ? { deleteSession: props.deleteSession } : {},
3294
- ...typeof props.forkSession === "function" ? { forkSession: props.forkSession } : {}
4058
+ ...typeof props.forkSession === "function" ? { forkSession: props.forkSession } : {},
4059
+ openTaskSettings: (request) => {
4060
+ requestAutomationTaskSettings(request);
4061
+ openSettingsSection(
4062
+ [t("tab"), "Scheduled tasks", "\u5B9A\u65F6\u4EFB\u52A1"],
4063
+ () => {
4064
+ requestAutomationTaskSettings(request);
4065
+ }
4066
+ );
4067
+ }
3295
4068
  });
3296
4069
  }
3297
4070
  });
@@ -3323,7 +4096,7 @@ function apply(ctx) {
3323
4096
  try {
3324
4097
  let AutomationNativeWorkspaceShell2 = function(innerProps) {
3325
4098
  const openSession = createScheduledSessionOpener(ctx, runtime, innerProps.openSession ?? innerProps.open);
3326
- return (0, import_react7.createElement)(NativeScheduleShell, {
4099
+ return (0, import_react11.createElement)(NativeScheduleShell, {
3327
4100
  t,
3328
4101
  runtime,
3329
4102
  hostProps: innerProps,
@@ -3409,7 +4182,7 @@ function createScheduledSessionOpener(ctx, runtime, hostOpen) {
3409
4182
  };
3410
4183
  }
3411
4184
  function PrefillBridge(props) {
3412
- (0, import_react7.useEffect)(() => {
4185
+ (0, import_react11.useEffect)(() => {
3413
4186
  const applyPrefill = (text) => {
3414
4187
  if (text === null || text === "") return;
3415
4188
  if (props.inputActions !== void 0) {