@michengai/dsh-automation 0.1.5 → 0.1.7

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/README.md CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE)
14
14
  [![npm package](https://img.shields.io/npm/v/%40michengai%2Fdsh-automation.svg?label=npm%20package)](https://www.npmjs.com/package/@michengai/dsh-automation)
15
+ [![npm downloads](https://img.shields.io/npm/dt/%40michengai%2Fdsh-automation.svg?label=npm%20downloads)](https://www.npmjs.com/package/@michengai/dsh-automation)
15
16
  [![DSH Web Plugin](https://img.shields.io/badge/DSH%20Web-Plugin-0f766e.svg)](https://github.com/MichengAI/dsh-automation)
16
17
  [![Node.js 22 or later](https://img.shields.io/badge/Node.js-22%20or%20later-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org/)
17
18
  </div>
@@ -24,7 +25,7 @@
24
25
  - Create, pause, resume, run now, and delete rules from the Web UI or Agent tools.
25
26
  - Start each occurrence in a fresh root Agent and Session. Source-chat history is not inherited.
26
27
  - Support once, interval, hourly, daily, weekly, monthly, and custom-every-N-days schedules.
27
- - Pick workspace, model, skills, and `read-only` / `workspace-write` in the create dialog.
28
+ - Pick workspace, model, skills, and any permission preset exposed by the Host.
28
29
  - Create from chat: describe the schedule in any conversation, then confirm with the official approval card.
29
30
  - Keep durable run history: `queued`, `running`, `succeeded`, `failed`, `skipped`, `cancelled`.
30
31
  - Add a sidebar **Scheduled** tab. Folders are task names and child sessions are run times. On stock DSH it wraps the official workspace tree and does not depend on `dsh-codex-ui`.
@@ -53,6 +54,17 @@ Run history stays in Settings and can be filtered by day, week, month, task, or
53
54
 
54
55
  ![Run history](assets/screenshots/settings-runs.png)
55
56
 
57
+ ## DSH product ecosystem
58
+
59
+ This product can be installed independently or used through the desktop app or Web suite. They share the same DSH core but serve different ways of working; on stock DSH, this product does not depend on Codex UI:
60
+
61
+ | Product | Relationship to this product |
62
+ | --- | --- |
63
+ | [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | The host runtime that provides models, sessions, tools, and the plugin system |
64
+ | [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop) | A ready-to-install desktop product with this product and the other five feature products built in |
65
+ | [DSH Codex Suite](https://github.com/MichengAI/dsh-codex-ui/tree/main/packages/dsh-codex-suite) | A one-click suite for existing DSH Web environments that installs this product and the other five feature products |
66
+ | Six feature products | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) · [IM Connect](https://github.com/MichengAI/dsh-im-connect) · [Automation](https://github.com/MichengAI/dsh-automation) · [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) · [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) · [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) |
67
+
56
68
  ## Prerequisites
57
69
 
58
70
  - A working DeepSeek Harness Web installation with `dsh` available in PowerShell.
@@ -112,8 +124,8 @@ Each dispatched run uses the saved prompt, workspace, model, and permission boun
112
124
 
113
125
  | Item | Behavior |
114
126
  | --- | --- |
115
- | Permission | Default is `read-only`. File writes require an explicit `workspace-write` choice. |
116
- | Full access | Unattended `danger-full-access` is not offered. |
127
+ | Permission | Options and the default come directly from the Host `permissionPresets` service, including custom presets. |
128
+ | Full access | The official `danger-full-access` option uses the same risk confirmation and orange warning as Chat. |
117
129
  | 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`. |
118
130
  | Retry | No automatic retry after a started run. |
119
131
  | Host restart | Leftover `queued` / `running` records become `failed(host_interrupted)`. |
@@ -156,4 +168,4 @@ pnpm build
156
168
 
157
169
  Start from the [documentation entry](docs/00-交接入口/00-阅读导航.md) for project status, architecture, and the current iteration. Product notes live in NOTICE.
158
170
 
159
- This project uses [Apache License 2.0](LICENSE).
171
+ This project uses [Apache License 2.0](LICENSE).
package/README.zh-CN.md CHANGED
@@ -12,6 +12,7 @@
12
12
 
13
13
  [![许可证:Apache-2.0](https://img.shields.io/badge/许可证-Apache--2.0-blue.svg)](LICENSE)
14
14
  [![npm package](https://img.shields.io/npm/v/%40michengai%2Fdsh-automation.svg?label=npm%20package)](https://www.npmjs.com/package/@michengai/dsh-automation)
15
+ [![npm 下载量](https://img.shields.io/npm/dt/%40michengai%2Fdsh-automation.svg?label=npm%20%E4%B8%8B%E8%BD%BD%E9%87%8F)](https://www.npmjs.com/package/@michengai/dsh-automation)
15
16
  [![DSH Web Plugin](https://img.shields.io/badge/DSH%20Web-Plugin-0f766e.svg)](https://github.com/MichengAI/dsh-automation)
16
17
  [![Node.js 22 or later](https://img.shields.io/badge/Node.js-22%20or%20later-339933.svg?logo=node.js&logoColor=white)](https://nodejs.org/)
17
18
  </div>
@@ -24,7 +25,7 @@
24
25
  - 支持 Web 设置页和 Agent 工具创建、暂停、恢复、立即运行和删除。
25
26
  - 每次到期都启动全新 root Agent 和 Session,不继承来源对话。
26
27
  - 计划类型包括不重复、间隔、每小时、每天、每周、每月和自定义间隔天数。
27
- - 新建弹窗可选择工作目录、模型、技能,以及 `read-only` / `workspace-write`。
28
+ - 新建弹窗可选择工作目录、模型、技能,以及 Host 官方提供的权限预设。
28
29
  - 在任意对话里描述定时任务即可创建;Full access 直接执行,其他权限走官方授权卡。
29
30
  - 运行状态包含 `queued`、`running`、`succeeded`、`failed`、`skipped`、`cancelled`。
30
31
  - 侧栏提供「定时」页签:文件夹是任务名称,子会话是执行时间。原生下只包裹官方任务树,不依赖 `dsh-codex-ui`。
@@ -53,6 +54,17 @@
53
54
 
54
55
  ![执行记录](assets/screenshots/settings-runs.png)
55
56
 
57
+ ## DSH 产品生态
58
+
59
+ 本产品既可以独立安装,也可以随桌面端或 Web 套件一起使用。它们共享同一个 DSH 核心,但面向不同的使用方式;在原生 DSH 下,本产品不依赖 Codex UI:
60
+
61
+ | 产品 | 与本产品的关系 |
62
+ | --- | --- |
63
+ | [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | 本产品的运行宿主,提供模型、会话、工具和插件系统 |
64
+ | [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop) | 下载安装即用的桌面产品,已内置本产品和其他 5 个功能产品 |
65
+ | [DSH Codex Suite](https://github.com/MichengAI/dsh-codex-ui/tree/main/packages/dsh-codex-suite) | 面向已有 DSH Web 环境的一键套件,会安装本产品和其他 5 个功能产品 |
66
+ | 6 个功能产品 | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) · [IM Connect](https://github.com/MichengAI/dsh-im-connect) · [Automation](https://github.com/MichengAI/dsh-automation) · [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) · [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) · [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) |
67
+
56
68
  ## 前置条件
57
69
 
58
70
  - 已可正常运行 DeepSeek Harness Web,且可在 PowerShell 中使用 `dsh`。
@@ -112,8 +124,8 @@ dsh --profile web --dump-config
112
124
 
113
125
  | 项目 | 行为 |
114
126
  | --- | --- |
115
- | 权限 | 默认 `read-only`。改文件必须显式选择 `workspace-write`。 |
116
- | 完全访问 | 不提供无人值守 `danger-full-access`。 |
127
+ | 权限 | 列表和默认值直接来自 Host 官方 `permissionPresets` 服务;支持 Host 注册的自定义预设。 |
128
+ | 完全访问 | 选择官方 `danger-full-access` 时显示与 Chat 一致的风险确认和橙色提示。 |
117
129
  | 审批 | 对话创建跟随当前会话策略。Full access(`never`)直接创建;Workspace Write / Read Only(`ask`)走官方授权卡。无人值守运行仍是 fail-closed 的 `never`。 |
118
130
  | 重试 | 已经开始的运行不会自动重试。 |
119
131
  | Host 重启 | 遗留的 `queued` / `running` 会变成 `failed(host_interrupted)`。 |
@@ -156,4 +168,4 @@ pnpm build
156
168
 
157
169
  项目状态、使用边界、技术架构和迭代记录从[文档交接入口](docs/00-交接入口/00-阅读导航.md)开始。补充说明见 NOTICE。
158
170
 
159
- 本项目采用 [Apache License 2.0](LICENSE)。
171
+ 本项目采用 [Apache License 2.0](LICENSE)。
package/lib/client.js CHANGED
@@ -63,7 +63,7 @@ function localDateTimeValue(date = /* @__PURE__ */ new Date()) {
63
63
  const offset = future.getTimezoneOffset() * 6e4;
64
64
  return new Date(future.getTime() - offset).toISOString().slice(0, 16);
65
65
  }
66
- function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], defaultModel) {
66
+ function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], defaultModel, defaultPermission = "") {
67
67
  return {
68
68
  name: "",
69
69
  prompt: "",
@@ -76,7 +76,7 @@ function defaultFormState(now = /* @__PURE__ */ new Date(), workspaces = [], def
76
76
  monthDay: "1",
77
77
  customDays: "2",
78
78
  timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone || "Asia/Shanghai",
79
- permission: "read-only",
79
+ permission: defaultPermission,
80
80
  workspaceId: workspaces[0]?.id ?? "",
81
81
  modelKey: defaultModel === void 0 || defaultModel === null ? "default" : `${defaultModel.provider}::${defaultModel.model}`,
82
82
  reasoningEffort: "high",
@@ -228,8 +228,8 @@ function startOfWeek(value) {
228
228
  next.setDate(next.getDate() - offset);
229
229
  return next;
230
230
  }
231
- function formFromAutomation(item, workspaces = [], defaultModel) {
232
- const base = defaultFormState(/* @__PURE__ */ new Date(), workspaces, defaultModel);
231
+ function formFromAutomation(item, workspaces = [], defaultModel, defaultPermission = item.permission) {
232
+ const base = defaultFormState(/* @__PURE__ */ new Date(), workspaces, defaultModel, defaultPermission);
233
233
  const schedule = item.schedule;
234
234
  const modelKey = item.provider && item.model ? `${item.provider}::${item.model}` : "default";
235
235
  const common = {
@@ -397,7 +397,24 @@ function RunningStateDot() {
397
397
  // src/client/create-modal.tsx
398
398
  var import_react2 = require("react");
399
399
 
400
+ // src/client/permissions.ts
401
+ var BUILT_IN_PERMISSION_LABELS = /* @__PURE__ */ new Map([
402
+ ["read-only", ["preset.readOnly", "Read Only"]],
403
+ ["workspace-write", ["preset.workspaceWrite", "Workspace Write"]],
404
+ ["danger-full-access", ["preset.fullAccess", "Full access"]]
405
+ ]);
406
+ function permissionLabel(option, t) {
407
+ const builtIn = BUILT_IN_PERMISSION_LABELS.get(option.value);
408
+ if (builtIn !== void 0 && (option.name === option.value || option.name === builtIn[1])) {
409
+ return t(builtIn[0]);
410
+ }
411
+ return option.name || option.value;
412
+ }
413
+
400
414
  // src/client/create-modal-logic.ts
415
+ function shouldConfirmFullAccess(current, next) {
416
+ return current !== next && next === "danger-full-access";
417
+ }
401
418
  async function adoptPickedWorkspace(input) {
402
419
  const path = await input.pick();
403
420
  if (path == null || path.trim() === "") return null;
@@ -606,6 +623,7 @@ function useMenuState() {
606
623
  }
607
624
 
608
625
  // src/client/create-modal.tsx
626
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
609
627
  var import_jsx_runtime3 = require("react/jsx-runtime");
610
628
  var WEEKDAYS = [1, 2, 3, 4, 5, 6, 7];
611
629
  var KINDS = ["once", "interval", "hourly", "daily", "weekly", "monthly", "custom"];
@@ -614,11 +632,14 @@ var MINUTES = Array.from({ length: 60 }, (_, index) => String(index).padStart(2,
614
632
  var EFFORTS = ["none", "low", "medium", "high"];
615
633
  function CreateModal({
616
634
  t,
635
+ permissionT,
617
636
  busy,
618
637
  workspaces,
619
638
  models,
620
639
  defaultModel,
621
640
  skills,
641
+ permissions,
642
+ defaultPermission,
622
643
  draft,
623
644
  editing,
624
645
  onClose,
@@ -626,12 +647,32 @@ function CreateModal({
626
647
  onAddWorkspace,
627
648
  pickWorkspaceDirectory
628
649
  }) {
629
- const [form, setForm] = (0, import_react2.useState)(() => ({ ...defaultFormState(/* @__PURE__ */ new Date(), workspaces, defaultModel), ...draft }));
650
+ const [form, setForm] = (0, import_react2.useState)(() => ({ ...defaultFormState(/* @__PURE__ */ new Date(), workspaces, defaultModel, defaultPermission), ...draft }));
630
651
  const [validationError, setValidationError] = (0, import_react2.useState)();
652
+ const [confirmingPermission, setConfirmingPermission] = (0, import_react2.useState)();
653
+ const [fullAccessAcknowledged, setFullAccessAcknowledged] = (0, import_react2.useState)(false);
631
654
  const update = (patch) => {
632
655
  setForm((current) => ({ ...current, ...patch }));
633
656
  setValidationError(void 0);
634
657
  };
658
+ const choosePermission = (permission) => {
659
+ if (shouldConfirmFullAccess(form.permission, permission)) {
660
+ setFullAccessAcknowledged(false);
661
+ setConfirmingPermission(permission);
662
+ return;
663
+ }
664
+ update({ permission });
665
+ };
666
+ const cancelFullAccessConfirmation = () => {
667
+ setFullAccessAcknowledged(false);
668
+ setConfirmingPermission(void 0);
669
+ };
670
+ const confirmFullAccess = () => {
671
+ if (!fullAccessAcknowledged) return;
672
+ if (confirmingPermission === void 0) return;
673
+ update({ permission: confirmingPermission });
674
+ cancelFullAccessConfirmation();
675
+ };
635
676
  (0, import_react2.useEffect)(() => {
636
677
  const onKey = (event) => {
637
678
  if (event.key !== "Escape") return;
@@ -820,12 +861,12 @@ function CreateModal({
820
861
  up: true,
821
862
  icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }),
822
863
  value: form.permission,
823
- options: [
824
- { value: "read-only", label: t("form.readOnly"), icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }) },
825
- { value: "workspace-write", label: t("form.workspaceWrite"), icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }) },
826
- { value: "full-access", label: t("form.fullAccess"), icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 }) }
827
- ],
828
- onChange: (value) => update({ permission: value })
864
+ options: permissions.map((option) => ({
865
+ value: option.value,
866
+ label: permissionLabel(option, permissionT),
867
+ icon: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ShieldIcon, { width: 14, height: 14 })
868
+ })),
869
+ onChange: choosePermission
829
870
  }
830
871
  )
831
872
  ] }),
@@ -849,7 +890,22 @@ function CreateModal({
849
890
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", className: "dsh-st-btn dsh-st-btn--primary", disabled: busy, children: t("modal.save") })
850
891
  ] })
851
892
  ] }),
852
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-flyout-root", ref: setMenuHost })
893
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "dsh-st-flyout-root", ref: setMenuHost }),
894
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
895
+ import_dsh_client_ui_primitives.RiskConfirmation,
896
+ {
897
+ open: confirmingPermission !== void 0,
898
+ title: permissionT("confirm.title"),
899
+ description: permissionT("confirm.description"),
900
+ acknowledgeLabel: permissionT("confirm.acknowledge"),
901
+ cancelLabel: permissionT("confirm.cancel"),
902
+ confirmLabel: permissionT("confirm.enable"),
903
+ acknowledged: fullAccessAcknowledged,
904
+ onAcknowledgedChange: setFullAccessAcknowledged,
905
+ onCancel: cancelFullAccessConfirmation,
906
+ onConfirm: confirmFullAccess
907
+ }
908
+ )
853
909
  ] }) });
854
910
  }
855
911
  function ModelPicker({
@@ -1155,7 +1211,7 @@ var EXAMPLES = [
1155
1211
  { name: "\u6BCF\u5468\u4F9D\u8D56\u5DE1\u68C0", scheduleKind: "weekly", time: "10:00", weekdays: [1] },
1156
1212
  { name: "\u5DE5\u4F5C\u65E5\u65E9\u62A5", scheduleKind: "weekly", time: "08:00", weekdays: [1, 2, 3, 4, 5] }
1157
1213
  ];
1158
- function AutomationView({ t, runtime, closeSettings, pickWorkspaceDirectory }) {
1214
+ function AutomationView({ t, permissionT, runtime, closeSettings, pickWorkspaceDirectory }) {
1159
1215
  const state = (0, import_react3.useSyncExternalStore)(runtime.source.subscribe, runtime.source.getSnapshot, runtime.source.getSnapshot);
1160
1216
  const [tab, setTab] = (0, import_react3.useState)("mine");
1161
1217
  const [query, setQuery] = (0, import_react3.useState)("");
@@ -1180,6 +1236,8 @@ function AutomationView({ t, runtime, closeSettings, pickWorkspaceDirectory }) {
1180
1236
  const snapshot = state.snapshot;
1181
1237
  const workspaces = snapshot?.workspaces ?? [];
1182
1238
  const models = snapshot?.models ?? [];
1239
+ const permissions = snapshot?.permissions ?? [];
1240
+ const defaultPermission = snapshot?.defaultPermission ?? "";
1183
1241
  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));
1184
1242
  const runs = (snapshot?.runs ?? []).filter((run) => {
1185
1243
  if (historyTask !== "all" && run.automationId !== historyTask) return false;
@@ -1204,13 +1262,14 @@ function AutomationView({ t, runtime, closeSettings, pickWorkspaceDirectory }) {
1204
1262
  setEditingId(void 0);
1205
1263
  };
1206
1264
  const openCreate = (partial) => {
1265
+ if (defaultPermission === "" || permissions.length === 0) return;
1207
1266
  setEditingId(void 0);
1208
1267
  setDraft(partial);
1209
1268
  setCreating(true);
1210
1269
  };
1211
1270
  const openEdit = (item) => {
1212
1271
  setEditingId(item.id);
1213
- setDraft(formFromAutomation(item, workspaces, snapshot?.defaultModel ?? null));
1272
+ setDraft(formFromAutomation(item, workspaces, snapshot?.defaultModel ?? null, snapshot?.defaultPermission ?? item.permission));
1214
1273
  setCreating(true);
1215
1274
  };
1216
1275
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "dsh-st-shell", children: [
@@ -1228,7 +1287,7 @@ function AutomationView({ t, runtime, closeSettings, pickWorkspaceDirectory }) {
1228
1287
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ChatIcon, {}),
1229
1288
  t("action.chatCreate")
1230
1289
  ] }),
1231
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", onClick: () => openCreate(), children: [
1290
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", className: "dsh-st-btn dsh-st-btn--primary", disabled: defaultPermission === "" || permissions.length === 0, onClick: () => openCreate(), children: [
1232
1291
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlusIcon, {}),
1233
1292
  t("action.create")
1234
1293
  ] }),
@@ -1248,6 +1307,7 @@ function AutomationView({ t, runtime, closeSettings, pickWorkspaceDirectory }) {
1248
1307
  {
1249
1308
  type: "button",
1250
1309
  className: "dsh-st-example",
1310
+ disabled: defaultPermission === "" || permissions.length === 0,
1251
1311
  onClick: () => openCreate({
1252
1312
  name: t(`examples.${index + 1}.title`),
1253
1313
  prompt: t(`examples.${index + 1}.body`),
@@ -1323,11 +1383,14 @@ function AutomationView({ t, runtime, closeSettings, pickWorkspaceDirectory }) {
1323
1383
  CreateModal,
1324
1384
  {
1325
1385
  t,
1386
+ permissionT,
1326
1387
  busy,
1327
1388
  workspaces,
1328
1389
  models,
1329
1390
  defaultModel: snapshot?.defaultModel ?? null,
1330
1391
  skills: snapshot?.skills ?? [],
1392
+ permissions,
1393
+ defaultPermission,
1331
1394
  onAddWorkspace: async (path) => runtime.addWorkspace(path).then((value) => value.id),
1332
1395
  ...pickWorkspaceDirectory === void 0 ? {} : { pickWorkspaceDirectory },
1333
1396
  editing: editingId !== void 0,
@@ -1557,11 +1620,6 @@ var en = {
1557
1620
  "form.days": "Weekdays",
1558
1621
  "form.timeZone": "Time zone",
1559
1622
  "form.permission": "Permission boundary",
1560
- "form.readOnly": "Read Only",
1561
- "form.readOnlyHint": "Inspect the workspace without changing files.",
1562
- "form.workspaceWrite": "Workspace Write",
1563
- "form.fullAccess": "Full access",
1564
- "form.workspaceWriteHint": "May change files in this workspace; past approvals are not reused.",
1565
1623
  "form.cancel": "Cancel",
1566
1624
  "form.submit": "Create automation",
1567
1625
  "form.submitting": "Creating\u2026",
@@ -1589,9 +1647,6 @@ var en = {
1589
1647
  "card.nextRun": "Next",
1590
1648
  "card.lastRun": "Last",
1591
1649
  "card.never": "Not yet run",
1592
- "card.permission.read-only": "Read-only",
1593
- "card.permission.workspace-write": "Workspace write",
1594
- "card.permission.full-access": "Full access",
1595
1650
  "schedule.onceAt": "Once \xB7 {time}",
1596
1651
  "schedule.everyMinutes": "Every {count} minutes",
1597
1652
  "schedule.dailyAt": "Daily \xB7 {time}",
@@ -1757,11 +1812,6 @@ var zh = {
1757
1812
  "form.days": "\u661F\u671F",
1758
1813
  "form.timeZone": "\u65F6\u533A",
1759
1814
  "form.permission": "\u6743\u9650\u8FB9\u754C",
1760
- "form.readOnly": "Read Only",
1761
- "form.readOnlyHint": "\u53EF\u4EE5\u68C0\u67E5\u5DE5\u4F5C\u533A\uFF0C\u4F46\u4E0D\u4F1A\u4FEE\u6539\u6587\u4EF6\u3002",
1762
- "form.workspaceWrite": "Workspace Write",
1763
- "form.fullAccess": "Full access",
1764
- "form.workspaceWriteHint": "\u53EF\u4EE5\u4FEE\u6539\u5F53\u524D\u5DE5\u4F5C\u533A\u6587\u4EF6\uFF1B\u4E0D\u4F1A\u7EE7\u627F\u5386\u53F2\u6279\u51C6\u3002",
1765
1815
  "form.cancel": "\u53D6\u6D88",
1766
1816
  "form.submit": "\u521B\u5EFA\u81EA\u52A8\u5316",
1767
1817
  "form.submitting": "\u521B\u5EFA\u4E2D\u2026",
@@ -1789,9 +1839,6 @@ var zh = {
1789
1839
  "card.nextRun": "\u4E0B\u6B21",
1790
1840
  "card.lastRun": "\u6700\u8FD1",
1791
1841
  "card.never": "\u5C1A\u672A\u8FD0\u884C",
1792
- "card.permission.read-only": "\u53EA\u8BFB",
1793
- "card.permission.workspace-write": "\u53EF\u5199\u5DE5\u4F5C\u533A",
1794
- "card.permission.full-access": "Full access",
1795
1842
  "schedule.onceAt": "\u5355\u6B21 \xB7 {time}",
1796
1843
  "schedule.everyMinutes": "\u6BCF {count} \u5206\u949F",
1797
1844
  "schedule.dailyAt": "\u6BCF\u5929 \xB7 {time}",
@@ -2959,6 +3006,7 @@ function apply(ctx) {
2959
3006
  ctx.effect(() => installStyles(), "dsh-automation: styles");
2960
3007
  ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-automation: locale");
2961
3008
  const t = ctx.locale.bind(NS);
3009
+ const permissionT = ctx.locale.bind("permission.access");
2962
3010
  const runtime = createAutomationRuntime(ctx.connection.rpc);
2963
3011
  ctx.effect(() => installSettingsNavIcon(() => [t("tab"), "Scheduled tasks", "\u5B9A\u65F6\u4EFB\u52A1"]), "dsh-automation: settings icon");
2964
3012
  ctx.slots.inject("settings.section", () => ctx.slots.register({
@@ -2970,7 +3018,7 @@ function apply(ctx) {
2970
3018
  icon: "schedule"
2971
3019
  }, function ScheduledTasksSettings(props) {
2972
3020
  const workspacesApi = readOptionalWorkspaces(ctx);
2973
- return (0, import_react7.createElement)(AutomationView, { t, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close }, ...workspacesApi === void 0 ? {} : { pickWorkspaceDirectory: () => workspacesApi.pickDirectory() } });
3021
+ return (0, import_react7.createElement)(AutomationView, { t, permissionT, runtime, ...props.close === void 0 ? {} : { closeSettings: props.close }, ...workspacesApi === void 0 ? {} : { pickWorkspaceDirectory: () => workspacesApi.pickDirectory() } });
2974
3022
  }));
2975
3023
  ctx.slots.inject("sidebar.schedule", () => ctx.slots.register({
2976
3024
  name: "sidebar.schedule",