dsh-bash-terminal-ts 0.2.5
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/LICENSE +21 -0
- package/README.en.md +195 -0
- package/README.ja.md +194 -0
- package/README.ko.md +192 -0
- package/README.md +192 -0
- package/cordis.patch.yml +5 -0
- package/dist/client.core.js +132 -0
- package/dist/client.js +141 -0
- package/dsh.plugin.json +22 -0
- package/lib/dsh-types.d.ts +260 -0
- package/lib/dsh-types.js +9 -0
- package/lib/dsh.d.ts +33 -0
- package/lib/dsh.js +29 -0
- package/lib/index.d.ts +201 -0
- package/lib/index.js +759 -0
- package/lib/terminal.d.ts +87 -0
- package/lib/terminal.js +273 -0
- package/package.json +122 -0
- package/scripts/build-client.mjs +46 -0
- package/src/client.tsx +161 -0
- package/src/dsh-types.ts +313 -0
- package/src/dsh.ts +68 -0
- package/src/index.ts +952 -0
- package/src/terminal.ts +368 -0
- package/tsconfig.client.json +17 -0
- package/tsconfig.json +23 -0
- package/tsconfig.test.json +11 -0
package/README.md
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# dsh-bash-terminal-ts
|
|
2
|
+
|
|
3
|
+
[](https://github.com/drscrewdriver/dsh-bash-terminal-ts/actions/workflows/test.yml)
|
|
4
|
+
|
|
5
|
+
[English](README.en.md) | [日本語](README.ja.md) | [한국어](README.ko.md) | **中文**
|
|
6
|
+
|
|
7
|
+
DSH(DeepSeek Harness)插件:一个 `shell` 工具,在 Windows 上统一执行 **PowerShell / Git Bash / MSYS2 / WSL** 四种终端命令。
|
|
8
|
+
|
|
9
|
+
终端由**你在 Web UI 里选**,模型不能改。选一次,之后所有命令都按你选的终端跑。
|
|
10
|
+
|
|
11
|
+
## 为什么用它
|
|
12
|
+
|
|
13
|
+
| 卖点 | 一句话 |
|
|
14
|
+
|------|--------|
|
|
15
|
+
| **MSYS2 真的能用** | 不是"加了个下拉选项",而是把 `bash.exe` 解析、登录 shell、`MSYSTEM` 环境三件事都做对了 —— 选 MSYS2 就能直接 `gcc`、`make`(见下方「MSYS2 支持」) |
|
|
16
|
+
| **TypeScript 源码** | `strict` + `noUncheckedIndexedAccess`;纯函数负责 argv/env 构造,可单测 |
|
|
17
|
+
| **以 DSH 0.1.2 为主版** | `engines.dsh: >=0.1.2-rc.1 <0.2.0-0`,随 0.1.2 的 `ctx.subprocess` / `ctx.sandbox` / PTY 接缝构建 |
|
|
18
|
+
| **四种终端一个工具** | 同一套 `shell` 工具覆盖 PowerShell / Git Bash / MSYS2 / WSL,模型不用学四套参数 |
|
|
19
|
+
| **沙箱对齐官方** | 走官方 `ctx.sandboxPolicy` + `ctx.sandbox`,fail-closed,拒绝时给出同轮升级提示 |
|
|
20
|
+
| **交互式终端** | 另有真 PTY 会话工具:`open / send / read / signal / close`,可 Ctrl+C,跨轮保持状态 |
|
|
21
|
+
|
|
22
|
+
## 支持的后端
|
|
23
|
+
|
|
24
|
+
| 后端 | 实际执行 | 语法 / 路径 | 环境变量 |
|
|
25
|
+
|------|----------|-------------|----------|
|
|
26
|
+
| `powershell`(默认) | `pwsh -NoLogo -NoProfile -NonInteractive -Command <cmd>` | PowerShell;`C:\...` | `$env:NAME` |
|
|
27
|
+
| `gitbash` | Git for Windows `bash -lc <cmd>` | POSIX;`/d/WorkSpace`;PATH 含 `/usr/bin`、`/mingw64/bin` | `$NAME` |
|
|
28
|
+
| `msys2` | `C:\msys64\usr\bin\bash.exe -lc <cmd>`(登录 shell;`MSYSTEM=MINGW64`) | POSIX;自带完整 GCC / mingw64 工具链 | `$NAME` |
|
|
29
|
+
| `wsl` | `wsl [-d <distro>] -e bash -lc <cmd>` | Linux;`/mnt/d/...` | `$NAME`(经 WSLENV) |
|
|
30
|
+
|
|
31
|
+
每次调用都启动全新 shell:**不保留状态**(cwd / 变量 / 别名)—— 请传 `workdir` 而不是用 `cd`。需要跨轮保持状态时用交互式终端工具。
|
|
32
|
+
|
|
33
|
+
## MSYS2 支持
|
|
34
|
+
|
|
35
|
+
MSYS2 看着只是"再加一个后端",实际有三个坑,插件逐个处理了:
|
|
36
|
+
|
|
37
|
+
**1. 不能启动 `msys2.exe`。**
|
|
38
|
+
`C:\msys64\msys2.exe` 是分配控制台窗口的 Cygwin 启动器。本插件用管道 stdio spawn(这是 DSH 的标准方式),此时它会 **exit 0 返回零字节输出** —— 命令静默失败,看起来"成功"了但什么都没做。所以候选顺序是:`usr\bin\bash.exe` → `bin\bash.exe` → `msys2.exe` 兜底,**可用的 `bash.exe` 永远优先**。
|
|
39
|
+
|
|
40
|
+
**2. `-lc` 不能省。**
|
|
41
|
+
只有登录 shell 会读 `/etc/profile`,而只有 `/etc/profile` 会把 `/usr/bin` 与 `/mingw64/bin` 加进 PATH。用裸 `-c` 的话 `tr`、`sed`、`gcc` 全是 `command not found`。
|
|
42
|
+
|
|
43
|
+
**3. 要注入 `MSYSTEM=MINGW64`。**
|
|
44
|
+
否则 `/etc/profile` 按默认 MSYS 环境初始化,`/mingw64/bin` 里的 gcc、make 不可用。插件经 `buildEnv` 注入(**你显式设置的值优先**),并且 `shell` 工具与交互式终端走的是同一个 `buildEnv` —— 不会出现"工具能跑、终端不能跑"的偏差。
|
|
45
|
+
|
|
46
|
+
实测(真 PTY):prompt 从 `MSYS` 变成 `MINGW64`,`command -v gcc` → `/mingw64/bin/gcc`。
|
|
47
|
+
|
|
48
|
+
这三条都有回归测试守着:`test/unit.ts` 断言 `bash.exe` 排在 `msys2.exe` 之前;`test/apply.ts` 断言 PTY 环境含 `MSYSTEM=MINGW64`,且不会泄漏到 gitbash。
|
|
49
|
+
|
|
50
|
+
## 设计要点
|
|
51
|
+
|
|
52
|
+
- **终端由用户决定,AI 无法更改**:Web UI 设置页(设置 → 通用)出现"默认终端"下拉(PowerShell / Git Bash / MSYS2 / WSL);`shell` 工具永远只使用该设置,不暴露终端参数给模型。设置通过 DSH settings 系统持久化(settings.yaml)。
|
|
53
|
+
- **不占用 `ctx.shell` 能力接缝**:DSH 自带的沙箱化 `pwsh` 工具保持原样可用;本插件的 `shell` 工具是**额外的**多终端入口。
|
|
54
|
+
- 通过共享的 `ctx.subprocess` seam 派生进程:进程树终止(Windows `taskkill /T`)、SIGTERM→grace→SIGKILL、输出 spill 文件,与官方 `dsh-tool-bash` / `dsh-tool-pwsh` 行为一致。
|
|
55
|
+
- 后台任务注册进通用 `jobs` registry,支持 `run_in_background` / `job_output` / `job_kill`。
|
|
56
|
+
- 工具参数 `shell` 是枚举(UI 自动渲染为下拉),模型每次调用自行选择终端。
|
|
57
|
+
- 四种后端在前端下拉里的 `<option>`、以及两种语言包里的 `shell.<id>` 文案,都有 drift 守卫测试 —— 加后端忘了改文案会直接测试失败。
|
|
58
|
+
|
|
59
|
+
## 安装
|
|
60
|
+
|
|
61
|
+
### 标准安装(npm)
|
|
62
|
+
|
|
63
|
+
```powershell
|
|
64
|
+
# 1. 安装插件包
|
|
65
|
+
npm install -g dsh-bash-terminal-ts
|
|
66
|
+
dsh plugin --profile web add dsh-bash-terminal-ts
|
|
67
|
+
|
|
68
|
+
# 2. patch DSH 设置白名单(DSH 限制,见下方说明;install.ps1 可单独执行此步)
|
|
69
|
+
powershell -ExecutionPolicy Bypass -File install.ps1 install
|
|
70
|
+
|
|
71
|
+
# 3. 重启 dsh web
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 本地开发安装(junction 直连,改源码即时生效)
|
|
75
|
+
|
|
76
|
+
```powershell
|
|
77
|
+
# 1. 链接插件包到 profile 的 node_modules(junction,改源码即时生效)
|
|
78
|
+
$profile = "$env:USERPROFILE\.dsh\profiles\web"
|
|
79
|
+
New-Item -ItemType Junction -Path "$profile\node_modules\dsh-bash-terminal-ts" -Target "D:\WorkSpace\projects\dsh-bash-terminal-ts" | Out-Null
|
|
80
|
+
|
|
81
|
+
# 2. 让插件能解析 @deepseek-ai/* 依赖(junction 到 profile 的依赖树)
|
|
82
|
+
New-Item -ItemType Junction -Path "D:\WorkSpace\projects\dsh-bash-terminal-ts\node_modules\@deepseek-ai" -Target "$profile\..\node_modules\@deepseek-ai" | Out-Null
|
|
83
|
+
|
|
84
|
+
# 3. 在 cordis.patch.yml 追加挂载行(见下方 patch 片段)
|
|
85
|
+
# 4. (仅修改前端源码后)重新打包 client bundle:
|
|
86
|
+
# cd D:\WorkSpace\projects\dsh-bash-terminal-ts && node scripts/build-client.mjs
|
|
87
|
+
# 5. 让设置 UI 接受本插件的设置写入(DSH 限制,见下方说明)
|
|
88
|
+
# 6. 重启 dsh web
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> **DSH 设置 UI 白名单限制**:DSH 的 api-gateway(dsh-host-apiproxy)对
|
|
92
|
+
> Web 设置客户端暴露的 settings namespace 有**硬编码白名单**(第三方插件
|
|
93
|
+
> 的设置默认会被 `settings-not-exposed` 拒绝,UI 里改了不生效)。
|
|
94
|
+
> install.ps1 会自动 patch 该白名单(加入 `bash-terminal`,先备份原文件)。
|
|
95
|
+
> **升级 DSH 后需重新运行 install.ps1** 恢复 patch。卸载时 install.ps1 会还原。
|
|
96
|
+
|
|
97
|
+
`cordis.patch.yml` 追加:
|
|
98
|
+
|
|
99
|
+
```yaml
|
|
100
|
+
- insert:
|
|
101
|
+
- id: tool-bash-terminal
|
|
102
|
+
name: 'dsh-bash-terminal-ts'
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
验证组合树(无需重启):
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
node "$env:APPDATA\nvm\v24.16.0\node_modules\@deepseek-ai\dsh\lib\bin.js" --profile web --dump-config | Select-String dsh-bash-terminal-ts
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 使用
|
|
112
|
+
|
|
113
|
+
**用户在 Web UI 设置默认终端**:打开设置(齿轮)→ 通用 →「默认终端」下拉,选择 PowerShell / Git Bash / MSYS2 / WSL 之一。改动即时生效并持久化。
|
|
114
|
+
|
|
115
|
+
模型看到 `shell` 工具后,执行命令时自动使用你选择的终端(工具不暴露终端参数,模型无法更改你的选择):
|
|
116
|
+
|
|
117
|
+
- 默认终端 = Git Bash 时:`shell(command: "git status")` 走 Git Bash
|
|
118
|
+
- 默认终端 = MSYS2 时:`shell(command: "gcc --version")` 走 MSYS2(登录 shell,PATH 含 `/usr/bin` 与 `/mingw64/bin`,自带完整 GCC / mingw64 工具链)
|
|
119
|
+
- 默认终端 = WSL 时:`shell(command: "ls -la /mnt/d/WorkSpace")` 走 WSL;传 `distro: "Ubuntu"` 可指定发行版
|
|
120
|
+
- 默认终端 = PowerShell 时:`shell(command: "Get-Process node")` 走 PowerShell
|
|
121
|
+
|
|
122
|
+
## 配置
|
|
123
|
+
|
|
124
|
+
**Web UI 设置**(推荐):设置 → 通用 →「默认终端」。
|
|
125
|
+
|
|
126
|
+
插件 row 的 `config`(覆盖默认,作为设置的 composition 基准):
|
|
127
|
+
|
|
128
|
+
| 键 | 默认 | 说明 |
|
|
129
|
+
|----|------|------|
|
|
130
|
+
| `defaultShell` | `powershell` | 设置未覆盖时的后端 |
|
|
131
|
+
| `timeoutMs` | 120000 | 默认超时 |
|
|
132
|
+
| `maxTimeoutMs` | 600000 | 调用方 timeoutMs 上限 |
|
|
133
|
+
| `pwshPath` | 自动探测 | 固定 pwsh.exe 路径 |
|
|
134
|
+
| `gitBashPath` | 自动探测 | 固定 git bash.exe 路径 |
|
|
135
|
+
| `msys2Path` | 自动探测 | 固定 MSYS2 入口路径(需指向 `bash.exe`,不要指向 `msys2.exe`;见「MSYS2 支持」) |
|
|
136
|
+
| `wslPath` | 自动探测 | 固定 wsl.exe 路径 |
|
|
137
|
+
|
|
138
|
+
## 卸载
|
|
139
|
+
|
|
140
|
+
```powershell
|
|
141
|
+
Remove-Item "$env:USERPROFILE\.dsh\profiles\web\node_modules\dsh-bash-terminal-ts" -Force
|
|
142
|
+
# 并从 cordis.patch.yml 删掉 insert 块,重启 dsh web
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## 沙箱(官方机制对接)
|
|
146
|
+
|
|
147
|
+
`shell` 工具走 DSH 官方沙箱接缝(`ctx.sandboxPolicy` + `ctx.sandbox`):
|
|
148
|
+
|
|
149
|
+
- 每次调用解析当前沙箱策略;`danger-full-access` 会话直接执行(不包装)。
|
|
150
|
+
- PowerShell / Git Bash / MSYS2 后端经 `ctx.sandbox.confine` 包装 argv —— 与官方 executor 相同的 **fail-closed** 语义:请求受限模式但无可用后端时抛 `SandboxUnavailableError`,拒绝裸跑。
|
|
151
|
+
- WSL 后端不包装:WSL 独立 Linux 虚拟机本身就是隔离(结果报告 `enforcement: wsl-isolation`)。
|
|
152
|
+
- 受限模式下被沙箱拒绝时,结果携带官方标记 `[sandbox: file access denied under <mode> mode]` 与同轮升级提示;模型可凭 `sandbox_permissions` + `justification` 发起一次升级(经 `ctx.approval` 用户审批),与官方 bash/pwsh 工具完全一致。
|
|
153
|
+
- 注意:DSH 的 Windows ACL 沙箱 launcher(`node-addon-landlock-run-win32-x64`)当前尚未在 npm 发布,本机沙箱后端暂不可用;架构已就绪,DSH 发布后自动生效。
|
|
154
|
+
|
|
155
|
+
## ⚠️ 安全说明
|
|
156
|
+
|
|
157
|
+
`shell` 工具的命令**在 DSH 沙箱之外**运行,与 dsh 进程同权限(等同完整访问的命令执行),
|
|
158
|
+
不享受 `pwsh` 工具的 ConstrainedLanguage 限制。DSH 的文件操作工具(read/write/edit)仍受文件沙箱约束。
|
|
159
|
+
仅在你信任的会话中使用;需要受沙箱保护的 PowerShell 时请继续使用官方 `pwsh` 工具。
|
|
160
|
+
|
|
161
|
+
## 已知限制
|
|
162
|
+
|
|
163
|
+
- 本插件仅在 `win32` 平台注册工具。
|
|
164
|
+
- WSL 后台进程在超时/中断后可能在发行版内短暂残留(WSL 实例在最后一个进程退出后自动关闭)。
|
|
165
|
+
- Git Bash 与 MSYS2 都是 msys2 环境,与 WSL 的 Linux 行为存在差异(路径映射、包可用性)。
|
|
166
|
+
- 若 `C:\msys64` 装在非默认位置且不在 PATH 上,需显式配置 `msys2Path`。
|
|
167
|
+
|
|
168
|
+
## 测试
|
|
169
|
+
|
|
170
|
+
```powershell
|
|
171
|
+
git clone https://github.com/drscrewdriver/dsh-bash-terminal-ts.git
|
|
172
|
+
cd dsh-bash-terminal-ts
|
|
173
|
+
npm install # 安装依赖(含 typescript)
|
|
174
|
+
npm run build # tsc 编译 src/*.ts → lib/*.js;client.tsx → dist/client.js;test/*.ts → test-dist/
|
|
175
|
+
npm test # node test-dist/unit.js → apply.js → client.js
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
CI 在 `windows-latest` 上跑同一套(`.github/workflows/test.yml`)。
|
|
179
|
+
|
|
180
|
+
## 技术实现
|
|
181
|
+
|
|
182
|
+
源码为 TypeScript(`strict` + `noUncheckedIndexedAccess`),编译产物 `lib/`、`dist/` 随仓库提交,DSH 直接按 `lib/index.js` 加载,**无需安装即可使用**。
|
|
183
|
+
|
|
184
|
+
require 侧依赖(`@deepseek-ai/*` 等 13 个包)全部声明为 `peerDependencies` + `peerDependenciesMeta.optional`,避免与宿主自带的副本重复安装。
|
|
185
|
+
|
|
186
|
+
## 致谢
|
|
187
|
+
|
|
188
|
+
本项目基于 [MAXeaglet/dsh-bash-terminal](https://github.com/MAXeaglet/dsh-bash-terminal) 演进 —— 原始的 `shell` 工具、PowerShell / Git Bash / WSL 三后端架构与沙箱接缝对接均来自原作者。本版在此基础上加入 MSYS2 后端、TypeScript 重写与 DSH 0.1.2 适配。
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT
|
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// src/client.tsx
|
|
20
|
+
var client_exports = {};
|
|
21
|
+
__export(client_exports, {
|
|
22
|
+
apply: () => apply,
|
|
23
|
+
inject: () => inject
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(client_exports);
|
|
26
|
+
var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
27
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
28
|
+
var SETTINGS_NS = "settings.bash-terminal";
|
|
29
|
+
var SETTINGS_NAMESPACE = "bash-terminal";
|
|
30
|
+
var zh = {
|
|
31
|
+
"shell.title": "\u9ED8\u8BA4\u7EC8\u7AEF",
|
|
32
|
+
"shell.description": "shell \u5DE5\u5177\u6267\u884C\u547D\u4EE4\u65F6\u4F7F\u7528\u7684\u7EC8\u7AEF\uFF08\u7531\u4F60\u51B3\u5B9A\uFF0CAI \u65E0\u6CD5\u66F4\u6539\uFF09",
|
|
33
|
+
"shell.powershell": "PowerShell",
|
|
34
|
+
"shell.gitbash": "Git Bash",
|
|
35
|
+
"shell.msys2": "MSYS2",
|
|
36
|
+
"shell.wsl": "WSL"
|
|
37
|
+
};
|
|
38
|
+
var en = {
|
|
39
|
+
"shell.title": "Default terminal",
|
|
40
|
+
"shell.description": "Terminal used by the shell tool (you control this; the AI cannot change it)",
|
|
41
|
+
"shell.powershell": "PowerShell",
|
|
42
|
+
"shell.gitbash": "Git Bash",
|
|
43
|
+
"shell.msys2": "MSYS2",
|
|
44
|
+
"shell.wsl": "WSL"
|
|
45
|
+
};
|
|
46
|
+
var inject = ["slots", "locale", "settingsScope"];
|
|
47
|
+
function ShellPreferenceRow({ t, useStore, setShell }) {
|
|
48
|
+
const shell = useStore((s) => s.shell);
|
|
49
|
+
const writable = useStore((s) => s.writable);
|
|
50
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
51
|
+
"div",
|
|
52
|
+
{
|
|
53
|
+
style: {
|
|
54
|
+
display: "flex",
|
|
55
|
+
alignItems: "center",
|
|
56
|
+
justifyContent: "space-between",
|
|
57
|
+
gap: 16,
|
|
58
|
+
padding: "12px 0"
|
|
59
|
+
},
|
|
60
|
+
children: [
|
|
61
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { minWidth: 0 }, children: [
|
|
62
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 14, fontWeight: 500, lineHeight: "22px", color: "var(--dsw-alias-label-primary, inherit)" }, children: t("shell.title") }),
|
|
63
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 12, lineHeight: "18px", opacity: 0.65 }, children: t("shell.description") })
|
|
64
|
+
] }),
|
|
65
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
66
|
+
"select",
|
|
67
|
+
{
|
|
68
|
+
value: shell,
|
|
69
|
+
disabled: !writable,
|
|
70
|
+
onChange: (e) => setShell(e.target.value),
|
|
71
|
+
style: {
|
|
72
|
+
fontSize: 14,
|
|
73
|
+
padding: "6px 10px",
|
|
74
|
+
borderRadius: 8,
|
|
75
|
+
border: "1px solid var(--dsw-alias-line-strong, #ccc)",
|
|
76
|
+
background: "var(--dsw-alias-bg-layer-2, #fff)",
|
|
77
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
78
|
+
outline: "none",
|
|
79
|
+
cursor: writable ? "pointer" : "not-allowed",
|
|
80
|
+
maxWidth: 180
|
|
81
|
+
},
|
|
82
|
+
children: [
|
|
83
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "powershell", children: t("shell.powershell") }),
|
|
84
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "gitbash", children: t("shell.gitbash") }),
|
|
85
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "msys2", children: t("shell.msys2") }),
|
|
86
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "wsl", children: t("shell.wsl") })
|
|
87
|
+
]
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
function apply(ctx) {
|
|
95
|
+
ctx.effect(() => ctx.locale.register(SETTINGS_NS, { zh, en }), "bash-terminal: settings dictionaries");
|
|
96
|
+
const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });
|
|
97
|
+
const store = (0, import_dsh_client_store.defineStore)({
|
|
98
|
+
init: () => ({ shell: "powershell", revision: -1, writable: false }),
|
|
99
|
+
actions: {
|
|
100
|
+
sync: (d, shell, revision, writable) => {
|
|
101
|
+
if (revision !== void 0 && revision <= d.revision) return;
|
|
102
|
+
if (shell !== void 0) d.shell = shell;
|
|
103
|
+
if (revision !== void 0) d.revision = revision;
|
|
104
|
+
if (writable !== void 0) d.writable = writable;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
let bound;
|
|
109
|
+
const push = (snap) => {
|
|
110
|
+
bound?.sync(snap.value?.defaultShell, snap.revision, snap.writable);
|
|
111
|
+
};
|
|
112
|
+
ctx.slots.inject(
|
|
113
|
+
"settings.general.item",
|
|
114
|
+
() => ctx.slots.register(
|
|
115
|
+
{
|
|
116
|
+
name: "settings.general.item",
|
|
117
|
+
id: "bash-terminal-shell",
|
|
118
|
+
order: 20,
|
|
119
|
+
store,
|
|
120
|
+
locale: SETTINGS_NS,
|
|
121
|
+
inject: (actions) => {
|
|
122
|
+
bound = actions;
|
|
123
|
+
push(scope.getSnapshot());
|
|
124
|
+
return { setShell: (value) => void scope.set("defaultShell", value) };
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
ShellPreferenceRow
|
|
128
|
+
),
|
|
129
|
+
"bash-terminal: settings row"
|
|
130
|
+
);
|
|
131
|
+
ctx.effect(() => scope.subscribe(() => push(scope.getSnapshot())), "bash-terminal: settings watch");
|
|
132
|
+
}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-bash-terminal-ts",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
var __defProp = Object.defineProperty;
|
|
7
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
8
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
23
|
+
|
|
24
|
+
// src/client.tsx
|
|
25
|
+
var client_exports = {};
|
|
26
|
+
__export(client_exports, {
|
|
27
|
+
apply: () => apply,
|
|
28
|
+
inject: () => inject
|
|
29
|
+
});
|
|
30
|
+
module.exports = __toCommonJS(client_exports);
|
|
31
|
+
var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
32
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
33
|
+
var SETTINGS_NS = "settings.bash-terminal";
|
|
34
|
+
var SETTINGS_NAMESPACE = "bash-terminal";
|
|
35
|
+
var zh = {
|
|
36
|
+
"shell.title": "\u9ED8\u8BA4\u7EC8\u7AEF",
|
|
37
|
+
"shell.description": "shell \u5DE5\u5177\u6267\u884C\u547D\u4EE4\u65F6\u4F7F\u7528\u7684\u7EC8\u7AEF\uFF08\u7531\u4F60\u51B3\u5B9A\uFF0CAI \u65E0\u6CD5\u66F4\u6539\uFF09",
|
|
38
|
+
"shell.powershell": "PowerShell",
|
|
39
|
+
"shell.gitbash": "Git Bash",
|
|
40
|
+
"shell.msys2": "MSYS2",
|
|
41
|
+
"shell.wsl": "WSL"
|
|
42
|
+
};
|
|
43
|
+
var en = {
|
|
44
|
+
"shell.title": "Default terminal",
|
|
45
|
+
"shell.description": "Terminal used by the shell tool (you control this; the AI cannot change it)",
|
|
46
|
+
"shell.powershell": "PowerShell",
|
|
47
|
+
"shell.gitbash": "Git Bash",
|
|
48
|
+
"shell.msys2": "MSYS2",
|
|
49
|
+
"shell.wsl": "WSL"
|
|
50
|
+
};
|
|
51
|
+
var inject = ["slots", "locale", "settingsScope"];
|
|
52
|
+
function ShellPreferenceRow({ t, useStore, setShell }) {
|
|
53
|
+
const shell = useStore((s) => s.shell);
|
|
54
|
+
const writable = useStore((s) => s.writable);
|
|
55
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
56
|
+
"div",
|
|
57
|
+
{
|
|
58
|
+
style: {
|
|
59
|
+
display: "flex",
|
|
60
|
+
alignItems: "center",
|
|
61
|
+
justifyContent: "space-between",
|
|
62
|
+
gap: 16,
|
|
63
|
+
padding: "12px 0"
|
|
64
|
+
},
|
|
65
|
+
children: [
|
|
66
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { minWidth: 0 }, children: [
|
|
67
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 14, fontWeight: 500, lineHeight: "22px", color: "var(--dsw-alias-label-primary, inherit)" }, children: t("shell.title") }),
|
|
68
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 12, lineHeight: "18px", opacity: 0.65 }, children: t("shell.description") })
|
|
69
|
+
] }),
|
|
70
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
71
|
+
"select",
|
|
72
|
+
{
|
|
73
|
+
value: shell,
|
|
74
|
+
disabled: !writable,
|
|
75
|
+
onChange: (e) => setShell(e.target.value),
|
|
76
|
+
style: {
|
|
77
|
+
fontSize: 14,
|
|
78
|
+
padding: "6px 10px",
|
|
79
|
+
borderRadius: 8,
|
|
80
|
+
border: "1px solid var(--dsw-alias-line-strong, #ccc)",
|
|
81
|
+
background: "var(--dsw-alias-bg-layer-2, #fff)",
|
|
82
|
+
color: "var(--dsw-alias-label-primary, inherit)",
|
|
83
|
+
outline: "none",
|
|
84
|
+
cursor: writable ? "pointer" : "not-allowed",
|
|
85
|
+
maxWidth: 180
|
|
86
|
+
},
|
|
87
|
+
children: [
|
|
88
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "powershell", children: t("shell.powershell") }),
|
|
89
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "gitbash", children: t("shell.gitbash") }),
|
|
90
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "msys2", children: t("shell.msys2") }),
|
|
91
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("option", { value: "wsl", children: t("shell.wsl") })
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
)
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
function apply(ctx) {
|
|
100
|
+
ctx.effect(() => ctx.locale.register(SETTINGS_NS, { zh, en }), "bash-terminal: settings dictionaries");
|
|
101
|
+
const scope = ctx.settingsScope.bind({ namespace: SETTINGS_NAMESPACE });
|
|
102
|
+
const store = (0, import_dsh_client_store.defineStore)({
|
|
103
|
+
init: () => ({ shell: "powershell", revision: -1, writable: false }),
|
|
104
|
+
actions: {
|
|
105
|
+
sync: (d, shell, revision, writable) => {
|
|
106
|
+
if (revision !== void 0 && revision <= d.revision) return;
|
|
107
|
+
if (shell !== void 0) d.shell = shell;
|
|
108
|
+
if (revision !== void 0) d.revision = revision;
|
|
109
|
+
if (writable !== void 0) d.writable = writable;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
let bound;
|
|
114
|
+
const push = (snap) => {
|
|
115
|
+
bound?.sync(snap.value?.defaultShell, snap.revision, snap.writable);
|
|
116
|
+
};
|
|
117
|
+
ctx.slots.inject(
|
|
118
|
+
"settings.general.item",
|
|
119
|
+
() => ctx.slots.register(
|
|
120
|
+
{
|
|
121
|
+
name: "settings.general.item",
|
|
122
|
+
id: "bash-terminal-shell",
|
|
123
|
+
order: 20,
|
|
124
|
+
store,
|
|
125
|
+
locale: SETTINGS_NS,
|
|
126
|
+
inject: (actions) => {
|
|
127
|
+
bound = actions;
|
|
128
|
+
push(scope.getSnapshot());
|
|
129
|
+
return { setShell: (value) => void scope.set("defaultShell", value) };
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
ShellPreferenceRow
|
|
133
|
+
),
|
|
134
|
+
"bash-terminal: settings row"
|
|
135
|
+
);
|
|
136
|
+
ctx.effect(() => scope.subscribe(() => push(scope.getSnapshot())), "bash-terminal: settings watch");
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return module.exports;
|
|
140
|
+
}
|
|
141
|
+
});
|
package/dsh.plugin.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dsh-bash-terminal-ts",
|
|
3
|
+
"name": "dsh-bash-terminal-ts",
|
|
4
|
+
"version": "0.2.5",
|
|
5
|
+
"description": {
|
|
6
|
+
"en": "One shell tool that runs commands through PowerShell, Git Bash, MSYS2 or WSL on Windows, with a user-chosen default terminal in the Web UI settings.",
|
|
7
|
+
"zh": "一个 shell 工具,可在 Windows 上通过 PowerShell / Git Bash / MSYS2 / WSL 执行命令,默认终端在 Web UI 设置中选择。"
|
|
8
|
+
},
|
|
9
|
+
"homepage": "https://github.com/drscrewdriver/dsh-bash-terminal-ts",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/drscrewdriver/dsh-bash-terminal-ts.git"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"engines": {
|
|
16
|
+
"dsh": ">=0.1.2-rc.1 <0.2.0-0"
|
|
17
|
+
},
|
|
18
|
+
"components": {
|
|
19
|
+
"host": "lib/index.js",
|
|
20
|
+
"client": "dist/client.js"
|
|
21
|
+
}
|
|
22
|
+
}
|