@michengai/dsh-automation 0.1.0

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.
Files changed (44) hide show
  1. package/LICENSE +201 -0
  2. package/NOTICE +9 -0
  3. package/README.md +136 -0
  4. package/README.zh-CN.md +136 -0
  5. package/cordis.patch.yml +9 -0
  6. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/00-/351/230/205/350/257/273/345/257/274/350/210/252.md +11 -0
  7. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/01-/351/241/271/347/233/256/346/246/202/350/247/210.md +22 -0
  8. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/02-/345/275/223/345/211/215/347/212/266/346/200/201.md +9 -0
  9. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/03-/345/276/205/345/212/236/344/270/216/351/230/273/345/241/236.md +7 -0
  10. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/04-/350/277/255/344/273/243/350/267/257/347/272/277/345/233/276.md +5 -0
  11. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/05-/346/212/200/346/234/257/346/236/266/346/236/204/345/237/272/347/272/277.md +10 -0
  12. package/docs/00-/344/272/244/346/216/245/345/205/245/345/217/243/06-/346/226/207/346/241/243/347/274/226/345/206/231/350/247/204/350/214/203.md +8 -0
  13. package/docs/01-/345/275/223/345/211/215/345/267/245/344/275/234/I001-/344/273/273/345/212/241/350/207/252/345/212/250/345/214/226/346/217/222/344/273/266/00-/350/277/255/344/273/243/346/200/273/350/247/210.md +47 -0
  14. package/docs/03-/346/212/200/346/234/257/346/236/266/346/236/204/00-/351/242/206/345/237/237/347/264/242/345/274/225.md +5 -0
  15. package/docs/03-/346/212/200/346/234/257/346/236/266/346/236/204/01-/350/260/203/345/272/246/344/270/216/346/211/247/350/241/214/346/250/241/345/236/213.md +30 -0
  16. package/lib/client.js +2792 -0
  17. package/lib/client.js.map +7 -0
  18. package/lib/index.js +22869 -0
  19. package/lib/types/client/AutomationView.d.ts +2 -0
  20. package/lib/types/client/ScheduleRail.d.ts +34 -0
  21. package/lib/types/client/contracts.d.ts +57 -0
  22. package/lib/types/client/create-modal.d.ts +30 -0
  23. package/lib/types/client/helpers.d.ts +67 -0
  24. package/lib/types/client/icons.d.ts +28 -0
  25. package/lib/types/client/index.d.ts +4 -0
  26. package/lib/types/client/locales.d.ts +187 -0
  27. package/lib/types/client/menu.d.ts +53 -0
  28. package/lib/types/client/native-session-list.d.ts +14 -0
  29. package/lib/types/client/native-tabs.d.ts +23 -0
  30. package/lib/types/client/prefill.d.ts +6 -0
  31. package/lib/types/client/protocol.d.ts +153 -0
  32. package/lib/types/client/runtime.d.ts +29 -0
  33. package/lib/types/client/schedule-rail-model.d.ts +87 -0
  34. package/lib/types/client/styles.d.ts +1 -0
  35. package/lib/types/domain.d.ts +67 -0
  36. package/lib/types/executor.d.ts +30 -0
  37. package/lib/types/index.d.ts +20 -0
  38. package/lib/types/recurrence.d.ts +7 -0
  39. package/lib/types/rpc.d.ts +13 -0
  40. package/lib/types/run-title.d.ts +3 -0
  41. package/lib/types/service.d.ts +110 -0
  42. package/lib/types/tools.d.ts +12 -0
  43. package/lib/types/types.d.ts +146 -0
  44. package/package.json +99 -0
package/lib/client.js ADDED
@@ -0,0 +1,2792 @@
1
+ window.__ModuleLoader__.load({ id: "@michengai/dsh-automation", factory: (require) => {
2
+ var module = { exports: {} }; var exports = module.exports;
3
+ "use strict";
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name2 in all)
10
+ __defProp(target, name2, { get: all[name2], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
21
+
22
+ // src/client/index.ts
23
+ var index_exports = {};
24
+ __export(index_exports, {
25
+ apply: () => apply,
26
+ inject: () => inject,
27
+ name: () => name
28
+ });
29
+ module.exports = __toCommonJS(index_exports);
30
+ var import_react6 = require("react");
31
+
32
+ // src/client/AutomationView.tsx
33
+ var import_react3 = require("react");
34
+
35
+ // src/client/helpers.ts
36
+ var AutomationFormError = class extends Error {
37
+ constructor(key) {
38
+ super(key);
39
+ this.key = key;
40
+ }
41
+ };
42
+ var SKILL_GESTURE_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
43
+ function skillGestureToken(skill) {
44
+ const raw = SKILL_GESTURE_NAME.test(skill.name) ? skill.name : skill.id;
45
+ return `/${raw}`;
46
+ }
47
+ function insertSkillGesture(prompt, token, caret) {
48
+ const normalized = token.startsWith("/") ? token : `/${token}`;
49
+ const escaped = normalized.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
50
+ if (new RegExp(`(^|\\s)${escaped}(?=\\s|$)`).test(prompt)) {
51
+ return { text: prompt, caret: Math.min(Math.max(caret, 0), prompt.length) };
52
+ }
53
+ const at = Math.min(Math.max(caret, 0), prompt.length);
54
+ const prefix = prompt.slice(0, at);
55
+ const suffix = prompt.slice(at);
56
+ const lead = prefix.length > 0 && !/\s$/.test(prefix) ? " " : "";
57
+ const inserted = `${lead}${normalized} `;
58
+ return { text: prefix + inserted + suffix, caret: prefix.length + inserted.length };
59
+ }
60
+ function localDateTimeValue(date = /* @__PURE__ */ new Date()) {
61
+ const future = new Date(date.getTime() + 60 * 60 * 1e3);
62
+ future.setMinutes(0, 0, 0);
63
+ const offset = future.getTimezoneOffset() * 6e4;
64
+ return new Date(future.getTime() - offset).toISOString().slice(0, 16);
65
+ }
66
+ function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], defaultModel) {
67
+ return {
68
+ name: "",
69
+ prompt: "",
70
+ scheduleKind: "daily",
71
+ onceAt: localDateTimeValue(now),
72
+ everyMinutes: "60",
73
+ time: "09:00",
74
+ weekdays: [1, 2, 3, 4, 5],
75
+ hourlyMinute: "00",
76
+ monthDay: "1",
77
+ customDays: "2",
78
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Shanghai",
79
+ permission: "read-only",
80
+ workspaceId: workspaces[0]?.id ?? "",
81
+ modelKey: defaultModel === void 0 || defaultModel === null ? "default" : `${defaultModel.provider}::${defaultModel.model}`,
82
+ reasoningEffort: "high",
83
+ skills: []
84
+ };
85
+ }
86
+ function buildCreateInput(form, workspaces, models, now = /* @__PURE__ */ new Date(), options = {}) {
87
+ const name2 = form.name.trim();
88
+ const prompt = form.prompt.trim();
89
+ if (name2 === "") throw new AutomationFormError("form.error.name");
90
+ if (prompt === "") throw new AutomationFormError("form.error.prompt");
91
+ const workspace = workspaces.find((item) => item.id === form.workspaceId);
92
+ if (workspace === void 0) throw new AutomationFormError("form.error.workspace");
93
+ let schedule;
94
+ switch (form.scheduleKind) {
95
+ case "once": {
96
+ const at = new Date(form.onceAt);
97
+ if (!Number.isFinite(at.getTime()) || options.allowPastOnce !== true && at.getTime() <= now.getTime()) {
98
+ throw new AutomationFormError("form.error.once");
99
+ }
100
+ schedule = { kind: "once", at: at.toISOString(), timeZone: form.timeZone };
101
+ break;
102
+ }
103
+ case "interval": {
104
+ const everyMinutes = Number(form.everyMinutes);
105
+ if (!Number.isInteger(everyMinutes) || everyMinutes < 5 || everyMinutes > 43200) {
106
+ throw new AutomationFormError("form.error.interval");
107
+ }
108
+ schedule = { kind: "interval", everyMinutes, anchor: now.toISOString(), timeZone: form.timeZone };
109
+ break;
110
+ }
111
+ case "daily":
112
+ schedule = { kind: "daily", time: form.time, timeZone: form.timeZone };
113
+ break;
114
+ case "weekly":
115
+ if (form.weekdays.length === 0) throw new AutomationFormError("form.error.weekdays");
116
+ schedule = { kind: "weekly", time: form.time, weekdays: [...form.weekdays].sort((a, b) => a - b), timeZone: form.timeZone };
117
+ break;
118
+ case "hourly": {
119
+ const minute = Number(form.hourlyMinute);
120
+ if (!Number.isInteger(minute) || minute < 0 || minute > 59) throw new AutomationFormError("form.error.interval");
121
+ schedule = { kind: "hourly", minute, timeZone: form.timeZone };
122
+ break;
123
+ }
124
+ case "monthly": {
125
+ const day = Number(form.monthDay);
126
+ if (!Number.isInteger(day) || day < 1 || day > 31) throw new AutomationFormError("form.error.interval");
127
+ schedule = { kind: "monthly", day, time: form.time, timeZone: form.timeZone };
128
+ break;
129
+ }
130
+ case "custom": {
131
+ const everyDays = Number(form.customDays);
132
+ if (!Number.isInteger(everyDays) || everyDays < 1) throw new AutomationFormError("form.error.interval");
133
+ schedule = { kind: "custom", everyDays, time: form.time, timeZone: form.timeZone };
134
+ break;
135
+ }
136
+ }
137
+ const selected = models.find((item) => `${item.provider}::${item.model}` === form.modelKey);
138
+ return {
139
+ name: name2,
140
+ prompt,
141
+ schedule,
142
+ timeZone: form.timeZone,
143
+ permission: form.permission,
144
+ workspaceId: workspace.id,
145
+ cwd: workspace.path,
146
+ ...selected === void 0 ? { provider: null, model: null } : { provider: selected.provider, model: selected.model },
147
+ reasoningEffort: form.reasoningEffort === "none" ? null : form.reasoningEffort
148
+ };
149
+ }
150
+ function formatSchedule(schedule, t) {
151
+ switch (schedule.kind) {
152
+ case "once":
153
+ return t("schedule.onceAt", { time: new Date(schedule.at).toLocaleString() });
154
+ case "interval":
155
+ return t("schedule.everyMinutes", { count: schedule.everyMinutes });
156
+ case "daily":
157
+ return t("schedule.dailyAt", { time: schedule.time });
158
+ case "weekly": {
159
+ const days = schedule.weekdays.map((day) => t(`day.${day}`)).join("\u3001");
160
+ return t("schedule.weeklyAt", { days, time: schedule.time });
161
+ }
162
+ case "hourly":
163
+ return t("schedule.hourlyAt", { minute: String(schedule.minute).padStart(2, "0") });
164
+ case "monthly":
165
+ return t("schedule.monthlyAt", { day: schedule.day, time: schedule.time });
166
+ case "custom":
167
+ return t("schedule.customAt", { count: schedule.everyDays, time: schedule.time });
168
+ }
169
+ }
170
+ function formatWithin(iso, now, t) {
171
+ const delta = Date.parse(iso) - now.getTime();
172
+ if (!Number.isFinite(delta) || delta <= 0) return t("time.now");
173
+ const minutes = Math.max(1, Math.ceil(delta / 6e4));
174
+ if (minutes < 60) return t("time.withinMinute", { count: minutes });
175
+ const hours = Math.ceil(minutes / 60);
176
+ if (hours < 24) return t("time.withinHour", { count: hours });
177
+ return t("time.withinDay", { count: Math.ceil(hours / 24) });
178
+ }
179
+ function formatDuration(startedAt, finishedAt) {
180
+ if (startedAt === void 0 || finishedAt === void 0) return void 0;
181
+ const seconds = (Date.parse(finishedAt) - Date.parse(startedAt)) / 1e3;
182
+ if (!Number.isFinite(seconds) || seconds < 0) return void 0;
183
+ return `${seconds.toFixed(1)}s`;
184
+ }
185
+ function clockTime(iso) {
186
+ const value = new Date(iso);
187
+ if (Number.isNaN(value.getTime())) return iso;
188
+ return value.toLocaleTimeString([], { hour: "2-digit", minute: "2-digit", hour12: false });
189
+ }
190
+ function groupHistory(runs, range, now, t) {
191
+ const buckets = /* @__PURE__ */ new Map();
192
+ for (const run of runs) {
193
+ const at = new Date(run.finishedAt ?? run.startedAt ?? run.scheduledFor);
194
+ if (Number.isNaN(at.getTime())) continue;
195
+ let key;
196
+ let label;
197
+ if (range === "month") {
198
+ key = `${at.getFullYear()}-${String(at.getMonth() + 1).padStart(2, "0")}`;
199
+ label = t("history.month", { month: `${at.getFullYear()}/${at.getMonth() + 1}` });
200
+ } else if (range === "week") {
201
+ const start = startOfWeek(at);
202
+ key = start.toISOString().slice(0, 10);
203
+ label = t("history.week", { date: `${start.getMonth() + 1}/${start.getDate()}` });
204
+ } else {
205
+ key = localDayKey(at);
206
+ const today = localDayKey(now);
207
+ const yesterday = localDayKey(new Date(now.getTime() - 864e5));
208
+ label = key === today ? t("history.today") : key === yesterday ? t("history.yesterday") : t("history.date", { date: `${at.getMonth() + 1}/${at.getDate()}` });
209
+ }
210
+ const existing = buckets.get(key) ?? [];
211
+ existing.push(run);
212
+ buckets.set(key, existing);
213
+ }
214
+ return [...buckets.entries()].map(([key, items]) => ({
215
+ key,
216
+ label: items[0] === void 0 ? key : range === "month" ? t("history.month", { month: key.replace("-", "/") }) : range === "week" ? t("history.week", { date: key.slice(5).replace("-", "/") }) : key === localDayKey(now) ? t("history.today") : key === localDayKey(new Date(now.getTime() - 864e5)) ? t("history.yesterday") : t("history.date", { date: key.slice(5).replace("-", "/") }),
217
+ items
218
+ }));
219
+ }
220
+ function localDayKey(value) {
221
+ return `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, "0")}-${String(value.getDate()).padStart(2, "0")}`;
222
+ }
223
+ function startOfWeek(value) {
224
+ const next = new Date(value);
225
+ const day = next.getDay();
226
+ const offset = day === 0 ? 6 : day - 1;
227
+ next.setHours(0, 0, 0, 0);
228
+ next.setDate(next.getDate() - offset);
229
+ return next;
230
+ }
231
+ function formFromAutomation(item, workspaces = [], defaultModel) {
232
+ const base = defaultFormState(/* @__PURE__ */ new Date(), workspaces, defaultModel);
233
+ const schedule = item.schedule;
234
+ const modelKey = item.provider && item.model ? `${item.provider}::${item.model}` : "default";
235
+ const common = {
236
+ ...base,
237
+ name: item.name,
238
+ prompt: item.prompt,
239
+ permission: item.permission,
240
+ workspaceId: item.workspaceId ?? base.workspaceId,
241
+ modelKey,
242
+ reasoningEffort: item.reasoningEffort ?? "high"
243
+ };
244
+ switch (schedule.kind) {
245
+ case "once":
246
+ return { ...common, scheduleKind: "once", onceAt: toLocalInput(schedule.at) };
247
+ case "interval":
248
+ return { ...common, scheduleKind: "interval", everyMinutes: String(schedule.everyMinutes) };
249
+ case "hourly":
250
+ return { ...common, scheduleKind: "hourly", hourlyMinute: String(schedule.minute).padStart(2, "0") };
251
+ case "daily":
252
+ return { ...common, scheduleKind: "daily", time: schedule.time };
253
+ case "weekly":
254
+ return { ...common, scheduleKind: "weekly", time: schedule.time, weekdays: [...schedule.weekdays] };
255
+ case "monthly":
256
+ return { ...common, scheduleKind: "monthly", time: schedule.time, monthDay: String(schedule.day) };
257
+ case "custom":
258
+ return { ...common, scheduleKind: "custom", time: schedule.time, customDays: String(schedule.everyDays) };
259
+ }
260
+ }
261
+ function toLocalInput(iso) {
262
+ const value = new Date(iso);
263
+ if (Number.isNaN(value.getTime())) return localDateTimeValue();
264
+ const offset = value.getTimezoneOffset() * 6e4;
265
+ return new Date(value.getTime() - offset).toISOString().slice(0, 16);
266
+ }
267
+
268
+ // src/client/icons.tsx
269
+ var import_jsx_runtime = require("react/jsx-runtime");
270
+ function IconFrame({ children, ...props }) {
271
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", stroke: "currentColor", strokeWidth: "1.8", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", ...props, children });
272
+ }
273
+ function PlusIcon(props) {
274
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 5v14M5 12h14" }) });
275
+ }
276
+ function RefreshIcon(props) {
277
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
278
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M19 7v5h-5" }),
279
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M18.1 15.5A7.5 7.5 0 1 1 19 12" })
280
+ ] });
281
+ }
282
+ function PlayIcon(props) {
283
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9 7 8 5-8 5V7Z" }) });
284
+ }
285
+ function TrashIcon(props) {
286
+ 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" }) });
287
+ }
288
+ function ShieldIcon(props) {
289
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
290
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3.8 19 6v5.1c0 4.3-2.6 7.4-7 9.1-4.4-1.7-7-4.8-7-9.1V6l7-2.2Z" }),
291
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "m9.4 12 1.7 1.7 3.7-4" })
292
+ ] });
293
+ }
294
+ function MoreIcon(props) {
295
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
296
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "6", cy: "12", r: "1.2", fill: "currentColor" }),
297
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "1.2", fill: "currentColor" }),
298
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "18", cy: "12", r: "1.2", fill: "currentColor" })
299
+ ] });
300
+ }
301
+ function InfoIcon(props) {
302
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
303
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "8.25" }),
304
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 10.4V16" }),
305
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 7.6h.01" })
306
+ ] });
307
+ }
308
+ function ClockIcon(props) {
309
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(IconFrame, { ...props, children: [
310
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "8.25" }),
311
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 7.6v4.6l3 1.8" })
312
+ ] });
313
+ }
314
+ function ChatIcon(props) {
315
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M5.5 6.5h13v9.2H9.2L5.5 18.8V6.5Z" }) });
316
+ }
317
+ function FolderIcon(props) {
318
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M4 7.2h6.1l1.7 1.8H20V18H4V7.2Z" }) });
319
+ }
320
+ function SparkleIcon(props) {
321
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconFrame, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M12 3.6 13.3 8.7 18.4 10 13.3 11.3 12 16.4 10.7 11.3 5.6 10 10.7 8.7 12 3.6Z" }) });
322
+ }
323
+ function FillIcon({ children, width = 16, height = 16 }) {
324
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { viewBox: "0 0 16 16", width, height, fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children });
325
+ }
326
+ function FolderClosedIcon(props) {
327
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FillIcon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M6.556 3.377 6.007 3.725l.549-.348ZM14.5 12.342h.65V6.397h-.65-.65v5.945h.65Zm-1.674-7.618v-.65H8.023v.65h4.803Zm-5.746-.519.55-.347-.525-.828-.549.348-.549.348.525.828.55-.348ZM5.613 2.858h0H3.174v.65h2.439v-.65ZM3 4.532v8.46h.65V4.532H3Zm11.326 9.484v-.65H4.674v.65h9.652ZM3 12.342h-.65A2.324 2.324 0 0 0 4.674 14.666v-1.3A.824.824 0 0 1 3.65 12.342H3Zm.174-9.484h0A2.324 2.324 0 0 0 2.35 4.532h1.3A.824.824 0 0 1 4.674 3.508h0V2.858Zm3.382.519.549-.348A1.824 1.824 0 0 0 5.613 2.208v1.3c.16 0 .308.082.394.217l.549-.348Zm1.467 1.347h0c-.16 0-.308-.082-.393-.216l-.55.347-.549.348A1.824 1.824 0 0 0 8.023 5.374v-1.3ZM14.5 6.397h.65A2.324 2.324 0 0 0 12.826 4.073v1.3c.565 0 1.024.458 1.024 1.024h.65Zm0 5.945h-.65c0 .565-.458 1.024-1.024 1.024v1.3A2.324 2.324 0 0 0 15.15 12.342h-.65Z" }) });
328
+ }
329
+ function FolderOpenIcon(props) {
330
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FillIcon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M5.196 1.571c.615 0 1.19.308 1.532.819l.471.708c.086.128.23.205.383.205h4.588A2.666 2.666 0 0 1 14.586 5.72v.907c.683.4 1.074 1.223.852 2.06l-1.053 3.971A2.666 2.666 0 0 1 12.05 14.453H2.917A2.416 2.416 0 0 1 .502 11.952V3.987A2.416 2.416 0 0 1 2.918 1.571h2.278Zm-1.417 6.185c-.469 0-.88.316-1.001.77l-.862 3.247c-.174.657.322 1.301 1.001 1.301H12.05c.469 0 .88-.316 1.001-.77l1.053-3.97c.078-.291-.142-.577-.444-.577H3.779Zm-.861-4.804c-.572 0-1.035.464-1.035 1.035v3.307a2.67 2.67 0 0 1 1.896-.919h9.426V5.72c0-.572-.464-1.035-1.035-1.035H7.582c-.615 0-1.19-.309-1.531-.82L5.579 3.156a.666.666 0 0 0-.383-.204H2.918Z" }) });
331
+ }
332
+ function ChevronIcon(props) {
333
+ 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", 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" }) });
334
+ }
335
+ function EllipsisIcon(props) {
336
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(FillIcon, { ...props, children: [
337
+ /* @__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" }),
338
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M9.1476 8.00001C9.1476 8.63513 8.63273 9.15001 7.9976 9.15001C7.36248 9.15001 6.8476 8.63513 6.8476 8.00001C6.8476 7.36488 7.36248 6.85001 7.9976 6.85001C8.63273 6.85001 9.1476 7.36488 9.1476 8.00001Z" }),
339
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M13.7486 8.00001C13.7486 8.63513 13.2338 9.15001 12.5986 9.15001C11.9635 9.15001 11.4486 8.63513 11.4486 8.00001C11.4486 7.36488 11.9635 6.85001 12.5986 6.85001C13.2338 6.85001 13.7486 7.36488 13.7486 8.00001Z" })
340
+ ] });
341
+ }
342
+ function PencilIcon(props) {
343
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FillIcon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M9.941 1.349a2.54 2.54 0 0 1 2.473 0c.292.171.555.442.897.784.341.341.612.604.783.896a2.54 2.54 0 0 1 0 2.473c-.171.292-.442.555-.784.896L6.659 13.05c-.378.378-.652.661-.994.86-.341.199-.722.298-1.238.44l-1.183.326c-.469.13-.899.25-1.243.292-.349.043-.821.033-1.19-.336-.369-.369-.379-.841-.336-1.19.042-.344.163-.774.292-1.243l.326-1.183c.143-.516.242-.897.44-1.238.199-.342.482-.615.86-.994l6.652-6.651c.341-.342.604-.613.896-.784Zm1.759 1.222a1.16 1.16 0 0 0-1.045 0c-.095.056-.206.158-.61.562L9.456 3.721l2.265 2.265.589-.588c.404-.403.507-.515.562-.61a1.16 1.16 0 0 0 0-1.045c-.056-.095-.158-.206-.562-.61-.404-.404-.515-.507-.61-.562ZM3.394 9.784c-.429.429-.551.56-.637.706-.085.147-.138.318-.3.903l-.326 1.183c-.129.468-.209.766-.242.978.212-.033.51-.112.979-.241l1.183-.327c.585-.161.756-.214.902-.3.147-.085.277-.208.706-.636l5.062-5.063-2.265-2.265-5.062 5.062Z" }) });
344
+ }
345
+ function BranchIcon(props) {
346
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(FillIcon, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", fillRule: "evenodd", clipRule: "evenodd", d: "M13.076 1.372c1.008 0 1.826.819 1.826 1.827s-.818 1.826-1.826 1.826c-.78 0-1.444-.488-1.706-1.175H4.355c.439.415.804.915 1.062 1.485l1.69 3.733a4.83 4.83 0 0 0 4.312 2.97c.29-.626.923-1.061 1.658-1.061 1.008 0 1.826.818 1.826 1.826s-.818 1.826-1.826 1.826c-.823 0-1.519-.545-1.747-1.293a6.34 6.34 0 0 1-5.406-3.731L4.232 5.871A3.83 3.83 0 0 0 1.098 3.85V2.549h10.272c.263-.687.927-1.177 1.706-1.177Zm0 10.904a.525.525 0 1 0 0 1.052.525.525 0 0 0 0-1.052Zm0-9.603a.526.526 0 1 0 0 1.053.526.526 0 0 0 0-1.053Z" }) });
347
+ }
348
+ function ArchiveIcon(props) {
349
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { viewBox: "0 0 20 20", width: props.width || 16, height: props.height || 16, fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", children: [
350
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", fillRule: "evenodd", clipRule: "evenodd", d: "M15.866 2.06a2.526 2.526 0 0 1 2.525 2.525v.902c0 .54-.172 1.04-.461 1.45l.009.085v5.866c0 .746 0 1.35-.039 1.837-.035.434-.106.825-.262 1.189l-.072.154a3.03 3.03 0 0 1-1.262 1.366l-.236.132c-.408.208-.848.294-1.344.334-.488.04-1.091.04-1.837.04H7.111c-.746 0-1.35 0-1.837-.04-.434-.035-.825-.105-1.189-.261l-.154-.073a3.03 3.03 0 0 1-1.366-1.262l-.132-.235a2.53 2.53 0 0 1-.335-1.344c-.04-.487-.039-1.091-.039-1.837V7.022c0-.029.005-.057.008-.086A2.48 2.48 0 0 1 1.609 5.487v-.902A2.526 2.526 0 0 1 4.134 2.06h11.732Zm.632 5.87a2.48 2.48 0 0 1-.632.083H4.134a2.48 2.48 0 0 1-.634-.083v4.959c0 .77 0 1.304.034 1.72.034.406.095.635.182.806l.076.137c.191.311.465.565.792.731l.141.061c.156.055.361.096.666.121.415.034.95.035 1.72.035h5.775c.77 0 1.305 0 1.72-.035.407-.033.636-.095.807-.182l.138-.077c.311-.191.565-.464.731-.791l.06-.142c.056-.155.097-.36.122-.665.034-.415.034-.95.034-1.72V7.93ZM4.134 3.5a1.086 1.086 0 0 0-1.085 1.085v.902c0 .599.486 1.085 1.085 1.085h11.732c.599 0 1.085-.486 1.085-1.085v-.902A1.086 1.086 0 0 0 15.866 3.5H4.134Z" }),
351
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "currentColor", d: "M12.796 12.566v-1.483H7.205v1.483h5.591Z" })
352
+ ] });
353
+ }
354
+ var RUNNING_CELLS = [
355
+ [0, 0],
356
+ [4, 0],
357
+ [8, 0],
358
+ [8, 4],
359
+ [8, 8],
360
+ [4, 8],
361
+ [0, 8],
362
+ [0, 4]
363
+ ];
364
+ function RunningStateDot() {
365
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("svg", { className: "dsh-st-run-dot", width: 10, height: 10, viewBox: "0 0 10 10", shapeRendering: "crispEdges", "aria-hidden": "true", children: RUNNING_CELLS.map(([x, y], index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
366
+ "rect",
367
+ {
368
+ className: "dsh-st-run-dot-cell",
369
+ x,
370
+ y,
371
+ width: "2",
372
+ height: "2",
373
+ style: { animationDelay: `${(index - RUNNING_CELLS.length) * 125}ms` }
374
+ },
375
+ `${x}-${y}`
376
+ )) });
377
+ }
378
+
379
+ // src/client/create-modal.tsx
380
+ var import_react2 = require("react");
381
+
382
+ // src/client/menu.tsx
383
+ var import_react = require("react");
384
+ var import_react_dom = require("react-dom");
385
+ var import_jsx_runtime2 = require("react/jsx-runtime");
386
+ var MenuHostContext = (0, import_react.createContext)(null);
387
+ function useMenuOpen() {
388
+ const [open, setOpen] = (0, import_react.useState)(false);
389
+ const root = (0, import_react.useRef)(null);
390
+ const menu = (0, import_react.useRef)(null);
391
+ (0, import_react.useEffect)(() => {
392
+ if (!open) return;
393
+ const close = (event) => {
394
+ const target = event.target;
395
+ if (root.current !== null && root.current.contains(target)) return;
396
+ if (menu.current !== null && menu.current.contains(target)) return;
397
+ setOpen(false);
398
+ };
399
+ document.addEventListener("mousedown", close);
400
+ return () => {
401
+ document.removeEventListener("mousedown", close);
402
+ };
403
+ }, [open]);
404
+ return { open, setOpen, root, menu };
405
+ }
406
+ function flyoutStyle(anchor, host, up, end) {
407
+ const box = anchor.getBoundingClientRect();
408
+ const frame = host.getBoundingClientRect();
409
+ const gap = 6;
410
+ return {
411
+ position: "absolute",
412
+ zIndex: 1200,
413
+ top: up === true ? "auto" : `${box.bottom - frame.top + gap}px`,
414
+ bottom: up === true ? `${frame.bottom - box.top + gap}px` : "auto",
415
+ left: end === true ? "auto" : `${box.left - frame.left}px`,
416
+ right: end === true ? `${frame.right - box.right}px` : "auto"
417
+ };
418
+ }
419
+ function MenuPopup({
420
+ open,
421
+ anchor,
422
+ menuRef,
423
+ up,
424
+ end,
425
+ className,
426
+ children,
427
+ onClick
428
+ }) {
429
+ const host = (0, import_react.useContext)(MenuHostContext);
430
+ const [style, setStyle] = (0, import_react.useState)({});
431
+ (0, import_react.useLayoutEffect)(() => {
432
+ if (!open || anchor.current === null || host === null) return;
433
+ const update = () => {
434
+ if (anchor.current !== null) setStyle(flyoutStyle(anchor.current, host, up, end));
435
+ };
436
+ update();
437
+ window.addEventListener("resize", update);
438
+ document.addEventListener("scroll", update, true);
439
+ return () => {
440
+ window.removeEventListener("resize", update);
441
+ document.removeEventListener("scroll", update, true);
442
+ };
443
+ }, [open, anchor, host, up, end]);
444
+ if (!open) return null;
445
+ const node = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
446
+ "div",
447
+ {
448
+ ref: menuRef,
449
+ className: `${className}${host !== null ? " is-float" : ""}`,
450
+ style: host !== null ? style : void 0,
451
+ onMouseDown: (event) => event.stopPropagation(),
452
+ onClick: (event) => {
453
+ event.stopPropagation();
454
+ onClick?.();
455
+ },
456
+ children
457
+ }
458
+ );
459
+ if (host !== null) return (0, import_react_dom.createPortal)(node, host);
460
+ return node;
461
+ }
462
+ function MenuHostProvider({
463
+ host,
464
+ children
465
+ }) {
466
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MenuHostContext.Provider, { value: host, children });
467
+ }
468
+ function MenuRow({
469
+ icon,
470
+ label,
471
+ hint,
472
+ active,
473
+ chevron,
474
+ kv,
475
+ onClick
476
+ }) {
477
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", className: `dsh-st-menu-row${active === true ? " is-on" : ""}${kv === true ? " is-kv" : ""}`, onClick, children: [
478
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dsh-st-menu-row-main", children: [
479
+ icon,
480
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: label })
481
+ ] }),
482
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "dsh-st-menu-row-side", children: [
483
+ hint,
484
+ active === true && chevron !== true && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dsh-st-tick" }),
485
+ chevron === true && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("i", { className: "dsh-st-next" })
486
+ ] })
487
+ ] });
488
+ }
489
+ function MenuSelect({
490
+ value,
491
+ options,
492
+ onChange,
493
+ wide,
494
+ pill,
495
+ up,
496
+ icon
497
+ }) {
498
+ const menu = useMenuOpen();
499
+ const current = options.find((item) => item.value === value)?.label ?? value;
500
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `dsh-st-select${wide === true ? " is-wide" : ""}${pill === true ? " is-pill" : ""}${menu.open ? " is-open" : ""}`, ref: menu.root, children: [
501
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
502
+ "button",
503
+ {
504
+ type: "button",
505
+ className: "dsh-st-select-btn",
506
+ onMouseDown: (event) => event.stopPropagation(),
507
+ onClick: () => menu.setOpen((value2) => !value2),
508
+ children: [
509
+ icon,
510
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: current }),
511
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("em", {})
512
+ ]
513
+ }
514
+ ),
515
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
516
+ MenuPopup,
517
+ {
518
+ open: menu.open,
519
+ anchor: menu.root,
520
+ menuRef: menu.menu,
521
+ up,
522
+ end: up,
523
+ className: `dsh-st-select-menu${pill === true ? " is-composer" : ""}${up === true ? " is-up" : ""}${up === true ? " is-end" : ""}`,
524
+ children: options.map((item) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
525
+ MenuRow,
526
+ {
527
+ icon: item.icon,
528
+ label: item.label,
529
+ active: item.value === value,
530
+ onClick: () => {
531
+ onChange(item.value);
532
+ menu.setOpen(false);
533
+ }
534
+ },
535
+ item.value
536
+ ))
537
+ }
538
+ )
539
+ ] });
540
+ }
541
+ function MenuPanel({
542
+ label,
543
+ children,
544
+ ghost,
545
+ up,
546
+ persist
547
+ }) {
548
+ const menu = useMenuOpen();
549
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `dsh-st-select${ghost === true ? " is-pill" : ""}${menu.open ? " is-open" : ""}`, ref: menu.root, children: [
550
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
551
+ "button",
552
+ {
553
+ type: "button",
554
+ className: "dsh-st-chip-btn",
555
+ onMouseDown: (event) => event.stopPropagation(),
556
+ onClick: () => menu.setOpen((value) => !value),
557
+ children: [
558
+ label,
559
+ ghost === true && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("em", {})
560
+ ]
561
+ }
562
+ ),
563
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
564
+ MenuPopup,
565
+ {
566
+ open: menu.open,
567
+ anchor: menu.root,
568
+ menuRef: menu.menu,
569
+ up,
570
+ className: `dsh-st-select-menu is-composer${up === true ? " is-up" : ""}`,
571
+ onClick: () => {
572
+ if (persist !== true) menu.setOpen(false);
573
+ },
574
+ children
575
+ }
576
+ )
577
+ ] });
578
+ }
579
+ function useMenuState() {
580
+ return useMenuOpen();
581
+ }
582
+
583
+ // src/client/create-modal.tsx
584
+ var import_jsx_runtime3 = require("react/jsx-runtime");
585
+ var WEEKDAYS = [1, 2, 3, 4, 5, 6, 7];
586
+ var KINDS = ["once", "interval", "hourly", "daily", "weekly", "monthly", "custom"];
587
+ var HOURS = Array.from({ length: 24 }, (_, index) => String(index).padStart(2, "0"));
588
+ var MINUTES = Array.from({ length: 60 }, (_, index) => String(index).padStart(2, "0"));
589
+ var EFFORTS = ["none", "low", "medium", "high"];
590
+ function CreateModal({
591
+ t,
592
+ busy,
593
+ workspaces,
594
+ models,
595
+ defaultModel,
596
+ skills,
597
+ draft,
598
+ editing,
599
+ onClose,
600
+ onSubmit,
601
+ onAddWorkspace
602
+ }) {
603
+ const [form, setForm] = (0, import_react2.useState)(() => ({ ...defaultFormState(/* @__PURE__ */ new Date(), workspaces, defaultModel), ...draft }));
604
+ const [validationError, setValidationError] = (0, import_react2.useState)();
605
+ const [addingWorkspace, setAddingWorkspace] = (0, import_react2.useState)(false);
606
+ const [workspacePath, setWorkspacePath] = (0, import_react2.useState)("");
607
+ const update = (patch) => {
608
+ setForm((current) => ({ ...current, ...patch }));
609
+ setValidationError(void 0);
610
+ };
611
+ (0, import_react2.useEffect)(() => {
612
+ const onKey = (event) => {
613
+ if (event.key !== "Escape") return;
614
+ event.preventDefault();
615
+ event.stopPropagation();
616
+ event.stopImmediatePropagation();
617
+ onClose();
618
+ };
619
+ window.addEventListener("keydown", onKey, true);
620
+ return () => {
621
+ window.removeEventListener("keydown", onKey, true);
622
+ };
623
+ }, [onClose]);
624
+ const handleSubmit = async (event) => {
625
+ event.preventDefault();
626
+ try {
627
+ await onSubmit(form);
628
+ } catch (caught) {
629
+ if (caught instanceof AutomationFormError) {
630
+ setValidationError(t(caught.key));
631
+ return;
632
+ }
633
+ setValidationError(caught instanceof Error ? caught.message : t("error.action"));
634
+ }
635
+ };
636
+ const datePart = form.onceAt.slice(0, 10);
637
+ const timePart = form.onceAt.slice(11, 16) || "09:00";
638
+ const today = localDateValue(/* @__PURE__ */ new Date());
639
+ const minOnceTime = datePart === today ? localTimeValue(/* @__PURE__ */ new Date()) : void 0;
640
+ const [menuHost, setMenuHost] = (0, import_react2.useState)(null);
641
+ const workspace = workspaces.find((item) => item.id === form.workspaceId);
642
+ const promptRef = (0, import_react2.useRef)(null);
643
+ const caretRef = (0, import_react2.useRef)(0);
644
+ const rememberCaret = () => {
645
+ const el = promptRef.current;
646
+ if (el !== null) caretRef.current = el.selectionStart;
647
+ };
648
+ const insertSkill = (skill) => {
649
+ const next = insertSkillGesture(form.prompt, skillGestureToken(skill), caretRef.current);
650
+ update({ prompt: next.text });
651
+ queueMicrotask(() => {
652
+ const el = promptRef.current;
653
+ if (el === null) return;
654
+ el.focus();
655
+ el.setSelectionRange(next.caret, next.caret);
656
+ caretRef.current = next.caret;
657
+ });
658
+ };
659
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
660
+ "div",
661
+ {
662
+ className: "dsh-st-mask",
663
+ role: "presentation",
664
+ onClick: (event) => {
665
+ if (event.target.closest(".dsh-st-select-menu") !== null) return;
666
+ onClose();
667
+ },
668
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MenuHostProvider, { host: menuHost, children: [
669
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { className: "dsh-st-modal", onClick: (event) => event.stopPropagation(), onSubmit: handleSubmit, children: [
670
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-modal-head", children: [
671
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
672
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h2", { children: editing === true ? t("modal.edit") : t("modal.title") }),
673
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { children: t("form.subtitle") })
674
+ ] }),
675
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dsh-st-icon", onClick: onClose, "aria-label": t("form.cancel"), children: "\xD7" })
676
+ ] }),
677
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "dsh-st-field", children: [
678
+ t("form.name"),
679
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: form.name, placeholder: t("form.namePlaceholder"), onChange: (event) => update({ name: event.target.value }) })
680
+ ] }),
681
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-field", children: [
682
+ t("form.planTime"),
683
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-inline", children: [
684
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
685
+ MenuSelect,
686
+ {
687
+ value: form.scheduleKind,
688
+ options: KINDS.map((kind) => ({ value: kind, label: t(`form.${kind}`) })),
689
+ onChange: (value) => update({ scheduleKind: value })
690
+ }
691
+ ),
692
+ form.scheduleKind === "once" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
693
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "date", min: today, value: datePart, onChange: (event) => update({ onceAt: clampOnceAt(`${event.target.value}T${timePart}`) }) }),
694
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: timePart, ...minOnceTime === void 0 ? {} : { minTime: minOnceTime }, onChange: (value) => update({ onceAt: clampOnceAt(`${datePart}T${value}`) }) })
695
+ ] }),
696
+ form.scheduleKind === "interval" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
697
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "is-narrow", type: "number", min: 5, value: form.everyMinutes, onChange: (event) => update({ everyMinutes: event.target.value }) }),
698
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.minutesShort") })
699
+ ] }),
700
+ form.scheduleKind === "hourly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
701
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuSelect, { value: form.hourlyMinute, options: MINUTES.map((item) => ({ value: item, label: item })), onChange: (value) => update({ hourlyMinute: value }) }),
702
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.minutesShort") })
703
+ ] }),
704
+ (form.scheduleKind === "daily" || form.scheduleKind === "weekly") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) }),
705
+ form.scheduleKind === "monthly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
706
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
707
+ MenuSelect,
708
+ {
709
+ value: form.monthDay,
710
+ options: Array.from({ length: 31 }, (_, index) => {
711
+ const day = String(index + 1);
712
+ return { value: day, label: t("form.monthDay", { day }) };
713
+ }),
714
+ onChange: (value) => update({ monthDay: value })
715
+ }
716
+ ),
717
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) })
718
+ ] }),
719
+ form.scheduleKind === "custom" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
720
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "is-narrow", type: "number", min: 1, value: form.customDays, onChange: (event) => update({ customDays: event.target.value }) }),
721
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.daysShort") }),
722
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) })
723
+ ] })
724
+ ] })
725
+ ] }),
726
+ form.scheduleKind === "weekly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-weekdays", children: WEEKDAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
727
+ "button",
728
+ {
729
+ type: "button",
730
+ className: form.weekdays.includes(day) ? "is-on" : "",
731
+ onClick: () => update({
732
+ weekdays: form.weekdays.includes(day) ? form.weekdays.filter((value) => value !== day) : [...form.weekdays, day]
733
+ }),
734
+ children: t(`day.${day}`)
735
+ },
736
+ day
737
+ )) }),
738
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-field", children: [
739
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t("form.prompt") }),
740
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-prompt-card", children: [
741
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("textarea", { ref: promptRef, value: form.prompt, placeholder: t("form.promptPlaceholder"), onChange: (event) => {
742
+ rememberCaret();
743
+ update({ prompt: event.target.value });
744
+ }, onSelect: rememberCaret, onClick: rememberCaret, onKeyUp: rememberCaret }),
745
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-composer", children: [
746
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-composer-left", children: [
747
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MenuPanel, { ghost: true, up: true, label: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
748
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FolderIcon, { width: 14, height: 14 }),
749
+ workspace?.title || t("form.workspace")
750
+ ] }), children: [
751
+ workspaces.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-select-empty", children: t("form.error.workspace") }),
752
+ workspaces.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
753
+ MenuRow,
754
+ {
755
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(FolderIcon, { width: 14, height: 14 }),
756
+ label: item.title,
757
+ active: item.id === form.workspaceId,
758
+ onClick: () => update({ workspaceId: item.id })
759
+ },
760
+ item.id
761
+ )),
762
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-menu-split" }),
763
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
764
+ MenuRow,
765
+ {
766
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PlusIcon, { width: 14, height: 14 }),
767
+ label: t("form.addWorkspace"),
768
+ onClick: () => {
769
+ setWorkspacePath("");
770
+ setAddingWorkspace(true);
771
+ }
772
+ }
773
+ )
774
+ ] }),
775
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MenuPanel, { ghost: true, up: true, label: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
776
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SparkleIcon, { width: 14, height: 14 }),
777
+ t("form.skills")
778
+ ] }), children: [
779
+ skills.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-select-empty", children: t("form.skillsEmpty") }),
780
+ skills.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
781
+ MenuRow,
782
+ {
783
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SparkleIcon, { width: 14, height: 14 }),
784
+ label: item.name,
785
+ onClick: () => insertSkill(item)
786
+ },
787
+ item.id
788
+ ))
789
+ ] }),
790
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
791
+ MenuSelect,
792
+ {
793
+ pill: true,
794
+ up: true,
795
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }),
796
+ value: form.permission,
797
+ options: [
798
+ { value: "read-only", label: t("form.readOnly"), icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }) },
799
+ { value: "workspace-write", label: t("form.workspaceWrite"), icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }) },
800
+ { value: "full-access", label: t("form.fullAccess"), icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }) }
801
+ ],
802
+ onChange: (value) => update({ permission: value })
803
+ }
804
+ )
805
+ ] }),
806
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-composer-right", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
807
+ ModelPicker,
808
+ {
809
+ t,
810
+ models,
811
+ modelKey: form.modelKey,
812
+ effort: form.reasoningEffort,
813
+ onModelKey: (value) => update({ modelKey: value }),
814
+ onEffort: (value) => update({ reasoningEffort: value })
815
+ }
816
+ ) })
817
+ ] })
818
+ ] })
819
+ ] }),
820
+ addingWorkspace && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-subdialog", children: [
821
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("strong", { children: t("form.addWorkspace") }),
822
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "dsh-st-field", children: [
823
+ t("form.workspacePath"),
824
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: workspacePath, placeholder: t("form.workspacePathPlaceholder"), onChange: (event) => setWorkspacePath(event.target.value) })
825
+ ] }),
826
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-modal-actions", children: [
827
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dsh-st-btn", onClick: () => setAddingWorkspace(false), children: t("form.cancel") }),
828
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
829
+ "button",
830
+ {
831
+ type: "button",
832
+ className: "dsh-st-btn dsh-st-btn--primary",
833
+ disabled: busy || onAddWorkspace === void 0,
834
+ onClick: async () => {
835
+ if (onAddWorkspace === void 0) return;
836
+ try {
837
+ const id = await onAddWorkspace(workspacePath);
838
+ update({ workspaceId: id });
839
+ setAddingWorkspace(false);
840
+ } catch (caught) {
841
+ setValidationError(caught instanceof Error ? caught.message : t("error.action"));
842
+ }
843
+ },
844
+ children: t("modal.save")
845
+ }
846
+ )
847
+ ] })
848
+ ] }),
849
+ validationError !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "dsh-st-error", children: validationError }),
850
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-modal-actions", children: [
851
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "button", className: "dsh-st-btn", onClick: onClose, disabled: busy, children: t("form.cancel") }),
852
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", className: "dsh-st-btn dsh-st-btn--primary", disabled: busy, children: t("modal.save") })
853
+ ] })
854
+ ] }),
855
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-flyout-root", ref: setMenuHost })
856
+ ] })
857
+ }
858
+ );
859
+ }
860
+ function ModelPicker({
861
+ t,
862
+ models,
863
+ modelKey,
864
+ effort,
865
+ onModelKey,
866
+ onEffort
867
+ }) {
868
+ const menu = useMenuState();
869
+ const [pane, setPane] = (0, import_react2.useState)("root");
870
+ const selected = models.find((item) => `${item.provider}::${item.model}` === modelKey);
871
+ const modelLabel = selected === void 0 ? t("form.modelDefault") : selected.label;
872
+ const effortLabel = t(`form.effort.${effort}`);
873
+ const trigger = effort === "none" ? modelLabel : `${modelLabel} ${effortLabel}`;
874
+ const open = (next) => {
875
+ setPane(next);
876
+ menu.setOpen(true);
877
+ };
878
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: `dsh-st-select is-pill${menu.open ? " is-open" : ""}`, ref: menu.root, children: [
879
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
880
+ "button",
881
+ {
882
+ type: "button",
883
+ className: "dsh-st-select-btn",
884
+ onMouseDown: (event) => event.stopPropagation(),
885
+ onClick: () => {
886
+ if (menu.open) {
887
+ menu.setOpen(false);
888
+ return;
889
+ }
890
+ open("root");
891
+ },
892
+ children: [
893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: trigger }),
894
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("em", {})
895
+ ]
896
+ }
897
+ ),
898
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(MenuPopup, { open: menu.open, anchor: menu.root, menuRef: menu.menu, up: true, end: true, className: "dsh-st-select-menu is-composer is-up is-end", children: [
899
+ pane === "root" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
900
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuRow, { kv: true, label: t("form.model"), hint: modelLabel, chevron: true, onClick: () => setPane("model") }),
901
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuRow, { kv: true, label: t("form.effort"), hint: effortLabel, chevron: true, onClick: () => setPane("effort") })
902
+ ] }),
903
+ pane === "model" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
904
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
905
+ MenuRow,
906
+ {
907
+ label: t("form.modelDefault"),
908
+ active: modelKey === "default",
909
+ onClick: () => {
910
+ onModelKey("default");
911
+ menu.setOpen(false);
912
+ }
913
+ }
914
+ ),
915
+ models.map((item) => {
916
+ const value = `${item.provider}::${item.model}`;
917
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
918
+ MenuRow,
919
+ {
920
+ label: item.label,
921
+ active: value === modelKey,
922
+ onClick: () => {
923
+ onModelKey(value);
924
+ menu.setOpen(false);
925
+ }
926
+ },
927
+ value
928
+ );
929
+ })
930
+ ] }),
931
+ pane === "effort" && EFFORTS.map((item) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
932
+ MenuRow,
933
+ {
934
+ label: t(`form.effort.${item}`),
935
+ active: item === effort,
936
+ onClick: () => {
937
+ onEffort(item);
938
+ menu.setOpen(false);
939
+ }
940
+ },
941
+ item
942
+ ))
943
+ ] })
944
+ ] });
945
+ }
946
+ function TimeSelect({
947
+ value,
948
+ onChange,
949
+ minTime
950
+ }) {
951
+ const hour = value.slice(0, 2) || "09";
952
+ const minute = value.slice(3, 5) || "00";
953
+ const minHour = minTime?.slice(0, 2);
954
+ const minMinute = minTime?.slice(3, 5);
955
+ const hours = HOURS.filter((item) => minHour === void 0 || item >= minHour);
956
+ const minutes = MINUTES.filter((item) => minHour === void 0 || hour > minHour || minMinute === void 0 || item >= minMinute);
957
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-time", children: [
958
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuSelect, { value: hour, options: hours.map((item) => ({ value: item, label: item })), onChange: (next) => onChange(`${next}:${minute}`) }),
959
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-time-sep", children: ":" }),
960
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuSelect, { value: minute, options: minutes.map((item) => ({ value: item, label: item })), onChange: (next) => onChange(`${hour}:${next}`) })
961
+ ] });
962
+ }
963
+ function localDateValue(now) {
964
+ const offset = now.getTimezoneOffset() * 6e4;
965
+ return new Date(now.getTime() - offset).toISOString().slice(0, 10);
966
+ }
967
+ function localTimeValue(now) {
968
+ const offset = now.getTimezoneOffset() * 6e4;
969
+ return new Date(now.getTime() - offset).toISOString().slice(11, 16);
970
+ }
971
+ function clampOnceAt(value) {
972
+ const selected = new Date(value);
973
+ const now = /* @__PURE__ */ new Date();
974
+ if (!Number.isFinite(selected.getTime()) || selected.getTime() > now.getTime()) return value;
975
+ const next = new Date(now.getTime() + 6e4);
976
+ next.setSeconds(0, 0);
977
+ const offset = next.getTimezoneOffset() * 6e4;
978
+ return new Date(next.getTime() - offset).toISOString().slice(0, 16);
979
+ }
980
+
981
+ // src/client/prefill.ts
982
+ var pending = null;
983
+ var listeners = /* @__PURE__ */ new Set();
984
+ function setChatPrefill(text) {
985
+ pending = text;
986
+ for (const listener of [...listeners]) listener(pending);
987
+ }
988
+ function takeChatPrefill() {
989
+ const value = pending;
990
+ pending = null;
991
+ return value;
992
+ }
993
+ function peekChatPrefill() {
994
+ return pending;
995
+ }
996
+ function subscribeChatPrefill(listener) {
997
+ listeners.add(listener);
998
+ return () => {
999
+ listeners.delete(listener);
1000
+ };
1001
+ }
1002
+ function applyPrefillToDom(text) {
1003
+ const seat = document.querySelector("[data-composer-seat] textarea");
1004
+ if (!(seat instanceof HTMLTextAreaElement)) return false;
1005
+ const descriptor = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, "value");
1006
+ descriptor?.set?.call(seat, text);
1007
+ seat.dispatchEvent(new InputEvent("input", { bubbles: true }));
1008
+ seat.focus();
1009
+ return true;
1010
+ }
1011
+
1012
+ // src/client/protocol.ts
1013
+ function unwrapRpcResult(value) {
1014
+ if (typeof value !== "object" || value === null || !("ok" in value)) {
1015
+ throw new Error("\u81EA\u52A8\u5316\u4E3B\u673A\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\u3002");
1016
+ }
1017
+ const result = value;
1018
+ if (result.ok === true && "value" in result) return result.value;
1019
+ if (result.ok === false && "error" in result) {
1020
+ const error = result.error;
1021
+ throw new Error(error?.message ?? "\u81EA\u52A8\u5316\u8BF7\u6C42\u5931\u8D25\u3002");
1022
+ }
1023
+ throw new Error("\u81EA\u52A8\u5316\u4E3B\u673A\u8FD4\u56DE\u4E86\u65E0\u6548\u54CD\u5E94\u3002");
1024
+ }
1025
+
1026
+ // src/client/runtime.ts
1027
+ var CHANNEL = "/dsh-automation";
1028
+ function isTransportError(error) {
1029
+ const message = error instanceof Error ? error.message : String(error);
1030
+ return /failed to fetch|networkerror|load failed|network request failed/i.test(message);
1031
+ }
1032
+ function createAutomationRuntime(rpc) {
1033
+ let state = { phase: "idle" };
1034
+ let refreshPromise;
1035
+ const listeners2 = /* @__PURE__ */ new Set();
1036
+ const publish = (next) => {
1037
+ state = next;
1038
+ for (const listener of [...listeners2]) listener();
1039
+ };
1040
+ const source = {
1041
+ getSnapshot: () => state,
1042
+ subscribe: (listener) => {
1043
+ listeners2.add(listener);
1044
+ return () => {
1045
+ listeners2.delete(listener);
1046
+ };
1047
+ }
1048
+ };
1049
+ const refresh = async () => {
1050
+ if (refreshPromise !== void 0) return refreshPromise;
1051
+ const previous = state.snapshot;
1052
+ publish(previous === void 0 ? { phase: "loading" } : {
1053
+ phase: "loading",
1054
+ snapshot: previous,
1055
+ ...state.refreshedAt === void 0 ? {} : { refreshedAt: state.refreshedAt }
1056
+ });
1057
+ refreshPromise = (async () => {
1058
+ try {
1059
+ const response = await rpc.call(CHANNEL, "snapshot", { sessionId: "settings" });
1060
+ const snapshot = unwrapRpcResult(response);
1061
+ publish({ phase: "ready", snapshot, refreshedAt: Date.now() });
1062
+ } catch (error) {
1063
+ const message = error instanceof Error ? error.message : String(error);
1064
+ publish(previous === void 0 ? { phase: "error", error: message } : {
1065
+ phase: "error",
1066
+ snapshot: previous,
1067
+ error: message,
1068
+ ...state.refreshedAt === void 0 ? {} : { refreshedAt: state.refreshedAt }
1069
+ });
1070
+ throw error;
1071
+ } finally {
1072
+ refreshPromise = void 0;
1073
+ }
1074
+ })();
1075
+ return refreshPromise;
1076
+ };
1077
+ const callRpc = async (endpoint, payload) => {
1078
+ try {
1079
+ return await rpc.call(CHANNEL, endpoint, payload);
1080
+ } catch (error) {
1081
+ if (!isTransportError(error)) throw error;
1082
+ return await rpc.call(CHANNEL, endpoint, payload);
1083
+ }
1084
+ };
1085
+ const mutateThenRefresh = async (endpoint, payload, patch) => {
1086
+ unwrapRpcResult(await callRpc(endpoint, payload));
1087
+ if (patch !== void 0 && state.snapshot !== void 0) {
1088
+ publish({ phase: "ready", snapshot: patch(state.snapshot), refreshedAt: Date.now() });
1089
+ }
1090
+ const pendingBeforeRefresh = refreshPromise;
1091
+ if (pendingBeforeRefresh !== void 0) await pendingBeforeRefresh.catch(() => void 0);
1092
+ try {
1093
+ await refresh();
1094
+ } catch {
1095
+ }
1096
+ };
1097
+ return {
1098
+ source,
1099
+ refresh,
1100
+ async createAutomation(input) {
1101
+ const payload = { sessionId: "settings", input };
1102
+ await mutateThenRefresh("create", payload);
1103
+ },
1104
+ async mutateAutomation(automationId, mutation) {
1105
+ const payload = { sessionId: "settings", automationId, mutation };
1106
+ await mutateThenRefresh("mutate", payload, mutation === "delete" ? (snapshot) => ({
1107
+ ...snapshot,
1108
+ automations: snapshot.automations.filter((item) => item.id !== automationId)
1109
+ }) : void 0);
1110
+ },
1111
+ async updateAutomation(automationId, input) {
1112
+ const payload = { sessionId: "settings", automationId, input };
1113
+ await mutateThenRefresh("update", payload);
1114
+ },
1115
+ async runNow(automationId) {
1116
+ const payload = { sessionId: "settings", automationId };
1117
+ await mutateThenRefresh("run-now", payload);
1118
+ },
1119
+ async markRunRead(runId) {
1120
+ const payload = { sessionId: "settings", runId };
1121
+ await mutateThenRefresh("mark-read", payload);
1122
+ },
1123
+ async adoptSession(sessionId) {
1124
+ unwrapRpcResult(await rpc.call(CHANNEL, "adopt-session", { sessionId }));
1125
+ },
1126
+ async forgetSession(sessionId) {
1127
+ await mutateThenRefresh("forget-session", { sessionId }, (snapshot) => ({
1128
+ ...snapshot,
1129
+ runs: snapshot.runs.map((run) => {
1130
+ if (run.sessionId !== sessionId) return run;
1131
+ const { sessionId: _ignored, ...rest } = run;
1132
+ return rest;
1133
+ })
1134
+ }));
1135
+ },
1136
+ async forgetAutomationSessions(automationId) {
1137
+ await mutateThenRefresh("forget-automation-sessions", { automationId }, (snapshot) => ({
1138
+ ...snapshot,
1139
+ runs: snapshot.runs.map((run) => {
1140
+ if (run.automationId !== automationId) return run;
1141
+ const { sessionId: _ignored, ...rest } = run;
1142
+ return rest;
1143
+ })
1144
+ }));
1145
+ },
1146
+ async addWorkspace(path) {
1147
+ const payload = { sessionId: "settings", path };
1148
+ const value = unwrapRpcResult(await rpc.call(CHANNEL, "add-workspace", payload));
1149
+ await refresh();
1150
+ return value;
1151
+ }
1152
+ };
1153
+ }
1154
+
1155
+ // src/client/AutomationView.tsx
1156
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1157
+ var POLL_INTERVAL_MS = 15e3;
1158
+ var EXAMPLES = [
1159
+ { name: "\u6BCF\u65E5\u56DE\u5F52\u68C0\u67E5", scheduleKind: "daily", time: "09:00", weekdays: [1, 2, 3, 4, 5] },
1160
+ { name: "\u6BCF\u5468\u4F9D\u8D56\u5DE1\u68C0", scheduleKind: "weekly", time: "10:00", weekdays: [1] },
1161
+ { name: "\u5DE5\u4F5C\u65E5\u65E9\u62A5", scheduleKind: "weekly", time: "08:00", weekdays: [1, 2, 3, 4, 5] }
1162
+ ];
1163
+ function AutomationView({ t, runtime, closeSettings }) {
1164
+ const state = (0, import_react3.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
1165
+ const [tab, setTab] = (0, import_react3.useState)("mine");
1166
+ const [query, setQuery] = (0, import_react3.useState)("");
1167
+ const [creating, setCreating] = (0, import_react3.useState)(false);
1168
+ const [editingId, setEditingId] = (0, import_react3.useState)();
1169
+ const [draft, setDraft] = (0, import_react3.useState)();
1170
+ const [busy, setBusy] = (0, import_react3.useState)(false);
1171
+ const [error, setError] = (0, import_react3.useState)();
1172
+ const [historyRange, setHistoryRange] = (0, import_react3.useState)("day");
1173
+ const [historyTask, setHistoryTask] = (0, import_react3.useState)("all");
1174
+ const [historyStatus, setHistoryStatus] = (0, import_react3.useState)("all");
1175
+ const now = (0, import_react3.useMemo)(() => new Date(state.snapshot?.serverNow ?? Date.now()), [state.snapshot?.serverNow, state.refreshedAt]);
1176
+ (0, import_react3.useEffect)(() => {
1177
+ void runtime.refresh().catch(() => void 0);
1178
+ const timer = window.setInterval(() => {
1179
+ void runtime.refresh().catch(() => void 0);
1180
+ }, POLL_INTERVAL_MS);
1181
+ return () => {
1182
+ window.clearInterval(timer);
1183
+ };
1184
+ }, [runtime]);
1185
+ const snapshot = state.snapshot;
1186
+ const workspaces = snapshot?.workspaces ?? [];
1187
+ const models = snapshot?.models ?? [];
1188
+ 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));
1189
+ const runs = (snapshot?.runs ?? []).filter((run) => {
1190
+ if (historyTask !== "all" && run.automationId !== historyTask) return false;
1191
+ if (historyStatus !== "all" && run.status !== historyStatus) return false;
1192
+ return true;
1193
+ });
1194
+ const groups = groupHistory(runs, historyRange, now, t);
1195
+ const runAction = async (action) => {
1196
+ setBusy(true);
1197
+ setError(void 0);
1198
+ try {
1199
+ await action();
1200
+ } catch (caught) {
1201
+ setError(caught instanceof AutomationFormError ? t(caught.key) : isTransportError(caught) ? t("error.offline") : caught instanceof Error ? caught.message : t("error.action"));
1202
+ } finally {
1203
+ setBusy(false);
1204
+ }
1205
+ };
1206
+ const closeModal = () => {
1207
+ setCreating(false);
1208
+ setDraft(void 0);
1209
+ setEditingId(void 0);
1210
+ };
1211
+ const openCreate = (partial) => {
1212
+ setEditingId(void 0);
1213
+ setDraft(partial);
1214
+ setCreating(true);
1215
+ };
1216
+ const openEdit = (item) => {
1217
+ setEditingId(item.id);
1218
+ setDraft(formFromAutomation(item, workspaces, snapshot?.defaultModel ?? null));
1219
+ setCreating(true);
1220
+ };
1221
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-shell", children: [
1222
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("header", { className: "dsh-st-top", children: [
1223
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-heading", children: [
1224
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h1", { children: t("tab") }),
1225
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t("header.lead") })
1226
+ ] }),
1227
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-toolbar", children: [
1228
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { className: "dsh-st-search", value: query, placeholder: t("search.placeholder"), onChange: (event) => setQuery(event.target.value) }),
1229
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "dsh-st-btn", onClick: () => {
1230
+ setChatPrefill(t("chat.prompt"));
1231
+ closeSettings?.();
1232
+ }, children: [
1233
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChatIcon, {}),
1234
+ t("action.chatCreate")
1235
+ ] }),
1236
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => openCreate(), children: [
1237
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlusIcon, {}),
1238
+ t("action.create")
1239
+ ] }),
1240
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-icon", onClick: () => {
1241
+ void runtime.refresh();
1242
+ }, "aria-label": t("section.refresh"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RefreshIcon, {}) })
1243
+ ] })
1244
+ ] }),
1245
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-banner", role: "note", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
1246
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(InfoIcon, {}),
1247
+ t("banner.wake")
1248
+ ] }) }),
1249
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "dsh-st-examples", children: [
1250
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-examples-head", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { children: t("examples.title") }) }),
1251
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-example-row", children: EXAMPLES.map((example, index) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1252
+ "button",
1253
+ {
1254
+ type: "button",
1255
+ className: "dsh-st-example",
1256
+ onClick: () => openCreate({
1257
+ name: t(`examples.${index + 1}.title`),
1258
+ prompt: t(`examples.${index + 1}.body`),
1259
+ scheduleKind: example.scheduleKind,
1260
+ time: example.time,
1261
+ weekdays: example.weekdays
1262
+ }),
1263
+ children: [
1264
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: t(`examples.${index + 1}.title`) }),
1265
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t(`examples.${index + 1}.body`) }),
1266
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "dsh-st-chip", children: [
1267
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ClockIcon, {}),
1268
+ t(`examples.${index + 1}.chip`)
1269
+ ] })
1270
+ ]
1271
+ },
1272
+ example.name
1273
+ )) })
1274
+ ] }),
1275
+ error !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-st-error", children: error }),
1276
+ (state.phase === "idle" || state.phase === "loading" && snapshot === void 0) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "dsh-st-muted", children: t("loading") }),
1277
+ state.phase === "error" && snapshot === void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-empty", children: [
1278
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: t("error.title") }),
1279
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: state.error }),
1280
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => {
1281
+ void runtime.refresh();
1282
+ }, children: t("error.retry") })
1283
+ ] }),
1284
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-tabs", children: [
1285
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: tab === "mine" ? "is-on" : "", onClick: () => setTab("mine"), children: t("tabs.mine") }),
1286
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: tab === "runs" ? "is-on" : "", onClick: () => setTab("runs"), children: t("tabs.runs") }),
1287
+ tab === "mine" && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "dsh-st-sort", children: t("sort.created") }),
1288
+ tab === "runs" && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-filters", children: [
1289
+ ["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)),
1290
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { value: historyTask, onChange: (event) => setHistoryTask(event.target.value), children: [
1291
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "all", children: t("history.allTasks") }),
1292
+ (snapshot?.automations ?? []).map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: item.id, children: item.name }, item.id))
1293
+ ] }),
1294
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("select", { value: historyStatus, onChange: (event) => setHistoryStatus(event.target.value), children: [
1295
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: "all", children: t("history.allStatus") }),
1296
+ ["succeeded", "failed", "running", "queued", "skipped", "cancelled"].map((status) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("option", { value: status, children: t(`status.${status}`) }, status))
1297
+ ] })
1298
+ ] })
1299
+ ] }),
1300
+ tab === "mine" && (automations.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-empty", children: [
1301
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: t("empty.title") }),
1302
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: t("empty.body") })
1303
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "dsh-st-grid", children: automations.map((item) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1304
+ TaskCard,
1305
+ {
1306
+ item,
1307
+ t,
1308
+ now,
1309
+ busy,
1310
+ onEdit: () => openEdit(item),
1311
+ onToggle: () => {
1312
+ void runAction(() => runtime.mutateAutomation(item.id, item.status === "active" ? "pause" : "resume"));
1313
+ },
1314
+ onRun: () => {
1315
+ void runAction(() => runtime.runNow(item.id));
1316
+ },
1317
+ onDelete: () => {
1318
+ void runAction(() => runtime.mutateAutomation(item.id, "delete"));
1319
+ }
1320
+ },
1321
+ item.id
1322
+ )) })),
1323
+ 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: [
1324
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: group.label }),
1325
+ group.items.map((run) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RunRow, { run, t }, run.id))
1326
+ ] }, group.key)) })),
1327
+ creating && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1328
+ CreateModal,
1329
+ {
1330
+ t,
1331
+ busy,
1332
+ workspaces,
1333
+ models,
1334
+ defaultModel: snapshot?.defaultModel ?? null,
1335
+ skills: snapshot?.skills ?? [],
1336
+ onAddWorkspace: async (path) => runtime.addWorkspace(path).then((value) => value.id),
1337
+ editing: editingId !== void 0,
1338
+ ...draft === void 0 ? {} : { draft },
1339
+ onClose: closeModal,
1340
+ onSubmit: async (form) => {
1341
+ const input = buildCreateInput(form, workspaces, models, /* @__PURE__ */ new Date(), {
1342
+ allowPastOnce: editingId !== void 0
1343
+ });
1344
+ await runAction(async () => {
1345
+ if (editingId === void 0) await runtime.createAutomation(input);
1346
+ else await runtime.updateAutomation(editingId, input);
1347
+ closeModal();
1348
+ });
1349
+ }
1350
+ },
1351
+ editingId ?? "create"
1352
+ )
1353
+ ] });
1354
+ }
1355
+ function TaskCard({
1356
+ item,
1357
+ t,
1358
+ now,
1359
+ busy,
1360
+ onEdit,
1361
+ onToggle,
1362
+ onRun,
1363
+ onDelete
1364
+ }) {
1365
+ const [menu, setMenu] = (0, import_react3.useState)(false);
1366
+ const root = (0, import_react3.useRef)(null);
1367
+ (0, import_react3.useEffect)(() => {
1368
+ if (!menu) return;
1369
+ const close = (event) => {
1370
+ if (root.current !== null && !root.current.contains(event.target)) setMenu(false);
1371
+ };
1372
+ document.addEventListener("mousedown", close);
1373
+ return () => {
1374
+ document.removeEventListener("mousedown", close);
1375
+ };
1376
+ }, [menu]);
1377
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("article", { className: "dsh-st-card", ref: root, onClick: onEdit, children: [
1378
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-card-head", children: [
1379
+ /* @__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) => {
1380
+ event.stopPropagation();
1381
+ onToggle();
1382
+ } }),
1383
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { type: "button", className: "dsh-st-more", onClick: (event) => {
1384
+ event.stopPropagation();
1385
+ setMenu((value) => !value);
1386
+ }, "aria-label": t("card.delete"), children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MoreIcon, {}) }),
1387
+ menu && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-menu", onClick: (event) => event.stopPropagation(), children: [
1388
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", disabled: busy, onClick: () => {
1389
+ setMenu(false);
1390
+ onRun();
1391
+ }, children: [
1392
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, {}),
1393
+ t("menu.run")
1394
+ ] }),
1395
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "is-danger", disabled: busy, onClick: () => {
1396
+ setMenu(false);
1397
+ onDelete();
1398
+ }, children: [
1399
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TrashIcon, {}),
1400
+ t("menu.delete")
1401
+ ] })
1402
+ ] })
1403
+ ] }),
1404
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h3", { children: item.name }),
1405
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { children: item.prompt }),
1406
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-card-foot", children: [
1407
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "dsh-st-chip", children: [
1408
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ClockIcon, {}),
1409
+ formatSchedule(item.schedule, t)
1410
+ ] }),
1411
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: item.nextRunAt === void 0 ? t("stats.noneScheduled") : t("history.nextApprox", { when: formatWithin(item.nextRunAt, now, t) }) })
1412
+ ] })
1413
+ ] });
1414
+ }
1415
+ function RunRow({ run, t }) {
1416
+ const duration = formatDuration(run.startedAt, run.finishedAt);
1417
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("article", { className: `dsh-st-run is-${run.status}`, children: [
1418
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("strong", { children: run.automationName }),
1419
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { children: [
1420
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: clockTime(run.startedAt ?? run.scheduledFor) }),
1421
+ duration !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: duration }),
1422
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("history.trigger") })
1423
+ ] })
1424
+ ] });
1425
+ }
1426
+
1427
+ // src/client/locales.ts
1428
+ var NS = "dsh-automation";
1429
+ var en = {
1430
+ tab: "Scheduled tasks",
1431
+ "sidebar.tab": "Scheduled",
1432
+ "sidebar.tabs": "Workspace views",
1433
+ "sidebar.tasksTab": "Tasks",
1434
+ "sidebar.channelsTab": "Channels",
1435
+ "sidebar.empty": "No scheduled runs yet.",
1436
+ "sidebar.tasksEmpty": "No web tasks yet.",
1437
+ "sidebar.ungrouped": "Ungrouped",
1438
+ "sidebar.section": "Scheduled",
1439
+ "header.lead": "Plan automatic tasks, or trigger them by hand. Describe the recurring work in any chat to create it quickly.",
1440
+ "examples.title": "Recommended examples",
1441
+ "examples.1.title": "Daily regression check",
1442
+ "examples.1.body": "Create a scheduled task that runs every day and inspects new test failures.",
1443
+ "examples.1.chip": "Every day 09:00",
1444
+ "examples.2.title": "Weekly dependency review",
1445
+ "examples.2.body": "Create a scheduled task that runs every Monday and reports outdated or risky dependencies.",
1446
+ "examples.2.chip": "Monday 10:00",
1447
+ "examples.3.title": "Weekday morning briefing",
1448
+ "examples.3.body": "Create a scheduled task that runs on weekdays and summarizes overnight changes.",
1449
+ "examples.3.chip": "Weekdays 08:00",
1450
+ "chat.hint": "In any conversation, describe the recurring work and ask the Agent to call automation_create.",
1451
+ "chat.prompt": "I want to create a scheduled task that runs every [interval] and does [the actual task]",
1452
+ "menu.run": "Run now",
1453
+ "menu.delete": "Delete task",
1454
+ "session.rename": "Rename",
1455
+ "session.fork": "Fork session",
1456
+ "session.archive": "Archive session",
1457
+ "session.delete": "Delete session",
1458
+ "session.deleteFolder": "Delete folder",
1459
+ "history.range.day": "By day",
1460
+ "history.range.week": "By week",
1461
+ "history.range.month": "By month",
1462
+ "history.allTasks": "All tasks",
1463
+ "history.allStatus": "All statuses",
1464
+ "history.today": "Today",
1465
+ "history.yesterday": "Yesterday",
1466
+ "history.date": "{date}",
1467
+ "history.week": "Week of {date}",
1468
+ "history.month": "{month}",
1469
+ "history.trigger": "Scheduled",
1470
+ "history.nextApprox": "Next run in about {when}",
1471
+ "time.withinMinute": "about {count} minutes",
1472
+ "time.withinHour": "about {count} hours",
1473
+ "time.withinDay": "about {count} days",
1474
+ "search.placeholder": "Search scheduled tasks...",
1475
+ "action.chatCreate": "Create in chat",
1476
+ "action.create": "New scheduled task",
1477
+ "banner.wake": "Scheduled tasks run only while this computer stays awake.",
1478
+ "tabs.mine": "My tasks",
1479
+ "tabs.runs": "Run history",
1480
+ "sort.created": "Newest first",
1481
+ "form.workspace": "Workspace",
1482
+ "form.addWorkspace": "Add workspace...",
1483
+ "form.workspacePath": "Folder path",
1484
+ "form.workspacePathPlaceholder": "D:\\work\\project",
1485
+ "form.model": "Model",
1486
+ "form.modelDefault": "Follow default model",
1487
+ "form.effort": "Reasoning",
1488
+ "form.effort.none": "Default",
1489
+ "form.effort.low": "Low",
1490
+ "form.effort.medium": "Medium",
1491
+ "form.effort.high": "High",
1492
+ "form.error.workspace": "Select a workspace.",
1493
+ "modal.title": "New scheduled task",
1494
+ "modal.edit": "Edit scheduled task",
1495
+ "modal.save": "Save",
1496
+ "header.eyebrow": "Unattended coding work",
1497
+ "header.title": "Automations",
1498
+ "header.subtitle": "Schedule standalone, auditable Agent runs for this workspace.",
1499
+ "header.create": "New automation",
1500
+ "header.closeCreate": "Hide form",
1501
+ "scope.workspace": "Workspace",
1502
+ "scope.folder": "Working directory",
1503
+ "stats.total": "All",
1504
+ "stats.active": "Active",
1505
+ "stats.next": "Next run",
1506
+ "stats.attention": "Needs attention",
1507
+ "stats.noneScheduled": "None scheduled",
1508
+ "stats.noAttention": "All clear",
1509
+ "section.automations": "Workspace automations",
1510
+ "section.automationsHint": "Each trigger starts a fresh DSH Session and keeps its own audit record.",
1511
+ "section.runs": "Recent runs",
1512
+ "section.runsHint": "Latest outcomes for this workspace.",
1513
+ "section.refresh": "Refresh",
1514
+ "empty.title": "Let recurring coding work run itself",
1515
+ "empty.body": "Save a self-contained task, a schedule, and a permission boundary. Every run starts in a new Session.",
1516
+ "empty.action": "Create the first automation",
1517
+ "runs.empty": "No runs yet. Run one now, or wait for the next scheduled occurrence.",
1518
+ "form.title": "Create automation",
1519
+ "form.subtitle": "Write a complete, standalone task. Scheduled runs do not inherit this conversation.",
1520
+ "form.name": "Name",
1521
+ "form.namePlaceholder": "Daily regression triage",
1522
+ "form.prompt": "Task prompt",
1523
+ "form.promptPlaceholder": "Inspect new test failures, locate the regression, and propose a verified minimal fix\u2026",
1524
+ "form.schedule": "Schedule",
1525
+ "form.planTime": "Schedule",
1526
+ "form.hourly": "Hourly",
1527
+ "form.monthly": "Monthly",
1528
+ "form.custom": "Custom",
1529
+ "form.minutesShort": "min",
1530
+ "form.daysShort": "days",
1531
+ "form.monthDay": "Day {day} of month",
1532
+ "form.skills": "Skills",
1533
+ "form.skillsEmpty": "No skills available",
1534
+ "schedule.hourlyAt": "Every hour at :{minute}",
1535
+ "schedule.monthlyAt": "Monthly on day {day} \xB7 {time}",
1536
+ "schedule.customAt": "Every {count} days \xB7 {time}",
1537
+ "form.once": "Does not repeat",
1538
+ "form.interval": "Interval",
1539
+ "form.daily": "Daily",
1540
+ "form.weekly": "Weekly",
1541
+ "form.runAt": "Run at",
1542
+ "form.every": "Every",
1543
+ "form.minutes": "minutes",
1544
+ "form.time": "Time",
1545
+ "form.days": "Weekdays",
1546
+ "form.timeZone": "Time zone",
1547
+ "form.permission": "Permission boundary",
1548
+ "form.readOnly": "Read Only",
1549
+ "form.readOnlyHint": "Inspect the workspace without changing files.",
1550
+ "form.workspaceWrite": "Workspace Write",
1551
+ "form.fullAccess": "Full access",
1552
+ "form.workspaceWriteHint": "May change files in this workspace; past approvals are not reused.",
1553
+ "form.cancel": "Cancel",
1554
+ "form.submit": "Create automation",
1555
+ "form.submitting": "Creating\u2026",
1556
+ "form.error.name": "Enter a name.",
1557
+ "form.error.prompt": "Enter a complete, standalone task prompt.",
1558
+ "form.error.once": "Choose a valid future date and time.",
1559
+ "form.error.interval": "The interval must be between 5 and 43,200 minutes.",
1560
+ "form.error.weekdays": "Select at least one weekday.",
1561
+ "day.1": "Mon",
1562
+ "day.2": "Tue",
1563
+ "day.3": "Wed",
1564
+ "day.4": "Thu",
1565
+ "day.5": "Fri",
1566
+ "day.6": "Sat",
1567
+ "day.7": "Sun",
1568
+ "status.active": "Active",
1569
+ "status.paused": "Paused",
1570
+ "status.queued": "Queued",
1571
+ "status.running": "Running",
1572
+ "status.succeeded": "Succeeded",
1573
+ "status.failed": "Failed",
1574
+ "status.skipped": "Skipped",
1575
+ "status.cancelled": "Cancelled",
1576
+ "status.interrupted": "Interrupted",
1577
+ "card.nextRun": "Next",
1578
+ "card.lastRun": "Last",
1579
+ "card.never": "Not yet run",
1580
+ "card.permission.read-only": "Read-only",
1581
+ "card.permission.workspace-write": "Workspace write",
1582
+ "card.permission.full-access": "Full access",
1583
+ "schedule.onceAt": "Once \xB7 {time}",
1584
+ "schedule.everyMinutes": "Every {count} minutes",
1585
+ "schedule.dailyAt": "Daily \xB7 {time}",
1586
+ "schedule.weeklyAt": "{days} \xB7 {time}",
1587
+ "card.pause": "Pause",
1588
+ "card.resume": "Resume",
1589
+ "card.runNow": "Run now",
1590
+ "card.delete": "Delete",
1591
+ "card.confirmDelete": "Delete this automation?",
1592
+ "card.confirmDeleteHint": "Run history is kept for audit.",
1593
+ "card.confirm": "Delete",
1594
+ "card.cancel": "Cancel",
1595
+ "run.trigger.schedule": "Scheduled",
1596
+ "run.trigger.manual": "Manual",
1597
+ "run.trigger.catch-up": "Catch-up",
1598
+ "run.openSession": "Session {id}",
1599
+ "run.markRead": "Mark reviewed",
1600
+ loading: "Loading automations\u2026",
1601
+ "error.title": "Automations could not be loaded",
1602
+ "error.retry": "Try again",
1603
+ "error.action": "The action failed. Please try again.",
1604
+ "error.offline": "Could not reach the local automation service. Check that DSH is still running and try again.",
1605
+ "time.now": "now",
1606
+ "time.minuteAgo": "{count}m ago",
1607
+ "time.hourAgo": "{count}h ago",
1608
+ "time.dayAgo": "{count}d ago",
1609
+ "time.inMinute": "in {count}m",
1610
+ "time.inHour": "in {count}h",
1611
+ "time.inDay": "in {count}d"
1612
+ };
1613
+ var zh = {
1614
+ tab: "\u5B9A\u65F6\u4EFB\u52A1",
1615
+ "sidebar.tab": "\u5B9A\u65F6",
1616
+ "sidebar.tabs": "\u5DE5\u4F5C\u533A\u5206\u7C7B",
1617
+ "sidebar.tasksTab": "\u4EFB\u52A1",
1618
+ "sidebar.channelsTab": "\u9891\u9053",
1619
+ "sidebar.empty": "\u8FD8\u6CA1\u6709\u5B9A\u65F6\u4EFB\u52A1\u6267\u884C\u8BB0\u5F55\u3002",
1620
+ "sidebar.tasksEmpty": "\u6682\u65E0\u7F51\u9875\u4EFB\u52A1",
1621
+ "sidebar.ungrouped": "\u672A\u5206\u7EC4",
1622
+ "sidebar.section": "\u5B9A\u65F6\u4EFB\u52A1",
1623
+ "header.lead": "\u6309\u8BA1\u5212\u81EA\u52A8\u6267\u884C\u4EFB\u52A1\uFF0C\u4E5F\u53EF\u968F\u65F6\u624B\u52A8\u89E6\u53D1\u3002\u5728\u4EFB\u610F\u5BF9\u8BDD\u4E2D\u63CF\u8FF0\u4F60\u60F3\u5B9A\u671F\u505A\u7684\u4E8B\uFF0C\u5373\u53EF\u5FEB\u901F\u521B\u5EFA",
1624
+ "examples.title": "\u63A8\u8350\u6848\u4F8B",
1625
+ "examples.1.title": "\u6BCF\u65E5\u56DE\u5F52\u68C0\u67E5",
1626
+ "examples.1.body": "\u6211\u8981\u521B\u5EFA\u4E00\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u6BCF\u3010\u5929\u3011\u6267\u884C\u3010\u68C0\u67E5\u65B0\u589E\u6D4B\u8BD5\u5931\u8D25\u5E76\u7ED9\u51FA\u6700\u5C0F\u4FEE\u590D\u3011\u3002",
1627
+ "examples.1.chip": "\u6BCF\u5929 09:00",
1628
+ "examples.2.title": "\u6BCF\u5468\u4F9D\u8D56\u5DE1\u68C0",
1629
+ "examples.2.body": "\u6211\u8981\u521B\u5EFA\u4E00\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u6BCF\u3010\u5468\u4E00\u3011\u6267\u884C\u3010\u68C0\u67E5\u8FC7\u671F\u6216\u6709\u98CE\u9669\u7684\u4F9D\u8D56\u5E76\u7ED9\u51FA\u5904\u7406\u5EFA\u8BAE\u3011\u3002",
1630
+ "examples.2.chip": "\u6BCF\u5468\u4E00 10:00",
1631
+ "examples.3.title": "\u5DE5\u4F5C\u65E5\u65E9\u62A5",
1632
+ "examples.3.body": "\u6211\u8981\u521B\u5EFA\u4E00\u4E2A\u5B9A\u65F6\u4EFB\u52A1\uFF0C\u6BCF\u3010\u5DE5\u4F5C\u65E5\u3011\u6267\u884C\u3010\u6C47\u603B\u6628\u591C\u4ED3\u5E93\u53D8\u66F4\u5E76\u7ED9\u51FA\u4ECA\u65E5\u5173\u6CE8\u70B9\u3011\u3002",
1633
+ "examples.3.chip": "\u5DE5\u4F5C\u65E5 08:00",
1634
+ "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",
1635
+ "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",
1636
+ "menu.run": "\u7ACB\u5373\u6267\u884C",
1637
+ "menu.delete": "\u5220\u9664\u4EFB\u52A1",
1638
+ "session.rename": "\u91CD\u547D\u540D",
1639
+ "session.fork": "\u5206\u53C9\u4F1A\u8BDD",
1640
+ "session.archive": "\u5F52\u6863\u4F1A\u8BDD",
1641
+ "session.delete": "\u5220\u9664\u4F1A\u8BDD",
1642
+ "session.deleteFolder": "\u5220\u9664\u6587\u4EF6\u5939",
1643
+ "history.range.day": "\u6309\u5929",
1644
+ "history.range.week": "\u6309\u5468",
1645
+ "history.range.month": "\u6309\u6708",
1646
+ "history.allTasks": "\u5168\u90E8\u4EFB\u52A1",
1647
+ "history.allStatus": "\u5168\u90E8\u72B6\u6001",
1648
+ "history.today": "\u4ECA\u5929",
1649
+ "history.yesterday": "\u6628\u5929",
1650
+ "history.date": "{date}",
1651
+ "history.week": "{date} \u5F53\u5468",
1652
+ "history.month": "{month}",
1653
+ "history.trigger": "\u5B9A\u65F6\u89E6\u53D1",
1654
+ "history.nextApprox": "\u4E0B\u6B21\u6267\u884C \u5927\u7EA6 {when}",
1655
+ "time.withinMinute": "{count} \u5206\u949F\u5185",
1656
+ "time.withinHour": "{count} \u5C0F\u65F6\u5185",
1657
+ "time.withinDay": "{count} \u5929\u5185",
1658
+ "search.placeholder": "\u641C\u7D22\u5B9A\u65F6\u4EFB\u52A1...",
1659
+ "action.chatCreate": "\u901A\u8FC7\u5BF9\u8BDD\u521B\u5EFA",
1660
+ "action.create": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
1661
+ "banner.wake": "\u5B9A\u65F6\u4EFB\u52A1\u4EC5\u5728\u7535\u8111\u4FDD\u6301\u5524\u9192\u65F6\u8FD0\u884C",
1662
+ "tabs.mine": "\u6211\u7684\u5B9A\u65F6\u4EFB\u52A1",
1663
+ "tabs.runs": "\u6267\u884C\u8BB0\u5F55",
1664
+ "sort.created": "\u6309\u521B\u5EFA\u65F6\u95F4\u5012\u5E8F",
1665
+ "form.workspace": "\u5DE5\u4F5C\u76EE\u5F55",
1666
+ "form.addWorkspace": "\u6DFB\u52A0\u5DE5\u4F5C\u533A...",
1667
+ "form.workspacePath": "\u76EE\u5F55\u8DEF\u5F84",
1668
+ "form.workspacePathPlaceholder": "D:\\work\\project",
1669
+ "form.model": "\u6A21\u578B",
1670
+ "form.modelDefault": "\u8DDF\u968F\u9ED8\u8BA4\u6A21\u578B",
1671
+ "form.effort": "\u63A8\u7406\u7B49\u7EA7",
1672
+ "form.effort.none": "\u9ED8\u8BA4",
1673
+ "form.effort.low": "Low",
1674
+ "form.effort.medium": "Medium",
1675
+ "form.effort.high": "High",
1676
+ "form.error.workspace": "\u8BF7\u9009\u62E9\u5DE5\u4F5C\u533A\u3002",
1677
+ "modal.title": "\u65B0\u5EFA\u5B9A\u65F6\u4EFB\u52A1",
1678
+ "modal.edit": "\u7F16\u8F91\u5B9A\u65F6\u4EFB\u52A1",
1679
+ "modal.save": "\u4FDD\u5B58",
1680
+ "header.eyebrow": "\u81EA\u4E3B\u7F16\u7801\u4EFB\u52A1",
1681
+ "header.title": "\u81EA\u52A8\u5316",
1682
+ "header.subtitle": "\u4E3A\u5F53\u524D\u5DE5\u4F5C\u533A\u5B89\u6392\u72EC\u7ACB\u3001\u53EF\u5BA1\u8BA1\u7684 Agent \u8FD0\u884C\u3002",
1683
+ "header.create": "\u65B0\u5EFA\u81EA\u52A8\u5316",
1684
+ "header.closeCreate": "\u6536\u8D77\u8868\u5355",
1685
+ "scope.workspace": "\u5DE5\u4F5C\u533A",
1686
+ "scope.folder": "\u5DE5\u4F5C\u76EE\u5F55",
1687
+ "stats.total": "\u5168\u90E8",
1688
+ "stats.active": "\u5DF2\u542F\u7528",
1689
+ "stats.next": "\u4E0B\u6B21\u8FD0\u884C",
1690
+ "stats.attention": "\u9700\u8981\u5173\u6CE8",
1691
+ "stats.noneScheduled": "\u6682\u65E0\u8BA1\u5212",
1692
+ "stats.noAttention": "\u4E00\u5207\u6B63\u5E38",
1693
+ "section.automations": "\u5DE5\u4F5C\u533A\u81EA\u52A8\u5316",
1694
+ "section.automationsHint": "\u6BCF\u6B21\u89E6\u53D1\u90FD\u4F1A\u521B\u5EFA\u4E00\u4E2A\u5168\u65B0\u7684 DSH Session\uFF0C\u5E76\u4FDD\u7559\u72EC\u7ACB\u5BA1\u8BA1\u8BB0\u5F55\u3002",
1695
+ "section.runs": "\u6700\u8FD1\u8FD0\u884C",
1696
+ "section.runsHint": "\u5F53\u524D\u5DE5\u4F5C\u533A\u6700\u8FD1\u7684\u6267\u884C\u72B6\u6001\u3002",
1697
+ "section.refresh": "\u5237\u65B0",
1698
+ "empty.title": "\u8BA9\u91CD\u590D\u7684\u7F16\u7801\u5DE5\u4F5C\u81EA\u52A8\u8FD0\u884C",
1699
+ "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",
1700
+ "empty.action": "\u521B\u5EFA\u7B2C\u4E00\u4E2A\u81EA\u52A8\u5316",
1701
+ "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",
1702
+ "form.title": "\u521B\u5EFA\u81EA\u52A8\u5316",
1703
+ "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",
1704
+ "form.name": "\u540D\u79F0",
1705
+ "form.namePlaceholder": "\u6BCF\u65E5\u56DE\u5F52\u6D4B\u8BD5\u5206\u8BCA",
1706
+ "form.prompt": "\u4EFB\u52A1\u6307\u4EE4",
1707
+ "form.promptPlaceholder": "\u68C0\u67E5\u65B0\u589E\u6D4B\u8BD5\u5931\u8D25\uFF0C\u5B9A\u4F4D\u56DE\u5F52\u539F\u56E0\uFF0C\u5E76\u7ED9\u51FA\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u6700\u5C0F\u4FEE\u590D\u65B9\u6848\u2026\u2026",
1708
+ "form.schedule": "\u8FD0\u884C\u8BA1\u5212",
1709
+ "form.planTime": "\u8BA1\u5212\u65F6\u95F4",
1710
+ "form.hourly": "\u6BCF\u5C0F\u65F6",
1711
+ "form.monthly": "\u6BCF\u6708",
1712
+ "form.custom": "\u81EA\u5B9A\u4E49",
1713
+ "form.minutesShort": "\u5206",
1714
+ "form.daysShort": "\u5929",
1715
+ "form.monthDay": "\u6BCF\u6708\u7B2C {day} \u5929",
1716
+ "form.skills": "\u6280\u80FD",
1717
+ "form.skillsEmpty": "\u6682\u65E0\u53EF\u7528\u6280\u80FD",
1718
+ "schedule.hourlyAt": "\u6BCF\u5C0F\u65F6 :{minute}",
1719
+ "schedule.monthlyAt": "\u6BCF\u6708 {day} \u65E5 \xB7 {time}",
1720
+ "schedule.customAt": "\u6BCF {count} \u5929 \xB7 {time}",
1721
+ "form.once": "\u4E0D\u91CD\u590D",
1722
+ "form.interval": "\u95F4\u9694",
1723
+ "form.daily": "\u6BCF\u5929",
1724
+ "form.weekly": "\u6BCF\u5468",
1725
+ "form.runAt": "\u8FD0\u884C\u65F6\u95F4",
1726
+ "form.every": "\u6BCF\u9694",
1727
+ "form.minutes": "\u5206\u949F",
1728
+ "form.time": "\u65F6\u95F4",
1729
+ "form.days": "\u661F\u671F",
1730
+ "form.timeZone": "\u65F6\u533A",
1731
+ "form.permission": "\u6743\u9650\u8FB9\u754C",
1732
+ "form.readOnly": "Read Only",
1733
+ "form.readOnlyHint": "\u53EF\u4EE5\u68C0\u67E5\u5DE5\u4F5C\u533A\uFF0C\u4F46\u4E0D\u4F1A\u4FEE\u6539\u6587\u4EF6\u3002",
1734
+ "form.workspaceWrite": "Workspace Write",
1735
+ "form.fullAccess": "Full access",
1736
+ "form.workspaceWriteHint": "\u53EF\u4EE5\u4FEE\u6539\u5F53\u524D\u5DE5\u4F5C\u533A\u6587\u4EF6\uFF1B\u4E0D\u4F1A\u7EE7\u627F\u5386\u53F2\u6279\u51C6\u3002",
1737
+ "form.cancel": "\u53D6\u6D88",
1738
+ "form.submit": "\u521B\u5EFA\u81EA\u52A8\u5316",
1739
+ "form.submitting": "\u521B\u5EFA\u4E2D\u2026",
1740
+ "form.error.name": "\u8BF7\u8F93\u5165\u540D\u79F0\u3002",
1741
+ "form.error.prompt": "\u8BF7\u8F93\u5165\u5B8C\u6574\u3001\u72EC\u7ACB\u7684\u4EFB\u52A1\u6307\u4EE4\u3002",
1742
+ "form.error.once": "\u8BF7\u9009\u62E9\u6709\u6548\u7684\u672A\u6765\u65E5\u671F\u548C\u65F6\u95F4\u3002",
1743
+ "form.error.interval": "\u8FD0\u884C\u95F4\u9694\u5FC5\u987B\u5728 5 \u5230 43,200 \u5206\u949F\u4E4B\u95F4\u3002",
1744
+ "form.error.weekdays": "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5929\u3002",
1745
+ "day.1": "\u5468\u4E00",
1746
+ "day.2": "\u5468\u4E8C",
1747
+ "day.3": "\u5468\u4E09",
1748
+ "day.4": "\u5468\u56DB",
1749
+ "day.5": "\u5468\u4E94",
1750
+ "day.6": "\u5468\u516D",
1751
+ "day.7": "\u5468\u65E5",
1752
+ "status.active": "\u5DF2\u542F\u7528",
1753
+ "status.paused": "\u5DF2\u6682\u505C",
1754
+ "status.queued": "\u6392\u961F\u4E2D",
1755
+ "status.running": "\u8FD0\u884C\u4E2D",
1756
+ "status.succeeded": "\u5DF2\u5B8C\u6210",
1757
+ "status.failed": "\u5931\u8D25",
1758
+ "status.skipped": "\u5DF2\u8DF3\u8FC7",
1759
+ "status.cancelled": "\u5DF2\u53D6\u6D88",
1760
+ "status.interrupted": "\u5DF2\u4E2D\u65AD",
1761
+ "card.nextRun": "\u4E0B\u6B21",
1762
+ "card.lastRun": "\u6700\u8FD1",
1763
+ "card.never": "\u5C1A\u672A\u8FD0\u884C",
1764
+ "card.permission.read-only": "\u53EA\u8BFB",
1765
+ "card.permission.workspace-write": "\u53EF\u5199\u5DE5\u4F5C\u533A",
1766
+ "card.permission.full-access": "Full access",
1767
+ "schedule.onceAt": "\u5355\u6B21 \xB7 {time}",
1768
+ "schedule.everyMinutes": "\u6BCF {count} \u5206\u949F",
1769
+ "schedule.dailyAt": "\u6BCF\u5929 \xB7 {time}",
1770
+ "schedule.weeklyAt": "{days} \xB7 {time}",
1771
+ "card.pause": "\u6682\u505C",
1772
+ "card.resume": "\u6062\u590D",
1773
+ "card.runNow": "\u7ACB\u5373\u8FD0\u884C",
1774
+ "card.delete": "\u5220\u9664",
1775
+ "card.confirmDelete": "\u786E\u8BA4\u5220\u9664\u8FD9\u4E2A\u81EA\u52A8\u5316\uFF1F",
1776
+ "card.confirmDeleteHint": "\u8FD0\u884C\u5386\u53F2\u4F1A\u4FDD\u7559\u7528\u4E8E\u5BA1\u8BA1\u3002",
1777
+ "card.confirm": "\u786E\u8BA4\u5220\u9664",
1778
+ "card.cancel": "\u53D6\u6D88",
1779
+ "run.trigger.schedule": "\u5B9A\u65F6",
1780
+ "run.trigger.manual": "\u624B\u52A8",
1781
+ "run.trigger.catch-up": "\u8865\u507F\u8FD0\u884C",
1782
+ "run.openSession": "Session {id}",
1783
+ "run.markRead": "\u6807\u8BB0\u5DF2\u5904\u7406",
1784
+ loading: "\u6B63\u5728\u52A0\u8F7D\u81EA\u52A8\u5316\u2026",
1785
+ "error.title": "\u65E0\u6CD5\u52A0\u8F7D\u81EA\u52A8\u5316",
1786
+ "error.retry": "\u91CD\u8BD5",
1787
+ "error.action": "\u64CD\u4F5C\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u3002",
1788
+ "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",
1789
+ "time.now": "\u521A\u521A",
1790
+ "time.minuteAgo": "{count} \u5206\u949F\u524D",
1791
+ "time.hourAgo": "{count} \u5C0F\u65F6\u524D",
1792
+ "time.dayAgo": "{count} \u5929\u524D",
1793
+ "time.inMinute": "{count} \u5206\u949F\u540E",
1794
+ "time.inHour": "{count} \u5C0F\u65F6\u540E",
1795
+ "time.inDay": "{count} \u5929\u540E"
1796
+ };
1797
+
1798
+ // src/client/native-tabs.ts
1799
+ var NATIVE_TABS_KEY = "__dshNativeTabs";
1800
+ function createNativeTabRegistry(officialTree) {
1801
+ const tabs = /* @__PURE__ */ new Map();
1802
+ const sessionFilters = [];
1803
+ const listeners2 = /* @__PURE__ */ new Set();
1804
+ let cachedTabs = [];
1805
+ const rebuild = () => {
1806
+ cachedTabs = [...tabs.values()].sort((left, right) => (left.order ?? 0) - (right.order ?? 0));
1807
+ };
1808
+ const emit = () => {
1809
+ for (const listener of listeners2) listener();
1810
+ };
1811
+ return {
1812
+ version: 1,
1813
+ officialTree,
1814
+ sessionFilters,
1815
+ getTabs() {
1816
+ return cachedTabs;
1817
+ },
1818
+ subscribe(listener) {
1819
+ listeners2.add(listener);
1820
+ return () => {
1821
+ listeners2.delete(listener);
1822
+ };
1823
+ },
1824
+ insert(tab) {
1825
+ if (tab.id === "") return () => void 0;
1826
+ const existed = tabs.get(tab.id);
1827
+ tabs.set(tab.id, tab);
1828
+ if (existed !== tab) {
1829
+ rebuild();
1830
+ emit();
1831
+ }
1832
+ return () => {
1833
+ tabs.delete(tab.id);
1834
+ rebuild();
1835
+ emit();
1836
+ };
1837
+ },
1838
+ addSessionFilter(filter) {
1839
+ sessionFilters.push(filter);
1840
+ emit();
1841
+ return () => {
1842
+ const index = sessionFilters.indexOf(filter);
1843
+ if (index >= 0) sessionFilters.splice(index, 1);
1844
+ emit();
1845
+ };
1846
+ }
1847
+ };
1848
+ }
1849
+ function getNativeTabRegistry(target) {
1850
+ if (target === void 0 || target === null || typeof target !== "object" && typeof target !== "function") return void 0;
1851
+ const registry = target[NATIVE_TABS_KEY];
1852
+ if (registry === void 0 || registry === null || typeof registry !== "object") return void 0;
1853
+ return typeof registry.insert === "function" ? registry : void 0;
1854
+ }
1855
+ function attachNativeTabRegistry(target, registry) {
1856
+ try {
1857
+ target[NATIVE_TABS_KEY] = registry;
1858
+ } catch {
1859
+ }
1860
+ return registry;
1861
+ }
1862
+ function findNativeTabRegistry(entry) {
1863
+ const record = entry;
1864
+ return getNativeTabRegistry(entry) ?? getNativeTabRegistry(record?.component);
1865
+ }
1866
+ function isForeignSidebarHost(component) {
1867
+ if (component === void 0 || component === null) return false;
1868
+ const flags = component;
1869
+ if (flags.__dshNativeTabHost === true) return true;
1870
+ if (flags.__imConnectWrapped === true) return true;
1871
+ return getNativeTabRegistry(component) !== void 0;
1872
+ }
1873
+
1874
+ // src/client/native-session-list.tsx
1875
+ var import_react4 = require("react");
1876
+
1877
+ // src/run-title.ts
1878
+ function formatRunStamp(iso) {
1879
+ const value = new Date(iso);
1880
+ if (Number.isNaN(value.getTime())) return iso;
1881
+ const date = `${value.getFullYear()}-${String(value.getMonth() + 1).padStart(2, "0")}-${String(value.getDate()).padStart(2, "0")}`;
1882
+ const time = `${String(value.getHours()).padStart(2, "0")}:${String(value.getMinutes()).padStart(2, "0")}`;
1883
+ return `${date} ${time}`;
1884
+ }
1885
+
1886
+ // src/client/schedule-rail-model.ts
1887
+ var AUTOMATION_SESSION_PREFIX = "dsh-automation-session-";
1888
+ var NATIVE_SIDEBAR_TAB_KEY = "dsh-automation.sidebar-tab";
1889
+ function groupScheduledSessions(automations, runs) {
1890
+ const nameById = /* @__PURE__ */ new Map();
1891
+ for (const item of automations) nameById.set(item.id, item.name);
1892
+ for (const run of runs) {
1893
+ const stored = (run.automationName || "").trim();
1894
+ if (stored !== "" && stored !== run.automationId && !nameById.has(run.automationId)) {
1895
+ nameById.set(run.automationId, stored);
1896
+ }
1897
+ }
1898
+ const ids = [];
1899
+ const seen = /* @__PURE__ */ new Set();
1900
+ for (const item of automations) {
1901
+ if (seen.has(item.id)) continue;
1902
+ ids.push(item.id);
1903
+ seen.add(item.id);
1904
+ }
1905
+ for (const run of runs) {
1906
+ if (run.sessionId === void 0 || run.sessionId === "" || seen.has(run.automationId)) continue;
1907
+ ids.push(run.automationId);
1908
+ seen.add(run.automationId);
1909
+ }
1910
+ return ids.map((id) => {
1911
+ const name2 = nameById.get(id) ?? id;
1912
+ return {
1913
+ id,
1914
+ name: name2,
1915
+ 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) => ({
1916
+ id: run.sessionId,
1917
+ running: run.status === "running" || run.status === "queued",
1918
+ label: formatRunStamp(run.startedAt ?? run.scheduledFor) + " - " + name2
1919
+ }))
1920
+ };
1921
+ }).filter((group) => group.sessions.length > 0);
1922
+ }
1923
+ function isNativeTaskSession(item) {
1924
+ if (item === void 0 || item.blank === true) return false;
1925
+ if (item.origin === "im" || item.origin === "subagent") return false;
1926
+ const id = item.id ?? "";
1927
+ if (id.startsWith("im:")) return false;
1928
+ if (id.startsWith(AUTOMATION_SESSION_PREFIX)) return false;
1929
+ return true;
1930
+ }
1931
+ function groupNativeTaskSessions(sessions, workspaces, ungroupedLabel) {
1932
+ const byId = sessions.byId ?? {};
1933
+ const archived = new Set(workspaces?.archivedSessionIds ?? []);
1934
+ const assigned = /* @__PURE__ */ new Set();
1935
+ const groups = [];
1936
+ for (const workspace of workspaces?.items ?? []) {
1937
+ const items = (workspace.sessionIds ?? []).map((id) => byId[id]).filter((item) => item !== void 0 && item.id !== void 0 && isNativeTaskSession(item) && !archived.has(item.id));
1938
+ for (const item of items) {
1939
+ if (item.id !== void 0) assigned.add(item.id);
1940
+ }
1941
+ if (items.length > 0) {
1942
+ groups.push({
1943
+ id: workspace.workspaceId ?? workspace.id ?? workspace.path ?? workspace.title ?? "workspace",
1944
+ label: workspace.title || workspace.path || ungroupedLabel,
1945
+ sessions: items
1946
+ });
1947
+ }
1948
+ }
1949
+ const ungrouped = (sessions.ids ?? []).map((id) => byId[id]).filter((item) => item !== void 0 && item.id !== void 0 && !assigned.has(item.id) && isNativeTaskSession(item) && !archived.has(item.id));
1950
+ if (ungrouped.length > 0) groups.push({ id: "", label: ungroupedLabel, sessions: ungrouped });
1951
+ return groups;
1952
+ }
1953
+ function readNativeSidebarTab(raw) {
1954
+ if (raw === "channels" || raw === "schedule" || raw === "tasks") return raw;
1955
+ return "tasks";
1956
+ }
1957
+ function tabForSessionId(sessionId) {
1958
+ if (sessionId === void 0 || sessionId === null || sessionId === "") return void 0;
1959
+ if (sessionId.startsWith(AUTOMATION_SESSION_PREFIX)) return "schedule";
1960
+ if (sessionId.startsWith("im:")) return "channels";
1961
+ return void 0;
1962
+ }
1963
+ function occupantLooksLikeCodexUi(value) {
1964
+ return /dsh-codex-ui|michengai-codex-ui|michengai\.codexUi|codex-ui/i.test(String(value ?? ""));
1965
+ }
1966
+ function slotOccupantName(item) {
1967
+ const record = item;
1968
+ return String(
1969
+ record?.options?.locale ?? record?.options?.id ?? record?.options?.name ?? record?.options?.registrant ?? record?.component?.displayName ?? record?.component?.name ?? record?.id ?? record?.name ?? ""
1970
+ );
1971
+ }
1972
+ function hasCodexUiSidebar(entries) {
1973
+ return (entries ?? []).some((item) => occupantLooksLikeCodexUi(slotOccupantName(item)));
1974
+ }
1975
+ function filterTaskSessionState(state) {
1976
+ const src = state ?? { ids: [], byId: {}, current: null };
1977
+ const ids = (src.ids ?? []).filter((id) => {
1978
+ const value = String(id);
1979
+ return !value.startsWith(AUTOMATION_SESSION_PREFIX) && !value.startsWith("im:");
1980
+ });
1981
+ const byId = {};
1982
+ for (const id of ids) {
1983
+ const item = src.byId?.[id];
1984
+ if (item !== void 0) byId[id] = item;
1985
+ }
1986
+ return { ...src, ids, byId };
1987
+ }
1988
+ function openScheduledSession(id, openRuntime, openHost) {
1989
+ if (id === "") return;
1990
+ const attempts = id.startsWith(AUTOMATION_SESSION_PREFIX) || id.startsWith("im:") ? [openRuntime, openHost] : [openHost, openRuntime];
1991
+ for (const attempt of attempts) {
1992
+ if (typeof attempt !== "function") continue;
1993
+ try {
1994
+ attempt(id);
1995
+ return;
1996
+ } catch {
1997
+ }
1998
+ }
1999
+ }
2000
+ function isHiddenSidebarSessionId(id) {
2001
+ return id.startsWith(AUTOMATION_SESSION_PREFIX) || id.startsWith("im:");
2002
+ }
2003
+ function filterWorkspaceListState(state) {
2004
+ const src = state ?? { items: [], archivedSessionIds: [] };
2005
+ const items = (src.items ?? []).map((workspace) => ({
2006
+ ...workspace,
2007
+ sessionIds: (workspace.sessionIds ?? []).filter((sid) => !isHiddenSidebarSessionId(String(sid)))
2008
+ }));
2009
+ return { ...src, items };
2010
+ }
2011
+ function wrapperFlags(component) {
2012
+ if (component === void 0 || component === null || typeof component !== "function" && typeof component !== "object") return {};
2013
+ return component;
2014
+ }
2015
+ function isOwnAutomationWrapper(component) {
2016
+ return wrapperFlags(component).__dshAutomationWrapped === true;
2017
+ }
2018
+ function resolveOfficialTreeComponent(component) {
2019
+ const seen = /* @__PURE__ */ new Set();
2020
+ let current = component;
2021
+ while (current !== void 0 && current !== null && !seen.has(current)) {
2022
+ seen.add(current);
2023
+ const flags = wrapperFlags(current);
2024
+ const next = flags.__dshAutomationOriginal ?? flags.__imConnectOriginal;
2025
+ if (next !== void 0 && next !== current) {
2026
+ current = next;
2027
+ continue;
2028
+ }
2029
+ if (flags.__dshAutomationWrapped === true || flags.__imConnectWrapped === true) return void 0;
2030
+ return current;
2031
+ }
2032
+ return void 0;
2033
+ }
2034
+ function isAutomationWorkspaceWrapper(item) {
2035
+ const record = item;
2036
+ const id = String(record?.options?.id ?? "");
2037
+ const name2 = String(record?.component?.displayName ?? record?.component?.name ?? "");
2038
+ return id === "dsh-automation-native-switcher" || id === "dsh-automation-wrap-bump" || name2 === "AutomationNativeWorkspaceShell" || name2 === "AutomationWrapBump" || isOwnAutomationWrapper(record?.component);
2039
+ }
2040
+ function pickWrappableWorkspacesEntry(entries) {
2041
+ for (const item of entries) {
2042
+ const record = item;
2043
+ if (record?.component === void 0) continue;
2044
+ if (isAutomationWorkspaceWrapper(item)) continue;
2045
+ return item;
2046
+ }
2047
+ return void 0;
2048
+ }
2049
+
2050
+ // src/client/native-session-list.tsx
2051
+ var import_jsx_runtime5 = require("react/jsx-runtime");
2052
+ var EMPTY_SESSION_BY_ID = {};
2053
+ function relativeTime(value) {
2054
+ const ts = Date.parse(value || "");
2055
+ if (!Number.isFinite(ts)) return "";
2056
+ const delta = Math.max(0, Date.now() - ts);
2057
+ const min = Math.floor(delta / 6e4);
2058
+ if (min < 1) return "\u521A\u521A";
2059
+ if (min < 60) return String(min) + "\u5206\u949F";
2060
+ const hour = Math.floor(min / 60);
2061
+ if (hour < 24) return String(hour) + "\u5C0F\u65F6";
2062
+ return String(Math.floor(hour / 24)) + "\u5929";
2063
+ }
2064
+ function NativeScheduleSessionList(props) {
2065
+ const { t, runtime, openSession, useSessions, useWorkspaces, renameSession, archiveSession, deleteSession, forkSession } = props;
2066
+ const state = (0, import_react4.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2067
+ const selectedId = useSessions ? useSessions((snap) => snap?.current ?? null) : null;
2068
+ const sessionById = useSessions ? useSessions((snap) => snap?.byId ?? EMPTY_SESSION_BY_ID) : EMPTY_SESSION_BY_ID;
2069
+ const archivedIds = useWorkspaces ? useWorkspaces((snap) => snap?.archivedSessionIds ?? []) : [];
2070
+ const [folded, setFolded] = (0, import_react4.useState)({});
2071
+ (0, import_react4.useEffect)(() => {
2072
+ void runtime.refresh().catch(() => void 0);
2073
+ const timer = window.setInterval(() => {
2074
+ void runtime.refresh().catch(() => void 0);
2075
+ }, 15e3);
2076
+ return () => {
2077
+ window.clearInterval(timer);
2078
+ };
2079
+ }, [runtime]);
2080
+ const archived = (0, import_react4.useMemo)(() => new Set(archivedIds), [archivedIds]);
2081
+ const groups = (0, import_react4.useMemo)(() => {
2082
+ const snapshot = state.snapshot;
2083
+ if (snapshot === void 0) return [];
2084
+ return groupScheduledSessions(snapshot.automations, snapshot.runs).map((group) => ({
2085
+ ...group,
2086
+ sessions: group.sessions.filter((session) => !archived.has(session.id)).map((session) => {
2087
+ const run = snapshot.runs.find((item) => item.sessionId === session.id);
2088
+ return {
2089
+ ...session,
2090
+ title: formatRunStamp(run && (run.startedAt || run.scheduledFor) || ""),
2091
+ updatedAt: run && (run.startedAt || run.scheduledFor) || "",
2092
+ running: session.running || sessionById[session.id]?.running === true
2093
+ };
2094
+ })
2095
+ })).filter((group) => group.sessions.length > 0);
2096
+ }, [archived, sessionById, state.snapshot]);
2097
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-n-tree", role: "tree", children: [
2098
+ state.phase === "loading" && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-empty", children: t("loading") }),
2099
+ groups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-empty", children: t("sidebar.empty") }),
2100
+ groups.map((group) => {
2101
+ const expanded = folded[group.id] !== true;
2102
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-n-group", children: [
2103
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "dsh-st-n-row", role: "treeitem", "aria-expanded": expanded, onClick: () => setFolded((current) => ({ ...current, [group.id]: expanded })), children: [
2104
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-slot dsh-st-n-folder", children: expanded ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FolderOpenIcon, { width: 16, height: 16 }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(FolderClosedIcon, { width: 16, height: 16 }) }),
2105
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-slot dsh-st-n-chevron", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: expanded ? "dsh-st-n-arrow is-open" : "dsh-st-n-arrow", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ChevronIcon, { width: 14, height: 14 }) }) }),
2106
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-title", children: group.name }),
2107
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2108
+ "button",
2109
+ {
2110
+ type: "button",
2111
+ className: "dsh-st-n-ico",
2112
+ "aria-label": t("session.deleteFolder"),
2113
+ onClick: (event) => {
2114
+ event.stopPropagation();
2115
+ void (async () => {
2116
+ for (const session of group.sessions) {
2117
+ try {
2118
+ await deleteSession?.(session.id);
2119
+ } catch {
2120
+ }
2121
+ }
2122
+ await runtime.forgetAutomationSessions(group.id);
2123
+ })();
2124
+ },
2125
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TrashIcon, { width: 16, height: 16 })
2126
+ }
2127
+ ) })
2128
+ ] }),
2129
+ expanded && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
2130
+ NativeSessionRow,
2131
+ {
2132
+ t,
2133
+ id: session.id,
2134
+ title: session.title,
2135
+ updatedAt: session.updatedAt,
2136
+ running: session.running,
2137
+ selected: selectedId === session.id,
2138
+ onOpen: () => {
2139
+ openSession?.(session.id);
2140
+ void runtime.adoptSession?.(session.id).catch(() => void 0);
2141
+ },
2142
+ onDelete: async () => {
2143
+ try {
2144
+ await deleteSession?.(session.id);
2145
+ } catch {
2146
+ }
2147
+ await runtime.forgetSession(session.id);
2148
+ },
2149
+ ...renameSession === void 0 ? {} : { renameSession },
2150
+ ...archiveSession === void 0 ? {} : { archiveSession },
2151
+ ...forkSession === void 0 ? {} : { forkSession }
2152
+ },
2153
+ session.id
2154
+ ))
2155
+ ] }, group.id);
2156
+ })
2157
+ ] }) });
2158
+ }
2159
+ function NativeSessionRow(props) {
2160
+ const { t, id, title, updatedAt, running, selected, onOpen, onDelete, renameSession, archiveSession, forkSession } = props;
2161
+ const [menu, setMenu] = (0, import_react4.useState)(false);
2162
+ const [renaming, setRenaming] = (0, import_react4.useState)(false);
2163
+ const [draft, setDraft] = (0, import_react4.useState)(title);
2164
+ (0, import_react4.useEffect)(() => {
2165
+ setDraft(title);
2166
+ }, [title]);
2167
+ (0, import_react4.useEffect)(() => {
2168
+ if (!menu) return;
2169
+ const close = (event) => {
2170
+ const target = event.target;
2171
+ if (target !== null && event.target.closest(".dsh-st-n-sess.is-menu") !== null) return;
2172
+ setMenu(false);
2173
+ };
2174
+ document.addEventListener("mousedown", close);
2175
+ return () => {
2176
+ document.removeEventListener("mousedown", close);
2177
+ };
2178
+ }, [menu]);
2179
+ const run = (action) => {
2180
+ void Promise.resolve(action()).catch(() => void 0);
2181
+ };
2182
+ const rowClass = "dsh-st-n-sess" + (selected ? " is-on" : "") + (menu ? " is-menu" : "");
2183
+ if (renaming) {
2184
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: rowClass, children: /* @__PURE__ */ (0, import_jsx_runtime5.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) => {
2185
+ if (event.key === "Enter") {
2186
+ event.preventDefault();
2187
+ setRenaming(false);
2188
+ if (draft.trim() !== "" && draft.trim() !== title) run(() => renameSession?.(id, draft.trim()));
2189
+ }
2190
+ if (event.key === "Escape") {
2191
+ event.preventDefault();
2192
+ setRenaming(false);
2193
+ setDraft(title);
2194
+ }
2195
+ }, onBlur: () => {
2196
+ setRenaming(false);
2197
+ if (draft.trim() !== "" && draft.trim() !== title) run(() => renameSession?.(id, draft.trim()));
2198
+ } }) });
2199
+ }
2200
+ const menuItems = [
2201
+ { id: "rename", label: t("session.rename"), icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(PencilIcon, { width: 16, height: 16 }), go: () => {
2202
+ setRenaming(true);
2203
+ } },
2204
+ { id: "fork", label: t("session.fork"), icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BranchIcon, { width: 16, height: 16 }), go: () => run(() => forkSession?.(id)) },
2205
+ { id: "archive", label: t("session.archive"), icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(ArchiveIcon, { width: 16, height: 16 }), go: () => run(() => archiveSession?.(id)) },
2206
+ { id: "delete", label: t("session.delete"), icon: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(TrashIcon, { width: 16, height: 16 }), danger: true, go: () => run(() => onDelete()) }
2207
+ ];
2208
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: rowClass, role: "treeitem", tabIndex: 0, "aria-selected": selected, onClick: onOpen, onKeyDown: (event) => {
2209
+ if (event.key === "Enter" || event.key === " ") {
2210
+ event.preventDefault();
2211
+ onOpen();
2212
+ }
2213
+ }, onContextMenu: (event) => {
2214
+ event.preventDefault();
2215
+ event.stopPropagation();
2216
+ setMenu((open) => !open);
2217
+ }, children: [
2218
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-slot", children: running ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(RunningStateDot, {}) : null }),
2219
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-title", children: title }),
2220
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-time", children: relativeTime(updatedAt) }),
2221
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-acts", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("button", { type: "button", className: "dsh-st-n-ico", "aria-label": title + " \u66F4\u591A", onClick: (event) => {
2222
+ event.stopPropagation();
2223
+ setMenu((open) => !open);
2224
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(EllipsisIcon, { width: 16, height: 16 }) }) }),
2225
+ menu && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "dsh-st-n-menu", onClick: (event) => event.stopPropagation(), children: menuItems.map((item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("button", { type: "button", className: item.danger === true ? "danger" : void 0, onClick: () => {
2226
+ setMenu(false);
2227
+ item.go();
2228
+ }, children: [
2229
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "dsh-st-n-mi", children: item.icon }),
2230
+ item.label
2231
+ ] }, item.id)) })
2232
+ ] });
2233
+ }
2234
+
2235
+ // src/client/ScheduleRail.tsx
2236
+ var import_react5 = require("react");
2237
+ var import_jsx_runtime6 = require("react/jsx-runtime");
2238
+ var EMPTY_EXTRA_TABS = [];
2239
+ var OfficialTreeGuard = class extends import_react5.Component {
2240
+ state = { failed: false };
2241
+ static getDerivedStateFromError() {
2242
+ return { failed: true };
2243
+ }
2244
+ componentDidCatch(error) {
2245
+ console.warn("[dsh-automation] official workspace tree crashed", error);
2246
+ }
2247
+ render() {
2248
+ return this.state.failed ? this.props.fallback : this.props.children;
2249
+ }
2250
+ };
2251
+ function ScheduleRail({
2252
+ t,
2253
+ runtime,
2254
+ openSession
2255
+ }) {
2256
+ const state = (0, import_react5.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
2257
+ const [folded, setFolded] = (0, import_react5.useState)({});
2258
+ (0, import_react5.useEffect)(() => {
2259
+ void runtime.refresh().catch(() => void 0);
2260
+ const timer = window.setInterval(() => {
2261
+ void runtime.refresh().catch(() => void 0);
2262
+ }, 15e3);
2263
+ return () => {
2264
+ window.clearInterval(timer);
2265
+ };
2266
+ }, [runtime]);
2267
+ const groups = (0, import_react5.useMemo)(() => {
2268
+ const snapshot = state.snapshot;
2269
+ if (snapshot === void 0) return [];
2270
+ return groupScheduledSessions(snapshot.automations, snapshot.runs);
2271
+ }, [state.snapshot]);
2272
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-rail", children: [
2273
+ state.phase === "loading" && groups.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-rail-empty", children: t("loading") }),
2274
+ groups.length === 0 && state.phase !== "loading" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.empty") }),
2275
+ groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "dsh-st-rail-group", children: [
2276
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2277
+ "button",
2278
+ {
2279
+ type: "button",
2280
+ className: "dsh-st-rail-head",
2281
+ onClick: () => setFolded((current) => ({ ...current, [group.id]: !current[group.id] })),
2282
+ children: [
2283
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-rail-folder", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ClockIcon, { width: 16, height: 16 }) }),
2284
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-rail-title", children: group.name })
2285
+ ]
2286
+ }
2287
+ ),
2288
+ folded[group.id] !== true && group.sessions.map((session) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
2289
+ "button",
2290
+ {
2291
+ type: "button",
2292
+ className: "dsh-st-rail-session",
2293
+ onClick: () => openSession?.(session.id),
2294
+ children: [
2295
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: session.label }),
2296
+ session.running && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(RunningStateDot, {})
2297
+ ]
2298
+ },
2299
+ session.id
2300
+ ))
2301
+ ] }, group.id))
2302
+ ] });
2303
+ }
2304
+ function NativeScheduleShell({
2305
+ t,
2306
+ runtime,
2307
+ officialTree,
2308
+ hostProps,
2309
+ openSession,
2310
+ useSessions,
2311
+ useWorkspaces,
2312
+ renderSlot,
2313
+ hasChannels,
2314
+ subscribeChannels,
2315
+ tabRegistry,
2316
+ wide
2317
+ }) {
2318
+ const Official = officialTree;
2319
+ const [tab, setTab] = (0, import_react5.useState)(() => {
2320
+ try {
2321
+ return readNativeSidebarTab(window.localStorage.getItem(NATIVE_SIDEBAR_TAB_KEY));
2322
+ } catch {
2323
+ return "tasks";
2324
+ }
2325
+ });
2326
+ const extraTabs = (0, import_react5.useSyncExternalStore)(
2327
+ tabRegistry?.subscribe ?? ((listener) => {
2328
+ listener();
2329
+ return () => void 0;
2330
+ }),
2331
+ () => tabRegistry?.getTabs() ?? EMPTY_EXTRA_TABS,
2332
+ () => EMPTY_EXTRA_TABS
2333
+ );
2334
+ const channelsReady = (0, import_react5.useSyncExternalStore)(
2335
+ subscribeChannels ?? ((listener) => {
2336
+ listener();
2337
+ return () => void 0;
2338
+ }),
2339
+ () => {
2340
+ try {
2341
+ return hasChannels?.() === true;
2342
+ } catch {
2343
+ return false;
2344
+ }
2345
+ },
2346
+ () => false
2347
+ );
2348
+ const currentId = useSessions?.((state) => state?.current ?? null);
2349
+ const useFilteredSessions = (0, import_react5.useCallback)((selector) => {
2350
+ if (useSessions === void 0) return selector({ ids: [], byId: {}, current: null });
2351
+ return useSessions((state) => selector(filterTaskSessionState(state)));
2352
+ }, [useSessions]);
2353
+ const useFilteredWorkspaces = (0, import_react5.useCallback)((selector) => {
2354
+ if (useWorkspaces === void 0) return selector({ items: [], archivedSessionIds: [] });
2355
+ return useWorkspaces((state) => selector(filterWorkspaceListState(state)));
2356
+ }, [useWorkspaces]);
2357
+ (0, import_react5.useEffect)(() => {
2358
+ try {
2359
+ window.localStorage.setItem(NATIVE_SIDEBAR_TAB_KEY, tab);
2360
+ } catch {
2361
+ }
2362
+ }, [tab]);
2363
+ (0, import_react5.useEffect)(() => {
2364
+ const next = tabForSessionId(currentId ?? void 0);
2365
+ if (next === "channels" && channelsReady) setTab("channels");
2366
+ const matched = extraTabs.find((item) => currentId !== void 0 && currentId !== null && item.matchSession?.(String(currentId)) === true);
2367
+ if (matched !== void 0) setTab(matched.id);
2368
+ }, [currentId, channelsReady, extraTabs]);
2369
+ const rawOfficialProps = { ...hostProps ?? {}, ...wide === void 0 ? {} : { wide } };
2370
+ const filteredOfficialProps = {
2371
+ ...rawOfficialProps,
2372
+ ...useSessions === void 0 ? {} : { useSessions: useFilteredSessions },
2373
+ ...useWorkspaces === void 0 ? {} : { useWorkspaces: useFilteredWorkspaces }
2374
+ };
2375
+ const renderOfficial = (props) => {
2376
+ if (Official === void 0) {
2377
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(NativeTaskRail, { t, ...openSession === void 0 ? {} : { openSession }, ...useSessions === void 0 ? {} : { useSessions: useFilteredSessions }, ...useWorkspaces === void 0 ? {} : { useWorkspaces } });
2378
+ }
2379
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(OfficialTreeGuard, { fallback: (0, import_react5.createElement)(Official, rawOfficialProps), children: (0, import_react5.createElement)(Official, props) });
2380
+ };
2381
+ if (wide === false) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_jsx_runtime6.Fragment, { children: renderOfficial(rawOfficialProps) });
2382
+ const visibleTab = tab === "channels" && !channelsReady ? "tasks" : tab;
2383
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-shell-rail", children: [
2384
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "dsh-st-shell-tabs", role: "tablist", "aria-label": t("sidebar.tabs"), children: [
2385
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "tasks", className: visibleTab === "tasks" ? "is-on" : void 0, onClick: () => setTab("tasks"), children: t("sidebar.tasksTab") }),
2386
+ extraTabs.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.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)),
2387
+ channelsReady && extraTabs.every((item) => item.id !== "channels") && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { type: "button", role: "tab", "aria-selected": visibleTab === "channels", className: visibleTab === "channels" ? "is-on" : void 0, onClick: () => setTab("channels"), children: t("sidebar.channelsTab") })
2388
+ ] }),
2389
+ extraTabs.find((item) => item.id === visibleTab) !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-shell-body", children: extraTabs.find((item) => item.id === visibleTab)?.render({ ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true }) }) : visibleTab === "channels" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-shell-body", children: renderSlot?.("sidebar.channels", { ...hostProps ?? {}, openSession, open: openSession, useSessions, wide: true }) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-official-tree", children: renderOfficial(filteredOfficialProps) })
2390
+ ] });
2391
+ }
2392
+ function NativeTaskRail({
2393
+ t,
2394
+ openSession,
2395
+ useSessions,
2396
+ useWorkspaces
2397
+ }) {
2398
+ const snap = useSessions === void 0 ? { ids: [], byId: {}, current: null } : useSessions((state) => state ?? { ids: [], byId: {}, current: null });
2399
+ const workspaces = useWorkspaces === void 0 ? void 0 : useWorkspaces((state) => state ?? { items: [], archivedSessionIds: [] });
2400
+ const groups = groupNativeTaskSessions(snap, workspaces, t("sidebar.ungrouped"));
2401
+ if (groups.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-rail-empty", children: t("sidebar.tasksEmpty") });
2402
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-rail", children: groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: "dsh-st-rail-group", children: [
2403
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "dsh-st-rail-head is-static", children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "dsh-st-rail-title", children: group.label }) }),
2404
+ group.sessions.map((item) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
2405
+ "button",
2406
+ {
2407
+ type: "button",
2408
+ className: `dsh-st-rail-session${snap.current === item.id ? " is-on" : ""}`,
2409
+ onClick: () => {
2410
+ if (item.id !== void 0) openSession?.(item.id);
2411
+ },
2412
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: item.title || item.id })
2413
+ },
2414
+ item.id
2415
+ ))
2416
+ ] }, group.id || "ungrouped")) });
2417
+ }
2418
+
2419
+ // src/client/styles.ts
2420
+ var STYLE_ID = "dsh-automation-styles";
2421
+ var CSS_TEXT = `
2422
+ .dsh-st-shell{box-sizing:border-box;max-width:1080px;width:100%;margin:0 auto;padding:0 0 32px;color:var(--dsw-alias-label-primary);font-family:var(--dsw-font-family,system-ui)}
2423
+ .dsh-st-top{display:flex;flex-direction:column;align-items:stretch;gap:12px;margin-bottom:12px}
2424
+ .dsh-st-heading h1,.dsh-st-top h1{margin:0;font-size:20px;line-height:28px;font-weight:650;letter-spacing:-.2px}
2425
+ .dsh-st-heading p,.dsh-st-top p{margin:4px 0 0;max-width:none;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
2426
+ .dsh-st-toolbar{display:flex;flex-wrap:nowrap;align-items:center;justify-content:flex-start;gap:8px}
2427
+ .dsh-st-search{flex:1;min-width:0;max-width:280px;height:32px;padding:0 12px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:var(--dsw-alias-bg-layer-3,var(--dsw-alias-bg-layer-1));color:inherit;font:inherit;font-size:13px}
2428
+ .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}
2429
+ .dsh-st-icon{width:32px;padding:0;flex:none}
2430
+ .dsh-st-btn--primary{border-color:transparent;background:var(--dsw-alias-button-primary-fill,#fff);color:var(--dsw-alias-label-primary-foreground,#111)}
2431
+ .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}
2432
+ .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}
2433
+ .dsh-st-banner>span{display:inline-flex;align-items:flex-start;gap:8px}
2434
+ .dsh-st-switch{width:42px;height:26px;border:0;border-radius:999px;background:rgba(120,120,128,.36);box-shadow:inset 0 0 0 1px rgba(255,255,255,.06);position:relative;cursor:pointer}
2435
+ .dsh-st-switch:after{content:'';position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.28);transition:transform .16s ease}
2436
+ .dsh-st-switch.is-on{background:#34c759}
2437
+ .dsh-st-switch.is-on:after{transform:translateX(16px)}
2438
+ .dsh-st-examples{margin-bottom:22px}
2439
+ .dsh-st-examples-head h2{margin:0 0 10px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary)}
2440
+ .dsh-st-example-row{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:10px}
2441
+ .dsh-st-example{display:flex;flex-direction:column;align-items:flex-start;gap:8px;min-height:132px;padding:14px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.03));color:inherit;text-align:left;cursor:pointer}
2442
+ .dsh-st-example:hover{border-color:rgba(75,124,255,.45)}
2443
+ .dsh-st-example strong{font-size:14px}
2444
+ .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}
2445
+ .dsh-st-tabs{display:flex;align-items:center;gap:16px;margin:4px 0 16px;border-bottom:1px solid var(--dsw-alias-border-l2)}
2446
+ .dsh-st-tabs>button{padding:8px 0;border:0;border-bottom:2px solid transparent;background:transparent;color:var(--dsw-alias-label-secondary);cursor:pointer}
2447
+ .dsh-st-tabs>button.is-on{border-bottom-color:currentColor;color:var(--dsw-alias-label-primary);font-weight:650}
2448
+ .dsh-st-sort{margin-left:auto;color:var(--dsw-alias-label-tertiary);font-size:12px}
2449
+ .dsh-st-filters{display:flex;flex-wrap:wrap;align-items:center;gap:6px;margin-left:auto}
2450
+ .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}
2451
+ .dsh-st-filters>button.is-on{background:rgba(255,255,255,.14)}
2452
+ .dsh-st-grid{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:12px}
2453
+ .dsh-st-card,.dsh-st-empty{position:relative;padding:16px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:var(--dsw-alias-bg-layer-2,rgba(255,255,255,.03))}
2454
+ .dsh-st-card{cursor:pointer}
2455
+ .dsh-st-card:hover{border-color:rgba(75,124,255,.45)}
2456
+ .dsh-st-card h3,.dsh-st-empty h3{margin:10px 0 6px;font-size:14px;font-weight:500}
2457
+ .dsh-st-card p,.dsh-st-empty p{margin:0 0 14px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:1.5;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
2458
+ .dsh-st-card-head{display:flex;align-items:center;justify-content:space-between}
2459
+ .dsh-st-card-foot{display:flex;align-items:center;justify-content:space-between;gap:10px;padding-top:12px;border-top:1px dashed var(--dsw-alias-border-l2);color:var(--dsw-alias-label-tertiary);font-size:12px}
2460
+ .dsh-st-chip{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;border-radius:999px;background:rgba(255,255,255,.06)}
2461
+ .dsh-st-more{width:28px;height:28px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-tertiary);cursor:pointer}
2462
+ .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)}
2463
+ .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}
2464
+ .dsh-st-menu button:hover{background:rgba(255,255,255,.06)}
2465
+ .dsh-st-menu .is-danger{color:#ff6b6b}
2466
+ .dsh-st-timeline{display:flex;flex-direction:column;gap:22px;padding-left:10px}
2467
+ .dsh-st-group{position:relative;padding-left:18px}
2468
+ .dsh-st-group:before{content:'';position:absolute;top:8px;bottom:0;left:4px;width:1px;background:rgba(255,255,255,.08)}
2469
+ .dsh-st-group h3{margin:0 0 10px;font-size:13px;font-weight:600}
2470
+ .dsh-st-run{position:relative;margin:0 0 12px}
2471
+ .dsh-st-run:after{content:'';position:absolute;top:6px;left:-18px;width:7px;height:7px;border-radius:50%;background:#34c759}
2472
+ .dsh-st-run.is-failed:after,.dsh-st-run.is-interrupted:after{background:#ff6b6b}
2473
+ .dsh-st-run.is-queued:after,.dsh-st-run.is-skipped:after,.dsh-st-run.is-cancelled:after{background:#8b8f98}
2474
+ .dsh-st-run strong{display:block;margin-bottom:4px;font-size:14px}
2475
+ .dsh-st-run p{display:flex;gap:10px;margin:0;color:var(--dsw-alias-label-tertiary);font-size:12px}
2476
+ .dsh-st-error{color:#ff6b6b;font-size:12px}
2477
+ .dsh-st-muted{color:var(--dsw-alias-label-secondary)}
2478
+ .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{pointer-events:auto}
2479
+ .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)}
2480
+ .dsh-st-modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}
2481
+ .dsh-st-modal-head h2{margin:0 0 4px;font-size:20px}
2482
+ .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}
2483
+ .dsh-st-field input,.dsh-st-field select,.dsh-st-field textarea{width:100%;padding:9px 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-1);color:inherit}
2484
+ .dsh-st-field textarea{min-height:140px;max-width:100%;resize:vertical}
2485
+ .dsh-st-inline{display:flex;flex-wrap:wrap;gap:8px;align-items:center}
2486
+ .dsh-st-inline select,.dsh-st-inline input{flex:1;min-width:120px}
2487
+ .dsh-st-weekdays{display:flex;flex-wrap:wrap;gap:6px;margin:0 0 12px}
2488
+ .dsh-st-weekdays button{min-width:40px;padding:6px 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:8px;background:transparent;color:inherit;cursor:pointer}
2489
+ .dsh-st-weekdays button.is-on{border-color:#4b7cff;color:#4b7cff}
2490
+ .dsh-st-check{display:inline-flex;align-items:center;gap:6px;margin:0 0 12px;font-size:12px}
2491
+ .dsh-st-modal-actions{display:flex;justify-content:flex-end;flex:none;gap:8px;margin-top:8px}
2492
+ @media(max-width:860px){.dsh-st-toolbar{flex-wrap:wrap}.dsh-st-search{flex-basis:100%;max-width:none}.dsh-st-grid,.dsh-st-example-row{grid-template-columns:1fr}.dsh-st-filters{width:100%;margin:8px 0}}
2493
+ .dsh-st-select{position:relative;min-width:108px;z-index:1}.dsh-st-select.is-open{z-index:30}
2494
+ .dsh-st-select.is-wide{min-width:148px}
2495
+ .dsh-st-select-btn,.dsh-st-field input,.dsh-st-field textarea{border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:rgba(255,255,255,.04);color:inherit}
2496
+ .dsh-st-select-btn{display:flex;align-items:center;justify-content:space-between;gap:10px;min-height:36px;width:100%;padding:0 12px;cursor:pointer}
2497
+ .dsh-st-select.is-pill{width:auto;min-width:0;flex:none}
2498
+ .dsh-st-select.is-pill .dsh-st-select-btn{width:auto;min-height:28px;height:28px;padding:0 8px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;gap:6px;white-space:nowrap}
2499
+ .dsh-st-select.is-pill .dsh-st-select-btn:hover{background:rgba(255,255,255,.06);color:var(--dsw-alias-label-primary)}
2500
+ .dsh-st-select.is-pill .dsh-st-select-menu,.dsh-st-select-menu.is-composer{min-width:260px}
2501
+ .dsh-st-select-btn em{width:8px;height:8px;border-right:1.5px solid currentColor;border-bottom:1.5px solid currentColor;transform:rotate(45deg) translateY(-2px);opacity:.7}
2502
+ .dsh-st-select-menu{position:absolute;top:calc(100% + 6px);left:0;z-index:30;min-width:196px;max-height:280px;overflow:auto;padding:6px;border:1px solid rgba(255,255,255,.08);border-radius:14px;background:#2a2c31;box-shadow:0 16px 40px rgba(0,0,0,.42)}
2503
+ .dsh-st-select-menu.is-up{top:auto;bottom:calc(100% + 6px)}
2504
+ .dsh-st-select-menu.is-end{left:auto;right:0}.dsh-st-select-menu.is-float{position:absolute;z-index:1200;max-height:min(280px,calc(100vh - 24px));box-sizing:border-box}
2505
+ .dsh-st-menu-row{white-space:nowrap}
2506
+ .dsh-st-menu-row.is-kv .dsh-st-menu-row-main{flex:none}
2507
+ .dsh-st-menu-row.is-kv .dsh-st-menu-row-side{flex:1;justify-content:flex-end;min-width:0}
2508
+ .dsh-st-select-menu button,.dsh-st-menu-row{display:flex;align-items:center;justify-content:space-between;gap:12px;width:100%;padding:8px 10px;border:0;border-radius:10px;background:transparent;color:inherit;text-align:left;cursor:pointer;font-size:13px}
2509
+ .dsh-st-menu-row-main{display:inline-flex;align-items:center;gap:8px;min-width:0}
2510
+ .dsh-st-menu-row-side{display:inline-flex;align-items:center;gap:8px;color:var(--dsw-alias-label-secondary);font-size:12px}
2511
+ .dsh-st-menu-row-side small{display:block;max-width:180px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dsw-alias-label-tertiary)}
2512
+ .dsh-st-select-menu button:hover,.dsh-st-menu-row:hover,.dsh-st-menu-row.is-on{background:rgba(255,255,255,.06)}
2513
+ .dsh-st-tick,.dsh-st-next{width:7px;height:11px;border-right:1.6px solid currentColor;border-bottom:1.6px solid currentColor;flex:none}
2514
+ .dsh-st-tick{height:12px;width:6px;transform:rotate(45deg) translateY(-2px);border-right-color:#7aa2ff;border-bottom-color:#7aa2ff}
2515
+ .dsh-st-next{height:7px;transform:rotate(-45deg);opacity:.55}
2516
+ .dsh-st-select-empty{padding:14px 12px;color:var(--dsw-alias-label-tertiary);font-size:12px;text-align:center}
2517
+ .dsh-st-chip-btn{display:inline-flex;align-items:center;gap:6px;min-height:28px;height:28px;padding:0 8px;border:0;border-radius:8px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;white-space:nowrap;cursor:pointer}
2518
+ .dsh-st-chip-btn:hover{background:rgba(255,255,255,.06);color:var(--dsw-alias-label-primary)}
2519
+ .dsh-st-chip-btn.is-static{cursor:default;opacity:.78}
2520
+ .dsh-st-chip-btn em,.dsh-st-select.is-pill .dsh-st-select-btn em{width:6px;height:6px;margin-left:2px;opacity:.55}
2521
+ .dsh-st-suffix{color:var(--dsw-alias-label-secondary);font-size:13px}
2522
+ .dsh-st-inline input.is-narrow{width:72px;flex:none}
2523
+ .dsh-st-time{display:inline-flex;align-items:center;gap:2px;min-height:36px;padding:0 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:12px;background:rgba(255,255,255,.04)}
2524
+ .dsh-st-time .dsh-st-select{min-width:48px}
2525
+ .dsh-st-time .dsh-st-select-btn{width:auto;min-height:32px;padding:0 6px;border:0;background:transparent}
2526
+ .dsh-st-time-sep{padding:0 2px;color:var(--dsw-alias-label-secondary)}
2527
+ .dsh-st-inline input[type=date]{min-width:148px;max-width:170px}
2528
+ .dsh-st-weekdays button{min-width:52px;height:34px;border-radius:999px;border:1px solid var(--dsw-alias-border-l2);background:transparent}
2529
+ .dsh-st-weekdays button.is-on{border-color:transparent;background:#fff;color:#111}
2530
+ .dsh-st-prompt-card{display:flex;flex-direction:column;flex:1;min-height:160px;max-width:100%;border:1px solid var(--dsw-alias-border-l2);border-radius:22px;overflow:visible;background:rgba(255,255,255,.03)}
2531
+ .dsh-st-prompt-card textarea{flex:1;width:100%;max-width:100%;min-height:140px;border:0;background:transparent;padding:16px 18px;font-size:14px;line-height:1.65;resize:none}
2532
+ .dsh-st-composer,.dsh-st-composer-left,.dsh-st-composer-right{display:flex;align-items:center;flex-wrap:nowrap}
2533
+ .dsh-st-composer{justify-content:space-between;gap:8px;padding:2px 8px 10px;border-top:0}
2534
+ .dsh-st-composer-left,.dsh-st-composer-right{gap:2px;min-width:0}
2535
+ .dsh-st-composer .dsh-st-select{min-width:0}
2536
+ .dsh-st-composer svg{flex:none}
2537
+ .dsh-st-menu-split{height:1px;margin:6px 8px;background:rgba(255,255,255,.08)}
2538
+ .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)}
2539
+ .dsh-st-subdialog>strong{display:block;margin:0 0 8px;font-size:13px}
2540
+ .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}
2541
+ .dsh-st-rail-empty{padding:16px 10px;color:var(--dsw-alias-label-tertiary,#8b8f98);font-size:12px}
2542
+ .dsh-st-rail-group{margin:0 0 8px}
2543
+ .dsh-st-rail-head,.dsh-st-rail-session{display:flex;align-items:center;gap:8px;width:100%;border:0;background:transparent;color:inherit;text-align:left;cursor:pointer}
2544
+ .dsh-st-rail-head{min-height:32px;padding:4px 8px;border-radius:8px;font-size:13px;font-weight:600}
2545
+ .dsh-st-rail-session{min-height:28px;padding:3px 8px 3px 28px;border-radius:8px;color:var(--dsw-alias-label-secondary,#9ca39f);font-size:12px}
2546
+ .dsh-st-rail-head:hover,.dsh-st-rail-session:hover{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
2547
+ .dsh-st-rail-folder{display:grid;place-items:center;width:16px;height:20px;flex:none;opacity:.8}
2548
+ .dsh-st-rail-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
2549
+ .dsh-st-rail-session span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
2550
+ .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}}
2551
+ .dsh-st-shell-rail{display:flex;flex-direction:column;min-height:0;flex:1;height:100%;overflow:hidden}
2552
+ .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))}
2553
+ .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}
2554
+ .dsh-st-shell-tabs button.is-on{color:var(--dsw-alias-label-primary,inherit);box-shadow:inset 0 -2px 0 currentColor}
2555
+ .dsh-st-shell-body{display:flex;min-height:0;flex:1;overflow:hidden}
2556
+ .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}
2557
+ .dsh-st-rail-head.is-static{cursor:default;font-weight:600}
2558
+ .dsh-st-rail-session.is-on{background:var(--dsw-alias-interactive-bg-hover,rgba(255,255,255,.06))}
2559
+ .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-head{flex:none;display:flex;align-items:center;height:36px;padding-left:4px;margin:2px 0 4px;color:var(--dsw-alias-label-tertiary,#81858C)}.dsh-st-n-head-label{font-size:14px;line-height:20px}.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 4px;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;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-row .dsh-st-n-chevron{display:none;color:var(--dsw-alias-label-caption,#ADB2B8)}.dsh-st-n-row:hover .dsh-st-n-chevron{display:inline-flex}.dsh-st-n-row:hover .dsh-st-n-folder{display:none}.dsh-st-n-arrow{transition:transform .15s ease}.dsh-st-n-arrow.is-open{transform:rotate(90deg)}.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{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-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}
2560
+ `;
2561
+ function installStyles() {
2562
+ const existing = document.getElementById(STYLE_ID);
2563
+ if (existing instanceof HTMLStyleElement) {
2564
+ existing.textContent = CSS_TEXT;
2565
+ return () => void 0;
2566
+ }
2567
+ const style = document.createElement("style");
2568
+ style.id = STYLE_ID;
2569
+ style.textContent = CSS_TEXT;
2570
+ document.head.append(style);
2571
+ return () => {
2572
+ style.remove();
2573
+ };
2574
+ }
2575
+
2576
+ // src/client/index.ts
2577
+ var name = "dsh-automation-client";
2578
+ var inject = ["slots", "locale", "connection", "sessions"];
2579
+ var SETTINGS_CLOCK_SVG = '<svg viewBox="0 0 16 16" width="16" height="16" fill="none" aria-hidden="true" data-dsh-schedule-icon="1"><path fill="currentColor" d="M8 1.15A6.85 6.85 0 1 0 8 14.85 6.85 6.85 0 0 0 8 1.15Zm0 1.4a5.45 5.45 0 1 1 0 10.9 5.45 5.45 0 0 1 0-10.9Z"/><path fill="currentColor" d="M8.62 4.35H7.28v4.2l3.02 1.78.67-1.13-2.35-1.39V4.35Z"/></svg>';
2580
+ function installSettingsNavIcon(labels) {
2581
+ const apply2 = () => {
2582
+ const wanted = new Set(labels().map((item) => item.trim()).filter((item) => item !== ""));
2583
+ const buttons = document.querySelectorAll("button");
2584
+ for (const button of buttons) {
2585
+ const text = (button.textContent ?? "").replace(/\s+/g, " ").trim();
2586
+ if (!wanted.has(text)) continue;
2587
+ const svg = button.querySelector("svg");
2588
+ if (svg === null || svg.getAttribute("data-dsh-schedule-icon") === "1") continue;
2589
+ svg.outerHTML = SETTINGS_CLOCK_SVG;
2590
+ }
2591
+ };
2592
+ apply2();
2593
+ const observer = new MutationObserver(apply2);
2594
+ observer.observe(document.documentElement, { childList: true, subtree: true });
2595
+ return () => {
2596
+ observer.disconnect();
2597
+ };
2598
+ }
2599
+ function apply(ctx) {
2600
+ ctx.effect(() => installStyles(), "dsh-automation: styles");
2601
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-automation: locale");
2602
+ const t = ctx.locale.bind(NS);
2603
+ const runtime = createAutomationRuntime(ctx.connection.rpc);
2604
+ ctx.effect(() => installSettingsNavIcon(() => [t("tab"), "Scheduled tasks", "\u5B9A\u65F6\u4EFB\u52A1"]), "dsh-automation: settings icon");
2605
+ ctx.slots.inject("settings.section", () => ctx.slots.register({
2606
+ name: "settings.section",
2607
+ id: "scheduled-tasks",
2608
+ order: 28,
2609
+ locale: NS,
2610
+ label: () => t("tab"),
2611
+ icon: "schedule"
2612
+ }, function ScheduledTasksSettings(props) {
2613
+ return (0, import_react6.createElement)(AutomationView, { t, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close } });
2614
+ }));
2615
+ ctx.slots.inject("sidebar.schedule", () => ctx.slots.register({
2616
+ name: "sidebar.schedule",
2617
+ id: "dsh-automation-schedule",
2618
+ order: 10,
2619
+ locale: NS,
2620
+ label: () => t("sidebar.tab")
2621
+ }, function AutomationScheduleRail(props) {
2622
+ return (0, import_react6.createElement)(ScheduleRail, {
2623
+ t,
2624
+ runtime,
2625
+ openSession: (id) => {
2626
+ openScheduledSession(id, (sessionId) => {
2627
+ ctx.sessions?.open(sessionId);
2628
+ }, props.openSession);
2629
+ }
2630
+ });
2631
+ }));
2632
+ ctx.slots.inject("sidebar.workspaces", () => {
2633
+ let wrappedEntry;
2634
+ let originalComp;
2635
+ let removeInsertedTab = () => void 0;
2636
+ let removeFilter = () => void 0;
2637
+ let syncing = false;
2638
+ const unwrap = () => {
2639
+ removeInsertedTab();
2640
+ removeInsertedTab = () => void 0;
2641
+ removeFilter();
2642
+ removeFilter = () => void 0;
2643
+ if (wrappedEntry !== void 0 && originalComp !== void 0) {
2644
+ try {
2645
+ wrappedEntry.component = originalComp;
2646
+ } catch {
2647
+ }
2648
+ }
2649
+ wrappedEntry = void 0;
2650
+ originalComp = void 0;
2651
+ };
2652
+ const insertScheduleTab = (entry, openSession) => {
2653
+ const registry = findNativeTabRegistry(entry);
2654
+ if (registry === void 0) return false;
2655
+ if (registry.getTabs().some((item) => item.id === "schedule")) return true;
2656
+ removeInsertedTab();
2657
+ removeInsertedTab = registry.insert({
2658
+ id: "schedule",
2659
+ label: t("sidebar.tab"),
2660
+ order: 30,
2661
+ matchSession: (sessionId) => sessionId.startsWith(AUTOMATION_SESSION_PREFIX),
2662
+ render: (props) => {
2663
+ const hostOpen = typeof props.openSession === "function" ? props.openSession : typeof props.open === "function" ? props.open : openSession;
2664
+ const opener = (id) => {
2665
+ openScheduledSession(id, (sessionId) => {
2666
+ ctx.sessions?.open(sessionId);
2667
+ }, hostOpen);
2668
+ };
2669
+ return (0, import_react6.createElement)(NativeScheduleSessionList, {
2670
+ t,
2671
+ runtime,
2672
+ openSession: opener,
2673
+ ...typeof props.useSessions === "function" ? { useSessions: props.useSessions } : {},
2674
+ ...typeof props.useWorkspaces === "function" ? { useWorkspaces: props.useWorkspaces } : {},
2675
+ ...typeof props.renameSession === "function" ? { renameSession: props.renameSession } : {},
2676
+ ...typeof props.archiveSession === "function" ? { archiveSession: props.archiveSession } : {},
2677
+ ...typeof props.deleteSession === "function" ? { deleteSession: props.deleteSession } : {},
2678
+ ...typeof props.forkSession === "function" ? { forkSession: props.forkSession } : {}
2679
+ });
2680
+ }
2681
+ });
2682
+ removeFilter();
2683
+ removeFilter = registry.addSessionFilter((id) => !id.startsWith(AUTOMATION_SESSION_PREFIX));
2684
+ return true;
2685
+ };
2686
+ const sync = () => {
2687
+ if (syncing) return;
2688
+ syncing = true;
2689
+ try {
2690
+ let AutomationNativeWorkspaceShell2 = function(innerProps) {
2691
+ const openSession = (id) => {
2692
+ openScheduledSession(id, (sessionId) => {
2693
+ ctx.sessions?.open(sessionId);
2694
+ }, innerProps.openSession ?? innerProps.open);
2695
+ };
2696
+ return (0, import_react6.createElement)(NativeScheduleShell, {
2697
+ t,
2698
+ runtime,
2699
+ hostProps: innerProps,
2700
+ openSession,
2701
+ tabRegistry: registry,
2702
+ ...innerProps.wide === void 0 ? {} : { wide: innerProps.wide },
2703
+ hasChannels: () => slotHasEntries(ctx, "sidebar.channels"),
2704
+ subscribeChannels: (listener) => ctx.slots.subscribe?.("sidebar.channels", listener) ?? (() => void 0),
2705
+ ...innerProps.useSessions === void 0 ? {} : { useSessions: innerProps.useSessions },
2706
+ ...innerProps.useWorkspaces === void 0 ? {} : { useWorkspaces: innerProps.useWorkspaces },
2707
+ ...innerProps.renderSlot === void 0 ? {} : { renderSlot: innerProps.renderSlot },
2708
+ ...originalComp === void 0 ? {} : { officialTree: originalComp }
2709
+ });
2710
+ };
2711
+ var AutomationNativeWorkspaceShell = AutomationNativeWorkspaceShell2;
2712
+ if (hasCodexUiSidebar(readSlotEntries(ctx, "sidebar"))) {
2713
+ unwrap();
2714
+ return;
2715
+ }
2716
+ const entries = readSlotEntries(ctx, "sidebar.workspaces");
2717
+ const occupant = pickWrappableWorkspacesEntry(entries);
2718
+ const current = occupant?.component;
2719
+ if (current !== void 0 && isForeignSidebarHost(current)) {
2720
+ if (insertScheduleTab(occupant) || insertScheduleTab(current)) return;
2721
+ return;
2722
+ }
2723
+ if (wrappedEntry?.component !== void 0 && wrappedEntry.component.__dshAutomationWrapped === true) {
2724
+ insertScheduleTab(wrappedEntry);
2725
+ return;
2726
+ }
2727
+ if (occupant?.component === void 0) return;
2728
+ const resolved = resolveOfficialTreeComponent(occupant.component);
2729
+ if (resolved === void 0) return;
2730
+ originalComp = resolved;
2731
+ const registry = createNativeTabRegistry(originalComp);
2732
+ attachNativeTabRegistry(occupant, registry);
2733
+ const marked = AutomationNativeWorkspaceShell2;
2734
+ marked.displayName = "AutomationNativeWorkspaceShell";
2735
+ marked.__dshNativeTabHost = true;
2736
+ marked.__dshAutomationWrapped = true;
2737
+ marked.__dshAutomationOriginal = originalComp;
2738
+ attachNativeTabRegistry(marked, registry);
2739
+ occupant.component = marked;
2740
+ wrappedEntry = occupant;
2741
+ insertScheduleTab(occupant, (id) => {
2742
+ ctx.sessions?.open(id);
2743
+ });
2744
+ } catch (error) {
2745
+ console.warn("[dsh-automation] \u5305\u88F9\u5B98\u65B9\u4EFB\u52A1\u6811\u5931\u8D25", error);
2746
+ } finally {
2747
+ syncing = false;
2748
+ }
2749
+ };
2750
+ sync();
2751
+ const unsub = typeof ctx.slots.subscribe === "function" ? ctx.slots.subscribe("sidebar.workspaces", sync) : () => void 0;
2752
+ return () => {
2753
+ unsub();
2754
+ unwrap();
2755
+ };
2756
+ });
2757
+ ctx.slots.inject("conversation.input.left", () => ctx.slots.register({
2758
+ name: "conversation.input.left",
2759
+ id: "dsh-automation-prefill",
2760
+ order: 80,
2761
+ locale: NS
2762
+ }, PrefillBridge));
2763
+ }
2764
+ function PrefillBridge(props) {
2765
+ (0, import_react6.useEffect)(() => {
2766
+ const applyPrefill = (text) => {
2767
+ if (text === null || text === "") return;
2768
+ if (props.inputActions !== void 0) {
2769
+ props.inputActions.setDraft(text);
2770
+ takeChatPrefill();
2771
+ return;
2772
+ }
2773
+ if (applyPrefillToDom(text)) takeChatPrefill();
2774
+ };
2775
+ applyPrefill(peekChatPrefill());
2776
+ return subscribeChatPrefill(applyPrefill);
2777
+ }, [props.inputActions]);
2778
+ return null;
2779
+ }
2780
+ function readSlotEntries(ctx, name2) {
2781
+ try {
2782
+ const read = ctx.slots.entriesOfSlot ?? ctx.slots.entries;
2783
+ return read?.call(ctx.slots, name2) ?? [];
2784
+ } catch {
2785
+ return [];
2786
+ }
2787
+ }
2788
+ function slotHasEntries(ctx, name2) {
2789
+ return readSlotEntries(ctx, name2).length > 0;
2790
+ }
2791
+ return module.exports; } });
2792
+ //# sourceMappingURL=client.js.map