# ideam-cli
**Repository Path**: cc123hh/ideam-cli
## Basic Information
- **Project Name**: ideam-cli
- **Description**: IDEA Java 项目命令行管理器:启动、停止、重启、日志,一条命令,零依赖
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-11-14
- **Last Updated**: 2026-11-14
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
ideam
在终端里把 IDEA 的 Java 项目管起来:启动、停止、重启、看日志,一条命令。
零依赖 · 单文件脚本 · 只杀自己启动的进程,绝不误伤 IDEA
---
## 📑 目录
- [快速开始](#-快速开始)
- [它解决什么问题](#-它解决什么问题)
- [安装](#-安装)
- [命令一览](#-命令一览)
- [设计要点](#-设计要点)
## 🚀 快速开始
```console
$ ideam add my-app --dir ~/Projects/my-app --port 8080 \
--jdk 21 --profile dev --from-log
已注册 my-app
$ ideam start my-app
[my-app] 增量编译中(--no-build 可跳过)…
[my-app] 启动中 PID 68446,日志 ~/.local/state/ideam/logs/my-app.log
[my-app] 就绪(第 2 轮探测,端口 8080 可达)
$ ideam list
名称 状态 PID 端口 主类
my-app managed 68446 8080 com.example.MyApplication
```
`--from-log` 填 IDEA 控制台第一行启动命令所在的日志文件,classpath 与主类自动提取,一次注册永久使用。
## 🤔 它解决什么问题
IDEA 管理的 Spring Boot 项目,服务生命周期被锁在图形界面里:agent / CI / 远程终端想重启一下后端,要么打开 IDEA 点按钮,要么手拼一长串 `java -classpath` 命令。`ideam` 把这件事翻译成四条命令:
- **classpath 自动提取**:IDEA 启动命令里的 classpath(含全部依赖与模块产物)从运行日志一次性提取,持久存入 `~/.config/ideam/projects.json`;
- **构建环境对齐**:按项目注册的 JDK 版本编译(规避系统 JDK 过新导致 Lombok 失效等环境坑),启动前自动增量编译(`--no-build` 可跳过);
- **就绪轮询**:启动后按端口探测直到服务可达,失败时自动回放日志尾部定位原因;
- **进程归属保护**:只管理本工具启动的进程(pidfile 记录);端口被 IDEA 或其他途径占用时标注 `external` 并拒绝操作,绝不误杀。
## 📦 安装
```bash
git clone https://gitee.com/cc123hh/ideam-cli.git
ln -sf $(pwd)/ideam-cli/ideam.py ~/.local/bin/ideam
```
要求:Python 3.10+(纯标准库,无第三方依赖)、macOS/Linux。
## ⌨️ 命令一览
| 命令 | 作用 |
|------|------|
| `ideam list` | 所有注册项目与运行状态(managed / external / stopped) |
| `ideam add <名> --dir <目录> [选项]` | 注册项目,`--from-log` 提取 classpath |
| `ideam start <名> [--no-build]` | 启动(默认先增量编译) |
| `ideam stop <名>` | 优雅停止(SIGTERM → 超时 SIGKILL) |
| `ideam restart <名> [--no-build]` | 重启 |
| `ideam status [名]` | 状态详情:PID、HTTP 探测、日志路径 |
| `ideam logs <名> [-f] [-n 行数]` | 查看 / 跟踪启动日志 |
| `ideam update-classpath <名> --from-log <日志>` | 依赖大变动后刷新 classpath |
| `ideam set <名> --port/--jdk/--profile/...` | 修改注册项 |
| `ideam outdated <名>` | 依赖体检:扫描全部 pom,对比 Maven Central |
| `ideam doctor <名>` | 环境体检:JDK 实测 / Maven / 资源过滤残留 / classpath 时效 |
| `ideam remove <名>` | 移除注册(不影响运行中进程) |
### 🔍 断点调试(JDWP)
注册调试端口后,启动的 JVM 自动挂上 JDWP agent,IDEA「Remote Debug」、VSCode 或 `jdb` 直接 attach,`suspend=n` 不阻塞启动:
```console
$ ideam set my-app --debug-port 5005
$ ideam restart my-app
$ ideam status my-app
JDWP 调试: 5005(可 attach)—— jdb -attach 5005 或 IDE Remote Debug
```
下次 restart 生效;不注册 debug_port 则行为与之前完全一致。
### 🛠️ 断点抓值(debug)
一行命令完成「设断点 → 触发 → 抓变量 → 放行」,全程无需打开 IDEA:
```console
$ ideam debug my-app --break "com.example.Foo.handleThing" \
--trigger "curl -s http://localhost:8080/api/thing" \
-p "request.getId()" -p "principal.getName()"
| 断点命中: "线程=http-nio-8080-exec-1", Foo.handleThing(), 行=42
| 方法参数:
| request = instance of com.example.ThingRequest
| principal = instance of UsernamePasswordAuthenticationToken
| principal.getName() = "1"
```
- `--break`:jdb 语法断点(类全限定名.方法);`--trigger`:断点就绪后自动执行的命令(curl / 脚本均可),不带则等待外部触发
- `-p`:命中后求值的表达式,可重复;默认输出 `where` 调用栈 + `locals` 全部变量
- 实现驱动 JDK 自带的 jdb,经 **pty** 交互(jdb 输出接管道是全缓冲,pty 才能实时逐行读);放行用 `cont`,调试会话结束服务无感继续
- 前置:`ideam set <名> --debug-port <端口>` + restart(挂 JDWP),`ideam status` 可确认「可 attach」
### 🩺 依赖与环境体检
```console
$ ideam outdated my-app # 扫描全部 pom(含多模块),对比 Maven Central
❗ org.example:some-lib 当前 1.2.0 落后 → 1.3.0
org.example:another-lib 当前 2.4.1 本地更新(索引滞后,标记 2.3.9)
$ ideam doctor my-app # 起不来 / 行为异常时先跑它
✓ JDK 21: 位于 /Library/Java/...(实际 21) # java -version 实测,不信注册值
✓ 资源过滤: target 下无 @xx@ 残留 # 占位符残留会导致启动即死
全部 7 项通过,环境健康
```
版本比对内置三层防误报:**预发布版**(alpha/beta/rc)不算落后、**Central 历史垃圾版本号**(如 commons-io 的 `20030203.000550`)标人工确认、**索引滞后**(本地比「最新」还新)不告警——search.maven.org 的 `latestVersion` 字段滞后严重,以本地实测为准。
## 🧭 设计要点
- **配置**:`~/.config/ideam/projects.json`(XDG)
- **运行状态**:`~/.local/state/ideam/`(pidfile 与日志,日志每次启动自动轮转)
- **双栈探测**:Java 进程可能只监听 IPv6 环回,端口与 HTTP 探测同时尝试 `::1` 与 `127.0.0.1`
- **优雅退出**:SIGTERM 等 5 秒不退再 SIGKILL
- **Maven profile 感知**:注册时记下 profile,编译时自动带上(`application.yml` 的 `@xx@` 占位符依赖资源过滤,漏了会启动即死)