dsh-open-terminal
Verifieddsh-open-terminal · v0.2.2 · MIT
dsh-TUI /term: open a system terminal in a workspace folder — blank opens the working-directory root, a fragment fuzzy-matches folders (unlimited candidates, managed picker), with ordered per-platform launcher chains for Windows / macOS / Linux (incl. WSL
Install
dsh plugin add dsh-open-terminal Confirm the layer applied with dsh --profile default --dump-config — see the install guide.
Source
Tags
Readme
dsh-open-terminal
中文 · English
/term —— 在工作区的任意文件夹里打开系统终端。不带参数时打开工作目录根;带参数时对文件夹做模糊搜索,多个匹配交给宿主的托管选择框。为
dsh-TUI 打造。
能力
/term(无参数)→ 在当前会话工作目录打开系统终端/term docs→ 工作目录旁已存在的同名文件夹直接打开,无需扫描工作区/term src/plugins→ 相对路径与绝对路径均可,两个平台的路径分隔符都接受/term ~/projects→~/~/…展开为主目录(~user不展开)/term guid→ 对工作区的文件夹做模糊搜索(大小写不敏感、支持中文,Unicode NFD/NFC 归一化)- 唯一命中 → 直接打开
- 多个命中 → 宿主托管选择框(TUI 接缝十),匹配数不限:弹窗按终端高度开窗,↑/↓ 滚动,Enter 打开,Esc 取消
- 命中超过宿主单次请求上限(100 项)→ 只显示前 100 项,标题写明
共 N 个匹配,仅显示前 100 个,绝不静默截断 - 零命中 → 明确报错,并提示留空参数可打开工作目录根
/term notes.txt→ 明确报错:这是文件,不是文件夹- 每次都开新窗口,绝不接管 TUI 自己的终端
安装
# 从 npm 安装(包名:dsh-open-terminal)
dsh plugin --profile dsh-tui add dsh-open-terminal
# 本地仓库安装(开发)
pnpm install --frozen-lockfile && pnpm build
dsh plugin --profile dsh-tui add file:<本仓库绝对路径>
安装后需在 TUI 内 /restart(或重开窗口)生效。
平台支持
打开动作按有序候选链执行:第一个能启动且未在 180 ms 宽限窗口内快速失败的候选胜出,否则自动回退下一个;整链失败时,报错会列出所有尝试过的程序。
| 平台 | 候选链 | 说明 |
|---|---|---|
| Windows | wt.exe -d <目录> → pwsh.exe → powershell.exe → cmd.exe |
wt.exe 直接 spawn(GUI 启动器:自己开窗、退出码可信);三个控制台 shell 经 cmd /d /s /c start "" "<exe>" 启动,这样才会开新窗口 —— 直接 spawn 会把它们挂到 TUI 的控制台上 |
| macOS | open -a Terminal <目录> |
Terminal.app 一定存在 |
| Linux | gnome-terminal --working-directory= → kgx --working-directory= → konsole --workdir → xfce4-terminal --working-directory= → mate-terminal --working-directory= → kitty --directory → alacritty --working-directory → wezterm start --cwd → foot --working-directory= → tilix --working-directory= → terminator --working-directory= → x-terminal-emulator → xterm |
发行版自带默认终端优先 —— kgx 即 GNOME Console,Fedora 与新版 GNOME 的默认终端。末尾的通用候选(x-terminal-emulator 是 Debian 的 alternatives 符号链接)不带参数,通过子进程工作目录落地。每个参数都取自程序自身的 manpage / 上游源码 |
| WSL | 先走 Linux 链,再兜底 cmd.exe /c start "" "wt.exe" -d "\\wsl$\<发行版>\…" |
有无 WSLg 均可用 |
两条 Windows 实测结论(2026-09-12)决定了实现方式:
cmd /d /s /c start "" <不存在的程序>退出码仍是 0,所以「程序缺失」无法从 shim 的退出码发现;候选程序一律先按PATH(含PATHEXT)解析,再启动。- 应用执行别名(
%LOCALAPPDATA%\Microsoft\WindowsApps\wt.exe、…\pwsh.exe)是APPEXECLINK重解析点:fs.existsSync()判定为不存在,fs.statSync()抛EACCES,只有fs.lstatSync()成功。基于existsSync的探测会静默漏掉用户最想要的那个终端。
语言 / Language
命令回执、错误提示与补全提示都跟随宿主语言,解析链与 dsh-TUI 一致:
DSH_TUI_LANG → 运行中的 dsh-tui 设置命名空间(/lang 的落点)→
~/.dsh-tui/lang.json → 系统 locale → 中文。
- 语言存在但不支持(如
fr)时回落英文;完全没有信息时沿用中文,保证中文宿主的行为与加入双语之前完全一致。 - 回执在每次调用时重新解析语言,
/lang切换无需重启;命令补全里的提示是注册时的快照,重启后跟随新语言。 DSH_OPEN_TERMINAL_LANG_FILE可覆盖偏好文件路径(测试与诊断用)。
配置
| 键 | 默认 | 说明 |
|---|---|---|
command |
'' |
用自定义启动模板取代内置链,{dir} 代表目标文件夹,例如 wt.exe -p "Git Bash" -d {dir} 或 gnome-terminal --working-directory={dir}。设置后模板即最终答案:程序解析不到就明确报错,绝不静默换成别的终端 |
maxDepth |
6 |
目录扫描深度上限(根 = 0) |
maxEntries |
20000 |
索引文件夹数量上限 |
maxCandidates |
0 |
交给选择框的候选数;0 = 不限(仍受宿主 100 项窗口约束,且标题会写明) |
includeHidden |
false |
是否索引点开头的隐藏文件夹 |
所有键都有默认值,缺省即按上表行为降级。配置经 /settings 或 profile 的 Cordis 配置覆盖。
模板语法:空白分隔参数,单/双引号可包裹含空格的参数(引号是分组语法,不进入参数本身),{dir} 可独立成项也可拼进参数(--working-directory={dir})。含 %、未知占位符(如 {cwd}),或在引号组内部再嵌套另一种引号的模板会被拒绝并说明原因 —— % 即使在引号内也会被 cmd 展开,无法安全透传。
% 是唯一还需要在 {dir} 替换后再查一遍的字符,因此替换后的命令行会再次校验:Windows 上目录名含 % 会明确报错,而不是把它交给 cmd(那会被展开);macOS/Linux 上 argv 直接 spawn,50%off 这类目录照常打开。
工作目录语义
命令以接收会话的工作目录(agent.session.header.cwd,DSH 会话头记录的 host-side cwd)为基准,而非宿主进程的 cwd。TUI 里 /workspace 切换会新建会话,新会话头即新目录,所以 /term 始终跟手;只暴露 session.meta.cwd 的旧版宿主同样支持,进程启动目录是最后兜底。
模糊索引的相对路径统一以 / 分隔,因此同一份索引在三个平台语义一致。
Model Experience
命令在 UI 命令平面执行,结果文本由适配器直接渲染:不产生模型消息、不计入模型 token、不进入模型 KV 缓存。command/run / command/done 仅以 log-only 事件记录到会话日志。
Known Limitations
- 打开是 fire-and-forget 交接:只在 180 ms 宽限窗口内观测失败,之后才崩溃的启动器不会被察觉;Windows 上「别名存在但实际起不来」会被上报为已打开。
- 模糊索引受深度(
maxDepth,默认 6 层)与条目数(maxEntries,默认 20000)上限约束;超大目录树上扫描在取消信号或上限处截止,超出的部分不被检索。 - 托管选择框的条数由宿主兜底:dsh-tui 0.10.x 的
tuiDialogs.select只保留请求里的前 100 个选项(超出静默丢弃,插件拿不到该常量)。本插件主动对齐 100 并写明丢弃数量,但超过 100 条的候选在当前宿主上无法展示;需要真·不限量得改走tuiScenes自绘选择器。 - Windows Terminal 按自身的
windowingBehavior设置决定开新窗口还是新标签页;本插件只传-d <目录>,不强制二者之一。 - 指向目录的符号链接会被索引为候选,但不会被递归遍历(防环、防越出工作区)。
~展开仅支持~/~/…/~\…,不解析~user。- Linux 上无图形会话时明确拒绝:需
DISPLAY或WAYLAND_DISPLAY(WSL 视为可经 Windows 侧打开)。Windows 上该检查是空操作 —— 一律假定有图形会话 —— 因此无桌面的 Windows 宿主不会报「无图形会话」,而是在后面的 spawn / 宽限窗口阶段失败。 - 目录名含
%时无法交给cmd:Windows 上配了command模板会明确报错(见配置一节);WSL 上只丢弃那个 Windows 侧兜底候选,上面的 Linux 链照常打开。 - 除自身日志
~/.dsh-tui/dsh-open-terminal.log外,本插件不写任何文件、不向工作区落盘、不追加 session 事件。
发布
- 仓库:https://github.com/VviLliAm-qwq/dsh-open-terminal(公开)
- 版本:语义化版本;发布由
v*tag 驱动(.github/workflows/release.yml校验 tag 与package.json一致 → build/test/manifest/pack 校验 →npm publish --provenance→ 创建 GitHub Release) - 前置:npm 包已配置 Trusted Publisher(GitHub Actions · 本仓库 ·
release.yml)——发布走 OIDC,无需在仓库里存放任何令牌 - 生态收录:本 README 顶部带有 https://dshtui.com/plugins/ 要求的 dsh-TUI 链接
开发与验证
本节命令都只适用于本仓库的本地检出(workspace checkout)。npm 发布包里只有 lib/、dsh-plugin.json、cordis.patch.yml 与文档 —— src/、test/、scripts/ 以及工作区的 tools/ 都不在其中(package.json 的 files 有意排除)。
pnpm install
pnpm build # tsc -> lib/
pnpm test # vitest(平台分支通过注入 platform/env/PATH 探测实现跨平台覆盖)
pnpm validate:manifest # dsh-plugin.json 准入形状检查
pnpm pack:verify # 发布包布局检查
pnpm prepublishOnly # 四合一
入口模块(src/index.ts → lib/index.js)刻意只再导出 { Config, apply, name };test/entry.test.ts 锁死该形状 —— 导出更多符号会让 dsh-TUI 的接缝静默拒绝整个插件的注册。
真实组合下的集成探测 —— 仅限本地检出:该脚本在工作区仓库的 tools/ 里,不在 npm 发布包中,所以从 npm 安装的用户跑不通这一行:
# 在工作区根目录(含 tools/ 与 plugins/ 的那一层)执行,且需先 pnpm build
node tools/probe-plugin.mjs plugins/dsh-open-terminal # 退出码 0 = 注册被宿主接受