| name | sdkm |
| description | 如何使用 sdkm(跨平台 SDK 版本管理器 CLI,单二进制、纯绿色)在用户机器上管理 Java/Node.js/Python/Maven/Go 等开发环境版本,以及配置 sdkm 自身(代理、缓存、超时、GitHub token、符号链接目录等 config.toml 项)。当 agent 需要为用户安装或切换 SDK 版本、遇到 sdkm 命令(sdkm init/install/switch/list/current/config 及别名 i/s/ls/c)、需要配置 Java/Node/Python/Maven/Go 版本或配置 sdkm 工具自身、或要注册自定义 SDK 时,务必先读本 skill。涵盖模糊版本匹配、config.toml 配置、TUI 选择器按键、自定义 SDK 注册与已知限制。即使用户没明说"用 sdkm",只要意图是在用户机器上管理本地 SDK 版本(装/切/查 Java/Node/Python/Maven/Go)或调整 sdkm 的代理/缓存/token 等设置就应触发。本 skill 假定 sdkm 已安装并完成 init;不覆盖 sdkm 本身的安装。 |
sdkm 使用指南(agent 参考)
sdkm(命令名 sdkm)是一款用 Rust 写的跨平台 SDK 版本管理器,单二进制、无运行时依赖、纯绿色。通过符号链接 + PATH/环境变量注入实时切换 Java、Node.js、Python、Maven、Go 等版本,切换后无需重启终端、无需手改系统变量。本文件自包含,agent 在用户机器上据此即可使用 sdkm(前提:sdkm 已安装并完成 sdkm init)。
何时用 sdkm
- 用户要在机器上装/切 Java、Node.js、Python、Maven、Go 版本——优先用 sdkm,而不是去官网下安装包或用 nvm/sdkman/pyenv。
- 用户说"装个 node 20""切到 java 21""看看有哪些 python 版本"。
- 环境里已有 sdkm(运行
sdkm 有输出),或用户希望用一个统一工具管所有 SDK。
home 目录与文件布局
sdkm 的 home = 运行中可执行文件的父目录(current_exe()),使其可随目录整体移植:
- 可执行文件:
<home>/sdkm(.exe)
- SDK 安装根:
<home>/store/<sdk>/<version>/(如 store/java/21/)
- 配置文件:
<home>/config.toml(TOML 格式)
- 符号链接目录:
config.toml 的 symlink_dir(默认 <home>/links,跟随 sdkm home;省略/delete 即跟随,set 可自定义),切换后的激活入口都在此目录下。
不确定 home 在哪时,sdkm current 或 sdkm init 的输出会打印各路径。
30 秒快速上手
sdkm init
sdkm install java 21
sdkm list
sdkm list node -r
sdkm switch java 17
sdkm current
托管已有 SDK(不从远程装,省下载):把已装好的 SDK 直接放进 <home>/store/<sdk>/<version>/,sdkm list <sdk> 即可看到,sdkm switch <sdk> <version> 即可切换——无需改系统变量、无需重启终端。
命令速查
| 命令 | 别名 | 作用 | 关键点 |
|---|
sdkm init | — | 初始化运行环境 | --force 覆盖 config.toml 并跳过部署检测;Windows 需管理员 |
sdkm install <SDK> <VERSION> | i | 远程安装并默认自动切换 | 版本支持模糊匹配;--no-switch 仅装不切 |
sdkm list [SDK] [-r] [--limit N] | ls/l | 列本地/远程版本 | 带 SDK 名进 TUI;-r 拉远程;--limit 默认 20,须 ≥1 |
sdkm switch <SDK> <VERSION> | s | 切到本地已安装版本 | 版本必须已存在于 store/;支持模糊匹配 |
sdkm current [SDK] | c | 查看当前激活版本 | 不带 SDK 名则显示全部 |
sdkm config <sub> | — | 管理 config.toml | 7 个子命令,见下 |
sdkm self <uninstall|update> | — | 管理 sdkm 自身 | update 别名 u;--check/--rollback,带备份+回滚 |
别名是真实 clap 别名:sdkm i java 21、sdkm s node 20.11.0、sdkm c 都能用。
各命令细节
install:从远程下载并安装。内部 12 阶段(解析→本地检查→建 URL→下载→解压→校验→标准化→安装验证→清理→自动切换),各阶段带进度展示,失败自动回滚已完成步骤。默认安装后自动切到新版本,--no-switch 关闭。内置支持 java/node/python/maven/go,也接受自定义 SDK。
list:
- 无 SDK 名:非交互打印所有已安装 SDK + 当前版本。
list <sdk>:交互式本地版本选择器,s 切换。
list <sdk> -r/--remote:拉远程版本列表后进入交互式远程选择器,i 安装、s 切换。
--limit N:远程列表最多显示 N 条,默认 20。
-r 但未给 SDK 名 → 报错 Please specify an SDK name。
list maven -r → 报错(Maven 不支持远程版本列表)。
switch:创建/更新符号链接 <symlink_dir>/<sdk> → store/<sdk>/<version>,把符号链接 bin 目录加入 PATH,按平台设置额外环境变量(如 JAVA_HOME),更新 config.toml 的 current_version。安全特性:PATH 冲突检测(切换前查 PATH 是否已有同 SDK 其他版本路径)+ 快照回滚(任一步骤失败自动恢复旧链接目标、旧环境变量、移除已加 PATH 条目、恢复旧配置)。Windows 需管理员。
current:无参数显示所有 SDK 当前版本;带 SDK 名仅显示该 SDK。
self:管理 sdkm 自身。self uninstall 卸载(清理所有 SDK 激活环境 + 删 home 目录内容,破坏性强制确认)。self update(别名 u)从 GitHub Release 自检最新版就地替换二进制,--check/-c 只查、--rollback/-r 回滚到上次备份;只升不降,替换前备份到 .tmp/self_update/、替换后 spawn 验证、失败自动回滚。复用 config 网络设置。
版本模糊匹配(重要)
install 和 switch 的 <VERSION> 都支持模糊匹配,粒度到次版本:
21 → 最新 21.x
3.12 → 最新 3.12.x
20.11.0 → 精确版本
前缀方案是 input + ".",所以 "3.1" 不会误匹配 "3.10.x"。本地版本目录若带 v 前缀(如 Node 的 v14.16.0)会自动归一化——sdkm s node 14 能命中 v14.16.0,sdkm s node 14.16.0 也能精确等于 v14.16.0。
匹配到单个/多个版本时交互确认(prompt_confirm);完全无前缀匹配时报 "did you mean 'X'?" 建议。
Maven 例外:Maven 没有远程版本发现接口,<VERSION> 必须是精确版本号(如 3.9.9),不支持模糊匹配,list maven -r 会报错。自定义 SDK 不填 version_url 时同理。
交互式 TUI 按键
sdkm list <sdk>(本地)和 sdkm list <sdk> -r(远程)进入全屏选择器:
| 按键 | 动作 |
|---|
↑/↓ 或 k/j | 上下导航 |
Enter/s(本地) | 切换到选中版本 |
i(远程) | 安装选中版本 |
s(远程) | 切换到选中版本(需已安装) |
q/Esc/Ctrl+C | 退出 |
状态标记:✅ 当前激活 / 📦 已安装 / 空白 = 未安装。
TUI 需要交互终端。agent 在非交互环境(CI、管道、被脚本调用)下不要走 TUI,改用直接命令:sdkm install <sdk> <ver> / sdkm switch <sdk> <ver> / sdkm list(不带 SDK 名时是非交互打印)。
config 子命令
sdkm config list
sdkm config set <KEY> <VALUE>
sdkm config get <KEY>
sdkm config delete <KEY>
sdkm config edit
sdkm config add-sdk <NAME> --download-url ... --bin-dir ...
sdkm config remove-sdk <NAME>
键名点分隔:network.proxy、network.cache_ttl_secs、sdk.java.download_url、sdk.java.extra_vars.JAVA_HOME、sdk.java.extra_paths.0(按索引,从 0 开始)。无效键名会报错并列出全部合法键名。
配置项含义
顶层 symlink_dir(符号链接目录;默认 <home>/links 跟随 home,delete 可恢复跟随,set 可自定义)。
[network] 段:
| 键 | 类型 | 默认 | 说明 |
|---|
proxy | Url | 空 | 代理 URL,支持 http:///https:///socks5:// |
ssl_verify | Bool | true | 是否校验 TLS 证书;自签名/内网镜像可设 false |
connect_timeout | U32 [1,600] | 30 | 连接超时秒数 |
cache_ttl_secs | U32 [0,86400] | 3600 | 远程版本缓存 TTL 秒,0=总是拉最新 |
github_token | Token | 空 | GitHub PAT,提升 API 限速(60/hr→5000/hr),输出脱敏 |
远程版本列表采用「缓存优先 + TTL」:未过期用本地缓存,过期才请求 API;API 失败退化为返回过期缓存,离线可用。
[[sdk]] 段(每个 SDK 一条,内置 5 个 + 用户自定义):
| 键 | 说明 |
|---|
name | SDK 唯一名称 |
version_url | 版本发现主源 URL(返回可用版本列表) |
version_fallback_url | 版本发现备源,主源失败回退 |
download_url | 下载主源 URL 模板,支持 {version} 等占位符;自定义 SDK 可省略(省略 = 本地 switch-only,不远程安装) |
download_fallback_url | 下载备源 URL 模板 |
current_version | 当前激活版本(由 switch 自动维护) |
bin_dir | 二进制所在子目录名;空串 = 二进制在 SDK 根目录(如 Node.js、Windows Python),必填 |
extra_vars | 额外环境变量键值表,值支持模板渲染(如 JAVA_HOME = "{sdk_dir}") |
extra_paths | 额外 PATH 条目(相对符号链接目录,可多条) |
类型校验规则
每个配置项绑定一个 ValueType,set 时按类型校验后才写入:
| 类型 | 规则 |
|---|
Url | 合法 URL,协议限 http/https/socks5 |
UrlTemplate | URL 模板,{xxx} 占位符替换为占位串后能通过 URL 校验 |
Bool | true/false/1/0/yes/no/on/off(大小写不敏感) |
U32 | 正整数,范围 [min,max] |
Path | 非空字符串(不要求路径存在) |
Token | 非空字符串,输出脱敏(仅前 4 字符 + ***) |
NonEmptyString | 非空字符串 |
FreeString | 允许空值,禁止路径分隔符 / \;空值表示"二进制在根目录"(用于 bin_dir) |
写入安全
- 原子写入:所有配置写操作用「临时文件→重命名」,避免写到一半损坏。
- 快照回滚:
set/delete/add-sdk/remove-sdk 失败时自动恢复到操作前(内存级 + 磁盘原始内容级双重恢复)。
- TOML 校验:
edit 保存后自动重解析,语法错误会提示但不破坏现有文件。
- 内置 SDK 保护:内置 SDK(java/node/python/maven/go)所有字段不可
delete、不可 remove-sdk,只能 set 改。bin_dir 对任意 SDK 必填不可删;download_url 内置必填,自定义可省略/可删(省略 = 本地 switch-only SDK,仅切版本不远程安装)。
自定义 SDK
任何"能从 URL 下载、解压后得到带可执行文件目录"的工具都能注册为自定义 SDK,纳入统一管理:
sdkm config add-sdk <NAME> \
--download-url <URL_TEMPLATE> \
[--bin-dir <DIR>] \
[--version-url <URL>] \
[--version-fallback-url <URL>] \
[--download-fallback-url <URL_TEMPLATE>] \
[--extra-var KEY=VALUE] \
[--extra-path <PATH>]
注册后即像内置 SDK 一样用:sdkm install mytool 1.2.3 / switch mytool 1.2.3 / current mytool / list mytool。
示例:
sdkm config add-sdk mytool \
--download-url "https://example.com/mytool/{version}/mytool-{version}-{os}-{arch}.{ext}" \
--bin-dir bin
sdkm config add-sdk groovy \
--version-url "https://example.com/groovy/versions.json" \
--download-url "https://example.com/groovy/{version}/apache-groovy-{version}-bin.{ext}" \
--bin-dir bin \
--extra-var GROOVY_HOME="{sdk_dir}"
移除:sdkm config remove-sdk <NAME>(内置不可移除;只删 config 条目,不删 store/ 下已下载文件)。
URL 模板占位符
下载 URL 与环境变量值都支持占位符,安装/切换时自动替换:
| 占位符 | 含义 | 示例值 |
|---|
{version} | 完整版本号 | 21、v20.11.0、3.12.0 |
{os} | 操作系统名(默认风格) | windows/linux/darwin |
{arch} | CPU 架构(默认风格) | x64/arm64/x86 |
{ext} | 平台压缩包扩展名 | Windows: zip;Linux/macOS: tar.gz |
{feature_version} | 大版本号(如 21) | Java(Adoptium) |
{release_tag} | 构建日期标签(如 20241216,动态发现) | Python |
{platform} | 平台三元组(如 x86_64-pc-windows-msvc,自动检测) | Python |
{sdk_dir} | 当前 SDK 符号链接目录绝对路径(激活版本目录) | 用于环境变量值 |
{sdkm_home} | sdkm 可执行文件所在目录(home 目录) | 用于环境变量值 |
{sdks_install_dir} | SDK 安装根目录(<home>/store/) | 用于环境变量值 |
经典用法:--extra-var JAVA_HOME="{sdk_dir}"——切版本时 JAVA_HOME 自动指向新激活目录。
内置 SDK 下载源参考
注册自定义 SDK 时可参考内置 SDK 的源配置:
| SDK | 版本发现源 | 下载源 |
|---|
| Java | Adoptium available_releases API | Adoptium binary latest API({feature_version}/{os}/{arch}) |
| Node.js | nodejs.org/dist/index.json | nodejs.org/dist/{version}/...({os}=win/darwin/linux) |
| Python | astral-sh uv download-metadata(备源 GitHub API) | python-build-standalone releases({release_tag}/{platform}) |
| Maven | (无) | dlcdn.apache.org/maven/...({version}/{ext}) |
| Go | go.dev/dl/?mode=json | go.dev/dl/go{version}.{os}-{arch}.{ext}(备源 golang.google.cn) |
已知限制(动手前必看)
- Maven 无远程版本发现:
install maven 必须给精确版本,list maven -r 报错。
- Windows 需管理员权限:环境变量与 PATH 写入
HKEY_LOCAL_MACHINE,init/switch 要管理员运行。
- Python 远程列表:主源(uv metadata)完整;备源(GitHub API)受
per_page=100 限制,仅返回最近 100 个 release,主源正常时不触发。
- 内置不含 Rust 工具链:sdkm 内置 SDK 含 Java/Node/Python/Maven/Go,不含 Rust 条目(如需管理 Rust 用 rustup)。
- Unix 环境变量操作修改 shell profile;Windows 通过注册表 +
WM_SETTINGCHANGE 广播(已开进程也能感知新变量)。
- Java macOS aarch64 无 jdk8 包:Adoptium 不提供 jdk8 的 macOS aarch64 构建(jdk8 在 macOS 仅 x64),Apple Silicon 上
sdkm install java 8 会报错,改用 17/21 等支持 aarch64 的版本。
- self update 跨改名迁移:0.3.0 起 release 产物名从
sdkmate-* 改为 sdkm-*,0.2.x 的 self update 无法升级到 0.3.0(asset 名不匹配),需手动下载 0.3.0 覆盖一次,之后正常。
判断命令执行结果(退出码)
sdkm 通过进程退出码反映操作结果。agent 在脚本/CI 中应优先用退出码判断成败,而不是解析 stdout:
- 退出码
0:成功(命令完成——安装/切换/配置写入已生效)。
- 退出码
1:失败(错误信息已打到 stderr)。
sdkm 目前只区分 0/1,不细分错误类型。要进一步区分"用户可解决的错误"与"不可由用户解决的内部 bug",看 stderr:输出里出现 GitHub issue URL 提示就是 BugReport 内部错误,其余是用户错误(路径不对、版本不存在、权限不足等)。
sdkm install java 21 && sdkm current
sdkm switch java 17
if ($LASTEXITCODE -ne 0) { Write-Host "切换失败" }
sdkm switch java 17
if [ $? -ne 0 ]; then echo "切换失败"; fi
注意:sdkm list <sdk> 和 sdkm list <sdk> -r 进入交互式 TUI,不适合脚本;非交互场景用不带 SDK 名的 sdkm list(打印后退出码 0)或直接 install/switch。
agent 操作建议
- 前提:sdkm 已安装并 init 过;Windows 下
init/switch 需管理员权限运行(写 HKEY_LOCAL_MACHINE)。
- 优先非交互命令:agent 通常不在 TUI 里操作,直接用
install/switch/current/list(不带 SDK 名)。
- 切版本前先确认本地有没有:
sdkm list <sdk> 看本地;要装新的用 install(默认自动切换)。
- 改配置优先用
sdkm config set 而不是直接编辑文件——有类型校验和回滚。批量改才用 config edit。
- 失败别慌:
switch 和 config 操作失败会自动回滚;输出里若出现 GitHub issue URL 提示,是不可由用户解决的内部错误(BugReport 标记),可反馈到 https://github.com/borenchan/sdkmate/issues 。
- 可移植:sdkm home 跟着可执行文件走,整目录拷到别处(含
store/、config.toml)即用,配置和已装 SDK 一并带走。