dsh-api-runner 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +391 -2
- package/client/client.js +1604 -0
- package/cordis.patch.yml +9 -0
- package/docs/screenshot-service.png +0 -0
- package/docs/screenshot-settings.png +0 -0
- package/docs/verified-dsh-version.png +0 -0
- package/dsh-api-runner.example.yml +92 -0
- package/package.json +75 -4
- package/scripts/stage.mjs +78 -0
- package/src/api.js +194 -0
- package/src/config.js +265 -0
- package/src/java-runner.js +623 -0
- package/src/java.js +658 -0
- package/src/log.js +209 -0
- package/src/main.js +586 -0
- package/src/ops.js +1039 -0
- package/src/project-store.js +334 -0
- package/src/restart.js +518 -0
- package/src/service.js +329 -0
- package/src/settings.js +109 -0
- package/src/util.js +182 -0
- package/test/client.mjs +109 -0
- package/test/java.mjs +298 -0
- package/test/managed.mjs +137 -0
- package/test/plugin.mjs +433 -0
- package/test/smoke.mjs +443 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Moz (lhhzmz229)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,392 @@
|
|
|
1
|
-
#
|
|
1
|
+
# dsh-api-runner
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](./LICENSE)
|
|
4
|
+
[](https://nodejs.org)
|
|
5
|
+
[](https://github.com/topics/dsh-plugin)
|
|
6
|
+
|
|
7
|
+
<!-- 被 dsh-plugin.org 收录后,把下面这行取消注释(slug 用详情页地址里的 owner/slug):
|
|
8
|
+
[](https://dsh-plugin.org/plugins/lhhzmz229/dsh-api-runner)
|
|
9
|
+
-->
|
|
10
|
+
|
|
11
|
+
DSH 插件:把「后端接口清单」「本地服务启停」「日志增量读取」三件事交给模型直接调用,并提供一个侧边栏面板做人工配置,形成「改完自己验」的闭环。
|
|
12
|
+
|
|
13
|
+
- **侧边栏面板「接口调试」**:可视化增删改接口配置、登录并保存 token、点按钮试调用、列出本机所有运行中的 Java 服务并一键设为 baseUrl。
|
|
14
|
+
- **可配置接口**:在 YAML 里声明接口,或在面板里点选添加(方法、URL、请求头、body 模板),模型按 id 调用,占位符自动替换。
|
|
15
|
+
- **登录态**:把某个接口标记为登录接口,调用成功后按 `tokenPath` 取出 token 存进项目档,后续接口自动注入 `Authorization`,不用手工复制。
|
|
16
|
+
- **服务重启**:`managed` 模式由插件托管进程(能 start/stop/restart,DSH 重启后服务仍在跑);`observe` 模式进程由 IDEA 启动,插件只轮询健康检查(配合 IDEA 的 restart 按钮)。
|
|
17
|
+
- **日志读取**:按文件 + 字节偏移增量 tail,支持正则过滤、等待特征出现,游标持久化,服务重启不丢。
|
|
18
|
+
|
|
19
|
+
> **能力分类**:开发与运维 | **平台**:Windows / macOS / Linux | **许可证**:MIT
|
|
20
|
+
> **一句话价值**:装上后模型能在对话里自己调接口、启停本地服务、读日志,改完代码自己验证。
|
|
21
|
+
|
|
22
|
+
## 效果
|
|
23
|
+
|
|
24
|
+
侧边栏「接口调试」的服务页:插件托管的 Java 服务按「已接管 / 运行中 / 已保存 / 已忽略」分组,业务 HTTP 端口与 Sentinel 之类的私有协议端口分开标注,每行可直接查询详情、重启、停止、保存启动配方。
|
|
25
|
+
|
|
26
|
+

|
|
27
|
+
|
|
28
|
+
「接口调试」的设置页:数据目录、默认工作区、Maven 主路径、接口基地址。
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
> 截图中的服务名、包名与本机路径做了模糊处理。验证环境:DSH `V0.2.1-alpha.1` / Windows([版本截图](./docs/verified-dsh-version.png))。
|
|
33
|
+
|
|
34
|
+
## 安装
|
|
35
|
+
|
|
36
|
+
装好之后,模型可以在对话里直接列接口、调接口、启停/重启本地服务、按字节偏移增量读日志,
|
|
37
|
+
形成「改完自己验」的闭环,不用再手工复制 curl、切窗口重启服务、翻日志找报错。
|
|
38
|
+
|
|
39
|
+
### 从 npm 安装(推荐)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
dsh plugin --profile web add dsh-api-runner
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
npm 上还没发这个版本时,先用下面的源码方式装;发布之后这条就是最短路径,也是 DSH「插件中心」里一键安装的形式。
|
|
46
|
+
|
|
47
|
+
### 从 GitHub 源码安装
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
dsh plugin --profile web add github:lhhzmz229/dsh-api-runner
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
DSH 会把仓库 clone 到 profile 的 `node_modules` 下。写成带包名的
|
|
54
|
+
`dsh-api-runner@github:lhhzmz229/dsh-api-runner` 也等价。这条依赖本机有 `git`;装完重启 DSH(或把 `dsh-api-runner` bundle 关掉再打开)生效。
|
|
55
|
+
|
|
56
|
+
### 本地开发:link 安装
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# 在插件目录下装依赖(只有一个运行时依赖 yaml;npm cache 目录无写权限时用 --cache 指到可写目录)
|
|
60
|
+
npm install
|
|
61
|
+
|
|
62
|
+
# 以 link 方式装进 desktop profile
|
|
63
|
+
dsh plugin --profile desktop add "link:/绝对路径/到/dsh-api-runner"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Windows 下 link 路径写成 `link:D:/path/to/dsh-api-runner` 也等价。
|
|
67
|
+
|
|
68
|
+
`dsh` 命令不在 PATH 时,用桌面版自带运行时(路径按你的安装位置调整):
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Windows
|
|
72
|
+
"<DSH 安装目录>/resources/runtime/bin/node.cmd" "<DSH 安装目录>/resources/app.asar/dsh/bin/dsh.js" plugin --profile desktop add "link:..."
|
|
73
|
+
# macOS / Linux
|
|
74
|
+
"<DSH 安装目录>/resources/runtime/bin/node" "<DSH 安装目录>/resources/app.asar/dsh/bin/dsh.js" plugin --profile desktop add "link:..."
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
装好后 profile 的 `package.json` 会出现依赖 `dsh-api-runner` 与 `dsh.profile.bundles` 里的 `dsh-api-runner` 条目;
|
|
78
|
+
插件自己的 `cordis.patch.yml` 负责把 entry 插进依赖树。
|
|
79
|
+
|
|
80
|
+
侧边栏页签依赖 **`dsh-better-sidebar`** 插件(`dsh.client.inject` 里声明了它)。没装这个插件时,
|
|
81
|
+
host 侧的工具(`ApiRunner`)与 HTTP 路由照常工作,只是不出现「接口调试」页签。
|
|
82
|
+
|
|
83
|
+
## 权限与风险
|
|
84
|
+
|
|
85
|
+
安装前请确认这些行为都在你的预期内:
|
|
86
|
+
|
|
87
|
+
| 项目 | 说明 |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| 执行本地命令 | 用 `jps` / `jcmd` / `mvn` / `netstat` / `lsof` 发现、接管、启停 Java 进程;`managed` 模式会按配置直接拉起与结束子进程 |
|
|
90
|
+
| 发起 HTTP 请求 | 只请求你在 YAML 或面板里配置的 URL,可按配置注入 `Authorization` 头 |
|
|
91
|
+
| 读取本地文件 | 读取你配置的日志文件(按字节偏移增量读),内容只回给模型,不上传 |
|
|
92
|
+
| 写入本地文件 | `<数据目录>/` 下的状态与 UI 配置;面板保存的 token 明文落在 `api-runner-ui.json`(见「已知限制」) |
|
|
93
|
+
| 外联上报 | 无遥测、无统计上报,插件自身不发起任何外部请求 |
|
|
94
|
+
|
|
95
|
+
## 兼容与运行要求
|
|
96
|
+
|
|
97
|
+
- **DSH**:`>=0.1.0-rc.6 <0.2.0-0 || >=0.2.0-rc.1 <0.3.0-0`
|
|
98
|
+
- **已验证环境**:DSH `0.2.1-alpha.1` / Windows
|
|
99
|
+
- **Node.js**:`>=20`
|
|
100
|
+
- **平台**:Windows / macOS / Linux(进程与端口发现按平台分流)
|
|
101
|
+
- **可选依赖**:`dsh-better-sidebar`(提供侧边栏「接口调试」页签,不装则只有模型侧工具与 HTTP 路由)
|
|
102
|
+
- **可选环境**:JDK(`jps` / `jcmd`,用于 Java 服务发现与接管)、Maven(`mvn`,用于接管时编译)
|
|
103
|
+
|
|
104
|
+
## 配置
|
|
105
|
+
|
|
106
|
+
配置文件按「内置默认 → 全局 → 项目」合并,后者覆盖前者:
|
|
107
|
+
|
|
108
|
+
| 位置 | 说明 |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| `${DSH_HOME}/api-runner.yml` | 全局,所有项目生效 |
|
|
111
|
+
| `<项目 cwd>/.dsh/api-runner.yml` | 项目级,建议放这个 |
|
|
112
|
+
|
|
113
|
+
文件名也支持 `api-runner.yaml` / `dsh-api-runner.yml`。**改完保存即生效**(按 mtime + size 缓存),不用重启 DSH。
|
|
114
|
+
|
|
115
|
+
完整示例见 [dsh-api-runner.example.yml](./dsh-api-runner.example.yml),最小可用示例:
|
|
116
|
+
|
|
117
|
+
```yaml
|
|
118
|
+
defaults:
|
|
119
|
+
timeoutMs: 30000
|
|
120
|
+
headers:
|
|
121
|
+
Content-Type: application/json
|
|
122
|
+
|
|
123
|
+
env:
|
|
124
|
+
TOKEN: ${DEV_TOKEN} # 引用环境变量
|
|
125
|
+
|
|
126
|
+
apis:
|
|
127
|
+
- id: get-user
|
|
128
|
+
name: 查询用户
|
|
129
|
+
method: GET
|
|
130
|
+
url: http://127.0.0.1:8080/api/users/{id}
|
|
131
|
+
headers:
|
|
132
|
+
Authorization: "Bearer ${TOKEN}"
|
|
133
|
+
|
|
134
|
+
- id: create-order
|
|
135
|
+
method: POST
|
|
136
|
+
url: http://127.0.0.1:8080/api/orders
|
|
137
|
+
body:
|
|
138
|
+
userId: "{userId}"
|
|
139
|
+
amount: "{amount}"
|
|
140
|
+
|
|
141
|
+
services:
|
|
142
|
+
# 插件托管:mvnw spring-boot:run
|
|
143
|
+
- id: app
|
|
144
|
+
mode: managed
|
|
145
|
+
cwd: ../
|
|
146
|
+
command: ./mvnw.cmd
|
|
147
|
+
args: ["spring-boot:run"]
|
|
148
|
+
logPath: ./logs/app.log
|
|
149
|
+
startupTimeoutMs: 90000
|
|
150
|
+
health:
|
|
151
|
+
url: http://127.0.0.1:8080/actuator/health
|
|
152
|
+
|
|
153
|
+
# IDEA 里跑,插件只观测(配合 IDEA restart 按钮)
|
|
154
|
+
- id: idea-app
|
|
155
|
+
mode: observe
|
|
156
|
+
health:
|
|
157
|
+
url: http://127.0.0.1:8080/actuator/health
|
|
158
|
+
ports: [8080]
|
|
159
|
+
|
|
160
|
+
logs:
|
|
161
|
+
- id: app-log
|
|
162
|
+
path: ./logs/app.log
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 两种占位符
|
|
166
|
+
|
|
167
|
+
| 写法 | 何时展开 | 用途 |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| `${NAME}` | 加载配置时 | 环境变量 / `env:` 段里定义的值,用于 URL、header、command |
|
|
170
|
+
| `{name}` | 调用接口时 | 模型通过 `params` 传入,替换 URL 与 body 里的同名占位 |
|
|
171
|
+
|
|
172
|
+
`headers` 里的 `${VAR}` 会展开成真实值,但在返回给模型的 `request.headers` 里按名字脱敏(`token`/`secret`/`password`/`key`/`auth` 等一律 `demo***3456`)。
|
|
173
|
+
|
|
174
|
+
## 工具与动作
|
|
175
|
+
|
|
176
|
+
模型通过 `ApiRunner` 工具调用,`action` 取值:
|
|
177
|
+
|
|
178
|
+
| action | 作用 |
|
|
179
|
+
| --- | --- |
|
|
180
|
+
| `describe` | 列出可用接口、服务、日志(含每个接口需要的参数名),不返回 header 值 |
|
|
181
|
+
| `call` | 按 `api_id` 调接口,`params` 传占位符;已保存 token 会自动注入 |
|
|
182
|
+
| `login` | 调登录接口并把 token 存进项目档(`api_id` 指向配了 `login.tokenPath` 的接口) |
|
|
183
|
+
| `java` | 本机 Java 服务:`java_action` = `list` / `detail`(详情+日志)/ `start`(接管启动)/ `stop` / `restart` / `log` / `ignore` / `unignore` / `save`(保存启动配方)/ `unsave` / `start_saved`(按配方启动,不需要 IDEA 里先有进程)/ `settings`(读或改全局设置)/ `status`,详见下文 |
|
|
184
|
+
| `service` | `service_action` = `start` / `stop` / `restart` / `wait` / `status` |
|
|
185
|
+
| `log` | 增量读日志(`pattern` 正则过滤,`max_bytes` / `max_lines` 限流) |
|
|
186
|
+
| `wait_log` | 等某个特征出现在日志里(`timeout_ms` 超时) |
|
|
187
|
+
| `reset_log` | 把游标重置到文件末尾 |
|
|
188
|
+
| `verify` | 一条命令串起「重启 → 等日志特征 → 调接口」,返回分步结果 |
|
|
189
|
+
|
|
190
|
+
`verify` 只有在所有步骤都成功(observe 模式下无法自动重启除外)才返回 `ok: true`;失败时给出 `code`(如 `STEP_FAILED:log`)与可读 `message`。
|
|
191
|
+
|
|
192
|
+
## 典型流程
|
|
193
|
+
|
|
194
|
+
```mermaid
|
|
195
|
+
flowchart LR
|
|
196
|
+
M["模型 / DSH 对话"] -->|"ApiRunner.call"| API["后端接口<br/>YAML 里配置的 URL"]
|
|
197
|
+
M -->|"ApiRunner.service start/stop/restart"| SVC["本地服务进程<br/>managed 托管 / observe 观测"]
|
|
198
|
+
M -->|"ApiRunner.log / wait_log"| LOG["日志文件<br/>按字节偏移增量读"]
|
|
199
|
+
M -->|"ApiRunner.verify"| V["重启 → 等日志特征 → 调接口"]
|
|
200
|
+
SVC -->|"stdout / stderr 追加"| LOG
|
|
201
|
+
UI["侧边栏「接口调试」"] -->|"增删改接口 · 登录存 token · 试调用"| API
|
|
202
|
+
UI -->|"列出本机 Java 服务 · 接管 · 重启 · 看日志"| SVC
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
典型的一轮「改完自己验」:改代码 → `service restart` → `wait_log` 等 `Started Application` →
|
|
206
|
+
`call` 打接口看返回 → 不对就 `log` 拉最近几百字节定位报错。也可以直接用 `verify` 一条串起来。
|
|
207
|
+
|
|
208
|
+
## 侧边栏面板
|
|
209
|
+
|
|
210
|
+
插件在右侧栏注册了一个「接口调试」标签页(`betterSidebar.registerTab`,单个实例)。右侧栏很窄,所以内容分成三个页签,顶部固定、下方独立滚动,一次只看一块:
|
|
211
|
+
|
|
212
|
+
**接口页签**
|
|
213
|
+
- 顶部是**按项目分类**的二级页签(只有存在第二个项目时出现):第一个永远是当前工作区,后面是其它已知项目(显示成末段目录名,重名时带上上一级;页签多了横向滚动)。二级页签没有灰底容器、选中项是品牌色实心块,和顶部那排灰底分段控件一眼能分开。
|
|
214
|
+
- 项目清单来自「当前会话的工作区 + 设置里的默认工作区 + 面板里存过的所有项目」,所以还没配过接口的项目也会出现——不然切不过去。
|
|
215
|
+
- 切到别的项目后,接口列表、基地址、token、保存/编辑/删除**都作用于那个项目自己的档**(请求带 `project`,后端按项目桶读写),不会污染当前工作区。要回到自己项目点第一个页签。
|
|
216
|
+
- 当前项目下:顶部筛选框可按 id / 名称 / 地址过滤;右侧「新增」展开内联编辑表单。
|
|
217
|
+
- 每条接口显示方法徽章、名称、地址(host 弱化、路径强化)、来源徽章(`YAML` = 来自配置文件,无徽章 = 面板新建)、占位参数列表。
|
|
218
|
+
- 行内操作:「测试」(用示例参数调用一次)、「登录并保存」(仅登录接口)、复制地址、清除 token、编辑、删除(只允许删面板自己建的)。
|
|
219
|
+
- 调用结果是一张卡片:状态码、耗时、响应大小,可在「响应 / 响应头 / 请求」之间切换,带复制与关闭。
|
|
220
|
+
- **编辑表单**:id / 名称 / 方法 / URL / baseUrl / 说明 / 请求头(JSON)/ body(JSON)/ 示例参数(JSON)/ 用哪个 token;勾「是登录接口」后展开 tokenPath(如 `data.token`)、注入头(默认 `Authorization`)、前缀(默认 `Bearer `)。
|
|
221
|
+
|
|
222
|
+
**服务页签**
|
|
223
|
+
- 每 5 秒刷新。服务页顶部还有一排**二级页签**(**已接管** / **运行中** / **已保存** / **已忽略**)。这一排样式和顶部「接口 / 服务 / 设置」不同:没有灰底容器,选中项是品牌色实心块,用来区分"页面级"和"分组级"两层导航。一次只看一组,不再纵向堆四块。
|
|
224
|
+
- 如果「已接管」是空的、而确实有服务在跑,进入服务页时会自动落到「运行中」,不用多点一次。
|
|
225
|
+
- 每行显示 pid、主类、端口、归属标记、debug 端口、`spring.profiles.active`。
|
|
226
|
+
- **端口带角色标注**:一个服务常常监听两个端口——业务 HTTP 端口(如 8080)和 **Sentinel 规则端口**(如 8719,回 `400 Invalid command`,不能当接口地址)。插件会逐个探测,把真正讲 HTTP 的标成 `HTTP` 并用作 baseUrl,Sentinel 端口灰显标注。
|
|
227
|
+
- 接管/重启时如果进程参数里读不到 `server.port`(端口常写在配置中心或外部配置文件里),插件会在进程起来后持续扫描真实监听端口并**回填到托管记录**,所以「已接管」里的端口与 `HTTP` 标注不会因为「参数里没端口」而空着。
|
|
228
|
+
- **接管启动** = 先 `mvn` 增量编译,再结束 IDEA 那个进程,然后用**同样的 classpath 和主类**重新拉起,交给插件托管;此后可在面板里停止、重启、看实时日志。
|
|
229
|
+
- **保存** 把当前进程的 classpath / 主类 / JVM 参数存成一套配方。存过之后**不需要 IDEA 里先有进程**:到「已保存」页签里点「启动」即可(会先编译,端口被占会提示你先停 IDEA 那份)。
|
|
230
|
+
- **查询详情**进入日志页:托管进程读插件写的 stdout 文件,IDEA 进程读它自己的 logback 文件(`<工作目录>/logs/<服务名>/info.log`)。
|
|
231
|
+
- 打开时默认只读**最后 200 行**(可点 100 / 200 / 500 / 1000 快速切换,右侧输入框还能自己填 1–5000,回车或失焦生效),之后按字节偏移增量追加,1.5 秒静默刷新且不打断你手动滚动。
|
|
232
|
+
- 支持**自动换行**开关(默认开)、在插件输出多段日志与 info.log / error.log 之间切换。
|
|
233
|
+
- **每次启动写一个独立日志文件**(`java-logs/<服务名>/<时间戳>.log`),重启多次不会混在同一个文件里,历史段可以单独翻。
|
|
234
|
+
- 「忽略」只是把这个服务从「运行中」里收起来,**不影响进程本身**,可在「已忽略」页签里点「取消忽略」恢复;已忽略的行只保留「取消忽略」一个动作,避免误点接管。
|
|
235
|
+
- 「用作 baseUrl」把项目接口基地址设为 `http://127.0.0.1:<HTTP 端口>`。
|
|
236
|
+
|
|
237
|
+
**设置页签**
|
|
238
|
+
- 接口基地址(接口自己没填 baseUrl 时用它)、已保存 token 列表(脱敏值 + 清除)、配置来源(项目路径、项目 key、命中的 YAML 文件)。
|
|
239
|
+
|
|
240
|
+
**DSH 设置里的插件主页**:设置 → 「接口调试」页(`settings.section`,order 80),放跨项目的全局项——**默认工作区**(没有会话上下文时用它当项目目录)、**Maven 主路径**(接管启动前编译用;留空自动探测 MAVEN_HOME → PATH → IDEA 自带,并读取项目 `.idea` 里的 settings.xml 与本地仓库)与**数据目录**(必须是绝对路径,改完后新日志立刻写过去;留空即回到 `DSH_HOME`)。
|
|
241
|
+
|
|
242
|
+
**数据位置**:面板数据存在 `${DSH_HOME}/api-runner-ui.json`(按项目 key 分开),YAML 里的接口与面板接口**按 id 合并**:面板改的同名 id 覆盖 YAML 的值,面板新增的与 YAML 的并存。
|
|
243
|
+
|
|
244
|
+
### 登录接口怎么写
|
|
245
|
+
|
|
246
|
+
```yaml
|
|
247
|
+
apis:
|
|
248
|
+
- id: login
|
|
249
|
+
method: POST
|
|
250
|
+
url: /api/login
|
|
251
|
+
baseUrl: http://127.0.0.1:8080
|
|
252
|
+
body:
|
|
253
|
+
username: "{username}"
|
|
254
|
+
password: "{password}"
|
|
255
|
+
login:
|
|
256
|
+
tokenPath: data.token # 从响应 JSON 取 token 的路径,支持 a.b[0].c
|
|
257
|
+
header: Authorization # 存下来后注入到哪个头
|
|
258
|
+
prefix: "Bearer " # 加在 token 前面
|
|
259
|
+
|
|
260
|
+
- id: me
|
|
261
|
+
method: GET
|
|
262
|
+
url: /api/me # 自动带上 Authorization: Bearer xxx
|
|
263
|
+
baseUrl: http://127.0.0.1:8080
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
然后 `ApiRunner { action: 'login', api_id: 'login', params: { username: 'alice', password: 'p@ss' } }`;
|
|
267
|
+
之后调 `me` 就会带 token,也可以在 `call` 里用 `token_from` 临时指定用哪个登录态。
|
|
268
|
+
|
|
269
|
+
`tokenPath` 没写对时不会白跑一趟:登录成功后会在响应里找像 token 的字段,
|
|
270
|
+
只有一个候选就自动用它并保存,同时告诉你该把它改成什么;
|
|
271
|
+
有多个候选则列出来让你选。面板里配置的接口会自动把这个路径写回配置,下次不再提示。
|
|
272
|
+
|
|
273
|
+
### 关于 IDEA 里的服务
|
|
274
|
+
|
|
275
|
+
**推荐做法:接管。** IDEA 起的服务,插件在服务页签里点「接管启动」(或调 `ApiRunner { action: 'java', java_action: 'start', pid }`),流程是:
|
|
276
|
+
1. 从 `jcmd` 读出该进程的 java 路径、工作目录、完整 classpath、主类、JVM 参数;
|
|
277
|
+
2. 用 `mvn -pl <模块> -am compile -DskipTests` 增量编译(模块与 reactor 根从 classpath 里的 `target/classes` 反推;Maven 依次找设置页里配的「Maven 主路径」→ `MAVEN_HOME`/`M2_HOME` → PATH → IDEA 自带)。编译参数会自动带上项目 `.idea/workspace.xml` 里 IDEA 用的 `settings.xml` 与本地仓库(`-s` / `-Dmaven.repo.local`),找不到时退回 Maven 安装目录的 `conf/settings.xml`;
|
|
278
|
+
3. 结束原进程树,等端口释放(Windows 用 `taskkill /T /F`;macOS/Linux 杀进程组 `kill -9 -<pid>`);
|
|
279
|
+
4. 用同样的 classpath/主类重新拉起,日志写 `<数据目录>/java-logs/<主类名>/<时间戳>.log`(每次启动一个文件),等端口健康后返回新 pid。
|
|
280
|
+
|
|
281
|
+
接管后 IDEA 的 Run 窗口会显示该进程「已结束」——因为新进程不再挂在 IDEA 下。但**调试能力没丢**:重启时会把原来的 `suspend=y` 调试参数改写成 `server=y,suspend=n,address=127.0.0.1:<原端口>`,你在 IDEA 里用「Remote JVM Debug」连这个端口就能继续断点。编译失败时不会动原进程。
|
|
282
|
+
|
|
283
|
+
插件启动的进程带 `-DdshApiRunner.runId=<服务名>` 标记,所以服务列表能稳定区分「谁起的」;即使状态文件丢了也能认出来。
|
|
284
|
+
|
|
285
|
+
另外两种模式仍然可用:
|
|
286
|
+
- **IDEA Run/Debug 按钮 + 不想被接管** → 配 `mode: observe`。模型调 `verify` 时不会杀进程,只等健康检查通过;需要重启时你在 IDEA 里点重启,模型调 `service action=wait` 等你起来。
|
|
287
|
+
- **完全交给插件** → 配 `mode: managed`,`command` 写成 `mvnw.cmd spring-boot:run` 这类可拉起的命令。注意 IDEA 和插件不要同时占用同一个端口。
|
|
288
|
+
|
|
289
|
+
## HTTP 接口
|
|
290
|
+
|
|
291
|
+
除工具外,插件还注册了同源路由(需要 DSH 会话认证):
|
|
292
|
+
|
|
293
|
+
- `GET /dsh-api-runner/api/config` → 配置摘要
|
|
294
|
+
- `POST /dsh-api-runner/api/call` → `{ api_id, params }`
|
|
295
|
+
- `POST /dsh-api-runner/api/service` → `{ service_id, service_action }`
|
|
296
|
+
- `POST /dsh-api-runner/api/log` → `{ log_id, ... }`
|
|
297
|
+
- `GET /dsh-api-runner/api/ui` → 面板数据(当前项目的接口与 token 状态、已忽略的 Java 服务、已知项目清单 `projects[]`;带 `?project=<绝对路径>` 可切到别的项目)
|
|
298
|
+
- `POST /dsh-api-runner/api/ui/api` → 保存/覆盖一个面板接口
|
|
299
|
+
- `POST /dsh-api-runner/api/ui/api/delete` → `{ id }`
|
|
300
|
+
- `POST /dsh-api-runner/api/ui/base-url` → `{ baseUrl }`
|
|
301
|
+
- `POST /dsh-api-runner/api/ui/token/clear` → `{ login_id }`
|
|
302
|
+
- `POST /dsh-api-runner/api/login` → `{ api_id, params }`
|
|
303
|
+
- `GET /dsh-api-runner/api/java` → 本机 Java 服务列表(含每个端口的角色、忽略状态、日志路径、已保存配方)
|
|
304
|
+
- `POST /dsh-api-runner/api/java/bind` → `{ binding: { pid, port, mainClass } }`
|
|
305
|
+
- `POST /dsh-api-runner/api/java/unbind` → `{ pid }`
|
|
306
|
+
- `POST /dsh-api-runner/api/java/ignore` → `{ item: { mainClass, name, kind } }` 忽略(只是不显示)
|
|
307
|
+
- `POST /dsh-api-runner/api/java/unignore` → `{ item: { mainClass, name, kind } }`
|
|
308
|
+
- `POST /dsh-api-runner/api/java/start` → `{ pid, port?, compile? }` 接管启动
|
|
309
|
+
- `POST /dsh-api-runner/api/java/stop` → `{ id | pid }`
|
|
310
|
+
- `POST /dsh-api-runner/api/java/restart` → `{ id | pid, compile? }`
|
|
311
|
+
- `POST /dsh-api-runner/api/java/save` → `{ id | pid }` 保存启动配方
|
|
312
|
+
- `POST /dsh-api-runner/api/java/unsave` → `{ id }`
|
|
313
|
+
- `POST /dsh-api-runner/api/java/start-saved` → `{ id, compile?, port?, debug?, timeout_ms? }` 按配方启动
|
|
314
|
+
- `GET /dsh-api-runner/api/java/log?id=<服务名>&from=<字节偏移>` → 插件启动服务的日志增量
|
|
315
|
+
- `GET /dsh-api-runner/api/java/detail?id=<id 或 pid>&source=&from=&lines=&max_bytes=` → 服务详情 + 日志(含可选日志文件清单;不给 `from` 时按 `lines` 取末尾若干行)
|
|
316
|
+
- `GET /dsh-api-runner/api/settings` → 全局设置(默认工作区、Maven 主路径、数据目录、生效目录)
|
|
317
|
+
- `POST /dsh-api-runner/api/settings` → `{ settings: { dataDir?, workspace?, mavenHome? } }`
|
|
318
|
+
|
|
319
|
+
未认证返回 401 JSON(`{ok:false, code:'UNAUTHORIZED'}`)。面板请求带 `x-dsh-session-id` 让 host 解析项目 cwd;没有会话时用 `?cwd=` 或 body 里的 `cwd` 兜底(必须是绝对路径)。
|
|
320
|
+
|
|
321
|
+
## 状态与清理
|
|
322
|
+
|
|
323
|
+
- 运行状态:`<数据目录>/api-runner-state.json`,`logs` 与 `services` 两个命名空间互不覆盖。
|
|
324
|
+
- 面板数据:`<数据目录>/api-runner-ui.json`,存 baseUrl、面板接口、登录态、token(含明文,注意别泄漏)、已忽略的 Java 服务清单、已保存的启动配方。
|
|
325
|
+
- 插件设置:`<数据目录>/api-runner-settings.json`,存默认工作区、Maven 主路径与自定义数据目录(本身永远在 `DSH_HOME` 下,否则会先有鸡还是先有蛋)。
|
|
326
|
+
- Java 服务日志:`<数据目录>/java-logs/<服务名>/<时间戳>.log`,每次启动一个文件。
|
|
327
|
+
- 数据目录默认是 `DSH_HOME`,可在 DSH 设置 →「接口调试」里改成任意绝对路径。
|
|
328
|
+
- 卸载插件不会杀 `managed` 服务(故意设计,避免 DSH 重启把后端带停);需要时手动停或调 `service_action=stop`。
|
|
329
|
+
|
|
330
|
+
## 开发
|
|
331
|
+
|
|
332
|
+
```powershell
|
|
333
|
+
node test/smoke.mjs # 单元 + 集成(起临时 http server 当后端)
|
|
334
|
+
node test/plugin.mjs # 插件入口契约 + 面板 HTTP 路由(桩 ctx)
|
|
335
|
+
node test/client.mjs # client bundle 形态(__ModuleLoader__ + registerTab)
|
|
336
|
+
node test/managed.mjs # managed 服务启停(真起 node 进程)
|
|
337
|
+
node test/java.mjs # 接管 IDEA 服务(真起 JVM:快照/剥调试参数/编译/停止/重启)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
### 改完源码要重新装载(重要)
|
|
341
|
+
|
|
342
|
+
DSH 用 ESM 动态 import 加载插件,Node 按 **模块 URL** 缓存。在同一个 DSH 进程里关掉再打开 bundle 只会重跑 `apply()`,
|
|
343
|
+
**不会重新 import 模块**,所以直接改 `src/` 看不到任何变化。必须让入口 URL 变化:
|
|
344
|
+
|
|
345
|
+
```powershell
|
|
346
|
+
node scripts/stage.mjs # 复制 src/ → build/vN/,并改写 cordis.patch.yml 的入口 URL
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
然后到 DSH 里把 `dsh-api-runner` bundle 关掉再打开。`scripts/stage.mjs --clean` 会顺手清理旧版本目录。
|
|
350
|
+
|
|
351
|
+
反过来,**提交代码前要跑 `node scripts/stage.mjs --release`**:它把 `cordis.patch.yml` 的入口从本机 `build/vN/main.js` 的 `file://` 路径改回包名 `dsh-api-runner`,这样别人装上才能正常解析入口,仓库里也不留本机绝对路径。
|
|
352
|
+
|
|
353
|
+
## 已知限制
|
|
354
|
+
|
|
355
|
+
- 只支持 HTTP/HTTPS 接口,没有 multipart 文件上传。
|
|
356
|
+
- `managed` 服务的进程发现依赖状态文件里的 pid;pid 被系统回收复用后可能误判存活(`isPidAlive` 只做存在性检查)。
|
|
357
|
+
- 日志按字节读,多字节编码(GBK 等)跨读取边界时可能出现半个字符。
|
|
358
|
+
- 侧边栏面板的接口页签负责「配置 + 试调用」,服务页签负责「列表 + 接管/停止/重启 + 实时日志」;`verify`(重启→等日志→调接口一条龙)仍只在对话里让模型调工具完成。
|
|
359
|
+
- Java 服务发现依赖 `jps`(取 `JAVA_HOME/bin/jps`,找不到就用 PATH 上的 `jps`),没有 JDK 时列表为空并给出提示;端口来源按平台分流(Windows `netstat -ano -p tcp`,macOS/Linux `lsof -nP -iTCP -sTCP:LISTEN`,没有 lsof 时退回 Linux `netstat -tlnp`),同一 pid 多端口时会逐个做 HTTP 探测挑出真正讲业务协议的端口。
|
|
360
|
+
- Maven 探测顺序:设置里的「Maven 主路径」→ `MAVEN_HOME` → `M2_HOME` → `PATH` → IDEA 自带 Maven(三个平台都会找 IDEA 进程路径);找不到 `mvn` 时接管启动会跳过编译并给出提示,服务仍按原参数拉起。
|
|
361
|
+
- 接管依赖 `jcmd`(同一个 JDK),且要求原进程是标准启动器起的(有 classpath)。用 `-jar` 或 argfile 启动的进程无法原样还原。
|
|
362
|
+
- 接管后进程不再挂在 IDEA 下(IDEA Run 窗口显示已结束),需用「Remote JVM Debug」连原调试端口继续断点。
|
|
363
|
+
- 面板保存的 token 是明文落在 `<数据目录>/api-runner-ui.json`(只在 UI 与工具输出里脱敏),本机共用的场景请自行注意。
|
|
364
|
+
- 按配方启动要求配方里有完整的 classpath(所以得先「保存」过一次);`.cmd`/`.bat` 的 Maven 用 `cmd.exe` 调用,路径含空格已处理。
|
|
365
|
+
- 日志首屏按行读末尾,历史大文件(几百 MB)会被截断到所选行数;要看更早的内容请切换日志文件或加大行数。
|
|
366
|
+
|
|
367
|
+
## 常见问题(排查)
|
|
368
|
+
|
|
369
|
+
**装完侧边栏没有「接口调试」页签?**
|
|
370
|
+
面板依赖 `dsh-better-sidebar`。它没装时 host 侧工具与 HTTP 路由照常工作,只是不出现页签;装上后硬刷新页面(Ctrl/Cmd+Shift+R),通常不用重启 DSH。
|
|
371
|
+
|
|
372
|
+
**工具列表里没有 `ApiRunner`?**
|
|
373
|
+
先看 profile 的 `package.json` 里有没有 `dsh-api-runner`、`dsh.profile.bundles` 里有没有对应条目、bundle 是否处于启用状态,再确认 DSH 版本在兼容范围内。
|
|
374
|
+
|
|
375
|
+
**别人装上却报「找不到入口 / build/vN/main.js 不存在」?**
|
|
376
|
+
仓库里的 `cordis.patch.yml` 被 `scripts/stage.mjs` 写成了本机 `file://` 路径。提交前跑 `node scripts/stage.mjs --release` 改回包名,再提交。
|
|
377
|
+
|
|
378
|
+
**`ApiRunner { action: 'java', java_action: 'list' }` 返回空列表?**
|
|
379
|
+
服务发现依赖 `jps`(优先 `JAVA_HOME/bin/jps`,其次 PATH)。没有 JDK 时列表为空并给出提示;有 JDK 仍为空,检查目标服务是否用标准启动器起的。
|
|
380
|
+
|
|
381
|
+
**接管启动失败 / 端口一直没起来?**
|
|
382
|
+
接管要求 `jcmd` 能读到完整 classpath,`-jar` 或 argfile 启动的进程无法原样还原;原端口被 IDEA 那份占着会先提示你先停掉;找不到 `mvn` 时跳过编译、仍按原参数拉起。端口写在配置中心时,插件会在进程起来后持续扫描真实监听端口并回填。
|
|
383
|
+
|
|
384
|
+
**日志读不到,或者出现半个字符?**
|
|
385
|
+
`logPath` 与 `cwd` 的相对路径按项目工作目录展开(没有工作区时按配置文件所在目录)。日志按字节读,GBK 等多字节编码跨读取边界时可能出现半个字符,换 UTF-8 日志或调大 `max_bytes`。
|
|
386
|
+
|
|
387
|
+
**接口一直 401?**
|
|
388
|
+
多半是面板里保存的 token 过期了。点「清除 token」后重新「登录并保存」;或检查登录接口的 `tokenPath`、注入头与前缀是否和实际响应一致。
|
|
389
|
+
|
|
390
|
+
## 许可证
|
|
391
|
+
|
|
392
|
+
MIT,见 [LICENSE](LICENSE)。
|