Command Manager
一个用 JavaFX 写的命令行管理与插件化运行工具 —— 把常用命令变成带图形参数面板的条目,底层挂一个常驻 shell 会话。
它解决什么
命令行很强,但参数难记、手册要翻、同一串命令得反复敲。Command Manager 把这些收敛成「条目」:每个条目就是一个插件,用一份 manifest.json 声明它需要哪些参数(文本 / 数字 / 下拉 / 文件 / 开关),运行时按声明动态渲染出表单,点执行就把拼好的命令送进底下的 shell。
既保留手敲命令的自由,又不用再记参数 —— 这是它和普通终端模拟器的区别。
核心特性
插件化架构
一份 manifest.json 就是一个插件,丢进 cmmgr/plugins/ 即可被扫描到。声明 id、名称、可执行文件和参数列表,不用改一行程序代码。
参数面板自动生成
支持 text / number / select / file / checkbox / flag 六种控件,按类型渲染对应输入组件。必填项留空会在执行前被拦下并列出缺哪个,而不是静默传个空值。
常驻 shell 会话
不是 cmd /c 那种跑完就退。命令写进 shell 的 stdin、输出从 stdout 读回,cd 和环境变量跨命令保留。
单文件分发
./gradlew fatJar 打出约 11 MB 的可执行 jar,JavaFX 原生库和 Jackson 一并打进去,java -jar 直接能跑,不需要配 --module-path。
编码自适应
PowerShell 7 走 UTF-8、Windows PowerShell 5.1 走 GBK。默认 shell 是 pwsh 7 时自动选 UTF-8;编码和 shell 对不上会明确提醒,而不是让你对着乱码猜。
配置持久化与迁移
设置存在 cmmgr/config/config.json,损坏或缺失时用默认值启动。旧布局(plugins/ 与 .command-manager/)在启动时自动搬迁,逐个文件移动、失败不丢数据。
插件长什么样
以自带的 ffmpeg 转码插件为例,整份声明如下:
{
"id": "ffmpeg.transcode",
"version": "0.1.0",
"name": "FFmpeg 转码",
"description": "用 ffmpeg 把视频转码 / 缩放。",
"type": "shell",
"executable": "powershell.exe -ExecutionPolicy Bypass -NoProfile -File \"cmmgr/plugins/ffmpeg/run.ps1\"",
"isExecutable": true,
"parameters": [
{ "name": "input", "label": "输入文件", "type": "file", "required": true },
{ "name": "output", "label": "输出文件", "type": "text", "required": true },
{ "name": "resolution", "label": "分辨率", "type": "select", "required": false,
"options": ["original", "1920:-1", "1280:-1", "854:-1", "640:-1"] },
{ "name": "quality", "label": "画质", "type": "select", "required": false,
"options": ["high", "medium", "low", "tiny"] }
]
}
程序按 parameters 渲染出表单,执行时拼成命令行写进 shell。含空格的值会自动加引号。
界面结构
主页
快捷入口。
终端
左侧插件列表、右侧参数面板、底部输出区与命令输入框。插件执行和手敲命令走同一条 shell。
插件
已加载插件列表,可移除条目、打开插件目录。
设置
shell 路径与启动参数、工作目录、输出编码、终端字号、回滚行数上限。
页面切换带方向动画:每个页面有一个数字 id,比较 id 大小决定滑入方向,缓动为 ease-out。
项目结构
command-manager/
├── build.gradle.kts 构建 + Shadow fat jar
├── cmmgr/ 运行期数据
│ ├── config/config.json 设置
│ └── plugins/ffmpeg/ 插件(含 run.ps1 包装脚本)
└── src/
├── main/java/org/passerbya/
│ ├── Main.java 入口
│ ├── core/ CommandManager · PluginManager · AppSettings · AppPaths
│ ├── tools/ manifest 数据模型与加载器
│ ├── debug/ DebugLogger
│ └── ui/ MainGUI · PageId · pages/ · components/
└── test/java/ 31 个单元测试
几个踩过的坑
JavaFX 的 CSS 变量会静默失效
把 CSS 变量赋给 -fx-border-radius 时,JavaFX 会先把值转成 Double 再强转 Size,抛 ClassCastException —— 圆角悄悄不生效,只刷一屏警告。最后改成写字面值。
同一仓库里 BOM 规则是相反的
Java 源文件带 BOM 会直接编译失败(非法字符: '\ufeff');而 PowerShell 5.1 读无 BOM 的 .ps1 会按 GBK 解码,把中文读乱、连带破坏语法解析。所以 .java 一律无 BOM,.ps1 一律有。
命令拼装模型没法在值前面插 flag
拼装方式是「executable + 按顺序的值」。像 ffmpeg 这种需要 -i / -vf / -crf 交错参数的,得套一层包装脚本,把 flag 编排收进脚本里,manifest 只声明「值」。
fat jar 里的 JavaFX 能直接跑
原生库(glass.dll、prism_d3d.dll 等)本就在 javafx-graphics-*-win.jar 内部,运行时 JavaFX 自己解压到临时目录再加载。所以 fat jar 不需要额外处理原生库。
截图
(截图待补 —— 把图片放进 assets/ 后替换上面三个占位块即可。)
构建与运行
- 准备 JDK 21
- 克隆仓库并进入目录
- 运行下面任意一条命令
./gradlew run # 直接运行
./gradlew test # 单元测试(31 个)
./gradlew fatJar # 打包成单文件可执行 jar
java -jar build/libs/command-manager-1.0-SNAPSHOT-all.jar
程序的工作目录就是启动时的当前目录,运行期数据都收在它下面的 cmmgr/ 里。