@michengai/dsh-automation 0.1.15 → 0.1.17

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,21 @@
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.17 — 2026-08-26
8
+
9
+ - Removed the redundant full-width divider below the scheduled-task tabs while retaining the active-tab underline.
10
+ - Matched the sorting control to Qianwen with a filled pill trigger, compact four-option menu, smaller arrow, and neutral selected state.
11
+
12
+ Published package: [`@michengai/dsh-automation@0.1.17`](https://www.npmjs.com/package/@michengai/dsh-automation/v/0.1.17).
13
+
14
+ ## 0.1.16 — 2026-08-26
15
+
16
+ - Added an Edit action to each scheduled-task card menu, reusing the existing task editor.
17
+ - Added a compact sorting dropdown for created time and planned time in ascending or descending order.
18
+ - Kept tasks without a next planned run at the end of the list and preserved created-time descending as the default.
19
+
20
+ Published package: [`@michengai/dsh-automation@0.1.16`](https://www.npmjs.com/package/@michengai/dsh-automation/v/0.1.16).
21
+
7
22
  ## 0.1.15 — 2026-08-26
8
23
 
9
24
  - Restored localized built-in permission labels in the scheduled-task composer instead of exposing missing `preset.*` translation keys.
@@ -24,15 +39,3 @@ Published package: [`@michengai/dsh-automation@0.1.14`](https://www.npmjs.com/pa
24
39
  - Logged internal RPC failures instead of leaving automation failures silent.
25
40
 
26
41
  Release commit: [`6f04ae9`](https://github.com/MichengAI/dsh-automation/commit/6f04ae9).
27
-
28
- ## 0.1.12 — 2026-08-23
29
-
30
- - Aligned automation permission behavior with interactive chat.
31
-
32
- Release commit: [`d116209`](https://github.com/MichengAI/dsh-automation/commit/d116209).
33
-
34
- ## 0.1.11 — 2026-08-23
35
-
36
- - Hardened automation safety checks and scheduling behavior.
37
-
38
- Release commit: [`1692ca6`](https://github.com/MichengAI/dsh-automation/commit/1692ca6).
@@ -4,6 +4,21 @@
4
4
 
5
5
  以下记录最近发布的五个版本。Git 标签与 GitHub Release 现已和这些条目同步;历史条目继续保留原始发布提交链接。
6
6
 
7
+ ## 0.1.17 — 2026-08-26
8
+
9
+ - 移除定时任务标签栏下方多余的整行分隔线,同时保留当前标签的短下划线。
10
+ - 参照千问重做排序控件,采用填充胶囊按钮、紧凑四选项菜单、更小的箭头和中性的选中状态。
11
+
12
+ 发布包:[`@michengai/dsh-automation@0.1.17`](https://www.npmjs.com/package/@michengai/dsh-automation/v/0.1.17)。
13
+
14
+ ## 0.1.16 — 2026-08-26
15
+
16
+ - 在每个定时任务卡片菜单中增加“编辑任务”,复用现有任务编辑器。
17
+ - 增加紧凑的排序下拉菜单,支持按创建时间或计划时间升序、倒序排列。
18
+ - 无下次计划时间的任务固定排在末尾,并继续以创建时间倒序作为默认值。
19
+
20
+ 发布包:[`@michengai/dsh-automation@0.1.16`](https://www.npmjs.com/package/@michengai/dsh-automation/v/0.1.16)。
21
+
7
22
  ## 0.1.15 — 2026-08-26
8
23
 
9
24
  - 恢复定时任务输入区内置权限预设的中文显示,不再暴露缺失的 `preset.*` 翻译键。
@@ -24,15 +39,3 @@
24
39
  - 记录内部 RPC 失败,避免自动化执行错误被静默吞掉。
25
40
 
26
41
  发布提交:[`6f04ae9`](https://github.com/MichengAI/dsh-automation/commit/6f04ae9)。
27
-
28
- ## 0.1.12 — 2026-08-23
29
-
30
- - 使自动化权限行为与交互式聊天保持一致。
31
-
32
- 发布提交:[`d116209`](https://github.com/MichengAI/dsh-automation/commit/d116209)。
33
-
34
- ## 0.1.11 — 2026-08-23
35
-
36
- - 加强自动化安全检查和调度行为。
37
-
38
- 发布提交:[`1692ca6`](https://github.com/MichengAI/dsh-automation/commit/1692ca6)。
package/lib/client.js CHANGED
@@ -187,6 +187,31 @@ function clockTime(iso) {
187
187
  if (Number.isNaN(value.getTime())) return iso;
188
188
  return value.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
189
189
  }
190
+ function sortStamp(value) {
191
+ const parsed = Date.parse(value);
192
+ return Number.isFinite(parsed) ? parsed : 0;
193
+ }
194
+ function sortAutomations(items, key, direction) {
195
+ const factor = direction === "asc" ? 1 : -1;
196
+ return items.slice().sort((left, right) => {
197
+ if (key === "planned") {
198
+ const leftNext = left.nextRunAt;
199
+ const rightNext = right.nextRunAt;
200
+ if (leftNext === void 0 || rightNext === void 0) {
201
+ if (leftNext === void 0 && rightNext === void 0) {
202
+ return left.name.localeCompare(right.name) || left.id.localeCompare(right.id);
203
+ }
204
+ return leftNext === void 0 ? 1 : -1;
205
+ }
206
+ const primary2 = sortStamp(leftNext) - sortStamp(rightNext);
207
+ if (primary2 !== 0) return primary2 * factor;
208
+ return left.name.localeCompare(right.name) || left.id.localeCompare(right.id);
209
+ }
210
+ const primary = sortStamp(left.createdAt) - sortStamp(right.createdAt);
211
+ if (primary !== 0) return primary * factor;
212
+ return left.id.localeCompare(right.id);
213
+ });
214
+ }
190
215
  function groupHistory(runs, range, now, t) {
191
216
  const buckets = /* @__PURE__ */ new Map();
192
217
  for (const run of runs) {
@@ -274,7 +299,7 @@ function RefreshIcon(props) {
274
299
  ] });
275
300
  }
276
301
  function PlayIcon(props) {
277
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9 7 8 5-8 5V7Z" }) });
302
+ 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" }) });
278
303
  }
279
304
  function TrashIcon(props) {
280
305
  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" }) });
@@ -344,6 +369,9 @@ function FolderOpenIcon(props) {
344
369
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", opacity: "0.2", d: "M13.6602 7.75525C13.9618 7.7556 14.1815 8.04179 14.1045 8.33337L13.0508 12.3031C12.9304 12.7567 12.5191 13.0725 12.0498 13.0726H2.91701C2.23744 13.0725 1.7417 12.4287 1.91603 11.7719L2.77834 8.52478C2.89898 8.07146 3.31018 7.75532 3.77931 7.75525H13.6602ZM5.1963 2.95154C5.34985 2.95159 5.49377 3.02803 5.57912 3.15564L6.0508 3.86365C6.39205 4.37553 6.96685 4.68385 7.58205 4.68396H12.1699C12.7416 4.68396 13.2049 5.14754 13.2051 5.71912V6.37439H3.77931C3.02267 6.37444 2.33067 6.72671 1.88283 7.29333V3.98669C1.88299 3.4152 2.34649 2.95168 2.91798 2.95154H5.1963Z" })
345
370
  ] });
346
371
  }
372
+ function ChevronIcon(props) {
373
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 14 14", width: props.width || 14, height: props.height || 14, fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M4.25 2.828v8.344c0 .49.592.735.939.389l4.172-4.172a.55.55 0 0 0 0-.778L5.189 2.439c-.347-.347-.939-.101-.939.389Z" }) });
374
+ }
347
375
  function EllipsisIcon(props) {
348
376
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(FillIcon, { ...props, children: [
349
377
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M4.55146 8.00001C4.55146 8.63513 4.03659 9.15001 3.40146 9.15001C2.76634 9.15001 2.25146 8.63513 2.25146 8.00001C2.25146 7.36488 2.76634 6.85001 3.40146 6.85001C4.03659 6.85001 4.55146 7.36488 4.55146 8.00001Z" }),
@@ -1274,13 +1302,19 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1274
1302
  const [historyRange, setHistoryRange] = (0, import_react3.useState)("day");
1275
1303
  const [historyTask, setHistoryTask] = (0, import_react3.useState)("all");
1276
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");
1277
1307
  const now = (0, import_react3.useMemo)(() => new Date(state.snapshot?.serverNow ?? Date.now()), [state.snapshot?.serverNow, state.refreshedAt]);
1278
1308
  const snapshot = state.snapshot;
1279
1309
  const workspaces = snapshot?.workspaces ?? [];
1280
1310
  const models = snapshot?.models ?? [];
1281
1311
  const permissions = snapshot?.permissions ?? [];
1282
1312
  const defaultPermission = snapshot?.defaultPermission ?? "";
1283
- const automations = (snapshot?.automations ?? []).filter((item) => query.trim() === "" || `${item.name} ${item.prompt}`.toLowerCase().includes(query.trim().toLowerCase())).slice().sort((left, right) => Date.parse(right.createdAt) - Date.parse(left.createdAt));
1313
+ const automations = sortAutomations(
1314
+ (snapshot?.automations ?? []).filter((item) => query.trim() === "" || `${item.name} ${item.prompt}`.toLowerCase().includes(query.trim().toLowerCase())),
1315
+ sortKey,
1316
+ sortDirection
1317
+ );
1284
1318
  const runs = (snapshot?.runs ?? []).filter((run) => {
1285
1319
  if (historyTask !== "all" && run.automationId !== historyTask) return false;
1286
1320
  if (historyStatus !== "all" && run.status !== historyStatus) return false;
@@ -1381,7 +1415,18 @@ function AutomationView({ t, permissionT, modelT, runtime, closeSettings }) {
1381
1415
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-tabs", children: [
1382
1416
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: tab === "mine" ? "is-on" : "", onClick: () => setTab("mine"), children: t("tabs.mine") }),
1383
1417
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: tab === "runs" ? "is-on" : "", onClick: () => setTab("runs"), children: t("tabs.runs") }),
1384
- tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-st-sort", children: t("sort.created") }),
1418
+ tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1419
+ SortMenu,
1420
+ {
1421
+ t,
1422
+ sortKey,
1423
+ sortDirection,
1424
+ onSelect: (key, direction) => {
1425
+ setSortKey(key);
1426
+ setSortDirection(direction);
1427
+ }
1428
+ }
1429
+ ),
1385
1430
  tab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-filters", children: [
1386
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)),
1387
1432
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { value: historyTask, onChange: (event) => setHistoryTask(event.target.value), children: [
@@ -1484,20 +1529,27 @@ function TaskCard({
1484
1529
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-more", onClick: (event) => {
1485
1530
  event.stopPropagation();
1486
1531
  setMenu((value) => !value);
1487
- }, "aria-label": t("card.delete"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) }),
1532
+ }, "aria-label": t("card.more"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) }),
1488
1533
  menu && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-menu", onClick: (event) => event.stopPropagation(), children: [
1489
1534
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1490
1535
  setMenu(false);
1491
1536
  onRun();
1492
1537
  }, children: [
1493
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, {}),
1538
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, { width: 16, height: 16 }),
1494
1539
  t("menu.run")
1495
1540
  ] }),
1541
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1542
+ setMenu(false);
1543
+ onEdit();
1544
+ }, children: [
1545
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PencilIcon, { width: 16, height: 16 }),
1546
+ t("menu.edit")
1547
+ ] }),
1496
1548
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "is-danger", disabled: busy, onClick: () => {
1497
1549
  setMenu(false);
1498
1550
  onDelete();
1499
1551
  }, children: [
1500
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrashIcon, {}),
1552
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrashIcon, { width: 16, height: 16 }),
1501
1553
  t("menu.delete")
1502
1554
  ] })
1503
1555
  ] })
@@ -1513,6 +1565,65 @@ function TaskCard({
1513
1565
  ] })
1514
1566
  ] });
1515
1567
  }
1568
+ function SortMenu({
1569
+ t,
1570
+ sortKey,
1571
+ sortDirection,
1572
+ onSelect
1573
+ }) {
1574
+ const [open, setOpen] = (0, import_react3.useState)(false);
1575
+ const root = (0, import_react3.useRef)(null);
1576
+ (0, import_react3.useEffect)(() => {
1577
+ if (!open) return;
1578
+ const close = (event) => {
1579
+ if (root.current !== null && !root.current.contains(event.target)) setOpen(false);
1580
+ };
1581
+ const closeOnEscape = (event) => {
1582
+ if (event.key === "Escape") setOpen(false);
1583
+ };
1584
+ document.addEventListener("mousedown", close);
1585
+ document.addEventListener("keydown", closeOnEscape);
1586
+ return () => {
1587
+ document.removeEventListener("mousedown", close);
1588
+ document.removeEventListener("keydown", closeOnEscape);
1589
+ };
1590
+ }, [open]);
1591
+ const options = [
1592
+ { key: "created", direction: "desc", label: t("sort.created.desc") },
1593
+ { key: "created", direction: "asc", label: t("sort.created.asc") },
1594
+ { key: "planned", direction: "asc", label: t("sort.planned.asc") },
1595
+ { key: "planned", direction: "desc", label: t("sort.planned.desc") }
1596
+ ];
1597
+ const selectedLabel = options.find((option) => option.key === sortKey && option.direction === sortDirection)?.label ?? t("sort.by");
1598
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-sort", ref: root, children: [
1599
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: `dsh-st-sort-btn${open ? " is-open" : ""}`, "aria-label": t("sort.by"), "aria-expanded": open, onClick: () => setOpen((value) => !value), children: [
1600
+ selectedLabel,
1601
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChevronIcon, { width: 10, height: 10, className: "dsh-st-sort-chevron" })
1602
+ ] }),
1603
+ open && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-sort-menu", children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1604
+ SortRow,
1605
+ {
1606
+ label: option.label,
1607
+ selected: sortKey === option.key && sortDirection === option.direction,
1608
+ onSelect: () => {
1609
+ setOpen(false);
1610
+ onSelect(option.key, option.direction);
1611
+ }
1612
+ },
1613
+ `${option.key}-${option.direction}`
1614
+ )) })
1615
+ ] });
1616
+ }
1617
+ function SortRow({
1618
+ label,
1619
+ selected,
1620
+ onSelect
1621
+ }) {
1622
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", "aria-pressed": selected, className: selected ? "is-selected" : void 0, onClick: onSelect, children: [
1623
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: label }),
1624
+ selected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckOutlineIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-st-sort-tick" })
1625
+ ] });
1626
+ }
1516
1627
  function RunRow({ run, t }) {
1517
1628
  const duration = formatDuration(run.startedAt, run.finishedAt);
1518
1629
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("article", { className: `dsh-st-run is-${run.status}`, children: [
@@ -1561,7 +1672,8 @@ var en = {
1561
1672
  "examples.3.chip": "Weekdays 08:00",
1562
1673
  "chat.hint": "In any conversation, describe the recurring work and ask the Agent to call automation_create.",
1563
1674
  "chat.prompt": "I want to create a scheduled task that runs every [interval] and does [the actual task]",
1564
- "menu.run": "Run now",
1675
+ "menu.run": "Run task",
1676
+ "menu.edit": "Edit task",
1565
1677
  "menu.delete": "Delete task",
1566
1678
  "session.rename": "Rename",
1567
1679
  "session.fork": "Fork session",
@@ -1594,7 +1706,11 @@ var en = {
1594
1706
  "banner.wake": "Scheduled tasks run only while this computer stays awake.",
1595
1707
  "tabs.mine": "My tasks",
1596
1708
  "tabs.runs": "Run history",
1597
- "sort.created": "Newest first",
1709
+ "sort.by": "Sort",
1710
+ "sort.created.asc": "Created time ascending",
1711
+ "sort.created.desc": "Created time descending",
1712
+ "sort.planned.asc": "Planned time ascending",
1713
+ "sort.planned.desc": "Planned time descending",
1598
1714
  "form.workspace": "Workspace",
1599
1715
  "form.workspacePath": "Folder path",
1600
1716
  "form.workspacePathPlaceholder": "D:\\work\\project",
@@ -1698,6 +1814,7 @@ var en = {
1698
1814
  "card.pause": "Pause",
1699
1815
  "card.resume": "Resume",
1700
1816
  "card.runNow": "Run now",
1817
+ "card.more": "More actions",
1701
1818
  "card.delete": "Delete",
1702
1819
  "card.confirmDelete": "Delete this automation?",
1703
1820
  "card.confirmDeleteHint": "Run history is kept for audit.",
@@ -1755,7 +1872,8 @@ var zh = {
1755
1872
  "examples.3.chip": "\u5DE5\u4F5C\u65E5 08:00",
1756
1873
  "chat.hint": "\u5728\u4EFB\u610F\u5BF9\u8BDD\u4E2D\u63CF\u8FF0\u4F60\u60F3\u5B9A\u671F\u505A\u7684\u4E8B\uFF0C\u5E76\u8BA9 Agent \u8C03\u7528 automation_create\u3002",
1757
1874
  "chat.prompt": "\u6211\u8981\u521B\u5EFA\u4E00\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u6BCF\u3010\u65F6\u95F4\u95F4\u9694\u3011\u6267\u884C\u3010\u5177\u4F53\u4EFB\u52A1\u3011",
1758
- "menu.run": "\u7ACB\u5373\u6267\u884C",
1875
+ "menu.run": "\u6267\u884C\u4EFB\u52A1",
1876
+ "menu.edit": "\u7F16\u8F91\u4EFB\u52A1",
1759
1877
  "menu.delete": "\u5220\u9664\u4EFB\u52A1",
1760
1878
  "session.rename": "\u91CD\u547D\u540D",
1761
1879
  "session.fork": "\u5206\u53C9\u4F1A\u8BDD",
@@ -1788,7 +1906,11 @@ var zh = {
1788
1906
  "banner.wake": "\u5B9A\u65F6\u4EFB\u52A1\u4EC5\u5728\u7535\u8111\u4FDD\u6301\u5524\u9192\u65F6\u8FD0\u884C",
1789
1907
  "tabs.mine": "\u6211\u7684\u5B9A\u65F6\u4EFB\u52A1",
1790
1908
  "tabs.runs": "\u6267\u884C\u8BB0\u5F55",
1791
- "sort.created": "\u6309\u521B\u5EFA\u65F6\u95F4\u5012\u5E8F",
1909
+ "sort.by": "\u6392\u5E8F",
1910
+ "sort.created.asc": "\u6309\u521B\u5EFA\u65F6\u95F4\u5347\u5E8F",
1911
+ "sort.created.desc": "\u6309\u521B\u5EFA\u65F6\u95F4\u5012\u5E8F",
1912
+ "sort.planned.asc": "\u6309\u8BA1\u5212\u65F6\u95F4\u5347\u5E8F",
1913
+ "sort.planned.desc": "\u6309\u8BA1\u5212\u65F6\u95F4\u5012\u5E8F",
1792
1914
  "form.workspace": "\u5DE5\u4F5C\u76EE\u5F55",
1793
1915
  "form.workspacePath": "\u76EE\u5F55\u8DEF\u5F84",
1794
1916
  "form.workspacePathPlaceholder": "D:\\work\\project",
@@ -1892,6 +2014,7 @@ var zh = {
1892
2014
  "card.pause": "\u6682\u505C",
1893
2015
  "card.resume": "\u6062\u590D",
1894
2016
  "card.runNow": "\u7ACB\u5373\u8FD0\u884C",
2017
+ "card.more": "\u66F4\u591A\u64CD\u4F5C",
1895
2018
  "card.delete": "\u5220\u9664",
1896
2019
  "card.confirmDelete": "\u786E\u8BA4\u5220\u9664\u8FD9\u4E2A\u81EA\u52A8\u5316\uFF1F",
1897
2020
  "card.confirmDeleteHint": "\u8FD0\u884C\u5386\u53F2\u4F1A\u4FDD\u7559\u7528\u4E8E\u5BA1\u8BA1\u3002",
@@ -2876,10 +2999,18 @@ var CSS_TEXT = `
2876
2999
  .dsh-st-example:hover{border-color:rgba(75,124,255,.45)}
2877
3000
  .dsh-st-example strong{font-size:14px}
2878
3001
  .dsh-st-example p{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
2879
- .dsh-st-tabs{display:flex;align-items:center;gap:16px;margin:4px 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2)}
3002
+ .dsh-st-tabs{display:flex;align-items:center;gap:16px;margin:4px 0 16px}
2880
3003
  .dsh-st-tabs>button{padding:8px 0;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}
2881
3004
  .dsh-st-tabs>button.is-on{border-bottom-color:currentColor;color:var(--dsw-alias-label-primary);font-weight:650}
2882
- .dsh-st-sort{margin-left:auto;color:var(--dsw-alias-label-tertiary);font-size:12px}
3005
+ .dsh-st-sort{position:relative;margin-left:auto}
3006
+ .dsh-st-sort-btn{display:inline-flex;align-items:center;gap:4px;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}
3007
+ .dsh-st-sort-btn:hover,.dsh-st-sort-btn.is-open{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.18))}
3008
+ .dsh-st-sort-chevron{transition:transform .16s ease;transform:rotate(90deg)}
3009
+ .dsh-st-sort-btn.is-open .dsh-st-sort-chevron{transform:rotate(-90deg)}
3010
+ .dsh-st-sort-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:30;width:180px;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))}
3011
+ .dsh-st-sort-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}
3012
+ .dsh-st-sort-menu button:hover,.dsh-st-sort-menu button.is-selected{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.08));color:var(--dsw-alias-label-primary,inherit)}
3013
+ .dsh-st-sort-tick{width:16px;height:16px;flex:none}
2883
3014
  .dsh-st-filters{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-left:auto}
2884
3015
  .dsh-st-filters>button,.dsh-st-filters>select{height:28px;padding:0 10px;border:0;border-radius:999px;background:rgba(255,255,255,.06);color:inherit;font-size:12px}
2885
3016
  .dsh-st-filters>button.is-on{background:rgba(255,255,255,.14)}
@@ -2895,6 +3026,7 @@ var CSS_TEXT = `
2895
3026
  .dsh-st-more{width:28px;height:28px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer}
2896
3027
  .dsh-st-menu{position:absolute;top:40px;right:12px;z-index:3;min-width:148px;padding:6px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-base);box-shadow:0 10px 30px rgba(0,0,0,.28)}
2897
3028
  .dsh-st-menu button{display:flex;width:100%;align-items:center;gap:8px;padding:8px 10px;border:0;border-radius:8px;background:transparent;color:inherit;cursor:pointer}
3029
+ .dsh-st-menu button svg{flex:none}
2898
3030
  .dsh-st-menu button:hover{background:rgba(255,255,255,.06)}
2899
3031
  .dsh-st-menu .is-danger{color:#ff6b6b}
2900
3032
  .dsh-st-timeline{display:flex;flex-direction:column;gap:22px;padding-left:10px}