@michengai/dsh-automation 0.1.26 → 0.1.28
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 -2
- package/CHANGELOG.zh-CN.md +11 -2
- package/lib/client.js +84 -14
- package/lib/client.js.map +2 -2
- package/lib/index.js +63 -9
- package/lib/types/client/runtime.d.ts +3 -0
- package/lib/types/client/schedule-rail-model.d.ts +7 -2
- package/lib/types/recurrence.d.ts +2 -0
- package/lib/types/run-title.d.ts +2 -2
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -15,15 +15,42 @@ import { setApprovalPolicy } from "@deepseek-ai/dsh-user-approval";
|
|
|
15
15
|
import { WorkspaceId } from "@deepseek-ai/dsh-workspace";
|
|
16
16
|
|
|
17
17
|
// src/run-title.ts
|
|
18
|
-
|
|
18
|
+
var RUN_STAMP_OPTIONS = {
|
|
19
|
+
year: "numeric",
|
|
20
|
+
month: "2-digit",
|
|
21
|
+
day: "2-digit",
|
|
22
|
+
hour: "2-digit",
|
|
23
|
+
minute: "2-digit",
|
|
24
|
+
hourCycle: "h23"
|
|
25
|
+
};
|
|
26
|
+
var zonedRunStampFormatters = /* @__PURE__ */ new Map();
|
|
27
|
+
function runStampFormatter(timeZone2) {
|
|
28
|
+
const cached2 = zonedRunStampFormatters.get(timeZone2);
|
|
29
|
+
if (cached2 !== void 0) return cached2;
|
|
30
|
+
const formatter = new Intl.DateTimeFormat("en-CA", { ...RUN_STAMP_OPTIONS, timeZone: timeZone2 });
|
|
31
|
+
zonedRunStampFormatters.set(timeZone2, formatter);
|
|
32
|
+
return formatter;
|
|
33
|
+
}
|
|
34
|
+
function formatRunStamp(iso, timeZone2) {
|
|
19
35
|
const value = new Date(iso);
|
|
20
36
|
if (Number.isNaN(value.getTime())) return iso;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
if (timeZone2 === void 0) {
|
|
38
|
+
const date5 = `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, "0")}-${String(value.getDate()).padStart(2, "0")}`;
|
|
39
|
+
const time3 = `${String(value.getHours()).padStart(2, "0")}:${String(value.getMinutes()).padStart(2, "0")}`;
|
|
40
|
+
return `${date5} ${time3}`;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const parts = runStampFormatter(timeZone2).formatToParts(value);
|
|
44
|
+
const part = (type) => parts.find((item) => item.type === type)?.value;
|
|
45
|
+
const [year, month, day, hour, minute] = ["year", "month", "day", "hour", "minute"].map((type) => part(type));
|
|
46
|
+
if ([year, month, day, hour, minute].some((item) => item === void 0)) return iso;
|
|
47
|
+
return `${year}-${month}-${day} ${hour}:${minute}`;
|
|
48
|
+
} catch {
|
|
49
|
+
return iso;
|
|
50
|
+
}
|
|
24
51
|
}
|
|
25
|
-
function automationSessionTitle(taskName, iso) {
|
|
26
|
-
return `${formatRunStamp(iso)} - ${taskName}`;
|
|
52
|
+
function automationSessionTitle(taskName, iso, timeZone2) {
|
|
53
|
+
return `${formatRunStamp(iso, timeZone2)} - ${taskName}`;
|
|
27
54
|
}
|
|
28
55
|
|
|
29
56
|
// src/executor.ts
|
|
@@ -151,7 +178,11 @@ async function executeAutomationRun(ctx, definition, run, config2) {
|
|
|
151
178
|
}));
|
|
152
179
|
await handle.agent.whenIdle();
|
|
153
180
|
await workspace.attachSession(sessionId);
|
|
154
|
-
pinAutomationSessionTitle(ctx, handle.agent.session, automationSessionTitle(
|
|
181
|
+
pinAutomationSessionTitle(ctx, handle.agent.session, automationSessionTitle(
|
|
182
|
+
definition.name,
|
|
183
|
+
run.startedAt ?? run.scheduledFor,
|
|
184
|
+
definition.timeZone
|
|
185
|
+
));
|
|
155
186
|
const firstSeq = handle.agent.session.seq;
|
|
156
187
|
handle.agent.followup(createUserMessage({
|
|
157
188
|
content: [{ type: "text", text: run.promptSnapshot }],
|
|
@@ -273,7 +304,7 @@ var AUTOMATION_CREATE_DESCRIPTION = [
|
|
|
273
304
|
"\u4E3A\u5F53\u524D\u5DE5\u4F5C\u533A\u521B\u5EFA\u4E00\u6761\u72EC\u7ACB DSH \u81EA\u52A8\u5316\uFF1B\u6BCF\u6B21\u89E6\u53D1\u5F00\u542F\u5168\u65B0 Session\uFF0C\u4E0D\u7EE7\u627F\u5F53\u524D\u5BF9\u8BDD\u3002",
|
|
274
305
|
'\u5DE5\u4F5C\u65E5\u65E9\u4E0A 8 \u70B9\u793A\u4F8B\uFF1Akind=weekly, weekdays=["MO","TU","WE","TH","FR"], time="08:00", time_zone="Asia/Shanghai"\u3002',
|
|
275
306
|
"\u540C\u65F6\u652F\u6301 hourly(minute)\u3001monthly(month_day + time) \u548C custom(every_days + time)\u3002",
|
|
276
|
-
"\u5FC5\u987B\u4F7F\u7528\u663E\u5F0F IANA \u65F6\u533A\u3002\u6700\u77ED\u95F4\u9694 5 \u5206\u949F\u3002\u9ED8\u8BA4\
|
|
307
|
+
"\u5FC5\u987B\u4F7F\u7528\u663E\u5F0F IANA \u65F6\u533A\u3002\u6700\u77ED\u95F4\u9694 5 \u5206\u949F\u3002\u9ED8\u8BA4\u6743\u9650\u6765\u81EA Host\uFF1B\u4E0D\u9700\u8981\u5199\u5165\u65F6\u5E94\u663E\u5F0F\u9009\u62E9 read-only\uFF0C\u53EA\u6709\u9700\u8981\u6539\u6587\u4EF6\u65F6\u624D\u9009 workspace-write\u3002"
|
|
277
308
|
].join("");
|
|
278
309
|
|
|
279
310
|
// src/service.ts
|
|
@@ -21364,6 +21395,29 @@ function normalizeSchedule(schedule) {
|
|
|
21364
21395
|
const selected = new Set(schedule.weekdays);
|
|
21365
21396
|
return { ...schedule, weekdays: WEEKDAY_ORDER.filter((day) => selected.has(day)) };
|
|
21366
21397
|
}
|
|
21398
|
+
function isEqualSchedule(left, right) {
|
|
21399
|
+
const normalizedLeft = normalizeSchedule(left);
|
|
21400
|
+
const normalizedRight = normalizeSchedule(right);
|
|
21401
|
+
if (normalizedLeft.kind !== normalizedRight.kind || normalizedLeft.timeZone !== normalizedRight.timeZone) {
|
|
21402
|
+
return false;
|
|
21403
|
+
}
|
|
21404
|
+
switch (normalizedLeft.kind) {
|
|
21405
|
+
case "once":
|
|
21406
|
+
return normalizedRight.kind === "once" && normalizedLeft.at === normalizedRight.at;
|
|
21407
|
+
case "interval":
|
|
21408
|
+
return normalizedRight.kind === "interval" && normalizedLeft.everyMinutes === normalizedRight.everyMinutes && normalizedLeft.anchor === normalizedRight.anchor;
|
|
21409
|
+
case "hourly":
|
|
21410
|
+
return normalizedRight.kind === "hourly" && normalizedLeft.minute === normalizedRight.minute;
|
|
21411
|
+
case "daily":
|
|
21412
|
+
return normalizedRight.kind === "daily" && normalizedLeft.time === normalizedRight.time;
|
|
21413
|
+
case "weekly":
|
|
21414
|
+
return normalizedRight.kind === "weekly" && normalizedLeft.time === normalizedRight.time && normalizedLeft.weekdays.length === normalizedRight.weekdays.length && normalizedLeft.weekdays.every((day, index) => day === normalizedRight.weekdays[index]);
|
|
21415
|
+
case "monthly":
|
|
21416
|
+
return normalizedRight.kind === "monthly" && normalizedLeft.day === normalizedRight.day && normalizedLeft.time === normalizedRight.time;
|
|
21417
|
+
case "custom":
|
|
21418
|
+
return normalizedRight.kind === "custom" && normalizedLeft.everyDays === normalizedRight.everyDays && normalizedLeft.time === normalizedRight.time;
|
|
21419
|
+
}
|
|
21420
|
+
}
|
|
21367
21421
|
function scheduleToRRule(schedule) {
|
|
21368
21422
|
const normalized = normalizeSchedule(schedule);
|
|
21369
21423
|
if (normalized.kind === "once") {
|
|
@@ -21968,7 +22022,7 @@ var AutomationService = class _AutomationService {
|
|
|
21968
22022
|
normalizedFields = { ...normalizedFields, workspaceId: target.id, cwd: target.path };
|
|
21969
22023
|
}
|
|
21970
22024
|
try {
|
|
21971
|
-
const scheduleChanged = fields.schedule !== void 0 &&
|
|
22025
|
+
const scheduleChanged = fields.schedule !== void 0 && !isEqualSchedule(fields.schedule, current.schedule);
|
|
21972
22026
|
if (scheduleChanged && fields.schedule?.kind === "once" && nextOccurrence(fields.schedule, now2) === null) {
|
|
21973
22027
|
throw new AutomationRequestError("\u4E00\u6B21\u6027\u81EA\u52A8\u5316\u5FC5\u987B\u5B89\u6392\u5728\u672A\u6765\u65F6\u95F4\u3002");
|
|
21974
22028
|
}
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { ClientRpc } from './contracts.js';
|
|
2
2
|
import type { AutomationSnapshot, CreateAutomationInput, MutateRequest } from './protocol.js';
|
|
3
|
+
export declare function snapshotPollIntervalMs(runs: readonly {
|
|
4
|
+
readonly status: string;
|
|
5
|
+
}[] | undefined): number;
|
|
3
6
|
export declare function isTransportError(error: unknown): boolean;
|
|
4
7
|
export interface AutomationClientState {
|
|
5
8
|
readonly phase: 'idle' | 'loading' | 'ready' | 'error';
|
|
@@ -43,6 +43,7 @@ export declare function sessionUpdatedAtIso(value: number | string | undefined,
|
|
|
43
43
|
export declare function groupScheduledSessions(automations: readonly {
|
|
44
44
|
readonly id: string;
|
|
45
45
|
readonly name: string;
|
|
46
|
+
readonly timeZone?: string;
|
|
46
47
|
}[], runs: readonly ScheduleRunLike[]): ScheduleRailGroup[];
|
|
47
48
|
export interface OverviewAutomationLike {
|
|
48
49
|
readonly id: string;
|
|
@@ -59,8 +60,12 @@ export interface TaskOverviewRow {
|
|
|
59
60
|
}
|
|
60
61
|
/** 任务总览:每个定义一行;最近一次留有会话的运行决定该行是否可点开。 */
|
|
61
62
|
export declare function deriveTaskOverviewRows(automations: readonly OverviewAutomationLike[], runs: readonly ScheduleRunLike[]): TaskOverviewRow[];
|
|
62
|
-
/**
|
|
63
|
-
export declare function keepScheduledSessionLink(sessionId: string | undefined, archived: ReadonlySet<string>,
|
|
63
|
+
/** 归档立即摘掉。宿主会话簿经常晚于自动化快照,缺席不能当成已删除。 */
|
|
64
|
+
export declare function keepScheduledSessionLink(sessionId: string | undefined, archived: ReadonlySet<string>, _presentIds?: ReadonlySet<string>): boolean;
|
|
65
|
+
/** 当前打开的是定时会话,但快照还没有这条执行记录时,侧栏应立刻再拉一次。 */
|
|
66
|
+
export declare function scheduledSessionNeedsSnapshotRefresh(sessionId: string | null | undefined, runs: readonly {
|
|
67
|
+
readonly sessionId?: string;
|
|
68
|
+
}[] | undefined): boolean;
|
|
64
69
|
export declare function collectScheduledSessionIds(runs: readonly {
|
|
65
70
|
readonly sessionId?: string | null;
|
|
66
71
|
}[] | undefined): Set<string>;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import type { AutomationSchedule } from './types.ts';
|
|
2
2
|
export declare function assertValidSchedule(schedule: AutomationSchedule): void;
|
|
3
3
|
export declare function normalizeSchedule(schedule: AutomationSchedule): AutomationSchedule;
|
|
4
|
+
/** 按计划字段比较语义,避免对象字段顺序影响变更判断。 */
|
|
5
|
+
export declare function isEqualSchedule(left: AutomationSchedule, right: AutomationSchedule): boolean;
|
|
4
6
|
export declare function scheduleToRRule(schedule: AutomationSchedule): string;
|
|
5
7
|
export declare function nextOccurrence(schedule: AutomationSchedule, afterExclusive: string): string | null;
|
|
6
8
|
export declare function latestDueOccurrence(schedule: AutomationSchedule, now: string): string | null;
|
package/lib/types/run-title.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
/** 定时执行 Session 的展示标题,Host 与侧栏共用。 */
|
|
2
|
-
export declare function formatRunStamp(iso: string): string;
|
|
3
|
-
export declare function automationSessionTitle(taskName: string, iso: string): string;
|
|
2
|
+
export declare function formatRunStamp(iso: string, timeZone?: string): string;
|
|
3
|
+
export declare function automationSessionTitle(taskName: string, iso: string, timeZone?: string): string;
|