@michengai/dsh-automation 0.1.29 → 0.1.30

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  The five most recent published versions are listed below. Git tags and GitHub Releases now mirror these entries; historical sections retain links to their original release commits.
6
6
 
7
+ ## 0.1.30 — 2026-09-04
8
+
9
+ - Kept standalone Web and Codex UI scheduled-task lists current without requiring a mounted plugin page, and refreshed the Host session index when Automation runs reference sessions that have not appeared there yet.
10
+ - Added bounded refresh-cycle backoff for delayed Host session creation, dynamically reading the current Host session store while suppressing repeated refresh warnings.
11
+ - Refined the native and Codex UI schedule sidebars with aligned folder and card gutters, more compact task cards, and accessible pause/resume switches in place of status badges.
12
+
7
13
  ## 0.1.29 — 2026-09-04
8
14
 
9
15
  - Refreshed scheduled execution records immediately when the DSH page regains focus or becomes visible, avoiding stale history when Chromium throttles background-tab timers.
@@ -4,6 +4,12 @@
4
4
 
5
5
  以下记录最近发布的五个版本。Git 标签与 GitHub Release 现已和这些条目同步;历史条目继续保留原始发布提交链接。
6
6
 
7
+ ## 0.1.30 — 2026-09-04
8
+
9
+ - 独立 Web 与 Codex UI 的定时任务列表不再依赖插件页面挂载即可持续更新;Automation 运行记录引用的 Session 尚未进入宿主索引时,会主动刷新 Host 会话列表。
10
+ - 针对 Host Session 延迟创建增加有上限的完整刷新周期退避,并动态读取当前 Host Session Store,同时抑制重复刷新告警。
11
+ - 统一原生与 Codex UI 定时侧栏的文件夹和卡片边距,压缩任务卡片高度,并以可访问的暂停/恢复开关替代状态徽标。
12
+
7
13
  ## 0.1.29 — 2026-09-04
8
14
 
9
15
  - DSH 页面重新获得焦点或恢复可见时立即刷新定时任务执行记录,避免 Chromium 节流后台标签页计时器后侧栏历史停留在旧状态。
package/lib/client.js CHANGED
@@ -341,9 +341,6 @@ function RefreshIcon(props) {
341
341
  function PlayIcon(props) {
342
342
  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" }) });
343
343
  }
344
- function PauseIcon(props) {
345
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M9 7v10M15 7v10" }) });
346
- }
347
344
  function TrashIcon(props) {
348
345
  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" }) });
349
346
  }
@@ -359,9 +356,6 @@ function CalendarIcon(props) {
359
356
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M8 3.8v3.4M16 3.8v3.4M4 9.5h16" })
360
357
  ] });
361
358
  }
362
- function CheckIcon(props) {
363
- 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" }) });
364
- }
365
359
  function MoreIcon(props) {
366
360
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
367
361
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "12", r: "1.2", fill: "currentColor" }),
@@ -1375,6 +1369,8 @@ function unwrapRpcResult(value) {
1375
1369
  var CHANNEL = "/dsh-automation";
1376
1370
  var IDLE_POLL_INTERVAL_MS = 15e3;
1377
1371
  var ACTIVE_POLL_INTERVAL_MS = 2e3;
1372
+ var HOST_SESSION_RETRY_REFRESH_GAPS = [1, 2, 4];
1373
+ var HOST_SESSION_MAX_ATTEMPTS = HOST_SESSION_RETRY_REFRESH_GAPS.length + 1;
1378
1374
  function snapshotPollIntervalMs(runs) {
1379
1375
  return (runs ?? []).some((run) => run.status === "running" || run.status === "queued") ? ACTIVE_POLL_INTERVAL_MS : IDLE_POLL_INTERVAL_MS;
1380
1376
  }
@@ -1382,6 +1378,87 @@ function isTransportError(error) {
1382
1378
  const message = error instanceof Error ? error.message : String(error);
1383
1379
  return /failed to fetch|networkerror|load failed|network request failed/i.test(message);
1384
1380
  }
1381
+ function installAutomationSessionSync(runtime, getSessions) {
1382
+ let stopped = false;
1383
+ let completedRefreshes = 0;
1384
+ let automationRefreshInProgress = runtime.source.getSnapshot().phase === "loading";
1385
+ let trackedSessions;
1386
+ let trackedMissingKey;
1387
+ let attempts = 0;
1388
+ let nextAttemptRefresh = 0;
1389
+ let warnedMissingKey;
1390
+ let hostRefreshPromise;
1391
+ let reconcileAfterRefresh = false;
1392
+ const resetAttempts = (missingKey) => {
1393
+ trackedMissingKey = missingKey;
1394
+ attempts = 0;
1395
+ nextAttemptRefresh = completedRefreshes;
1396
+ warnedMissingKey = void 0;
1397
+ };
1398
+ const missingSessionKey = (sessions) => {
1399
+ const snapshot = runtime.source.getSnapshot().snapshot;
1400
+ const hostSnapshot = sessions?.list?.getSnapshot();
1401
+ if (snapshot === void 0 || hostSnapshot === void 0 || sessions?.refresh === void 0) return void 0;
1402
+ const present = /* @__PURE__ */ new Set([
1403
+ ...hostSnapshot.ids ?? [],
1404
+ ...Object.keys(hostSnapshot.byId ?? {})
1405
+ ]);
1406
+ return [...new Set(snapshot.runs.map((run) => run.sessionId).filter((sessionId) => sessionId !== void 0 && sessionId !== ""))].filter((sessionId) => !present.has(sessionId)).sort().join("\0");
1407
+ };
1408
+ const reconcile = () => {
1409
+ if (stopped) return;
1410
+ const sessions = getSessions();
1411
+ if (sessions !== trackedSessions) {
1412
+ trackedSessions = sessions;
1413
+ resetAttempts();
1414
+ }
1415
+ const missingKey = missingSessionKey(sessions);
1416
+ if (missingKey === void 0) return;
1417
+ if (missingKey === "") {
1418
+ resetAttempts();
1419
+ return;
1420
+ }
1421
+ if (missingKey !== trackedMissingKey) resetAttempts(missingKey);
1422
+ if (attempts >= HOST_SESSION_MAX_ATTEMPTS || completedRefreshes < nextAttemptRefresh) return;
1423
+ if (hostRefreshPromise !== void 0) {
1424
+ reconcileAfterRefresh = true;
1425
+ return;
1426
+ }
1427
+ const attemptIndex = attempts;
1428
+ attempts += 1;
1429
+ const retryGap = HOST_SESSION_RETRY_REFRESH_GAPS[attemptIndex];
1430
+ nextAttemptRefresh = retryGap === void 0 ? Number.POSITIVE_INFINITY : completedRefreshes + retryGap;
1431
+ hostRefreshPromise = Promise.resolve().then(async () => {
1432
+ await sessions.refresh();
1433
+ }).catch((error) => {
1434
+ if (!stopped && warnedMissingKey !== missingKey) {
1435
+ warnedMissingKey = missingKey;
1436
+ console.warn("[dsh-automation] \u5237\u65B0 Host \u4F1A\u8BDD\u5217\u8868\u5931\u8D25", error);
1437
+ }
1438
+ }).finally(() => {
1439
+ hostRefreshPromise = void 0;
1440
+ if (stopped || !reconcileAfterRefresh) return;
1441
+ reconcileAfterRefresh = false;
1442
+ reconcile();
1443
+ });
1444
+ };
1445
+ const unsubscribe = runtime.source.subscribe(() => {
1446
+ const phase = runtime.source.getSnapshot().phase;
1447
+ if (phase === "loading") {
1448
+ automationRefreshInProgress = true;
1449
+ } else if (automationRefreshInProgress) {
1450
+ automationRefreshInProgress = false;
1451
+ completedRefreshes += 1;
1452
+ }
1453
+ reconcile();
1454
+ });
1455
+ reconcile();
1456
+ return () => {
1457
+ stopped = true;
1458
+ reconcileAfterRefresh = false;
1459
+ unsubscribe();
1460
+ };
1461
+ }
1385
1462
  function createAutomationRuntime(rpc) {
1386
1463
  let state = { phase: "idle" };
1387
1464
  let refreshPromise;
@@ -2701,6 +2778,9 @@ function groupScheduledSessions(automations, runs) {
2701
2778
  };
2702
2779
  }).filter((group) => group.sessions.length > 0);
2703
2780
  }
2781
+ function automationToggleMutation(status) {
2782
+ return status === "active" ? "pause" : "resume";
2783
+ }
2704
2784
  function deriveTaskOverviewRows(automations, runs) {
2705
2785
  const lastByAutomation = /* @__PURE__ */ new Map();
2706
2786
  for (const run of runs) {
@@ -2978,10 +3058,12 @@ function ScheduleOverview({
2978
3058
  openSession,
2979
3059
  serverNow,
2980
3060
  archived,
2981
- presentIds
3061
+ presentIds,
3062
+ onToggleAutomation
2982
3063
  }) {
2983
3064
  const [sortKey, setSortKey] = (0, import_react7.useState)(() => readSortDefault(SORT_STORAGE2, OVERVIEW_SORT_DEFAULT_KEY)?.key ?? "planned");
2984
3065
  const [sortDirection, setSortDirection] = (0, import_react7.useState)(() => readSortDefault(SORT_STORAGE2, OVERVIEW_SORT_DEFAULT_KEY)?.direction ?? "asc");
3066
+ const [busyIds, setBusyIds] = (0, import_react7.useState)(() => /* @__PURE__ */ new Set());
2985
3067
  const now = (0, import_react7.useMemo)(() => new Date(serverNow ?? Date.now()), [serverNow]);
2986
3068
  const rows = (0, import_react7.useMemo)(() => {
2987
3069
  const sorted = sortAutomations(automations, sortKey, sortDirection);
@@ -2994,6 +3076,19 @@ function ScheduleOverview({
2994
3076
  });
2995
3077
  }, [archived, automations, presentIds, runs, sortDirection, sortKey]);
2996
3078
  const scheduleSummaries = (0, import_react7.useMemo)(() => new Map(automations.map((item) => [item.id, formatSchedule(item.schedule, t)])), [automations, t]);
3079
+ const toggleAutomation = (automationId, mutation) => {
3080
+ if (onToggleAutomation === void 0 || busyIds.has(automationId)) return;
3081
+ setBusyIds((current) => new Set(current).add(automationId));
3082
+ void Promise.resolve(onToggleAutomation(automationId, mutation)).catch((error) => {
3083
+ console.warn("[dsh-automation] \u5207\u6362\u4EFB\u52A1\u72B6\u6001\u5931\u8D25", error);
3084
+ }).finally(() => {
3085
+ setBusyIds((current) => {
3086
+ const next = new Set(current);
3087
+ next.delete(automationId);
3088
+ return next;
3089
+ });
3090
+ });
3091
+ };
2997
3092
  return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview", children: [
2998
3093
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview-head", children: [
2999
3094
  /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "dsh-st-overview-title", children: [
@@ -3018,7 +3113,19 @@ function ScheduleOverview({
3018
3113
  }
3019
3114
  )
3020
3115
  ] }),
3021
- 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))
3116
+ 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)(
3117
+ OverviewRow,
3118
+ {
3119
+ t,
3120
+ row,
3121
+ now,
3122
+ scheduleSummary: scheduleSummaries.get(row.id) ?? "",
3123
+ toggleDisabled: onToggleAutomation === void 0 || busyIds.has(row.id),
3124
+ onToggleAutomation: toggleAutomation,
3125
+ ...openSession === void 0 ? {} : { openSession }
3126
+ },
3127
+ row.id
3128
+ ))
3022
3129
  ] });
3023
3130
  }
3024
3131
  function OverviewRow({
@@ -3026,41 +3133,57 @@ function OverviewRow({
3026
3133
  row,
3027
3134
  now,
3028
3135
  scheduleSummary,
3029
- openSession
3136
+ openSession,
3137
+ toggleDisabled,
3138
+ onToggleAutomation
3030
3139
  }) {
3031
3140
  const paused = row.status !== "active";
3032
3141
  const nextRun = row.nextRunAt === void 0 ? t("stats.noneScheduled") : formatWithin(row.nextRunAt, now, t);
3033
- const status = paused ? t("status.paused") : t("status.active");
3034
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3035
- "button",
3036
- {
3037
- type: "button",
3038
- className: `dsh-st-overview-row${paused ? " is-paused" : ""}`,
3039
- disabled: row.lastSessionId === void 0,
3040
- title: paused ? t("status.paused") : t("status.active"),
3041
- onClick: () => {
3042
- if (row.lastSessionId !== void 0) openSession?.(row.lastSessionId);
3043
- },
3044
- children: [
3045
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-copy", children: [
3046
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-status", children: [
3047
- paused ? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(PauseIcon, { width: 14, height: 14 }) : /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CheckIcon, { width: 14, height: 14 }),
3048
- status
3142
+ const toggleLabel = paused ? t("card.resume") : t("card.pause");
3143
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: `dsh-st-overview-row${paused ? " is-paused" : ""}`, children: [
3144
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
3145
+ "button",
3146
+ {
3147
+ type: "button",
3148
+ className: "dsh-st-overview-open",
3149
+ disabled: row.lastSessionId === void 0,
3150
+ onClick: () => {
3151
+ if (row.lastSessionId !== void 0) openSession?.(row.lastSessionId);
3152
+ },
3153
+ children: [
3154
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-copy", children: [
3155
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-overview-name", children: row.name }),
3156
+ scheduleSummary !== "" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-schedule", children: [
3157
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CalendarIcon, { width: 14, height: 14 }),
3158
+ scheduleSummary
3159
+ ] })
3049
3160
  ] }),
3050
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "dsh-st-overview-name", children: row.name }),
3051
- scheduleSummary !== "" && /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-schedule", children: [
3052
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(CalendarIcon, { width: 14, height: 14 }),
3053
- scheduleSummary
3054
- ] })
3055
- ] }),
3056
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-next", children: [
3057
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: t("stats.next") }),
3058
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: nextRun })
3059
- ] }),
3060
- row.lastSessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChevronIcon, { width: 12, height: 12, className: "dsh-st-overview-chevron" })
3061
- ]
3062
- }
3063
- );
3161
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { className: "dsh-st-overview-next", children: [
3162
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { children: t("stats.next") }),
3163
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("strong", { children: nextRun })
3164
+ ] }),
3165
+ row.lastSessionId !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(ChevronIcon, { width: 12, height: 12, className: "dsh-st-overview-chevron" })
3166
+ ]
3167
+ }
3168
+ ),
3169
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("label", { className: "dsh-st-overview-toggle", title: toggleLabel, children: [
3170
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
3171
+ "input",
3172
+ {
3173
+ type: "checkbox",
3174
+ role: "switch",
3175
+ checked: !paused,
3176
+ "aria-checked": !paused,
3177
+ "aria-label": toggleLabel,
3178
+ disabled: toggleDisabled,
3179
+ onChange: () => {
3180
+ onToggleAutomation?.(row.id, automationToggleMutation(row.status));
3181
+ }
3182
+ }
3183
+ ),
3184
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { "aria-hidden": "true" })
3185
+ ] })
3186
+ ] });
3064
3187
  }
3065
3188
 
3066
3189
  // src/client/workspace-toolbar.tsx
@@ -3242,6 +3365,7 @@ function NativeScheduleSessionList(props) {
3242
3365
  t,
3243
3366
  automations: state.snapshot.automations,
3244
3367
  runs: state.snapshot.runs,
3368
+ onToggleAutomation: (automationId, mutation) => runtime.mutateAutomation(automationId, mutation),
3245
3369
  ...openSession === void 0 ? {} : { openSession },
3246
3370
  ...state.snapshot.serverNow === void 0 ? {} : { serverNow: state.snapshot.serverNow },
3247
3371
  archived,
@@ -3584,6 +3708,7 @@ function ScheduleRail({
3584
3708
  t,
3585
3709
  automations: snapshot.automations,
3586
3710
  runs: snapshot.runs,
3711
+ onToggleAutomation: (automationId, mutation) => runtime.mutateAutomation(automationId, mutation),
3587
3712
  ...openSession === void 0 ? {} : { openSession },
3588
3713
  ...snapshot.serverNow === void 0 ? {} : { serverNow: snapshot.serverNow }
3589
3714
  }
@@ -3924,19 +4049,26 @@ var CSS_TEXT = `
3924
4049
  .dsh-st-overview-title strong{font-size:14px;font-weight:400;line-height:20px}
3925
4050
  .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}
3926
4051
  .dsh-st-overview-sort{display:flex;align-items:center}
3927
- .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}
3928
- .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))}
3929
- .dsh-st-overview-row:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4c8dff);outline-offset:2px}
3930
- .dsh-st-overview-row:disabled{cursor:default}
3931
- .dsh-st-overview-copy{display:flex;flex:1;min-width:0;flex-direction:column;gap:4px}
3932
- .dsh-st-overview-name{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:18px;font-weight:580}
3933
- .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}
3934
- .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)}
3935
- .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}
3936
- .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}
4052
+ .dsh-st-overview-row{position:relative;width:100%;min-height:56px;margin:0 0 8px;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);box-shadow:inset 0 1px rgba(255,255,255,.025);transition:background .14s ease,border-color .14s ease;overflow:hidden}
4053
+ .dsh-st-overview-row:hover{border-color:var(--dsw-alias-border-inverted,rgba(255,255,255,.18));background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.06))}
4054
+ .dsh-st-overview-open{display:grid;grid-template-columns:minmax(0,1fr) auto 12px;grid-template-rows:18px 18px;align-items:center;gap:4px 8px;width:100%;min-height:56px;padding:8px 9px;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}
4055
+ .dsh-st-overview-open:focus-visible{outline:2px solid var(--dsw-alias-state-business-primary,#4c8dff);outline-offset:-2px}
4056
+ .dsh-st-overview-open:disabled{cursor:default}
4057
+ .dsh-st-overview-copy{display:contents}
4058
+ .dsh-st-overview-name{box-sizing:border-box;grid-column:1/4;grid-row:1;min-width:0;padding-right:44px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;line-height:18px;font-weight:580}
4059
+ .dsh-st-overview-schedule{display:inline-flex;grid-column:1;grid-row:2;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}
4060
+ .dsh-st-overview-next{display:inline-flex;grid-column:2;grid-row:2;flex:none;min-width:0;flex-direction:row;align-items:baseline;gap:4px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:10px;line-height:14px;white-space:nowrap}
3937
4061
  .dsh-st-overview-next strong{color:var(--dsw-alias-label-secondary,#b6bac2);font-size:12px;font-weight:600;line-height:16px;white-space:nowrap}
3938
4062
  .dsh-st-overview-row:not(.is-paused) .dsh-st-overview-next strong{color:#45d483}
3939
- .dsh-st-overview-chevron{flex:none;color:var(--dsw-alias-label-tertiary,#8b8f98)}
4063
+ .dsh-st-overview-chevron{grid-column:3;grid-row:2;flex:none;color:var(--dsw-alias-label-tertiary,#8b8f98)}
4064
+ .dsh-st-overview-toggle{position:absolute;top:3px;right:2px;z-index:1;display:inline-flex;align-items:center;justify-content:center;width:44px;height:28px;cursor:pointer}
4065
+ .dsh-st-overview-toggle input{position:absolute;width:1px;height:1px;opacity:0;pointer-events:none}
4066
+ .dsh-st-overview-toggle>span{position:relative;width:28px;height:16px;border-radius:999px;background:var(--dsw-alias-bg-layer-3,rgba(255,255,255,.14));box-shadow:inset 0 0 0 1px var(--dsw-alias-border-l2,rgba(255,255,255,.12));transition:background .14s ease}
4067
+ .dsh-st-overview-toggle>span::after{position:absolute;top:2px;left:2px;width:12px;height:12px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.32);content:"";transition:transform .14s ease}
4068
+ .dsh-st-overview-toggle input:checked+span{background:#32cd8f;box-shadow:none}
4069
+ .dsh-st-overview-toggle input:checked+span::after{transform:translateX(12px)}
4070
+ .dsh-st-overview-toggle input:focus-visible+span{outline:2px solid var(--dsw-alias-state-business-primary,#4c8dff);outline-offset:2px}
4071
+ .dsh-st-overview-toggle:has(input:disabled){cursor:wait;opacity:.62}
3940
4072
  .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}
3941
4073
  .dsh-st-rail-empty{padding:16px 10px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px}
3942
4074
  .dsh-st-rail-group{margin:0 0 8px}
@@ -3957,6 +4089,7 @@ var CSS_TEXT = `
3957
4089
  .dsh-st-rail-head.is-static{cursor:default;font-weight:600}
3958
4090
  .dsh-st-rail-session.is-on{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
3959
4091
  .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}
4092
+ .dsh-st-n-row{padding-left:8px}
3960
4093
  .dsh-st-n-row.is-menu{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
3961
4094
  .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)}
3962
4095
  .dsh-st-n-row[aria-expanded="true"].has-current-session .dsh-st-n-folder{color:var(--dsw-static-deepseek-450,#4c8dff)}
@@ -4102,6 +4235,7 @@ function apply(ctx) {
4102
4235
  const permissionT = ctx.locale.bind("permission.access");
4103
4236
  const modelT = ctx.locale.bind("model");
4104
4237
  const runtime = createAutomationRuntime(ctx.connection.rpc);
4238
+ ctx.effect(() => installAutomationSessionSync(runtime, () => ctx.sessions), "dsh-automation: session sync");
4105
4239
  ctx.effect(() => installSettingsNavIcon(() => [t("tab"), "Scheduled tasks", "\u5B9A\u65F6\u4EFB\u52A1"]), "dsh-automation: settings icon");
4106
4240
  ctx.slots.inject("settings.section", () => ctx.slots.register({
4107
4241
  name: "settings.section",