본문으로 건너뛰기
cccskills
무료GitHub에 공개

sdkm

安装并使用 sdkm(跨平台 SDK 版本管理器 CLI,单二进制、纯绿色)在用户机器上管理 Java/Node.js/Python/Maven/Go 等开发环境版本,以及配置 sdkm 自身(代理、缓存、超时、GitHub token、符号链接目录等 config.toml 项)。

当用户机器上还没有 sdkm 时,按本 skill 的安装章节从 GitHub Release 下载最新版并初始化(含配套安装脚本 scripts/install.sh / scripts/install.ps1,可直接调用)。

当 agent 需要为用户安装或切换/卸载 SDK 版本、遇到 sdkm 命令(sdkm init/install/uninstall/switch/use/list/current/config/self 及别名 i/rm/s/ls/c/u)、需要配置 Java/Node/Python/Maven/Go 版本、配置 sdkm 工具自身、或要注册自定义 SDK 时,务必先读本 skill。

涵盖多作用域版本切换(全局/项目/临时)、模糊版本匹配、config.toml 配置、TUI 选择器按键、自定义 SDK 注册与已知限制。

即使用户没明说"用 sdkm",只要意图是在用户机器上安装/管理本地 SDK 版本(装/切/卸/查 Java/Node/Python/Maven/Go)或调整 sdkm 的代理/缓存/token 等设置就应触发。

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

borenchan/sdkmate스타 107(GitHub 107 + cccskills 0)
연동 도구GitHub

실행 점수 미검증

설치 방법 보기

포함된 파일(3)

  • SKILL.md23.5 KB
  • scripts/install.ps12.8 KB
  • scripts/install.sh3.2 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

sdkm 使用指南(agent 参考)

sdkm(命令名 sdkm)是一款用 Rust 写的跨平台 SDK 版本管理器,单二进制、无运行时依赖、纯绿色。通过符号链接 + PATH/环境变量注入实时切换 Java、Node.js、Python、Maven、Go 等版本,切换后无需重启终端、无需手改系统变量。本文件自包含:agent 据此可从零安装 sdkm,并在用户机器上使用它管理 SDK。

何时用 sdkm

  • 用户机器上没有 sdkm,但需要装/切 Java、Node.js、Python、Maven、Go 版本——先按安装 sdkm装好,再用它管理。
  • 用户要在机器上装/切/卸 Java、Node.js、Python、Maven、Go 版本——优先用 sdkm,而不是去官网下安装包或用 nvm/sdkman/pyenv。
  • 用户说"装个 node 20""切到 java 21""这个项目用 node 16""看看有哪些 python 版本"。
  • 环境里已有 sdkm(运行 sdkm 有输出),或用户希望用一个统一工具管所有 SDK。

安装 sdkm

已装过就跳过本节(sdkm --version 有输出即已装;sdkm self update 可就地升级,无需重装)。

sdkm 发布为 GitHub Release 预编译压缩包,包内 .sdkm/ 目录包裹二进制,解压即得完整目录结构。两种安装方式任选:

方式一:直接调用配套安装脚本(推荐)

本 skill 同目录下的 scripts/ 提供现成安装脚本,自动识别平台、下载最新版、解压到目标目录并初始化:

# Linux / macOS(含自动识别 glibc 与 musl 兼容性)
bash scripts/install.sh                      # 默认装到 ~/.sdkm
bash scripts/install.sh -d /opt/sdkm         # 自定义安装目录
# Windows(需管理员权限终端,init/switch 要写注册表 + 建符号链接)
powershell -ExecutionPolicy Bypass -File scripts\install.ps1            # 默认装到 %USERPROFILE%\.sdkm
powershell -ExecutionPolicy Bypass -File scripts\install.ps1 -Dest D:\sdkm   # 自定义安装目录

脚本做完后按输出提示把 .sdkm 加入 PATH(或由 sdkm init 自动完成),然后跑 sdkm init。

方式二:手动下载(脚本不可用时)

  1. 从 GitHub API 拿最新 release 的下载地址(按平台选资产):
# 查最新版资产列表
curl -s https://api.github.com/repos/borenchan/sdkmate/releases/latest | grep browser_download_url
平台资产名格式
Windows x64sdkm-windows-x86_64.zipzip
Linux x64(glibc 2.35+,Ubuntu 22.04+/Debian 12+)sdkm-linux-x86_64-gnu.tar.gztar.gz
Linux x64(任意发行版/Alpine/老系统,全静态)sdkm-linux-x86_64-musl.tar.gztar.gz
macOS Apple Siliconsdkm-macos-aarch64.tar.gztar.gz
macOS Intelsdkm-macos-x86_64.tar.gztar.gz
  1. 下载对应压缩包,解压到目标位置(得到 <安装目录>/.sdkm/sdkm(.exe)——sdkm 的 home 就是这个 .sdkm 目录,SDK、配置都装在这里,整目录可移植)。
  2. 首次初始化:
.sdkm/sdkm init          # unix;Windows: .sdkm\sdkm.exe init

init 会创建 store/(SDK 安装根)、写 config.toml,并把 sdkm 自身注册到 PATH(Unix 追加 shell profile;Windows 写注册表 PATH)。Windows 的 init/switch 需管理员权限(写 HKEY_LOCAL_MACHINE + 创建符号链接)。

安装校验

sdkm --version           # 打印版本号即安装成功
sdkm current             # 打印 home 路径与各 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 i java 21               # 远程安装 Java 21 最新版并自动切换(支持模糊版本;install 别名 i)
sdkm ls                      # 列出所有已安装 SDK + 当前版本
sdkm ls node -r              # 交互式浏览远程 Node 版本,按 i 安装、s 切换
sdkm s java 17               # 切换到本地已安装的 Java 17
sdkm c                       # 查看当前激活版本
sdkm rm node 16              # 卸载本地 Node 16(uninstall 别名 rm;-y 跳过确认)

托管已有 SDK(不从远程装,省下载):把已装好的 SDK 直接放进 <home>/store/<sdk>/<version>/,sdkm ls <sdk> 即可看到,sdkm s <sdk> <version> 即可切换——无需改系统变量、无需重启终端。

命令速查

命令别名作用关键点
sdkm init—初始化运行环境--force 覆盖 config.toml 并跳过部署检测;Windows 需管理员
sdkm install <SDK> <VERSION>i远程安装并默认自动切换版本支持模糊匹配;--no-switch 仅装不切
sdkm uninstall <SDK> <VERSION>rm/un卸载本地版本模糊匹配;-y/--yes 跳过确认(脚本/agent 用)
sdkm list [SDK] [-r] [--limit N]ls/l列本地/远程版本带 SDK 名进 TUI;-r 拉远程;--limit 默认 20,须 ≥1
sdkm switch <SDK> <VERSION>s切到本地已安装版本(全局)版本必须已存在于 store/;支持模糊匹配
sdkm use <SDK> <VERSION>—项目级固定版本(写 .sdkm.toml)需 hook;--shell 走临时会话级,见"多作用域"
sdkm current [SDK]c查看当前激活版本不带 SDK 名则显示全部
sdkm config <sub>—管理 config.toml7 个子命令,见下
sdkm hook [SHELL]—打印 shell hook 注册脚本手动注入 hook 用;init 已自动注入
sdkm env [SHELL]—打印当前目录应 eval 的环境脚本hook 高频调用;手动调试 hook 时用
sdkm self <uninstall|update>—管理 sdkm 自身update 别名 u;--check/--rollback,带备份+回滚

别名是真实 clap 别名:sdkm i java 21、sdkm rm node 16、sdkm s node 20.11.0、sdkm c、sdkm self u --check 都能用。

多作用域版本切换(重要)

版本切换按作用域分三档,优先级从高到低:临时 > 项目 > 全局。

优先级作用域命令载体生效方式
1(最高)临时 · 当前终端sdkm use --shell <SDK> <V>环境变量 SDKM_ACTIVE_<SDK>eval 输出脚本,仅本 shell,关终端失效
2项目 · 当前目录及子目录sdkm use <SDK> <V>当前目录 .sdkm.tomlhook 进目录自动切、离开自动还原
3全局 · 整个系统sdkm s <SDK> <V>符号链接 + config current_version已注入 hook 时按一下回车即生效(hook 每次回车从 config 动态重建 PATH);未注入 hook 需重启终端
sdkm s java 21                              # 全局:整个系统都用 Java 21
sdkm use java 21                            # 项目:仅当前目录用 Java 21(需 hook)
sdkm use --shell java 21                    # 临时:仅当前终端
# bash/zsh:
eval "$(sdkm use --shell java 21)"          # 临时级需 eval 包一层
# PowerShell:
Invoke-Expression ((sdkm use --shell java 21) -join "`n")
  • agent 在脚本/非交互环境用临时级时:直接在要用的命令前 eval 对应 shell 语法;或干脆退回全局级 switch(脚本场景通常无"当前终端"概念)。
  • 临时级清除:bash/zsh unset SDKM_ACTIVE_JAVA;PowerShell Remove-Item Env:SDKM_ACTIVE_JAVA;或直接开新 shell。
  • 项目级/临时级依赖 shell hook(init 自动注入,bash/zsh/fish/PowerShell 均支持);无 hook 时只有全局 switch 生效。

各命令细节

install:从远程下载并安装。内部 12 阶段(解析→本地检查→建 URL→下载→解压→校验→标准化→安装验证→清理→自动切换),各阶段带进度展示,失败自动回滚已完成步骤。默认安装后自动切到新版本,--no-switch 关闭。内置支持 java/node/python/maven/go,也接受自定义 SDK。

uninstall:卸载本地版本并清理。模糊匹配(sdkm rm node 16 命中本地 v16.x);若卸的是当前激活版本,自动清理其激活环境(PATH 条目、env vars、config 的 current_version)。交互式确认,-y/--yes 跳过(agent/脚本务必带 -y)。

list:

  • 无 SDK 名:非交互打印所有已安装 SDK + 当前版本。
  • list <sdk>:交互式本地版本选择器,s 切换、d 卸载。
  • 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。已注入 hook 时切换后按一下回车即生效(hook 每次回车触发 sdkm env 从 config 动态重建 PATH);未注入 hook 需重启终端。安全特性:PATH 冲突检测(切换前查 PATH 是否已有同 SDK 其他版本路径)+ 快照回滚(任一步骤失败自动恢复旧链接目标、旧环境变量、移除已加 PATH 条目、恢复旧配置)。Windows 需管理员。

use:项目级(默认)写当前目录 .sdkm.toml 声明 pin,hook 自动生效;--shell 走临时会话级(输出 eval 脚本)。详见上文"多作用域版本切换"。

current:无参数显示所有 SDK 当前版本;带 SDK 名仅显示该 SDK。

self:管理 sdkm 自身。self uninstall 卸载(清理所有 SDK 激活环境 + 删 home 目录内容,破坏性强制确认)。self update(别名 u)从 GitHub Release 自检最新版就地替换二进制,--check/-c 只查、--rollback/-r 回滚到上次备份;只升不降,替换前备份到 .tmp/self_update/、替换后 spawn 验证、失败自动回滚。复用 config 网络设置。升级 sdkm 优先用 sdkm self update,不要重跑安装脚本。

版本模糊匹配(重要)

install、uninstall、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 ls <sdk>(本地)和 sdkm ls <sdk> -r(远程)进入全屏选择器:

按键动作
↑/↓ 或 k/j上下导航
Enter/s(本地)切换到选中版本
d/Delete(本地)卸载选中版本
i(远程)安装选中版本
s(远程)切换到选中版本(需已安装)
q/Esc/Ctrl+C退出

状态标记:✅ 当前激活 / 📦 已安装 / 空白 = 未安装。

TUI 需要交互终端。agent 在非交互环境(CI、管道、被脚本调用)下不要走 TUI,改用直接命令:sdkm i <sdk> <ver> / sdkm s <sdk> <ver> / sdkm rm <sdk> <ver> -y / sdkm ls(不带 SDK 名时是非交互打印)。

config 子命令

sdkm config list                                 # 列出全部配置
sdkm config set <KEY> <VALUE>                    # 按类型校验后写入
sdkm config get <KEY>                            # 读取(敏感值自动脱敏)
sdkm config delete <KEY>                         # 删除(恢复默认;内置 SDK 字段不可删)
sdkm config edit                                 # 用系统编辑器打开 config.toml,保存时校验 TOML
sdkm config add-sdk <NAME> --download-url ... --bin-dir ...   # 注册自定义 SDK
sdkm config remove-sdk <NAME>                    # 移除自定义 SDK(内置不可移除)

键名点分隔: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] 段:

键类型默认说明
proxyUrl空代理 URL,支持 http:///https:///socks5://
ssl_verifyBooltrue是否校验 TLS 证书;自签名/内网镜像可设 false
connect_timeoutU32 [1,600]30连接超时秒数
cache_ttl_secsU32 [0,86400]3600远程版本缓存 TTL 秒,0=总是拉最新
github_tokenToken空GitHub PAT,提升 API 限速(60/hr→5000/hr),输出脱敏

远程版本列表采用「缓存优先 + TTL」:未过期用本地缓存,过期才请求 API;API 失败退化为返回过期缓存,离线可用。

[[sdk]] 段(每个 SDK 一条,内置 5 个 + 用户自定义):

键说明
nameSDK 唯一名称
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
UrlTemplateURL 模板,{xxx} 占位符替换为占位串后能通过 URL 校验
Booltrue/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>] \                  # 省略 = 二进制在根目录;传值须是简单目录名(bin/Scripts),不含 /\分隔符
  [--version-url <URL>] \              # 不填 = 只支持精确版本安装,不支持模糊匹配与 list -r
  [--version-fallback-url <URL>] \
  [--download-fallback-url <URL_TEMPLATE>] \
  [--extra-var KEY=VALUE] \            # 可重复,值支持占位符
  [--extra-path <PATH>]                # 可重复,相对符号链接目录

注册后即像内置 SDK 一样用:sdkm i mytool 1.2.3 / s mytool 1.2.3 / c mytool / ls 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版本发现源下载源
JavaAdoptium available_releases APIAdoptium binary latest API({feature_version}/{os}/{arch})
Node.jsnodejs.org/dist/index.jsonnodejs.org/dist/{version}/...({os}=win/darwin/linux)
Pythonastral-sh uv download-metadata(备源 GitHub API)python-build-standalone releases({release_tag}/{platform})
Maven(无)dlcdn.apache.org/maven/...({version}/{ext})
Gogo.dev/dl/?mode=jsongo.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 内部错误,其余是用户错误(路径不对、版本不存在、权限不足等)。

# bash:成功才继续
sdkm i java 21 && sdkm c

# PowerShell:
sdkm s java 17
if ($LASTEXITCODE -ne 0) { Write-Host "切换失败" }

# bash:
sdkm s java 17
if [ $? -ne 0 ]; then echo "切换失败"; fi

注意:sdkm ls <sdk> 和 sdkm ls <sdk> -r 进入交互式 TUI,不适合脚本;非交互场景用不带 SDK 名的 sdkm ls(打印后退出码 0)或直接 i/s/rm -y。

agent 操作建议

  • 先检查是否已装:sdkm --version;没有则按安装 sdkm装(优先用 scripts/ 下的安装脚本)。
  • 前提:装好后跑过 sdkm init;Windows 下 init/switch 需管理员权限运行。
  • 优先非交互命令:agent 通常不在 TUI 里操作,直接用 i/s/rm -y/c/ls(不带 SDK 名)。
  • 切版本前先确认本地有没有:sdkm ls <sdk> 看本地;要装新的用 i(默认自动切换);不要的版本用 sdkm rm <sdk> <ver> -y 卸载。
  • 改配置优先用 sdkm config set 而不是直接编辑文件——有类型校验和回滚。批量改才用 config edit。
  • 失败别慌:switch 和 config 操作失败会自动回滚;输出里若出现 GitHub issue URL 提示,是不可由用户解决的内部错误(BugReport 标记),可反馈到 https://github.com/borenchan/sdkmate/issues 。
  • 可移植:sdkm home 跟着可执行文件走,整目录拷到别处(含 store/、config.toml)即用,配置和已装 SDK 一并带走。

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

이 스킬의 문제 신고