dsh-bash-guard 0.1.0 → 0.1.1

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
@@ -3,6 +3,7 @@
3
3
  <p align="center">4 个范围 × 3 种权限。12 个开关,一个原生菜单。</p>
4
4
 
5
5
  <p align="center">
6
+ <a href="https://www.npmjs.com/package/dsh-bash-guard"><img alt="npm version" src="https://img.shields.io/npm/v/dsh-bash-guard"></a>
6
7
  <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue"></a>
7
8
  <img alt="DSH Web plugin" src="https://img.shields.io/badge/DSH-Web_plugin-555">
8
9
  <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-policy_classifier-3178C6?logo=typescript&logoColor=white">
@@ -18,7 +19,7 @@
18
19
 
19
20
  **DSH Bash Guard 是 DeepSeek Harness 的独立 Web 插件。** 它把 Bash Agent / Bash Guard 的四位权限思路带进 DSH 原生权限菜单,让你按范围控制工具操作,而不必在“只读”和“全部放开”之间二选一。
20
21
 
21
- 不改宿主源码,不增加一排数字预设,也不用记斜杠命令。展开 `bash-guard 自定义`,直接调整系统、外部、网络和工作区的读、写、执行权限。
22
+ 不改宿主源码,不增加一排数字预设,也不用记斜杠命令。展开 `Bash Guard 自定义`,直接调整系统、外部、网络和工作区的读、写、执行权限。
22
23
 
23
24
  > **它是额外的工具权限检查,不是沙箱替代品。** 即使设为 `7777`,DSH 原生沙箱和审批仍然适用。
24
25
 
@@ -32,9 +33,34 @@
32
33
 
33
34
  ## 快速开始
34
35
 
35
- ### 从源码安装
36
+ ### 从 npm 安装(推荐)
36
37
 
37
- 需要 Git、Node.js / npm,以及支持插件的 DSH。当前版本针对 DSH Web 集成验证,尚未声明跨宿主版本兼容。
38
+ 需要 DSH `0.2.0-rc.2` 或更新版本;兼容范围说明见下文。插件安装到 DSH 的 `web` profile,无需全局安装 npm 包,也无需克隆或手动构建。
39
+
40
+ ```bash
41
+ dsh plugin --profile web add dsh-bash-guard
42
+ dsh --profile web
43
+ ```
44
+
45
+ 安装后重新启动对应的 DSH Web 实例,在权限菜单中选择 **Bash Guard 自定义**。
46
+
47
+ [npm 包页面](https://www.npmjs.com/package/dsh-bash-guard) · 当前发布版本:`0.1.0`
48
+
49
+ 升级到最新发布版本:
50
+
51
+ ```bash
52
+ dsh plugin --profile web add dsh-bash-guard@latest
53
+ ```
54
+
55
+ 如果 npm 镜像尚未同步新版本,可以显式使用官方 registry:
56
+
57
+ ```bash
58
+ dsh plugin --profile web add dsh-bash-guard@latest --registry=https://registry.npmjs.org
59
+ ```
60
+
61
+ ### 从源码安装(开发者)
62
+
63
+ 需要 Git、Node.js / npm,以及上述版本的 DSH。
38
64
 
39
65
  ```bash
40
66
  git clone https://github.com/lloydzhou/dsh-bash-guard.git
@@ -46,14 +72,10 @@ dsh plugin --profile web add .
46
72
  dsh --profile web
47
73
  ```
48
74
 
49
- 在输入框附近打开权限菜单,选择 **bash-guard 自定义**。
75
+ 在输入框附近打开权限菜单,选择 **Bash Guard 自定义**。
50
76
 
51
77
  目录安装采用链接。更新插件后重新构建;宿主入口或插件配置变化时,重启对应的 DSH 实例。
52
78
 
53
- ### npm 发布状态
54
-
55
- 包名为 `dsh-bash-guard`。本仓库已准备 npm 打包配置,但本说明不表示该包已经发布;发布前请使用上面的源码安装方式。
56
-
57
79
  ## 在菜单中操作
58
80
 
59
81
  | 入口 | 行为 |
@@ -61,12 +83,14 @@ dsh --profile web
61
83
  | 单个权限格 | 独立切换该范围的读、写或执行位 |
62
84
  | 系统 / 外部 / 网络 / 工作区 | 已全选则清空该行,否则全选该行 |
63
85
  | 全选 | 当前不是 `7777` 时显示,点击将全部 Guard 位设为 `7777` |
64
- | 默认 | 当前是 `7777` 时显示,点击恢复 `0477` |
86
+ | 默认 | 当前是 `7777` 时显示,点击恢复 `4667` |
65
87
  | 原生权限预设 | 停用 Guard,保留记忆的四位值 |
66
88
 
67
89
  方向键在矩阵中移动焦点,不修改权限;空格切换当前按钮,Escape 关闭菜单。状态由服务端确认,保存时不插入提示行或改变菜单高度。
68
90
 
69
- **当前默认值有两种用途:** 新会话的初始记忆值是 `0467`,且 Guard 默认不激活;菜单“默认”按钮的恢复值是 `0477`。已有会话不会因升级自动重置。
91
+ **统一默认值为 `4667`:** 系统只读、外部读写、网络读写、工作区全部。新会话初始记忆值和菜单“默认”按钮的恢复值一致,Guard 初始不激活;已有会话不会因升级自动重置。
92
+
93
+ 界面支持中文和英文,跟随 DSH 的语言设置,无需单独配置。品牌名统一显示为 **Bash Guard**。
70
94
 
71
95
  ## 权限怎么读
72
96
 
@@ -108,7 +132,7 @@ dsh --profile web
108
132
  | 模式 | 表达的策略 |
109
133
  | :---: | :--- |
110
134
  | `0467` | 系统关闭;外部只读;网络读写;工作区全部 |
111
- | `0477` | 与上项相比,增加网络执行位;菜单“默认”的恢复值 |
135
+ | `4667` | 默认:系统只读;外部与网络读写;工作区全部 |
112
136
  | `4447` | 系统、外部、网络只读;工作区全部 |
113
137
  | `0007` | 仅开放工作区的三个权限位 |
114
138
  | `7777` | Guard 全部位开放,**不等于原生完全权限** |
@@ -175,7 +199,7 @@ npm pack --dry-run
175
199
  - [矩阵编辑器](src/GuardEditor.js):单格、整行及全局开关。
176
200
  - [测试](tests/):分类器、RPC、原生菜单和矩阵交互。
177
201
 
178
- 当前回归测试共 174 项,包括全部 4096 种模式的客户端校验。测试覆盖不代表对任意 Shell 程序的安全证明。npm 打包前会自动构建;构建产物与依赖目录不提交到 Git。
202
+ 当前回归测试共 177 项,包括全部 4096 种模式的客户端校验。测试覆盖不代表对任意 Shell 程序的安全证明。npm 打包前会自动构建;构建产物与依赖目录不提交到 Git。
179
203
 
180
204
  ## 来源与致谢
181
205
 
package/client.js CHANGED
@@ -7,77 +7,71 @@ exports.commandResult = commandResult;
7
7
  exports.decodeGuardState = decodeGuardState;
8
8
  exports.createGuardTransport = createGuardTransport;
9
9
  exports.createPermissionControl = createPermissionControl;
10
+ exports.createGuardRemoteContribution = createGuardRemoteContribution;
10
11
  exports.apply = apply;
11
12
  const GuardEditor_js_1 = require("./GuardEditor.js");
13
+ const locales_js_1 = require("./locales.js");
12
14
  // A missing guard service must never hide the host's native permission choices.
13
- exports.inject = ['sessions', 'slots', 'remote', 'remote.permissionPresets'];
14
- function commandResult(reply) {
15
+ exports.inject = ['sessions', 'slots', 'locale', 'remote', 'remote.permissionPresets'];
16
+ function commandResult(reply, t = locales_js_1.defaultT) {
15
17
  if (!reply?.ok)
16
- throw new Error(reply?.error?.message || '权限请求失败');
18
+ throw (reply?.error?.message ? new Error(reply?.error?.message) : (0, locales_js_1.localeError)(t, 'error.permissionRequest'));
17
19
  if (!reply.value?.matched)
18
- throw new Error('宿主未提供此权限命令');
20
+ throw (0, locales_js_1.localeError)(t, 'error.permissionCommand');
19
21
  const result = reply.value.result;
20
22
  if (result?.kind === 'error')
21
- throw new Error(result.text || '权限请求失败');
23
+ throw (result.text ? new Error(result.text) : (0, locales_js_1.localeError)(t, 'error.permissionRequest'));
22
24
  return result;
23
25
  }
24
- function decodeGuardState(reply) {
26
+ function decodeGuardState(reply, t = locales_js_1.defaultT) {
25
27
  if (!reply?.ok)
26
- throw new Error(reply?.error?.message || 'Bash Guard 不可用');
28
+ throw (reply?.error?.message ? new Error(reply?.error?.message) : (0, locales_js_1.localeError)(t, 'error.unavailable'));
27
29
  const state = reply.value;
28
30
  if (!/^[0-7]{4}$(?![\s\S])/.test(state?.mode) || typeof state.active !== 'boolean' || !Number.isSafeInteger(state.revision) || state.revision < 0) {
29
- throw new Error('Bash Guard 返回了无效状态');
31
+ throw (0, locales_js_1.localeError)(t, 'error.invalidState');
30
32
  }
31
33
  return { mode: state.mode, active: state.active, revision: state.revision };
32
34
  }
33
- function createGuardTransport(remote, sessionId, sessionFor) {
35
+ function createGuardTransport(remote, sessionId, sessionFor, t = locales_js_1.defaultT) {
34
36
  const guard = () => {
35
37
  if (!remote.bashGuard)
36
- throw new Error('Bash Guard 不可用');
38
+ throw (0, locales_js_1.localeError)(t, 'error.unavailable');
37
39
  return remote.bashGuard;
38
40
  };
39
41
  return {
40
- get: async () => decodeGuardState(await guard().get(sessionId)),
42
+ get: async () => decodeGuardState(await guard().get(sessionId), t),
41
43
  write: async (action, state, mode) => decodeGuardState(await guard().update(sessionId, {
42
44
  action, revision: state.revision, ...(mode === undefined ? {} : { mode }),
43
- })),
45
+ }), t),
44
46
  // Deliberately independent of guard reads, readiness, and failures.
45
47
  preset: async (id) => {
46
48
  const live = sessionFor();
47
49
  if (!live)
48
- throw new Error('会话尚未就绪,请稍后重试');
49
- return commandResult(await live.command(`/permission ${id}`));
50
+ throw (0, locales_js_1.localeError)(t, 'error.sessionNotReady');
51
+ return commandResult(await live.command(`/permission ${id}`), t);
50
52
  },
51
53
  catalog: async () => {
52
54
  const reply = await remote.permissionPresets.catalog();
53
55
  if (!reply?.ok)
54
- throw new Error(reply?.error?.message || '权限列表不可用');
56
+ throw (reply?.error?.message ? new Error(reply?.error?.message) : (0, locales_js_1.localeError)(t, 'error.catalogUnavailable'));
55
57
  if (!Array.isArray(reply.value?.options))
56
- throw new Error('权限列表无效');
58
+ throw (0, locales_js_1.localeError)(t, 'error.invalidCatalog');
57
59
  return reply.value;
58
60
  },
59
61
  subscribeCatalog: callback => remote.$on?.('permission-presets/catalog-changed', callback),
60
62
  };
61
63
  }
62
- const copy = {
63
- 'preset.readOnly': '仅可查看', 'preset.workspaceWrite': '工作区内修改', 'preset.fullAccess': '完全权限',
64
- 'close': '关闭', 'confirm.cancel': '取消',
65
- 'confirm.title': '确认启用完全权限?',
66
- 'confirm.description': '启用完全权限后,智能体将减少确认步骤,并且可以直接执行更多操作,包括敏感操作、文件修改或外部命令。仅建议在你信任当前任务时使用。',
67
- 'confirm.acknowledge': '我已了解风险,并愿意继续', 'confirm.enable': '启用完全权限',
68
- 'auto.label': 'Auto review', 'auto.badge': 'EXP',
69
- 'auto.description': '无沙箱运行;每次原生工具调用和 PTC 内层调用前由同一模型进行实验性审查。',
70
- 'auto.confirm.title': '确认启用 Auto review(实验)?',
71
- 'auto.confirm.description': 'Auto review 不使用沙箱。每次原生工具调用和 PTC 内层调用前,都会由与当前 agent 相同的模型进行审查;审查拒绝的调用由你批准或拒绝。此功能仍属实验性,可能误放行或误拒绝,并会消耗额外 token。',
72
- 'auto.confirm.acknowledge': '我已了解这些风险,并愿意继续', 'auto.confirm.enable': '启用 Auto review',
73
- };
74
64
  const labels = { 'read-only': ['preset.readOnly', 'Read Only'], 'workspace-write': ['preset.workspaceWrite', 'Workspace Write'], 'danger-full-access': ['preset.fullAccess', 'Full access'] };
75
65
  function createPermissionControl(React, primitives) {
76
66
  const h = React.createElement;
77
- const { Menu, RiskConfirmation, PermissionIconReadOnlyRegular, PermissionIconWorkspaceWriteRegular, PermissionIconFullAccessRegular, IconChevronDownOutlineRegular, IconSettingsOutlineRegular } = primitives;
78
- const icons = { 'read-only': PermissionIconReadOnlyRegular, 'workspace-write': PermissionIconWorkspaceWriteRegular, 'danger-full-access': PermissionIconFullAccessRegular, 'bash-guard': IconSettingsOutlineRegular };
67
+ const { Menu, RiskConfirmation, PermissionIconReadOnlyRegular, PermissionIconWorkspaceWriteRegular, PermissionIconFullAccessRegular, IconChevronDownOutlineRegular, IconShieldOutlineRegular } = primitives;
68
+ // Keep the host shield artwork; only the inner adjustment marks are plugin-owned.
69
+ function GuardPermissionIcon() {
70
+ return h('span', { className: 'dsh-bg-guard-icon', 'aria-hidden': true }, h(IconShieldOutlineRegular), h('svg', { className: 'dsh-bg-guard-marks', viewBox: '0 0 16 16', fill: 'none', stroke: 'currentColor', strokeWidth: 1 }, h('path', { d: 'M5 6.5h6M5 9.5h6M7 5.5v2M9.5 8.5v2', strokeLinecap: 'round' })));
71
+ }
72
+ const icons = { 'read-only': PermissionIconReadOnlyRegular, 'workspace-write': PermissionIconWorkspaceWriteRegular, 'danger-full-access': PermissionIconFullAccessRegular, 'bash-guard': GuardPermissionIcon };
79
73
  const GuardEditor = (0, GuardEditor_js_1.createGuardEditor)(React, primitives.IconCheckOutlineRegular);
80
- return function PermissionControl({ sessionId, transport, locked, useProjection, t = key => copy[key] }) {
74
+ return function PermissionControl({ sessionId, transport, locked, useProjection, t = locales_js_1.defaultT }) {
81
75
  const selection = useProjection('permissions');
82
76
  const [state, setState] = React.useState(null);
83
77
  const [catalog, setCatalog] = React.useState(null);
@@ -93,7 +87,7 @@ function createPermissionControl(React, primitives) {
93
87
  const stateRef = React.useRef(null), api = React.useRef(transport);
94
88
  api.current = transport;
95
89
  const publish = next => { stateRef.current = next; setState(next); };
96
- const message = cause => cause instanceof Error ? cause.message : String(cause);
90
+ const message = cause => cause?.localeKey ? t(cause.localeKey) : cause instanceof Error ? cause.message : String(cause);
97
91
  const read = async () => {
98
92
  if (writing.current)
99
93
  return;
@@ -109,7 +103,7 @@ function createPermissionControl(React, primitives) {
109
103
  catch (cause) {
110
104
  if (generation === epoch.current && ticket === request.current) {
111
105
  publish(null);
112
- setError(message(cause));
106
+ setError(cause);
113
107
  }
114
108
  }
115
109
  finally {
@@ -128,7 +122,7 @@ function createPermissionControl(React, primitives) {
128
122
  }
129
123
  catch (cause) {
130
124
  if (generation === epoch.current && ticket === catalogRequest.current)
131
- setNativeError(message(cause));
125
+ setNativeError(cause);
132
126
  }
133
127
  };
134
128
  React.useEffect(() => {
@@ -170,7 +164,7 @@ function createPermissionControl(React, primitives) {
170
164
  }
171
165
  catch (cause) {
172
166
  if (generation === epoch.current) {
173
- setError(message(cause));
167
+ setError(cause);
174
168
  try {
175
169
  const next = await api.current.get();
176
170
  if (generation === epoch.current)
@@ -211,7 +205,7 @@ function createPermissionControl(React, primitives) {
211
205
  }
212
206
  catch (cause) {
213
207
  if (generation === epoch.current)
214
- setNativeError(message(cause));
208
+ setNativeError(cause);
215
209
  }
216
210
  finally {
217
211
  if (generation === epoch.current) {
@@ -251,7 +245,7 @@ function createPermissionControl(React, primitives) {
251
245
  const icon = id => icons[id] ? h(icons[id]) : undefined;
252
246
  const current = state?.active ? 'bash-guard' : selection?.currentValue;
253
247
  const option = catalog?.options.find(item => item.value === current);
254
- const label = current === 'bash-guard' ? `bash-guard ${state.mode}` : labelFor(current || '权限', option?.name);
248
+ const label = current === 'bash-guard' ? `Bash Guard ${state.mode}` : (current ? labelFor(current, option?.name) : t('permission'));
255
249
  const items = (catalog?.options || []).map(option => ({
256
250
  id: option.value, icon: icon(option.value),
257
251
  label: option.value === 'auto' ? h('span', { className: 'dsh-bg-option-label', 'aria-label': `${t('auto.label')} ${t('auto.badge')}` }, t('auto.label'), h('sup', { className: 'dsh-bg-badge' }, t('auto.badge'))) : labelFor(option.value, option.name),
@@ -259,19 +253,19 @@ function createPermissionControl(React, primitives) {
259
253
  }));
260
254
  items.push({ id: 'guard-separator', type: 'separator' }, {
261
255
  id: 'bash-guard', icon: icon('bash-guard'), disabled: !!locked || !state,
262
- label: h('span', null, 'bash-guard 自定义', state && h('span', { className: 'dsh-bg-mode' }, ` ${state.mode}`)),
256
+ label: h('span', null, t('guard.custom'), state && h('span', { className: 'dsh-bg-mode' }, ` ${state.mode}`)),
263
257
  });
264
258
  const closeConfirmation = () => { setConfirmation(null); setAcknowledged(false); };
265
259
  const riskPrefix = confirmation === 'auto' ? 'auto.confirm.' : 'confirm.';
266
260
  return h(React.Fragment, null, h(Menu, { open, items, selectedId: current, onSelect: choose, onClose: () => setOpen(false), side: 'top', portal: true,
267
261
  anchor: h('button', { type: 'button', className: 'dsh-bg-trigger', disabled: !!locked || picking || confirmation !== null,
268
- 'aria-label': `访问模式,当前:${label}`, 'aria-haspopup': 'menu', 'aria-expanded': open,
262
+ 'aria-label': t('mode', { name: label }), 'aria-haspopup': 'menu', 'aria-expanded': open,
269
263
  title: current === 'auto' ? t('auto.description') : option?.description, onClick: () => setOpen(!open),
270
264
  }, icon(current) && h('span', { className: 'dsh-bg-trigger-icon', 'aria-hidden': true }, icon(current)), h('span', { className: 'dsh-bg-trigger-label' }, label), current === 'auto' && h('sup', { className: 'dsh-bg-badge' }, t('auto.badge')), h('span', { className: `dsh-bg-chevron${open ? ' dsh-bg-chevron-open' : ''}`, 'aria-hidden': true }, h(IconChevronDownOutlineRegular))),
271
- }, state && h(GuardEditor, { mode: state.mode, active: state.active, pending, locked,
265
+ }, state && h(GuardEditor, { mode: state.mode, active: state.active, pending, locked, t,
272
266
  onModeChange: mode => submit('mode', mode),
273
267
  onChange: (row, digit) => submit('mode', stateRef.current.mode.slice(0, row) + digit + stateRef.current.mode.slice(row + 1)),
274
- }), h('span', { className: 'dsh-bg-sr-only', role: 'status' }, pending ? '正在同步权限' : ''), error && h('div', { className: 'dsh-bg-error', role: 'alert' }, error, h('button', { type: 'button', disabled: pending, onClick: read }, '重试')), nativeError && h('div', { className: 'dsh-bg-error', role: 'alert' }, nativeError, h('button', { type: 'button', onClick: readCatalog }, '重试'))), confirmation !== null && h(RiskConfirmation, { open: true, title: t(`${riskPrefix}title`), description: t(`${riskPrefix}description`),
268
+ }), h('span', { className: 'dsh-bg-sr-only', role: 'status' }, pending ? t('syncing') : ''), error && h('div', { className: 'dsh-bg-error', role: 'alert' }, message(error), h('button', { type: 'button', disabled: pending, onClick: read }, t('retry'))), nativeError && h('div', { className: 'dsh-bg-error', role: 'alert' }, message(nativeError), h('button', { type: 'button', onClick: readCatalog }, t('retry')))), confirmation !== null && h(RiskConfirmation, { open: true, title: t(`${riskPrefix}title`), description: t(`${riskPrefix}description`),
275
269
  acknowledgeLabel: t(`${riskPrefix}acknowledge`), cancelLabel: t('confirm.cancel'), closeLabel: t('close'), confirmLabel: t(`${riskPrefix}enable`),
276
270
  acknowledged, disabled: !!locked || picking, onAcknowledgedChange: setAcknowledged, onCancel: closeConfirmation,
277
271
  onConfirm: () => { if (!acknowledged || locked || picking)
@@ -281,27 +275,32 @@ function createPermissionControl(React, primitives) {
281
275
  }
282
276
  // Client-owned Typert contribution: mount the namespace before rendering the seat.
283
277
  // Structural schemas keep this artifact on host modules (no bundled Zod/React).
284
- exports.guardRemoteContribution = {
285
- package: 'dsh-bash-guard',
286
- descriptors: ['get', 'update'].map(method => ({
287
- id: `dsh-bash-guard#bashGuard/${method}`, service: 'bashGuard', namespace: 'bashGuard', method,
288
- invocation: { kind: 'direct' },
289
- parameters: [
290
- { name: 'sessionId', wire: 'sessionId', source: 'json', codec: { mode: 'strict', typeSymbol: 'dsh-bash-guard#SessionId', create: () => ({ parse(value) {
291
- if (typeof value !== 'string' || !value.trim())
292
- throw new Error('A session ID is required');
293
- return value;
294
- } }) } },
295
- ...(method === 'update' ? [{ name: 'request', wire: 'request', source: 'json', codec: { mode: 'strict', typeSymbol: 'dsh-bash-guard#GuardUpdate', create: () => ({ parse(value) {
296
- if (!value || !['activate', 'mode', 'deactivate'].includes(value.action) || !Number.isSafeInteger(value.revision) || value.revision < 0 || (value.mode !== undefined && !/^[0-7]{4}$(?![\s\S])/.test(value.mode)) || (value.action === 'mode' && value.mode === undefined))
297
- throw new Error('Invalid Bash Guard update');
298
- return { action: value.action, revision: value.revision, ...(value.mode === undefined ? {} : { mode: value.mode }) };
299
- } }) } }] : []),
300
- ],
301
- result: { mode: 'strict', typeSymbol: 'dsh-bash-guard#GuardRecord', create: () => ({ parse: value => decodeGuardState({ ok: true, value }) }) },
302
- })),
303
- };
278
+ function createGuardRemoteContribution(t = key => key === 'error.sessionId' || key === 'error.invalidUpdate' ? locales_js_1.en[key] : (0, locales_js_1.defaultT)(key)) {
279
+ return {
280
+ package: 'dsh-bash-guard',
281
+ descriptors: ['get', 'update'].map(method => ({
282
+ id: `dsh-bash-guard#bashGuard/${method}`, service: 'bashGuard', namespace: 'bashGuard', method,
283
+ invocation: { kind: 'direct' },
284
+ parameters: [
285
+ { name: 'sessionId', wire: 'sessionId', source: 'json', codec: { mode: 'strict', typeSymbol: 'dsh-bash-guard#SessionId', create: () => ({ parse(value) {
286
+ if (typeof value !== 'string' || !value.trim())
287
+ throw (0, locales_js_1.localeError)(t, 'error.sessionId');
288
+ return value;
289
+ } }) } },
290
+ ...(method === 'update' ? [{ name: 'request', wire: 'request', source: 'json', codec: { mode: 'strict', typeSymbol: 'dsh-bash-guard#GuardUpdate', create: () => ({ parse(value) {
291
+ if (!value || !['activate', 'mode', 'deactivate'].includes(value.action) || !Number.isSafeInteger(value.revision) || value.revision < 0 || (value.mode !== undefined && !/^[0-7]{4}$(?![\s\S])/.test(value.mode)) || (value.action === 'mode' && value.mode === undefined))
292
+ throw (0, locales_js_1.localeError)(t, 'error.invalidUpdate');
293
+ return { action: value.action, revision: value.revision, ...(value.mode === undefined ? {} : { mode: value.mode }) };
294
+ } }) } }] : []),
295
+ ],
296
+ result: { mode: 'strict', typeSymbol: 'dsh-bash-guard#GuardRecord', create: () => ({ parse: value => decodeGuardState({ ok: true, value }, t) }) },
297
+ })),
298
+ };
299
+ }
300
+ exports.guardRemoteContribution = createGuardRemoteContribution();
304
301
  async function apply(ctx) {
302
+ ctx.effect(() => ctx.locale.register(locales_js_1.BASH_GUARD_NS, { zh: locales_js_1.zh, en: locales_js_1.en }), 'bash-guard: dictionaries');
303
+ const t = ctx.locale.bind(locales_js_1.BASH_GUARD_NS);
305
304
  // Resolve host modules inside apply: the browser loader owns React and styles.
306
305
  const React = require('react');
307
306
  const primitives = require('@deepseek-ai/dsh-client-ui-primitives');
@@ -315,17 +314,17 @@ async function apply(ctx) {
315
314
  $on: (event, listener) => scope.remote.$on(event, listener),
316
315
  };
317
316
  scope.slots.inject('conversation.input.permission', () => scope.slots.register({
318
- name: 'conversation.input.permission', priority: -100, locale: 'permission.access',
319
- inject: sessionId => ({ sessionId, transport: createGuardTransport(remote, sessionId, () => scope.sessions.binding(sessionId)?.session) }),
317
+ name: 'conversation.input.permission', priority: -100, locale: locales_js_1.BASH_GUARD_NS,
318
+ inject: sessionId => ({ sessionId, transport: createGuardTransport(remote, sessionId, () => scope.sessions.binding(sessionId)?.session, t) }),
320
319
  }, Control));
321
320
  };
322
321
  // Leave the host seat intact while the injected guard namespace resolves.
323
322
  // On mount failure, native choices still work through the guard-free adapter.
324
323
  try {
325
- await ctx.remote.$mount(exports.guardRemoteContribution);
324
+ await ctx.remote.$mount(createGuardRemoteContribution(t));
326
325
  }
327
326
  catch (error) {
328
- console.warn('Bash Guard RPC unavailable', error);
327
+ console.warn(t('error.rpcUnavailable'), error);
329
328
  register(ctx, undefined);
330
329
  return;
331
330
  }
@@ -337,12 +336,13 @@ async function apply(ctx) {
337
336
  "use strict";
338
337
  Object.defineProperty(exports, "__esModule", { value: true });
339
338
  exports.createGuardEditor = createGuardEditor;
339
+ const locales_js_1 = require("./locales.js");
340
340
  // Independent permission bits; the host owns React and the check glyph.
341
- const scopes = ['系统', '外部', '网络', '工作区'];
342
- const permissions = [{ label: '读', bit: 4 }, { label: '写', bit: 2 }, { label: '执行', bit: 1 }];
341
+ const scopes = ['system', 'external', 'network', 'workspace'];
342
+ const permissions = [{ key: 'read', bit: 4 }, { key: 'write', bit: 2 }, { key: 'execute', bit: 1 }];
343
343
  function createGuardEditor(React, CheckIcon) {
344
344
  const h = React.createElement;
345
- return function GuardEditor({ mode, active, pending = false, locked = false, error, onChange, onModeChange }) {
345
+ return function GuardEditor({ mode, active, pending = false, locked = false, error, onChange, onModeChange, t = locales_js_1.defaultT }) {
346
346
  if (!active)
347
347
  return null;
348
348
  const disabled = pending || locked;
@@ -355,24 +355,24 @@ function createGuardEditor(React, CheckIcon) {
355
355
  const root = event.currentTarget.closest('[data-guard-editor]');
356
356
  root?.querySelector(`[data-cell="${Math.max(0, Math.min(3, row + delta[0]))}-${Math.max(0, Math.min(2, col + delta[1]))}"]`)?.focus();
357
357
  };
358
- return h('div', { className: 'dsh-bg-editor', 'data-guard-editor': '', 'aria-busy': pending }, h('div', { className: 'dsh-bg-scope dsh-bg-head' }, h('button', {
358
+ return h('div', { className: `dsh-bg-editor${t('scope.workspace') === 'Workspace' ? ' dsh-bg-editor-en' : ''}`, 'data-guard-editor': '', 'aria-busy': pending }, h('div', { className: 'dsh-bg-scope dsh-bg-head' }, h('button', {
359
359
  type: 'button', className: 'dsh-bg-scope-label dsh-bg-all-toggle dsh-bg-scope-toggle',
360
360
  disabled: locked, 'aria-disabled': disabled,
361
- title: mode === '7777' ? '恢复默认权限 0477' : '开启全部 Guard 权限',
361
+ title: t(mode === '7777' ? 'restoreDefaults' : 'enableAll'),
362
362
  onClick: event => { event.stopPropagation(); if (!disabled)
363
- onModeChange(mode === '7777' ? '0477' : '7777'); },
364
- }, mode === '7777' ? '默认' : '全选'), ...permissions.map(p => h('span', { className: 'dsh-bg-column', key: p.bit }, p.label))), ...scopes.map((scope, row) => h('div', { className: 'dsh-bg-scope', key: row, role: 'group', 'aria-label': `${scope}权限` }, h('button', {
363
+ onModeChange(mode === '7777' ? '4667' : '7777'); },
364
+ }, t(mode === '7777' ? 'defaults' : 'selectAll')), ...permissions.map(p => h('span', { className: 'dsh-bg-column', key: p.bit }, t(`bit.${p.key}`)))), ...scopes.map(key => t(`scope.${key}`)).map((scope, row) => h('div', { className: 'dsh-bg-scope', key: row, role: 'group', 'aria-label': t('scope.permissions', { scope }) }, h('button', {
365
365
  type: 'button', className: 'dsh-bg-scope-label dsh-bg-scope-toggle',
366
366
  disabled: locked, 'aria-disabled': disabled,
367
- 'aria-label': `${scope}:${mode[row] === '7' ? '取消全选' : '全选'}`,
368
- title: mode[row] === '7' ? '取消该范围全部权限' : '开启该范围全部权限',
367
+ 'aria-label': t('scope.toggle', { scope, action: t(mode[row] === '7' ? 'clearAll' : 'selectAll') }),
368
+ title: t(mode[row] === '7' ? 'scope.clearAll' : 'scope.enableAll'),
369
369
  onClick: event => { event.stopPropagation(); if (!disabled)
370
370
  onChange(row, mode[row] === '7' ? 0 : 7); },
371
371
  }, scope), ...permissions.map((permission, col) => {
372
372
  const checked = (Number(mode[row]) & permission.bit) !== 0;
373
373
  return h('button', {
374
374
  type: 'button', key: permission.bit, role: 'checkbox', 'aria-checked': checked,
375
- 'aria-label': `${scope} · ${permission.label}权限`, title: `${scope} · ${permission.label}权限:${checked ? '开启' : '关闭'}`,
375
+ 'aria-label': t('bit.label', { scope, permission: t(`bit.${permission.key}`) }), title: t('bit.status', { scope, permission: t(`bit.${permission.key}`), status: t(checked ? 'enabled' : 'disabled') }),
376
376
  'data-cell': `${row}-${col}`, disabled: locked, 'aria-disabled': disabled, className: 'dsh-bg-level',
377
377
  onClick: event => { event.stopPropagation(); if (!disabled)
378
378
  onChange(row, Number(mode[row]) ^ permission.bit); },
@@ -382,5 +382,101 @@ function createGuardEditor(React, CheckIcon) {
382
382
  };
383
383
  }
384
384
 
385
+ },
386
+ "./locales.js": (module,exports,require) => {
387
+ "use strict";
388
+ Object.defineProperty(exports, "__esModule", { value: true });
389
+ exports.en = exports.zh = exports.BASH_GUARD_NS = void 0;
390
+ exports.defaultT = defaultT;
391
+ exports.localeError = localeError;
392
+ // Plugin-owned dictionaries: the host locale service is the only language setting.
393
+ exports.BASH_GUARD_NS = 'bash-guard';
394
+ exports.zh = {
395
+ 'permission': '权限',
396
+ 'mode': '访问模式,当前:{name}',
397
+ 'guard.custom': 'Bash Guard 自定义',
398
+ 'syncing': '正在同步权限',
399
+ 'retry': '重试',
400
+ 'scope.system': '系统', 'scope.external': '外部', 'scope.network': '网络', 'scope.workspace': '工作区',
401
+ 'bit.read': '读', 'bit.write': '写', 'bit.execute': '执行',
402
+ 'scope.permissions': '{scope}权限',
403
+ 'scope.toggle': '{scope}:{action}',
404
+ 'scope.enableAll': '开启该范围全部权限',
405
+ 'scope.clearAll': '取消该范围全部权限',
406
+ 'bit.label': '{scope} · {permission}权限',
407
+ 'bit.status': '{scope} · {permission}权限:{status}',
408
+ 'enabled': '开启', 'disabled': '关闭',
409
+ 'selectAll': '全选', 'clearAll': '取消全选', 'defaults': '默认',
410
+ 'restoreDefaults': '恢复默认权限 4667',
411
+ 'enableAll': '开启全部 Guard 权限',
412
+ 'error.permissionRequest': '权限请求失败',
413
+ 'error.permissionCommand': '宿主未提供此权限命令',
414
+ 'error.unavailable': 'Bash Guard 不可用',
415
+ 'error.invalidState': 'Bash Guard 返回了无效状态',
416
+ 'error.sessionNotReady': '会话尚未就绪,请稍后重试',
417
+ 'error.catalogUnavailable': '权限列表不可用',
418
+ 'error.invalidCatalog': '权限列表无效',
419
+ 'error.sessionId': '必须提供会话 ID',
420
+ 'error.invalidUpdate': '无效的 Bash Guard 更新',
421
+ 'error.rpcUnavailable': 'Bash Guard RPC 不可用',
422
+ 'preset.readOnly': '仅可查看', 'preset.workspaceWrite': '工作区内修改', 'preset.fullAccess': '完全权限',
423
+ 'close': '关闭', 'confirm.cancel': '取消',
424
+ 'confirm.title': '确认启用完全权限?',
425
+ 'confirm.description': '启用完全权限后,智能体将减少确认步骤,并且可以直接执行更多操作,包括敏感操作、文件修改或外部命令。仅建议在你信任当前任务时使用。',
426
+ 'confirm.acknowledge': '我已了解风险,并愿意继续', 'confirm.enable': '启用完全权限',
427
+ 'auto.label': 'Auto review', 'auto.badge': 'EXP',
428
+ 'auto.description': '无沙箱运行;每次原生工具调用和 PTC 内层调用前由同一模型进行实验性审查。',
429
+ 'auto.confirm.title': '确认启用 Auto review(实验)?',
430
+ 'auto.confirm.description': 'Auto review 不使用沙箱。每次原生工具调用和 PTC 内层调用前,都会由与当前 agent 相同的模型进行审查;审查拒绝的调用由你批准或拒绝。此功能仍属实验性,可能误放行或误拒绝,并会消耗额外 token。',
431
+ 'auto.confirm.acknowledge': '我已了解这些风险,并愿意继续', 'auto.confirm.enable': '启用 Auto review',
432
+ };
433
+ exports.en = {
434
+ 'permission': 'Permission',
435
+ 'mode': 'Access mode, current: {name}',
436
+ 'guard.custom': 'Bash Guard Custom',
437
+ 'syncing': 'Syncing permissions',
438
+ 'retry': 'Retry',
439
+ 'scope.system': 'System', 'scope.external': 'External', 'scope.network': 'Network', 'scope.workspace': 'Workspace',
440
+ 'bit.read': 'Read', 'bit.write': 'Write', 'bit.execute': 'Execute',
441
+ 'scope.permissions': '{scope} permissions',
442
+ 'scope.toggle': '{scope}: {action}',
443
+ 'scope.enableAll': 'Enable all permissions in this scope',
444
+ 'scope.clearAll': 'Clear all permissions in this scope',
445
+ 'bit.label': '{scope} · {permission} permission',
446
+ 'bit.status': '{scope} · {permission} permission: {status}',
447
+ 'enabled': 'On', 'disabled': 'Off',
448
+ 'selectAll': 'Select all', 'clearAll': 'Clear all', 'defaults': 'Default',
449
+ 'restoreDefaults': 'Restore default permissions 4667',
450
+ 'enableAll': 'Enable all Guard permissions',
451
+ 'error.permissionRequest': 'Permission request failed',
452
+ 'error.permissionCommand': 'The host does not provide this permission command',
453
+ 'error.unavailable': 'Bash Guard is unavailable',
454
+ 'error.invalidState': 'Bash Guard returned an invalid state',
455
+ 'error.sessionNotReady': 'The session is not ready yet. Please try again later',
456
+ 'error.catalogUnavailable': 'Permission catalog is unavailable',
457
+ 'error.invalidCatalog': 'Invalid permission catalog',
458
+ 'error.sessionId': 'A session ID is required',
459
+ 'error.invalidUpdate': 'Invalid Bash Guard update',
460
+ 'error.rpcUnavailable': 'Bash Guard RPC unavailable',
461
+ 'preset.readOnly': 'Read Only', 'preset.workspaceWrite': 'Workspace Write', 'preset.fullAccess': 'Full access',
462
+ 'close': 'Close', 'confirm.cancel': 'Cancel',
463
+ 'confirm.title': 'Enable Full access?',
464
+ 'confirm.description': 'Full access reduces confirmation steps and lets the agent perform more actions directly, including sensitive operations, file changes, or external commands. Only use it when you trust the current task.',
465
+ 'confirm.acknowledge': 'I understand the risks and want to continue', 'confirm.enable': 'Enable Full access',
466
+ 'auto.label': 'Auto review', 'auto.badge': 'EXP',
467
+ 'auto.description': 'Run without a sandbox after an experimental same-model review of every native tool call and PTC inner call.',
468
+ 'auto.confirm.title': 'Enable Auto review (experimental)?',
469
+ 'auto.confirm.description': 'Auto review runs without a sandbox. Before every native tool call and PTC inner call, the same model as the current agent reviews whether to allow it; you approve or reject each call it denies. This feature is experimental, can falsely allow or deny actions, and uses additional tokens.',
470
+ 'auto.confirm.acknowledge': 'I understand these risks and want to continue', 'auto.confirm.enable': 'Enable Auto review',
471
+ };
472
+ // Keep the historical Chinese defaults for standalone helpers and editor consumers.
473
+ function defaultT(key, values = {}) {
474
+ return (exports.zh[key] ?? key).replace(/\{(\w+)\}/g, (match, name) => values[name] ?? match);
475
+ }
476
+ // Retain the key so an already-visible local error follows reactive slot language changes.
477
+ function localeError(t, key) {
478
+ return Object.assign(new Error(t(key)), { localeKey: key });
479
+ }
480
+
385
481
  }};const cache={};function require(id){if(!factories[id])return hostRequire(id);if(cache[id])return cache[id].exports;const module={exports:{}};cache[id]=module;factories[id](module,module.exports,require);return module.exports;}
386
- const api=require('./client.js');const original=api.apply;api.apply=(ctx)=>{ctx.effect(()=>{const style=document.createElement('style');style.dataset.plugin='dsh-bash-guard';style.textContent="/* Native permission trigger declarations, namespaced; Menu owns all menu chrome. */\n.dsh-bg-trigger { border-radius: var(--dsw-radius-sm); min-width: 0; max-width: 220px; height: 28px; color: var(--dsw-alias-label-secondary); cursor: pointer; background: transparent; border: none; outline: none; align-items: center; gap: 4px; padding: 0 4px 0 8px; font-size: 13px; font-weight: 500; line-height: 20px; display: inline-flex; }\n.dsh-bg-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n.dsh-bg-trigger:focus-visible { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }\n.dsh-bg-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }\n.dsh-bg-trigger-icon { flex: none; display: inline-flex; }\n.dsh-bg-trigger-icon svg { width: 14px; height: 14px; }\n.dsh-bg-trigger-label { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }\n.dsh-bg-option-label { align-items: baseline; gap: 4px; min-width: 0; max-width: 100%; display: inline-flex; }\n.dsh-bg-badge { color: var(--dsw-alias-label-tertiary); letter-spacing: .2px; flex: none; align-self: flex-start; margin-top: -1px; font-size: 8px; font-weight: 600; line-height: 10px; }\n.dsh-bg-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform .12s; display: inline-flex; }\n.dsh-bg-chevron-open { transform: rotate(180deg); }\n@container (width <= 460px) { .dsh-bg-trigger:has(.dsh-bg-trigger-icon) .dsh-bg-trigger-label { display: none; } }\n.dsh-bg-editor { padding: 0 8px 4px 32px; color: var(--dsw-alias-label-primary); }\n.dsh-bg-scope { display: grid; grid-template-columns: 48px repeat(3, 32px); align-items: center; gap: 8px; min-height: 32px; }\n.dsh-bg-head { min-height: 26px; }\n.dsh-bg-column { text-align: center; font-size: 12px; color: var(--dsw-alias-label-secondary); }\n.dsh-bg-level svg { width: 16px; height: 16px; }\n.dsh-bg-scope-label { width: 42px; flex: 0 0 42px; color: var(--dsw-alias-label-secondary); font-size: 12px; }\n.dsh-bg-scope-toggle { appearance: none; border: 0; background: transparent; border-radius: var(--dsw-radius-sm); box-sizing: border-box; width: max-content; max-width: none; justify-self: start; height: 24px; margin-left: -6px; padding: 0 6px; text-align: left; white-space: nowrap; font-family: inherit; cursor: pointer; }\n.dsh-bg-scope-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n.dsh-bg-level { appearance: none; border: 1px solid var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); border-radius: var(--dsw-radius-sm); width: 32px; height: 24px; padding: 0; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }\n.dsh-bg-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n.dsh-bg-level:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n.dsh-bg-level[aria-checked=\"true\"] { background: var(--dsw-alias-interactive-bg-hover-solid); color: var(--dsw-alias-label-primary); }\n.dsh-bg-editor button:focus-visible, .dsh-bg-error button:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-label-secondary)); outline-offset: 1px; }\n.dsh-bg-editor button:disabled { cursor: default; color: var(--dsw-alias-label-tertiary); }\n.dsh-bg-error, .dsh-bg-status { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; padding: 6px 8px; overflow-wrap: anywhere; max-width: 300px; }\n.dsh-bg-error button { margin-left: 8px; padding: 2px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: var(--dsw-radius-sm); background: transparent; color: inherit; font: inherit; cursor: pointer; }\n.dsh-bg-mode { font: 12px var(--ds-font-family-code, monospace); color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }\n@media (max-width: 360px) { .dsh-bg-editor { padding-left: 24px; } .dsh-bg-level { padding-inline: 4px; } }\n@media (prefers-reduced-motion: reduce) { .dsh-bg-chevron { transition: none; } }\n";document.head.append(style);return ()=>style.remove()});return original(ctx)};return api;}});
482
+ const api=require('./client.js');const original=api.apply;api.apply=(ctx)=>{ctx.effect(()=>{const style=document.createElement('style');style.dataset.plugin='dsh-bash-guard';style.textContent="/* Native permission trigger declarations, namespaced; Menu owns all menu chrome. */\n.dsh-bg-trigger { border-radius: var(--dsw-radius-sm); min-width: 0; max-width: 220px; height: 28px; color: var(--dsw-alias-label-secondary); cursor: pointer; background: transparent; border: none; outline: none; align-items: center; gap: 4px; padding: 0 4px 0 8px; font-size: 13px; font-weight: 500; line-height: 20px; display: inline-flex; }\n.dsh-bg-trigger:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n.dsh-bg-trigger:focus-visible { box-shadow: 0 0 0 2px var(--dsw-focus-ring-color, var(--dsw-alias-state-business-primary)); }\n.dsh-bg-trigger:disabled { color: var(--dsw-alias-label-dimmed); cursor: default; }\n.dsh-bg-trigger-icon { flex: none; display: inline-flex; }\n.dsh-bg-trigger-icon svg { width: 14px; height: 14px; }\n.dsh-bg-guard-icon { position: relative; display: inline-flex; width: 16px; height: 16px; flex: none; }\n.dsh-bg-guard-icon > svg { width: 100%; height: 100%; }\n.dsh-bg-guard-marks { position: absolute; inset: 0; pointer-events: none; }\n.dsh-bg-trigger-icon .dsh-bg-guard-icon { width: 14px; height: 14px; }\n.dsh-bg-trigger-label { text-overflow: ellipsis; white-space: nowrap; min-width: 0; overflow: hidden; }\n.dsh-bg-option-label { align-items: baseline; gap: 4px; min-width: 0; max-width: 100%; display: inline-flex; }\n.dsh-bg-badge { color: var(--dsw-alias-label-tertiary); letter-spacing: .2px; flex: none; align-self: flex-start; margin-top: -1px; font-size: 8px; font-weight: 600; line-height: 10px; }\n.dsh-bg-chevron { color: var(--dsw-alias-label-caption); flex: none; transition: transform .12s; display: inline-flex; }\n.dsh-bg-chevron-open { transform: rotate(180deg); }\n@container (width <= 460px) { .dsh-bg-trigger:has(.dsh-bg-trigger-icon) .dsh-bg-trigger-label { display: none; } }\n.dsh-bg-editor { padding: 0 8px 4px 32px; color: var(--dsw-alias-label-primary); }\n.dsh-bg-scope { display: grid; grid-template-columns: 48px repeat(3, 32px); align-items: center; gap: 8px; min-height: 32px; }\n.dsh-bg-head { min-height: 26px; }\n.dsh-bg-editor-en .dsh-bg-scope { grid-template-columns: 72px repeat(3, 44px); }\n.dsh-bg-editor-en .dsh-bg-level { justify-self: center; }\n.dsh-bg-column { text-align: center; font-size: 12px; color: var(--dsw-alias-label-secondary); }\n.dsh-bg-level svg { width: 16px; height: 16px; }\n.dsh-bg-scope-label { width: 42px; flex: 0 0 42px; color: var(--dsw-alias-label-secondary); font-size: 12px; }\n.dsh-bg-scope-toggle { appearance: none; border: 0; background: transparent; border-radius: var(--dsw-radius-sm); box-sizing: border-box; width: max-content; max-width: none; justify-self: start; height: 24px; margin-left: -6px; padding: 0 6px; text-align: left; white-space: nowrap; font-family: inherit; cursor: pointer; }\n.dsh-bg-scope-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n.dsh-bg-level { appearance: none; border: 1px solid var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); border-radius: var(--dsw-radius-sm); width: 32px; height: 24px; padding: 0; display: inline-flex; align-items: center; justify-content: center; cursor: pointer; }\n.dsh-bg-sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }\n.dsh-bg-level:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n.dsh-bg-level[aria-checked=\"true\"] { background: var(--dsw-alias-interactive-bg-hover-solid); color: var(--dsw-alias-label-primary); }\n.dsh-bg-editor button:focus-visible, .dsh-bg-error button:focus-visible { outline: 2px solid var(--dsw-focus-ring-color, var(--dsw-alias-label-secondary)); outline-offset: 1px; }\n.dsh-bg-editor button:disabled { cursor: default; color: var(--dsw-alias-label-tertiary); }\n.dsh-bg-error, .dsh-bg-status { color: var(--dsw-alias-label-secondary); font-size: 12px; line-height: 18px; padding: 6px 8px; overflow-wrap: anywhere; max-width: 300px; }\n.dsh-bg-error button { margin-left: 8px; padding: 2px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: var(--dsw-radius-sm); background: transparent; color: inherit; font: inherit; cursor: pointer; }\n.dsh-bg-mode { font: 12px var(--ds-font-family-code, monospace); color: var(--dsw-alias-label-secondary); font-variant-numeric: tabular-nums; }\n@media (max-width: 360px) { .dsh-bg-editor { padding-left: 24px; } .dsh-bg-level { padding-inline: 4px; } }\n@media (prefers-reduced-motion: reduce) { .dsh-bg-chevron { transition: none; } }\n";document.head.append(style);return ()=>style.remove()});return original(ctx)};return api;}});
package/cordis.patch.yml CHANGED
@@ -3,4 +3,4 @@
3
3
  - id: bash-guard
4
4
  name: dsh-bash-guard
5
5
  config:
6
- mode: '0467'
6
+ mode: '4667'
package/lib/index.js CHANGED
@@ -48,7 +48,7 @@ export class BashGuardService extends TypertRemoteService {
48
48
  update(sessionId, request) { return this.mutate(sessionId, request); }
49
49
  }
50
50
  export async function apply(ctx, config = {}) {
51
- const fallback = config.mode ?? '0467';
51
+ const fallback = config.mode ?? '4667';
52
52
  if (!valid(fallback))
53
53
  throw new Error('bash-guard: expected four octal digits');
54
54
  const domain = await ctx.storageDomain.open({ name: 'bash_guard', version: 1, layout: 'per-record', tables: { sessions: { valueSchema: recordSchema } } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-bash-guard",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "license": "MIT",
5
5
  "author": "lloydzhou (https://github.com/lloydzhou)",
6
6
  "homepage": "https://github.com/lloydzhou/dsh-bash-guard#readme",