@michengai/dsh-automation 0.1.27 → 0.1.29
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 +11 -0
- package/CHANGELOG.zh-CN.md +11 -0
- package/lib/client.js +59 -7
- package/lib/client.js.map +2 -2
- package/lib/index.js +63 -9
- package/lib/types/client/schedule-rail-model.d.ts +1 -0
- package/lib/types/recurrence.d.ts +2 -0
- package/lib/types/run-title.d.ts +2 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
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.29 — 2026-09-04
|
|
8
|
+
|
|
9
|
+
- Refreshed scheduled execution records immediately when the DSH page regains focus or becomes visible, avoiding stale history when Chromium throttles background-tab timers.
|
|
10
|
+
- Removed page-resume listeners after the final client subscriber disconnects.
|
|
11
|
+
|
|
12
|
+
## 0.1.28 — 2026-09-04
|
|
13
|
+
|
|
14
|
+
- Compared normalized schedules semantically so property order no longer makes an unchanged overdue one-time schedule look edited.
|
|
15
|
+
- Formatted scheduled-session and execution-record titles in the task's IANA time zone. Host-local fallback formatting now follows the runtime time zone dynamically.
|
|
16
|
+
- Clarified that the unattended tool guard is layered on top of the selected permission preset, and ignored the repository-local pnpm store.
|
|
17
|
+
|
|
7
18
|
## 0.1.27 — 2026-09-03
|
|
8
19
|
|
|
9
20
|
- Fixed the scheduled execution-record list staying empty after a run until the sidebar was switched several times. New runs now stay visible even when the Host session index has not caught up yet, the snapshot refreshes immediately when the open session is a scheduled run, and polling speeds up while a run is queued or running.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,17 @@
|
|
|
4
4
|
|
|
5
5
|
以下记录最近发布的五个版本。Git 标签与 GitHub Release 现已和这些条目同步;历史条目继续保留原始发布提交链接。
|
|
6
6
|
|
|
7
|
+
## 0.1.29 — 2026-09-04
|
|
8
|
+
|
|
9
|
+
- DSH 页面重新获得焦点或恢复可见时立即刷新定时任务执行记录,避免 Chromium 节流后台标签页计时器后侧栏历史停留在旧状态。
|
|
10
|
+
- 最后一个客户端订阅释放后同步移除页面恢复监听,避免遗留无效监听器。
|
|
11
|
+
|
|
12
|
+
## 0.1.28 — 2026-09-04
|
|
13
|
+
|
|
14
|
+
- 改用语义方式比较规范化计划,避免属性顺序不同导致未变更的过期单次计划被误判为已编辑。
|
|
15
|
+
- 定时会话与执行记录标题按任务的 IANA 时区显示;未指定时区时的宿主本地 fallback 会动态跟随运行时区。
|
|
16
|
+
- 明确无人值守工具守卫叠加于所选权限预设之上,并忽略仓库本地 pnpm 存储目录。
|
|
17
|
+
|
|
7
18
|
## 0.1.27 — 2026-09-03
|
|
8
19
|
|
|
9
20
|
- 修复定时任务已经执行、但侧栏执行记录要多次切换后才出现的问题。宿主会话簿尚未收录时仍显示新记录,当前打开的若是定时会话会立即刷新快照,排队或执行中时加快轮询。
|
package/lib/client.js
CHANGED
|
@@ -1386,6 +1386,7 @@ function createAutomationRuntime(rpc) {
|
|
|
1386
1386
|
let state = { phase: "idle" };
|
|
1387
1387
|
let refreshPromise;
|
|
1388
1388
|
let pollTimer;
|
|
1389
|
+
let removePageResumeListeners = () => void 0;
|
|
1389
1390
|
const listeners2 = /* @__PURE__ */ new Set();
|
|
1390
1391
|
const armPoll = () => {
|
|
1391
1392
|
if (pollTimer !== void 0) clearInterval(pollTimer);
|
|
@@ -1397,6 +1398,23 @@ function createAutomationRuntime(rpc) {
|
|
|
1397
1398
|
void refresh().catch(() => void 0);
|
|
1398
1399
|
}, snapshotPollIntervalMs(state.snapshot?.runs));
|
|
1399
1400
|
};
|
|
1401
|
+
const armPageResumeListeners = () => {
|
|
1402
|
+
removePageResumeListeners();
|
|
1403
|
+
if (listeners2.size === 0) return;
|
|
1404
|
+
const refreshOnResume = () => {
|
|
1405
|
+
void refresh().catch(() => void 0);
|
|
1406
|
+
};
|
|
1407
|
+
const refreshOnVisible = () => {
|
|
1408
|
+
if (document.visibilityState === "visible") refreshOnResume();
|
|
1409
|
+
};
|
|
1410
|
+
if (typeof window !== "undefined") window.addEventListener("focus", refreshOnResume);
|
|
1411
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", refreshOnVisible);
|
|
1412
|
+
removePageResumeListeners = () => {
|
|
1413
|
+
if (typeof window !== "undefined") window.removeEventListener("focus", refreshOnResume);
|
|
1414
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", refreshOnVisible);
|
|
1415
|
+
removePageResumeListeners = () => void 0;
|
|
1416
|
+
};
|
|
1417
|
+
};
|
|
1400
1418
|
const publish = (next) => {
|
|
1401
1419
|
const previousInterval = snapshotPollIntervalMs(state.snapshot?.runs);
|
|
1402
1420
|
state = next;
|
|
@@ -1412,6 +1430,7 @@ function createAutomationRuntime(rpc) {
|
|
|
1412
1430
|
if (listeners2.size > 0) void refresh().catch(() => void 0);
|
|
1413
1431
|
});
|
|
1414
1432
|
armPoll();
|
|
1433
|
+
armPageResumeListeners();
|
|
1415
1434
|
}
|
|
1416
1435
|
return () => {
|
|
1417
1436
|
listeners2.delete(listener);
|
|
@@ -1419,6 +1438,7 @@ function createAutomationRuntime(rpc) {
|
|
|
1419
1438
|
clearInterval(pollTimer);
|
|
1420
1439
|
pollTimer = void 0;
|
|
1421
1440
|
}
|
|
1441
|
+
if (listeners2.size === 0) removePageResumeListeners();
|
|
1422
1442
|
};
|
|
1423
1443
|
}
|
|
1424
1444
|
};
|
|
@@ -2605,12 +2625,39 @@ async function archiveScheduledGroup(sessionIds, archiveSession) {
|
|
|
2605
2625
|
}
|
|
2606
2626
|
|
|
2607
2627
|
// src/run-title.ts
|
|
2608
|
-
|
|
2628
|
+
var RUN_STAMP_OPTIONS = {
|
|
2629
|
+
year: "numeric",
|
|
2630
|
+
month: "2-digit",
|
|
2631
|
+
day: "2-digit",
|
|
2632
|
+
hour: "2-digit",
|
|
2633
|
+
minute: "2-digit",
|
|
2634
|
+
hourCycle: "h23"
|
|
2635
|
+
};
|
|
2636
|
+
var zonedRunStampFormatters = /* @__PURE__ */ new Map();
|
|
2637
|
+
function runStampFormatter(timeZone) {
|
|
2638
|
+
const cached = zonedRunStampFormatters.get(timeZone);
|
|
2639
|
+
if (cached !== void 0) return cached;
|
|
2640
|
+
const formatter = new Intl.DateTimeFormat("en-CA", { ...RUN_STAMP_OPTIONS, timeZone });
|
|
2641
|
+
zonedRunStampFormatters.set(timeZone, formatter);
|
|
2642
|
+
return formatter;
|
|
2643
|
+
}
|
|
2644
|
+
function formatRunStamp(iso, timeZone) {
|
|
2609
2645
|
const value = new Date(iso);
|
|
2610
2646
|
if (Number.isNaN(value.getTime())) return iso;
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2647
|
+
if (timeZone === void 0) {
|
|
2648
|
+
const date = `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, "0")}-${String(value.getDate()).padStart(2, "0")}`;
|
|
2649
|
+
const time = `${String(value.getHours()).padStart(2, "0")}:${String(value.getMinutes()).padStart(2, "0")}`;
|
|
2650
|
+
return `${date} ${time}`;
|
|
2651
|
+
}
|
|
2652
|
+
try {
|
|
2653
|
+
const parts = runStampFormatter(timeZone).formatToParts(value);
|
|
2654
|
+
const part = (type) => parts.find((item) => item.type === type)?.value;
|
|
2655
|
+
const [year, month, day, hour, minute] = ["year", "month", "day", "hour", "minute"].map((type) => part(type));
|
|
2656
|
+
if ([year, month, day, hour, minute].some((item) => item === void 0)) return iso;
|
|
2657
|
+
return `${year}-${month}-${day} ${hour}:${minute}`;
|
|
2658
|
+
} catch {
|
|
2659
|
+
return iso;
|
|
2660
|
+
}
|
|
2614
2661
|
}
|
|
2615
2662
|
|
|
2616
2663
|
// src/client/schedule-rail-model.ts
|
|
@@ -2618,7 +2665,11 @@ var AUTOMATION_SESSION_PREFIX = "dsh-automation-session-";
|
|
|
2618
2665
|
var NATIVE_SIDEBAR_TAB_KEY = "dsh-automation.sidebar-tab";
|
|
2619
2666
|
function groupScheduledSessions(automations, runs) {
|
|
2620
2667
|
const nameById = /* @__PURE__ */ new Map();
|
|
2621
|
-
|
|
2668
|
+
const timeZoneById = /* @__PURE__ */ new Map();
|
|
2669
|
+
for (const item of automations) {
|
|
2670
|
+
nameById.set(item.id, item.name);
|
|
2671
|
+
if (item.timeZone !== void 0) timeZoneById.set(item.id, item.timeZone);
|
|
2672
|
+
}
|
|
2622
2673
|
for (const run of runs) {
|
|
2623
2674
|
const stored = (run.automationName || "").trim();
|
|
2624
2675
|
if (stored !== "" && stored !== run.automationId && !nameById.has(run.automationId)) {
|
|
@@ -2645,7 +2696,7 @@ function groupScheduledSessions(automations, runs) {
|
|
|
2645
2696
|
sessions: runs.filter((run) => run.automationId === id && run.sessionId !== void 0 && run.sessionId !== "").slice().sort((left, right) => Date.parse(right.startedAt ?? right.scheduledFor) - Date.parse(left.startedAt ?? left.scheduledFor)).map((run) => ({
|
|
2646
2697
|
id: run.sessionId,
|
|
2647
2698
|
running: run.status === "running" || run.status === "queued",
|
|
2648
|
-
label: formatRunStamp(run.startedAt ?? run.scheduledFor) + " - " + name2
|
|
2699
|
+
label: formatRunStamp(run.startedAt ?? run.scheduledFor, timeZoneById.get(id)) + " - " + name2
|
|
2649
2700
|
}))
|
|
2650
2701
|
};
|
|
2651
2702
|
}).filter((group) => group.sessions.length > 0);
|
|
@@ -3133,13 +3184,14 @@ function NativeScheduleSessionList(props) {
|
|
|
3133
3184
|
const groups = (0, import_react9.useMemo)(() => {
|
|
3134
3185
|
const snapshot = state.snapshot;
|
|
3135
3186
|
if (snapshot === void 0) return [];
|
|
3187
|
+
const timeZoneById = new Map(snapshot.automations.map((item) => [item.id, item.timeZone]));
|
|
3136
3188
|
return groupScheduledSessions(snapshot.automations, snapshot.runs).map((group) => ({
|
|
3137
3189
|
...group,
|
|
3138
3190
|
sessions: group.sessions.filter((session) => keepScheduledSessionLink(session.id, archived, presentIds)).map((session) => {
|
|
3139
3191
|
const run = snapshot.runs.find((item) => item.sessionId === session.id);
|
|
3140
3192
|
return {
|
|
3141
3193
|
...session,
|
|
3142
|
-
title: formatRunStamp(run && (run.startedAt || run.scheduledFor) || ""),
|
|
3194
|
+
title: formatRunStamp(run && (run.startedAt || run.scheduledFor) || "", timeZoneById.get(group.id)),
|
|
3143
3195
|
updatedAt: run && (run.startedAt || run.scheduledFor) || "",
|
|
3144
3196
|
running: session.running || sessionById[session.id]?.running === true
|
|
3145
3197
|
};
|