@michengai/dsh-automation 0.1.39 → 0.1.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -1
- package/CHANGELOG.zh-CN.md +11 -1
- package/README.md +11 -7
- package/README.zh-CN.md +13 -7
- package/lib/client.js +97 -51
- package/lib/client.js.map +2 -2
- package/lib/index.js +39 -17
- package/lib/types/client/helpers.d.ts +2 -1
- package/lib/types/client/locales.d.ts +4 -1
- package/lib/types/client/protocol.d.ts +2 -0
- package/lib/types/service.d.ts +1 -0
- package/lib/types/types.d.ts +3 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
[简体中文](CHANGELOG.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Upcoming changes and recent published versions are listed below. Git tags and GitHub Releases now mirror these entries; historical sections retain links to their original release commits.
|
|
6
|
+
|
|
7
|
+
## 0.1.41 - 2026-09-14
|
|
8
|
+
|
|
9
|
+
- Fix Scheduled and execution-history navigation disappearing when used with the archive and IM plugins.
|
|
10
|
+
|
|
11
|
+
## 0.1.40 - 2026-09-12
|
|
12
|
+
|
|
13
|
+
- Configure concurrency per automation to allow overlapping executions of the same task. The default is `1`, preserving existing task behavior. When full, scheduled triggers are skipped and manual starts are rejected; lowering the limit does not cancel existing runs.
|
|
14
|
+
- Reduce the minimum interval from 5 minutes to 1 minute.
|
|
15
|
+
- Agent create/update tools accept `max_concurrent_runs`, and Web RPC accepts per-task `maxConcurrentRuns`; these are separate from the retired plugin-level global concurrency setting.
|
|
6
16
|
|
|
7
17
|
## 0.1.39 - 2026-09-12
|
|
8
18
|
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -2,7 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
[English](CHANGELOG.md)
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
以下记录待发布变更及近期已发布版本。Git 标签与 GitHub Release 现已和这些条目同步;历史条目继续保留原始发布提交链接。
|
|
6
|
+
|
|
7
|
+
## 0.1.41 - 2026-09-14
|
|
8
|
+
|
|
9
|
+
- 修复与归档、IM 插件组合使用时,侧栏定时入口及执行记录入口可能消失的问题。
|
|
10
|
+
|
|
11
|
+
## 0.1.40 - 2026-09-12
|
|
12
|
+
|
|
13
|
+
- 支持为单个自动化设置并发数量,让同一任务的多次执行可以同时进行。默认 `1`,旧任务保持原有行为;满额时跳过定时触发并拒绝手动启动,调低上限不取消已有运行。
|
|
14
|
+
- 间隔计划的最短间隔由 5 分钟缩短为 1 分钟。
|
|
15
|
+
- Agent 创建、更新工具支持 `max_concurrent_runs`,Web RPC 支持任务级 `maxConcurrentRuns`;它们与已停用的插件级全局并发配置无关。
|
|
6
16
|
|
|
7
17
|
## 0.1.39 - 2026-09-12
|
|
8
18
|
|
package/README.md
CHANGED
|
@@ -55,18 +55,21 @@ Run history stays in Settings and can be filtered by day, week, month, task, or
|
|
|
55
55
|
|
|
56
56
|
## DSH product ecosystem
|
|
57
57
|
|
|
58
|
-
For a
|
|
58
|
+
For a desktop workbench, download [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop/releases). Existing [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) installations can add plugins as needed by following each project's README. Below are 11 first-party plugins; consult the corresponding desktop release notes and bundled catalog for what that version includes.
|
|
59
59
|
|
|
60
60
|
| Plugin | What you can do |
|
|
61
61
|
| --- | --- |
|
|
62
62
|
| [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | Organize projects and conversations, search tasks, and navigate chat turns |
|
|
63
|
-
| [
|
|
64
|
-
| [Automation](https://github.com/MichengAI/dsh-automation) | Schedule tasks and review each run |
|
|
63
|
+
| [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | Choose and summon specialists for your task |
|
|
65
64
|
| [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | Find, enable, create, and import local skills |
|
|
66
65
|
| [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | Search, restore, or clean up archived conversations |
|
|
67
|
-
| [
|
|
66
|
+
| [IM Connect](https://github.com/MichengAI/dsh-im-connect) | Send tasks and receive replies through messaging platforms |
|
|
67
|
+
| [Automation](https://github.com/MichengAI/dsh-automation) | Schedule tasks and review each run |
|
|
68
68
|
| [BTW](https://github.com/MichengAI/dsh-btw) | Ask side questions without interrupting the main task |
|
|
69
|
-
| [Simplify](https://github.com/MichengAI/dsh-simplify) | Use
|
|
69
|
+
| [Simplify](https://github.com/MichengAI/dsh-simplify) | Use `/simplify` to improve code within your Git changes |
|
|
70
|
+
| [PUA](https://github.com/MichengAI/dsh-pua) | Guide the Agent to try new approaches after failures, investigate causes, and verify results before completion |
|
|
71
|
+
| [Code Review](https://github.com/MichengAI/dsh-code-review) | Use `/review` to request an independent Agent code review and receive the report in the current conversation |
|
|
72
|
+
| [Codex Pet](https://github.com/MichengAI/dsh-codex-pet) | View conversation notifications and respond to tool approvals and questions through a desktop pet |
|
|
70
73
|
|
|
71
74
|
## Prerequisites
|
|
72
75
|
|
|
@@ -130,8 +133,9 @@ Each dispatched run uses the saved prompt, workspace, model, and permission boun
|
|
|
130
133
|
| Approval | Chat create follows the session policy. Full access (`never`) proceeds; Workspace Write / Read Only (`ask`) shows the official card. Unattended runs stay fail-closed `never`. |
|
|
131
134
|
| Retry | No automatic retry after a started run. |
|
|
132
135
|
| Host restart | Leftover `queued` / `running` records become `failed(host_interrupted)`. |
|
|
133
|
-
| Concurrency | Different automations have no plugin-level global concurrency cap, including those in the same directory. The legacy `maxConcurrentRuns`
|
|
134
|
-
|
|
|
136
|
+
| Concurrency | Different automations have no plugin-level global concurrency cap, including those in the same directory. The legacy plugin-level global concurrency setting (`maxConcurrentRuns` in plugin config) no longer takes effect; it is separate from the per-task field below. |
|
|
137
|
+
| Minimum interval | Since `0.1.40`, interval schedules accept whole minutes starting at `1`. Missed triggers are not replayed individually; only the latest due occurrence is considered within the recovery window. |
|
|
138
|
+
| Per-task concurrency | Available since `0.1.40`. Set Concurrency in the create/edit dialog (positive integer, default `1`). Queued and running executions share this limit. When full, scheduled triggers become `skipped(overlap)` and manual runs return a limit error. Lowering the limit does not cancel existing runs. Agent create/update tools accept `max_concurrent_runs`; Web RPC accepts `maxConcurrentRuns`. Existing tasks default to `1`. |
|
|
135
139
|
|
|
136
140
|
A schedule stores future intent. It is not a cached permission grant.
|
|
137
141
|
|
package/README.zh-CN.md
CHANGED
|
@@ -55,18 +55,21 @@
|
|
|
55
55
|
|
|
56
56
|
## DSH 产品生态
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
想使用桌面工作台,可下载 [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop/releases);已有 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 环境,可按各项目 README 按需安装。以下列出 11 个自研插件;桌面端实际随附范围以对应版本的发行说明和内置清单为准。
|
|
59
59
|
|
|
60
60
|
| 插件 | 你可以用它做什么 |
|
|
61
61
|
| --- | --- |
|
|
62
62
|
| [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | 整理项目与会话、搜索任务、跳转对话轮次 |
|
|
63
|
-
| [
|
|
64
|
-
| [Automation](https://github.com/MichengAI/dsh-automation) | 按计划执行任务,查看每次运行的结果 |
|
|
63
|
+
| [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | 按任务选择并召唤专业角色 |
|
|
65
64
|
| [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | 统一查找、启停、创建和导入本机技能 |
|
|
66
65
|
| [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | 搜索、恢复或清理已归档会话 |
|
|
67
|
-
| [
|
|
66
|
+
| [IM Connect](https://github.com/MichengAI/dsh-im-connect) | 从消息平台下任务、收回复 |
|
|
67
|
+
| [Automation](https://github.com/MichengAI/dsh-automation) | 按计划执行任务,查看每次运行的结果 |
|
|
68
68
|
| [BTW](https://github.com/MichengAI/dsh-btw) | 在当前上下文中临时旁问,不打断主任务 |
|
|
69
|
-
| [Simplify](https://github.com/MichengAI/dsh-simplify) | 用
|
|
69
|
+
| [Simplify](https://github.com/MichengAI/dsh-simplify) | 用 `/simplify` 整理 Git 改动范围内的代码 |
|
|
70
|
+
| [PUA](https://github.com/MichengAI/dsh-pua) | 引导 Agent 在失败时换方法、查原因,并在完成前验证结果 |
|
|
71
|
+
| [Code Review](https://github.com/MichengAI/dsh-code-review) | 用 `/review` 发起独立 Agent 代码审查,在当前会话接收报告 |
|
|
72
|
+
| [Codex Pet](https://github.com/MichengAI/dsh-codex-pet) | 通过桌面宠物查看会话提醒、处理工具审批和问题回答 |
|
|
70
73
|
|
|
71
74
|
## 前置条件
|
|
72
75
|
|
|
@@ -130,8 +133,9 @@ dsh --profile web --dump-config
|
|
|
130
133
|
| 审批 | 对话创建跟随当前会话策略。Full access(`never`)直接创建;Workspace Write / Read Only(`ask`)走官方授权卡。无人值守运行仍是 fail-closed 的 `never`。 |
|
|
131
134
|
| 重试 | 已经开始的运行不会自动重试。 |
|
|
132
135
|
| Host 重启 | 遗留的 `queued` / `running` 会变成 `failed(host_interrupted)`。 |
|
|
133
|
-
| 并发 |
|
|
134
|
-
|
|
|
136
|
+
| 并发 | 不同自动化任务不设插件级全局并发上限,同一目录下也可同时运行。旧插件级全局并发配置(插件 config 中的 `maxConcurrentRuns`)不再生效,与下方任务级字段不同。 |
|
|
137
|
+
| 最短间隔 | 自 `0.1.40` 起,间隔计划支持最短 `1` 分钟,仅接受整数分钟。恢复时仅处理补跑窗口内最近的到期点,不逐次补齐漏掉的触发。 |
|
|
138
|
+
| 单任务并发 | 自 `0.1.40` 起支持。在任务的新建/编辑页设置“并发数量”(正整数,默认 `1`)。同一任务的排队及运行记录共用此上限;满额时定时触发记为 `skipped(overlap)`,手动运行返回上限提示。调低上限不取消已有运行。Agent 创建/更新工具使用 `max_concurrent_runs`,Web RPC 使用 `maxConcurrentRuns`;旧任务默认 `1`。 |
|
|
135
139
|
|
|
136
140
|
计划只表达未来意图,不是缓存下来的授权。
|
|
137
141
|
|
|
@@ -185,6 +189,8 @@ pnpm build
|
|
|
185
189
|
|
|
186
190
|
`pnpm check` 会连续执行类型检查、单元测试、真实宿主兼容测试和构建。`pnpm test:host` 不加载宿主运行时桩,使用官方 AgentLoop、Session V3 和权限服务,模型响应由本地固定适配器提供,不调用外部模型。浏览器交互和真实模型调用需另行验收。
|
|
187
191
|
|
|
192
|
+
跨插件侧栏回归可运行 `node --import tsx scripts/verify-sidebar-composition.mjs <dsh-im-connect 检出目录>`。它执行两仓库的接入逻辑和页签注册表,覆盖归档、IM、定时及 Codex UI 的注册顺序、延迟通知与卸载接管;插槽和计时器使用模拟环境,不替代 Desktop 渲染验收,也不安装插件。
|
|
193
|
+
|
|
188
194
|
`pnpm test:matrix` 先构建发布包,再联网为上述四个版本分别建立临时 npm 环境,执行严格 peer 安装、整棵官方依赖树版本检查、发布入口加载、真实 AgentLoop 执行和服务回归。四版均通过;服务回归中的持久化枚举使用内存夹具,覆盖新旧冷会话格式,不等同于真实 Profile 的磁盘迁移验收。脚本输出证据目录,保留各版安装锁文件、测试日志和 `results.json`。矩阵不修改开发依赖,也不连接用户 Profile。
|
|
189
195
|
|
|
190
196
|
## 许可证
|
package/lib/client.js
CHANGED
|
@@ -74,6 +74,7 @@ function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], def
|
|
|
74
74
|
scheduleKind: "daily",
|
|
75
75
|
onceAt: localDateTimeValue(now),
|
|
76
76
|
everyMinutes: "60",
|
|
77
|
+
maxConcurrentRuns: "1",
|
|
77
78
|
intervalAnchor: "",
|
|
78
79
|
time: "09:00",
|
|
79
80
|
weekdays: [1, 2, 3, 4, 5],
|
|
@@ -89,6 +90,8 @@ function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], def
|
|
|
89
90
|
};
|
|
90
91
|
}
|
|
91
92
|
function buildCreateInput(form, workspaces, models, now = /* @__PURE__ */ new Date(), options = {}) {
|
|
93
|
+
const maxConcurrentRuns = Number(form.maxConcurrentRuns);
|
|
94
|
+
if (!Number.isSafeInteger(maxConcurrentRuns) || maxConcurrentRuns < 1) throw new AutomationFormError("form.error.maxConcurrentRuns");
|
|
92
95
|
const name2 = form.name.trim();
|
|
93
96
|
const prompt = form.prompt.trim();
|
|
94
97
|
if (name2 === "") throw new AutomationFormError("form.error.name");
|
|
@@ -107,7 +110,7 @@ function buildCreateInput(form, workspaces, models, now = /* @__PURE__ */ new Da
|
|
|
107
110
|
}
|
|
108
111
|
case "interval": {
|
|
109
112
|
const everyMinutes = Number(form.everyMinutes);
|
|
110
|
-
if (!Number.isInteger(everyMinutes) || everyMinutes <
|
|
113
|
+
if (!Number.isInteger(everyMinutes) || everyMinutes < 1 || everyMinutes > 43200) {
|
|
111
114
|
throw new AutomationFormError("form.error.interval");
|
|
112
115
|
}
|
|
113
116
|
schedule = {
|
|
@@ -151,6 +154,7 @@ function buildCreateInput(form, workspaces, models, now = /* @__PURE__ */ new Da
|
|
|
151
154
|
schedule,
|
|
152
155
|
timeZone: form.timeZone,
|
|
153
156
|
permission: form.permission,
|
|
157
|
+
maxConcurrentRuns,
|
|
154
158
|
workspaceId: workspace.id,
|
|
155
159
|
cwd: workspace.path,
|
|
156
160
|
...selected === void 0 ? { provider: null, model: null } : { provider: selected.provider, model: selected.model },
|
|
@@ -306,6 +310,7 @@ function formFromAutomation(item, workspaces = [], defaultModel, defaultPermissi
|
|
|
306
310
|
name: item.name,
|
|
307
311
|
prompt: item.prompt,
|
|
308
312
|
permission: item.permission,
|
|
313
|
+
maxConcurrentRuns: String(item.maxConcurrentRuns ?? 1),
|
|
309
314
|
workspaceId: item.workspaceId ?? base.workspaceId,
|
|
310
315
|
modelKey,
|
|
311
316
|
reasoningEffort: item.reasoningEffort ?? "none",
|
|
@@ -1141,49 +1146,55 @@ function CreateModal({
|
|
|
1141
1146
|
t("form.name"),
|
|
1142
1147
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: form.name, placeholder: t("form.namePlaceholder"), onChange: (event) => update({ name: event.target.value }) })
|
|
1143
1148
|
] }),
|
|
1144
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1148
|
-
MenuSelect,
|
|
1149
|
-
{
|
|
1150
|
-
value: form.scheduleKind,
|
|
1151
|
-
options: KINDS.map((kind) => ({ value: kind, label: t(`form.${kind}`) })),
|
|
1152
|
-
onChange: (value) => update({ scheduleKind: value })
|
|
1153
|
-
}
|
|
1154
|
-
),
|
|
1155
|
-
form.scheduleKind === "once" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1156
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "date", min: today, value: datePart, onChange: (event) => update({ onceAt: clampOnceAt(`${event.target.value}T${timePart}`) }) }),
|
|
1157
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: timePart, ...minOnceTime === void 0 ? {} : { minTime: minOnceTime }, onChange: (value) => update({ onceAt: clampOnceAt(`${datePart}T${value}`) }) })
|
|
1158
|
-
] }),
|
|
1159
|
-
form.scheduleKind === "interval" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1160
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "is-narrow", type: "number", min: 5, value: form.everyMinutes, onChange: (event) => update({ everyMinutes: event.target.value }) }),
|
|
1161
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.minutesShort") })
|
|
1162
|
-
] }),
|
|
1163
|
-
form.scheduleKind === "hourly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1164
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuSelect, { value: form.hourlyMinute, options: MINUTES.map((item) => ({ value: item, label: item })), onChange: (value) => update({ hourlyMinute: value }) }),
|
|
1165
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.minutesShort") })
|
|
1166
|
-
] }),
|
|
1167
|
-
(form.scheduleKind === "daily" || form.scheduleKind === "weekly") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) }),
|
|
1168
|
-
form.scheduleKind === "monthly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1149
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-plan-row", children: [
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-field", children: [
|
|
1151
|
+
t("form.planTime"),
|
|
1152
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "dsh-st-inline", children: [
|
|
1169
1153
|
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1170
1154
|
MenuSelect,
|
|
1171
1155
|
{
|
|
1172
|
-
value: form.
|
|
1173
|
-
options:
|
|
1174
|
-
|
|
1175
|
-
return { value: day, label: t("form.monthDay", { day }) };
|
|
1176
|
-
}),
|
|
1177
|
-
onChange: (value) => update({ monthDay: value })
|
|
1156
|
+
value: form.scheduleKind,
|
|
1157
|
+
options: KINDS.map((kind) => ({ value: kind, label: t(`form.${kind}`) })),
|
|
1158
|
+
onChange: (value) => update({ scheduleKind: value })
|
|
1178
1159
|
}
|
|
1179
1160
|
),
|
|
1180
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
/* @__PURE__ */ (0, import_jsx_runtime3.
|
|
1185
|
-
|
|
1161
|
+
form.scheduleKind === "once" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1162
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "date", min: today, value: datePart, onChange: (event) => update({ onceAt: clampOnceAt(`${event.target.value}T${timePart}`) }) }),
|
|
1163
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: timePart, ...minOnceTime === void 0 ? {} : { minTime: minOnceTime }, onChange: (value) => update({ onceAt: clampOnceAt(`${datePart}T${value}`) }) })
|
|
1164
|
+
] }),
|
|
1165
|
+
form.scheduleKind === "interval" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1166
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "is-narrow", type: "number", min: 1, value: form.everyMinutes, onChange: (event) => update({ everyMinutes: event.target.value }) }),
|
|
1167
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.minutesShort") })
|
|
1168
|
+
] }),
|
|
1169
|
+
form.scheduleKind === "hourly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1170
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(MenuSelect, { value: form.hourlyMinute, options: MINUTES.map((item) => ({ value: item, label: item })), onChange: (value) => update({ hourlyMinute: value }) }),
|
|
1171
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.minutesShort") })
|
|
1172
|
+
] }),
|
|
1173
|
+
(form.scheduleKind === "daily" || form.scheduleKind === "weekly") && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) }),
|
|
1174
|
+
form.scheduleKind === "monthly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1175
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1176
|
+
MenuSelect,
|
|
1177
|
+
{
|
|
1178
|
+
value: form.monthDay,
|
|
1179
|
+
options: Array.from({ length: 31 }, (_, index) => {
|
|
1180
|
+
const day = String(index + 1);
|
|
1181
|
+
return { value: day, label: t("form.monthDay", { day }) };
|
|
1182
|
+
}),
|
|
1183
|
+
onChange: (value) => update({ monthDay: value })
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) })
|
|
1187
|
+
] }),
|
|
1188
|
+
form.scheduleKind === "custom" && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
1189
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "is-narrow", type: "number", min: 1, value: form.customDays, onChange: (event) => update({ customDays: event.target.value }) }),
|
|
1190
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "dsh-st-suffix", children: t("form.daysShort") }),
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TimeSelect, { value: form.time, onChange: (value) => update({ time: value }) })
|
|
1192
|
+
] })
|
|
1186
1193
|
] })
|
|
1194
|
+
] }),
|
|
1195
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "dsh-st-field dsh-st-concurrency", title: t("form.maxConcurrentRunsHint"), children: [
|
|
1196
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t("form.maxConcurrentRuns") }),
|
|
1197
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { type: "number", min: 1, step: 1, required: true, value: form.maxConcurrentRuns, onChange: (event) => update({ maxConcurrentRuns: event.target.value }) })
|
|
1187
1198
|
] })
|
|
1188
1199
|
] }),
|
|
1189
1200
|
form.scheduleKind === "weekly" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-weekdays", children: WEEKDAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
@@ -2633,6 +2644,9 @@ var en = {
|
|
|
2633
2644
|
"form.time": "Time",
|
|
2634
2645
|
"form.days": "Weekdays",
|
|
2635
2646
|
"form.timeZone": "Time zone",
|
|
2647
|
+
"form.maxConcurrentRuns": "Concurrency",
|
|
2648
|
+
"form.maxConcurrentRunsHint": "Queued and running executions share this limit. Defaults to 1; when full, scheduled triggers are skipped and manual runs are rejected.",
|
|
2649
|
+
"form.error.maxConcurrentRuns": "Enter a positive whole number for concurrent runs.",
|
|
2636
2650
|
"form.permission": "Permission boundary",
|
|
2637
2651
|
"permission.readOnly": "Read Only",
|
|
2638
2652
|
"permission.workspaceWrite": "Workspace Write",
|
|
@@ -2643,7 +2657,7 @@ var en = {
|
|
|
2643
2657
|
"form.error.name": "Enter a name.",
|
|
2644
2658
|
"form.error.prompt": "Enter a complete, standalone task prompt.",
|
|
2645
2659
|
"form.error.once": "Choose a valid future date and time.",
|
|
2646
|
-
"form.error.interval": "The interval must be between
|
|
2660
|
+
"form.error.interval": "The interval must be between 1 and 43,200 minutes.",
|
|
2647
2661
|
"form.error.weekdays": "Select at least one weekday.",
|
|
2648
2662
|
"day.1": "Mon",
|
|
2649
2663
|
"day.2": "Tue",
|
|
@@ -2848,6 +2862,9 @@ var zh = {
|
|
|
2848
2862
|
"form.time": "\u65F6\u95F4",
|
|
2849
2863
|
"form.days": "\u661F\u671F",
|
|
2850
2864
|
"form.timeZone": "\u65F6\u533A",
|
|
2865
|
+
"form.maxConcurrentRuns": "\u5E76\u53D1\u6570\u91CF",
|
|
2866
|
+
"form.maxConcurrentRunsHint": "\u540C\u4E00\u4EFB\u52A1\u7684\u6392\u961F\u53CA\u8FD0\u884C\u6B21\u6570\u5171\u7528\u6B64\u4E0A\u9650\uFF0C\u9ED8\u8BA4 1\uFF1B\u6EE1\u989D\u65F6\u8DF3\u8FC7\u5F53\u6B21\u5B9A\u65F6\u89E6\u53D1\uFF0C\u624B\u52A8\u8FD0\u884C\u5C06\u88AB\u62D2\u7EDD\u3002",
|
|
2867
|
+
"form.error.maxConcurrentRuns": "\u5E76\u53D1\u6570\u91CF\u5FC5\u987B\u4E3A\u5927\u4E8E\u7B49\u4E8E 1 \u7684\u6574\u6570\u3002",
|
|
2851
2868
|
"form.permission": "\u6743\u9650\u8FB9\u754C",
|
|
2852
2869
|
"permission.readOnly": "\u53EA\u8BFB",
|
|
2853
2870
|
"permission.workspaceWrite": "\u5DE5\u4F5C\u533A\u5199\u5165",
|
|
@@ -2858,7 +2875,7 @@ var zh = {
|
|
|
2858
2875
|
"form.error.name": "\u8BF7\u8F93\u5165\u540D\u79F0\u3002",
|
|
2859
2876
|
"form.error.prompt": "\u8BF7\u8F93\u5165\u5B8C\u6574\u3001\u72EC\u7ACB\u7684\u4EFB\u52A1\u6307\u4EE4\u3002",
|
|
2860
2877
|
"form.error.once": "\u8BF7\u9009\u62E9\u6709\u6548\u7684\u672A\u6765\u65E5\u671F\u548C\u65F6\u95F4\u3002",
|
|
2861
|
-
"form.error.interval": "\u8FD0\u884C\u95F4\u9694\u5FC5\u987B\u5728
|
|
2878
|
+
"form.error.interval": "\u8FD0\u884C\u95F4\u9694\u5FC5\u987B\u5728 1 \u5230 43,200 \u5206\u949F\u4E4B\u95F4\u3002",
|
|
2862
2879
|
"form.error.weekdays": "\u8BF7\u81F3\u5C11\u9009\u62E9\u4E00\u5929\u3002",
|
|
2863
2880
|
"day.1": "\u5468\u4E00",
|
|
2864
2881
|
"day.2": "\u5468\u4E8C",
|
|
@@ -4051,6 +4068,7 @@ var CSS_TEXT = `
|
|
|
4051
4068
|
.dsh-st-model-select{position:relative;z-index:1;min-width:0;flex:none}.dsh-st-model-select.is-open{z-index:30}.dsh-st-model-select-trigger{display:flex;align-items:center;gap:4px;min-width:0;max-width:260px;height:28px;padding:0 4px 0 8px;border:0;border-radius:24px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;font-weight:500;line-height:20px;cursor:pointer}.dsh-st-model-select-trigger:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.dsh-st-model-select-trigger>span:first-child{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dsh-st-model-trigger-effort{flex:none;color:var(--dsw-alias-label-tertiary);white-space:nowrap}.dsh-st-model-trigger-chevron{flex:none;transition:transform .16s ease}.dsh-st-model-trigger-chevron.is-open{transform:rotate(180deg)}.dsh-st-model-select-menu{z-index:30;width:max-content;min-width:min(240px,calc(100vw - 32px));max-width:calc(100vw - 32px);max-height:min(360px,calc(100vh - 96px));overflow-y:auto;padding:4px;border:1px solid var(--dsw-alias-border-inverted,var(--dsw-alias-border-l2));border-radius:12px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-base));box-shadow:var(--dsw-shadow-lv3)}.dsh-st-model-select-menu.is-float{position:absolute;z-index:1200;box-sizing:border-box}.dsh-st-model-select-menu .dsh-st-menu-row{min-height:40px;padding:0 10px;border-radius:10px;font-size:14px}.dsh-st-model-select-menu .dsh-st-menu-row-side>span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dsh-st-model-select-menu .dsh-st-menu-row.is-kv .dsh-st-menu-row-side{font-size:13px;color:var(--dsw-alias-label-tertiary)}.dsh-st-model-group+.dsh-st-model-group{margin-top:4px}.dsh-st-model-group-title{position:sticky;top:0;z-index:1;padding:5px 8px 3px;background:var(--dsw-specific-menu,var(--dsw-alias-bg-base));color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:500;line-height:18px}.dsh-st-model-option{display:flex;width:100%;min-height:38px;align-items:center;gap:8px;padding:6px 8px;border:0;border-radius:10px;background:transparent;color:var(--dsw-alias-label-primary);text-align:left;cursor:pointer}.dsh-st-model-option:hover,.dsh-st-model-option:focus-visible{background:var(--dsw-alias-interactive-bg-hover);outline:none}.dsh-st-model-option-copy{display:flex;min-width:0;flex:1;flex-direction:column}.dsh-st-model-name{overflow:hidden;font-size:14px;font-weight:500;line-height:20px;text-overflow:ellipsis;white-space:nowrap}.dsh-st-model-description{overflow:hidden;color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap}.dsh-st-model-check{display:grid;flex:0 0 18px;place-items:center;color:var(--dsw-alias-label-primary)}.dsh-st-model-warning{margin:4px;padding:8px;border-radius:8px;background:var(--dsw-alias-interactive-bg-hover-danger,rgba(248,81,73,.1));color:var(--dsw-alias-state-error-primary,#f85149);font-size:12px;line-height:18px}.dsh-st-model-empty{padding:14px 12px;color:var(--dsw-alias-label-tertiary);font-size:12px;text-align:center}
|
|
4052
4069
|
.dsh-st-suffix{color:var(--dsw-alias-label-secondary);font-size:13px}
|
|
4053
4070
|
.dsh-st-inline input.is-narrow{width:72px;flex:none}
|
|
4071
|
+
.dsh-st-plan-row{display:flex;align-items:flex-start;gap:16px}.dsh-st-plan-row>.dsh-st-field:first-child{flex:1}.dsh-st-plan-row>.dsh-st-concurrency{flex:0 0 120px}
|
|
4054
4072
|
.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)}
|
|
4055
4073
|
.dsh-st-time .dsh-st-select{min-width:48px}
|
|
4056
4074
|
.dsh-st-time .dsh-st-select-btn{width:auto;min-height:32px;padding:0 6px;border:0;background:transparent}
|
|
@@ -4630,10 +4648,16 @@ function apply(ctx) {
|
|
|
4630
4648
|
ctx.slots.inject("sidebar.workspaces", () => {
|
|
4631
4649
|
let wrappedEntry;
|
|
4632
4650
|
let originalComp;
|
|
4651
|
+
let ownedWrapper;
|
|
4652
|
+
let ownedRegistry;
|
|
4653
|
+
let insertedRegistry;
|
|
4633
4654
|
let removeInsertedTab = () => void 0;
|
|
4634
4655
|
let wrapped = false;
|
|
4635
4656
|
let syncing = false;
|
|
4636
4657
|
let retryTimer;
|
|
4658
|
+
const notifyPeers = () => {
|
|
4659
|
+
queueMicrotask(() => window.dispatchEvent(new Event("dsh-native-sidebar-change")));
|
|
4660
|
+
};
|
|
4637
4661
|
const listenChannels = (listener) => ctx.slots.subscribe?.("sidebar.channels", listener) ?? (() => void 0);
|
|
4638
4662
|
const stopRetry = () => {
|
|
4639
4663
|
if (retryTimer !== void 0) {
|
|
@@ -4645,19 +4669,27 @@ function apply(ctx) {
|
|
|
4645
4669
|
stopRetry();
|
|
4646
4670
|
removeInsertedTab();
|
|
4647
4671
|
removeInsertedTab = () => void 0;
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4672
|
+
insertedRegistry = void 0;
|
|
4673
|
+
if (wrappedEntry !== void 0) {
|
|
4674
|
+
if (originalComp !== void 0 && wrappedEntry.component === ownedWrapper) wrappedEntry.component = originalComp;
|
|
4675
|
+
const record = wrappedEntry;
|
|
4676
|
+
if (record.__dshNativeTabs === ownedRegistry) delete record.__dshNativeTabs;
|
|
4677
|
+
notifyPeers();
|
|
4653
4678
|
}
|
|
4654
4679
|
wrappedEntry = void 0;
|
|
4655
4680
|
originalComp = void 0;
|
|
4681
|
+
ownedWrapper = void 0;
|
|
4682
|
+
ownedRegistry = void 0;
|
|
4656
4683
|
wrapped = false;
|
|
4657
4684
|
};
|
|
4658
4685
|
const insertScheduleTab = (entry, openSession) => {
|
|
4659
4686
|
const registry = findNativeTabRegistry(entry);
|
|
4660
4687
|
if (registry === void 0) return false;
|
|
4688
|
+
if (insertedRegistry !== registry) {
|
|
4689
|
+
removeInsertedTab();
|
|
4690
|
+
removeInsertedTab = () => void 0;
|
|
4691
|
+
insertedRegistry = registry;
|
|
4692
|
+
}
|
|
4661
4693
|
if (registry.getTabs().some((item) => item.id === "schedule")) return true;
|
|
4662
4694
|
removeInsertedTab = registry.insert({
|
|
4663
4695
|
id: "schedule",
|
|
@@ -4689,7 +4721,7 @@ function apply(ctx) {
|
|
|
4689
4721
|
const record = entry;
|
|
4690
4722
|
if (insertScheduleTab(entry) || insertScheduleTab(record.component)) return true;
|
|
4691
4723
|
}
|
|
4692
|
-
return
|
|
4724
|
+
return false;
|
|
4693
4725
|
};
|
|
4694
4726
|
const ensureScheduleTab = () => {
|
|
4695
4727
|
if (insertIntoKnownHosts()) {
|
|
@@ -4722,7 +4754,7 @@ function apply(ctx) {
|
|
|
4722
4754
|
...innerProps.useSessions === void 0 ? {} : { useSessions: innerProps.useSessions },
|
|
4723
4755
|
...innerProps.useWorkspaces === void 0 ? {} : { useWorkspaces: innerProps.useWorkspaces },
|
|
4724
4756
|
...innerProps.renderSlot === void 0 ? {} : { renderSlot: innerProps.renderSlot },
|
|
4725
|
-
|
|
4757
|
+
officialTree: tree
|
|
4726
4758
|
});
|
|
4727
4759
|
};
|
|
4728
4760
|
var AutomationNativeWorkspaceShell = AutomationNativeWorkspaceShell2;
|
|
@@ -4731,13 +4763,19 @@ function apply(ctx) {
|
|
|
4731
4763
|
return;
|
|
4732
4764
|
}
|
|
4733
4765
|
const entries = readSlotEntries(ctx, "sidebar.workspaces");
|
|
4734
|
-
const
|
|
4735
|
-
|
|
4736
|
-
if (
|
|
4766
|
+
const active = entries.find((entry) => entry?.component !== void 0);
|
|
4767
|
+
if (wrappedEntry !== void 0 && (active !== wrappedEntry || active.component !== ownedWrapper)) unwrap();
|
|
4768
|
+
if (active === wrappedEntry && active?.component === ownedWrapper && ownedWrapper !== void 0) {
|
|
4737
4769
|
ensureScheduleTab();
|
|
4738
4770
|
return;
|
|
4739
4771
|
}
|
|
4740
|
-
if (
|
|
4772
|
+
if (active === void 0) {
|
|
4773
|
+
unwrap();
|
|
4774
|
+
return;
|
|
4775
|
+
}
|
|
4776
|
+
const occupant = pickWrappableWorkspacesEntry(entries);
|
|
4777
|
+
const current = occupant?.component;
|
|
4778
|
+
if (current !== void 0 && isForeignSidebarHost(current)) {
|
|
4741
4779
|
ensureScheduleTab();
|
|
4742
4780
|
return;
|
|
4743
4781
|
}
|
|
@@ -4746,17 +4784,21 @@ function apply(ctx) {
|
|
|
4746
4784
|
if (resolved === void 0) return;
|
|
4747
4785
|
originalComp = resolved;
|
|
4748
4786
|
const registry = createNativeTabRegistry(originalComp);
|
|
4787
|
+
ownedRegistry = registry;
|
|
4749
4788
|
attachNativeTabRegistry(occupant, registry);
|
|
4750
4789
|
const marked = AutomationNativeWorkspaceShell2;
|
|
4751
4790
|
marked.displayName = "AutomationNativeWorkspaceShell";
|
|
4752
4791
|
marked.__dshNativeTabHost = true;
|
|
4753
4792
|
marked.__dshAutomationWrapped = true;
|
|
4754
4793
|
marked.__dshAutomationOriginal = originalComp;
|
|
4794
|
+
const tree = originalComp;
|
|
4755
4795
|
attachNativeTabRegistry(marked, registry);
|
|
4756
4796
|
occupant.component = marked;
|
|
4797
|
+
ownedWrapper = marked;
|
|
4757
4798
|
wrappedEntry = occupant;
|
|
4758
4799
|
wrapped = true;
|
|
4759
4800
|
ensureScheduleTab();
|
|
4801
|
+
notifyPeers();
|
|
4760
4802
|
} catch (error) {
|
|
4761
4803
|
console.warn("[dsh-automation] \u5305\u88F9\u5B98\u65B9\u4EFB\u52A1\u6811\u5931\u8D25", error);
|
|
4762
4804
|
} finally {
|
|
@@ -4765,9 +4807,13 @@ function apply(ctx) {
|
|
|
4765
4807
|
};
|
|
4766
4808
|
sync();
|
|
4767
4809
|
const unsub = typeof ctx.slots.subscribe === "function" ? ctx.slots.subscribe("sidebar.workspaces", sync) : () => void 0;
|
|
4810
|
+
const unsubSidebar = ctx.slots.subscribe?.("sidebar", sync) ?? (() => void 0);
|
|
4811
|
+
window.addEventListener("dsh-native-sidebar-change", sync);
|
|
4768
4812
|
ensureScheduleTab();
|
|
4769
4813
|
return () => {
|
|
4770
4814
|
unsub();
|
|
4815
|
+
unsubSidebar();
|
|
4816
|
+
window.removeEventListener("dsh-native-sidebar-change", sync);
|
|
4771
4817
|
unwrap();
|
|
4772
4818
|
};
|
|
4773
4819
|
});
|