opencode-idea 0.1.4 → 0.1.5

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/README.md CHANGED
@@ -9,10 +9,9 @@ OpenCode 插件,面向 JetBrains 项目 (IntelliJ IDEA / PyCharm / WebStorm 等)
9
9
  2. **优先使用 IDE 工具** —— IDE 可用时,向模型注入 **逐项目**的引导:在哪个项目里工作,就用哪个项目前缀的工具;IDE 不可用时
10
10
  回退原生工具 (正常回退,无需声明)。
11
11
 
12
- > **需要项目环境的命令走 IDE 终端 / Run Configuration**:跑 `java` / `python` / `npm` 这类依赖项目配好的 JDK / Node / Python 版本的
13
- > **一次性命令**,用配套插件提供的 `ide_project_sdk_terminal`(它带项目 SDK 环境);**反复发生的流程**仍固化成 Run Configuration。
14
- > **IDE 内置的 `ide_execute_terminal_command` 继续隐藏** —— 实测它不继承项目环境,已被 `project_sdk_terminal` 取代。
15
- > 详见「Run Configuration 全套」与「终端全套」。
12
+ > **需要项目环境的命令也走原生 shell**:项目配置的 JDK / Node / Go / Maven / Python 由配套插件的 `get_project_env` 取出,
13
+ > 本插件在每条 shell 创建前注入到它的 `PATH` 与环境变量里;**反复发生的流程**仍固化成 Run Configuration。
14
+ > **IDE 内置的 `ide_execute_terminal_command` 继续隐藏** —— 实测它不继承项目环境。详见「Run Configuration 全套」与「终端全套」。
16
15
 
17
16
  非 JetBrains 项目完全不受影响。 **手动接入**:插件启动不探测、不连接任何 IDE。三个命令管全部:
18
17
 
@@ -136,6 +135,51 @@ configure_ide_project({ path: "modelserver", ide: "pycharm" }) // 配置一个
136
135
 
137
136
  **热更新会断开**:插件源码变更会触发 V2 热重载,注册随旧实例一起释放。 **改完插件后重跑一次 `/open-in-ide`** 即可恢复。
138
137
 
138
+ ## 远程配置 (`/persist-remote-config` 与两条提示词命令)
139
+
140
+ ### `/persist-remote-config`
141
+
142
+ 把 IDE 里配置的 server 与 deployment 写进 `<项目>/.opencode/remote-shell/hosts.json`:
143
+
144
+ - 读配套插件的 `get_deployment_servers`(IDE 必须连着;没连上会提示先 `/open-in-ide`)
145
+ - **同名覆盖、项目独有保留**:IDE 有的整体更新,IDE 没有的原样留着
146
+ - 写之前备份 `hosts.json.bak`
147
+ - 写完整凭据(`password` / `privateKeyPath`) —— **这个文件要不要提交进 git,由你决定**,插件不改 `.gitignore`
148
+ - 写完立刻让服务器缓存失效,紧接着的 `remote_exec` 就能用
149
+
150
+ ```json
151
+ {
152
+ "hosts": {
153
+ "mbptest": {
154
+ "host": "yutaodeMacBook-Pro.local",
155
+ "port": 22,
156
+ "username": "yutao",
157
+ "authType": "PASSWORD",
158
+ "password": "…",
159
+ "deployments": [
160
+ {
161
+ "name": "mcp-test-project",
162
+ "localPath": "/Users/yutao/IdeaProjects/mcp-test-project",
163
+ "deployPath": "/Users/yutao/Desktop/data/test"
164
+ }
165
+ ]
166
+ }
167
+ }
168
+ }
169
+ ```
170
+
171
+ ### `/remote-shell` 与 `/remote-deployment`
172
+
173
+ 这两条是**提示词命令**:不执行任何东西,只往会话里注入一段规则(和 `~/.config/opencode/commands/readonly.md` 同一个思路),
174
+ 让模型走 `remote_exec` / `remote_upload` / `remote_download`,而不是自己拼 `ssh` / `scp` / `rsync`。
175
+
176
+ ```
177
+ /remote-shell mbp 看下磁盘
178
+ /remote-deployment mcp-test-project download
179
+ ```
180
+
181
+ 参数原样附在提示词末尾;**没带参数时,提示词会要求模型先问清楚**(服务器 / 命令 / 哪条 deployment),不会自己挑一台。
182
+
139
183
  ## 按能力选工具 (直接调用引导)
140
184
 
141
185
  IDE MCP 可用时,插件通过 **系统提示注入**告诉模型 **哪些事该走 IDE**;除下面「工具参数与输出」那几处刻意的接管
@@ -168,8 +212,7 @@ IDE MCP 可用时,插件通过 **系统提示注入**告诉模型 **哪些事该
168
212
  | 批量改文件 | `ide_apply_patch` |
169
213
  | 校验 | `ide_lint_files` / `ide_get_file_problems` / `ide_build_project` |
170
214
  | 运行配置 | `ide_get_run_configurations` / `ide_execute_run_configuration`(+ 配套插件的启停工具) |
171
- | 终端 | `ide_project_sdk_terminal` / `ide_terminal_read` / `ide_terminal_interrupt` / `ide_list_terminals` / `ide_execute_in_remote_host`(远程执行还要求 Ultimate + Deployment SFTP) |
172
- | 部署 | `ide_list_server_deployments` / `ide_upload_to_deployment` / `ide_download_from_deployment` / `ide_get_deployment_task_status`(要求 Ultimate) |
215
+ | 远程执行 / 同步 | `remote_exec` / `remote_list_servers` / `remote_upload` / `remote_download`(本插件自带,凭据与路径映射来自 IDE 的 Deployment 配置,IDE 没开时退到 hosts.json);本机环境变量由 `get_project_env` + shell hook 注入 |
173
216
 
174
217
  **读、找文本、找文件、改单个文件一律用 OpenCode 自带的工具**(`read` / `grep` / `glob` / `write` / `edit`):
175
218
  这几件事走 IDE 只是多一跳,所以映射表里**不出现** `ide_search_text` / `ide_search_regex` / `ide_search_file`。
@@ -280,15 +323,20 @@ IDE 内置的 MCP Server 只能 **启动已有**的 run configuration (`execute_
280
323
  | `ide_stop_run_configuration` | 停掉该配置的**全部**实例并等它们退出;没在跑也返回成功(幂等) |
281
324
  | `ide_rerun_run_configuration` | 等同 IDE 的 **Rerun** 按钮:在跑就重启、没在跑就启动,读 `started` 判断是否真起来了 |
282
325
 
283
- **需要项目环境的命令走 IDE 终端 / run configuration** —— 判据是这条命令 **依赖项目的运行时版本**
284
- (IDE 里配好的 JDK / Node / Python 等)。是 → **一次性命令**走配套插件的 `ide_project_sdk_terminal`;**会反复发生的流程 / 常驻
285
- 服务**固化成 run configuration;不是 (看文件、git、临时脚本)→ 原生 shell。配置必须 **先在 IDEA 里存在**(由用户建),
286
- 没有就请用户建一个再跑;要不要建、建什么,按 `idea-run-config-manager` skill 的判据走。
326
+ **需要项目环境的命令也走原生 shell** —— 项目配置的 JDK / Node / Go / Maven / Python 由配套插件的 `get_project_env`
327
+ 取出来,再由本插件的 `shell.hook("create.before")` **注入到每个新 shell 的 `PATH` 与环境变量里**,所以 `java` / `node` /
328
+ `go` / `mvn` / `python` 在原生 shell 里就是项目配置的版本。**会反复发生的流程 / 常驻服务**仍然固化成 run configuration;
329
+ 看文件、git、临时脚本也走原生 shell。配置必须 **先在 IDEA 里存在**(由用户建),没有就请用户建一个再跑;要不要建、建什么,
330
+ 按 `idea-run-config-manager` skill 的判据走。
287
331
 
288
332
  > **为什么内置 IDE 终端仍然隐藏**:`ide_execute_terminal_command` 之前被当成"自动继承 IDE 项目环境"的通道而保留暴露,但实测
289
333
  > **它拿不到项目配好的 JDK / Node / Python 版本**,和原生 shell 没有区别。既然没有优势,就把它从模型可见的工具表里
290
- > 隐藏掉 (`HIDDEN_IDE_TOOL_SUFFIXES`)。配套插件的 `project_sdk_terminal` 走的是另一条路:**主动把项目 SDK / Maven /
291
- > Node / Python 的路径注入终端环境**,所以它才是"需要项目环境"的那条路由。
334
+ > 隐藏掉 (`HIDDEN_IDE_TOOL_SUFFIXES`)。
335
+ >
336
+ > **项目环境现在由本插件自己注入**:连接 IDE 时调一次配套插件的 `get_project_env`(不进模型可见的工具表),把返回的
337
+ > `PATH` **前置**拼到每条新 shell 的 PATH 上,其余变量(`GOROOT` / `MAVEN_HOME` / `VIRTUAL_ENV` …)直接覆盖。所以原生
338
+ > shell 就是"项目 shell",不需要一个单独的 `project_sdk_terminal` 工具;配套插件里那套本地终端能力已经整体移除。
339
+ > 拉不到环境变量时连接按**没做完**处理(`env-unready`),不会静默降级成"工具有、环境是空的"。
292
340
 
293
341
  配置名有自己的文法:**`[os@]base[@env]`** —— os 段 (`win` = Windows,缺省 = macOS / Linux)、base 段 (配置本体)、env 段 (环境名,
294
342
  缺省 = 默认环境 —— 起一批时逐条解析:有 `@<env>` 用它,没有就用默认)。`win@base` 与 `base@env` 都是同一个 base 的 **变体**,档案里只登记 base。解析 **交给工具**:
@@ -405,88 +453,76 @@ opencode-idea 对这一组工具做两件事:
405
453
  事实一律先查后写:配置名来自 `ide_get_run_configurations`,`热重载` 来自运行方式,端口读不到就问用户 —— 不猜。
406
454
  **只动自己的标记块**:根 `AGENTS.md` 是共享文件 (`project-scaffold` 的宪法、项目自己的内容都在里面),标记之外一字不改。
407
455
 
408
- ## Deployment 全套 (配套插件 `idea-mcp-enhance`)
456
+ ## 文件同步 (自带,不再依赖 IDE 的 deployment 工具)
409
457
 
410
- IDE 内置的 MCP Server **完全不碰部署** —— 既不报 IDE 里配了哪些 Deployment 服务器,也不能把文件传上去 / 拉下来。
411
- 配套插件 [`idea-mcp-enhance`](https://github.com/syllr/idea-mcp-enhance)(IDEA 2026.2+,必须安装)补齐这四个:
458
+ 上传 / 下载由本插件的 `remote_upload` / `remote_download` 直接走 SFTP,不再经过 IDE 的
459
+ `upload_to_deployment` / `download_from_deployment`:
412
460
 
413
- | 工具 (OpenCode 里叫 `ide_*`) | 作用 |
414
- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
415
- | `ide_list_server_deployments` | 本项目可用的**服务器**,以及每台服务器上的 **deployment(路径映射)**。Server 是连接目标(`servers[].name` → 远程终端的 `serverName`),deployment 是挂在它上面的一条映射(`servers[].deployments[].name` → 上传 / 下载的 `deploymentName`,全局唯一)。server 可以 0 个 deployment,那样只能远程执行。另带 `level` / `accessType` / `host` / `port` / `rootFolder` / `hasCredentials` / `validationIssue` / `isDefault`、项目级 `options` 与 `warnings[]`。**只读 IDE 配置,不联网** |
416
- | `ide_upload_to_deployment` | 把**一条 deployment**(本地映射目录)传到服务器(等同 IDE 的 Upload to …)。`deploymentName` 传 `servers[].deployments[].name`,**不是 `serverName`**。`mode` 默认 `mirror` —— **会删掉服务器上多出来的文件**;`upload` 则保留远端多余文件。**破坏性** |
417
- | `ide_download_from_deployment` | 把**一条 deployment** 从服务器拉回本地(等同 IDE 的 Download from …),**以服务器为准**:两边都有的文件被远端覆盖(相同则不写)。同样传 `deploymentName`。**没有"保留我的版本"这个选项** |
418
- | `ide_get_deployment_task_status` | 用 `handle` 查一次传输的状态与计数;**永不启动任何传输** |
461
+ | 工具 | 作用 |
462
+ | --- | --- |
463
+ | `remote_upload` | 把一条 deployment 的本地目录传到远程目录。`mode` 默认 `overwrite`(只覆盖 / 新增),`mirror` 额外删掉远程多余的文件 |
464
+ | `remote_download` | 反向拉回本地,语义相同(默认 `overwrite`,`mirror` 删本地多余) |
419
465
 
420
- opencode-idea 对它做的是**同一套两件事**(透传 / 无条件引导),不再按工具快照裁剪文本:
466
+ 路径映射(本地目录 ↔ 远程目录)和服务器一样走三级配置,同名以高优先级为准:
421
467
 
422
- - **前提**:部署工具除配套插件外,还要求 `com.jetbrains.plugins.webDeployment`(**仅 Ultimate**)。引导默认它在,
423
- 所以「服务器文件同步」节始终出现;Community 上调用这些工具会失败 —— 这属于配套环境没装全,不做兼容判断;
424
- - **契约**:`DeploymentSchemas.kt` 就是这组工具的对外形状(参数名、返回字段),引导按它写,不再单独维护工具名清单。
468
+ 1. **IDE** —— `get_deployment_servers` 返回的 `deployments[]`(`name` / `localPath` / `deployPath`;
469
+ `deployPath` 已拼上 server 的 `rootFolder`,是能直接用的绝对路径)
470
+ 2. **项目级** `<项目>/.opencode/remote-shell/hosts.json` 里 host 条目下的 `deployments`
471
+ 3. **全局** `~/.config/remote-shell/hosts.json` 同上
425
472
 
426
- 这节存在的理由是 **一条路由规则**:往服务器传 / 取文件要走这些工具 —— IDE 的连接、路径映射、排除规则都在它后面,
427
- 手工拼的那份与 IDE 看到、管理的不是同一份。文案里同时点明两件容易读错的事:
428
- `mirror` 是 **默认值**且 **会删远端文件**(而 MCP 路径上没有确认步骤),下载 **以远端为准**、没有"保留我的版本"。
473
+ `remote_list_servers` 会把每条 mapping 一起列出来(`本地目录 ↔ 远程目录`)。
429
474
 
430
- **同步只是上半段**:每条 deployment 都属于某台 Server,传完之后在那台 Server 上启动刚传上去的二进制、重启服务、看日志,
431
- 走 `execute_in_remote_host`(`serverName` 用服务器名,不是 deployment 名)。**这两步都不要用 `scp` / `rsync` / `ssh`
432
- 手工顶替** —— 手工那条路既没有 IDE 的路径映射,也常常根本没有权限(实测过一次:模型拿到服务器名之后转去读
433
- `~/.ssh/config`、逐个试用户名,失败后回头找用户要密码,而 `execute_in_remote_host` 一直都在工具表里)。
475
+ **`mirror` 会删文件**:上传时删远程多余,下载时删本地多余,而且没有确认步骤。默认 `overwrite` 只覆盖 / 新增。
434
476
 
435
- 还有一个语义必须写明,否则模型会把正常的中间态当失败去重试:上传 / 下载默认**同步等结果**,传完立刻返回
436
- `state: "completed"`;只有超过 300 秒等待窗口还没传完,才返回 `state: "in_progress"` + `handle`,这是 **正常**的
437
- (它也可能以 **error 结果**回来)—— 拿 `handle` 调 `get_deployment_task_status` 接着看,**不要用重复调上传 / 下载
438
- 来代替**(那样会再起一次传输)。`completed` 之后 `counters` 才可信,而且数的是**操作次数**,不是文件数
439
- (删掉整个目录也只算 1)。
477
+ **同步只是上半段**:每条 deployment 都属于某台服务器,传完之后在它上面启动刚传上去的二进制、重启服务、看日志,
478
+ 走 `remote_exec`。这两步都不要用 `scp` / `rsync` / `ssh` 手工顶替 —— 手工那条路既没有 IDE 的路径映射,
479
+ 也常常根本没有权限。
440
480
 
441
- > **这一组没有 skill,和 run configuration 不同。** run configuration 要 skill 是因为"某种类型怎么写"是一批得逐类型实测的
442
- > 模板 (`assets/types/`);部署没有这层知识 —— 四个工具的 schema 已经说清 `serverName` / `deploymentName` / `mode` 怎么填,
443
- > 而"该不该传、传给谁"是模型当场看 `list_server_deployments` 的判断。再加一个 skill 只是把同一段话抄第二遍。
481
+ > 配套插件里那四个 deployment 工具(`list_server_deployments` / `upload_to_deployment` /
482
+ > `download_from_deployment` / `get_deployment_task_status`)**已经删除** —— 传输完全由这里的
483
+ > `remote_upload` / `remote_download` 负责。
444
484
 
445
- ## 终端全套 (配套插件 `idea-mcp-enhance`)
485
+ ## 远程执行 (自带,不再依赖 IDE 的远程终端)
446
486
 
447
- IDE 内置的 `execute_terminal_command` **不继承项目环境**(实测拿不到项目配好的 JDK / Node / Python),所以它被隐藏。配套插件
448
- 补上的是一个**真正的 IDE 终端**,外加远程 SSH 终端和一套"接着用同一个 tab"的读写工具:
487
+ 远程命令由本插件的 `remote_exec` 直接跑(SSH),不再经过 IDE 的 `execute_in_remote_host`:
449
488
 
450
- | 工具 (OpenCode 里叫 `ide_*`) | 作用 |
489
+ | 工具 | 作用 |
451
490
  | --- | --- |
452
- | `ide_project_sdk_terminal` | 在本项目 SDK 终端里跑**一条**命令,返回输出 + `tab`。**默认复用**本项目的默认 tab(第一次调用创建,`list_terminals` 该组的 `default` 就是它);传 `tab` 指定、传 `newTab: true` 新开(不抢默认)、带 `env` 时强制新开(`env` 只在 shell 启动时生效)。命令跑得久时先返回 `running: true`(同一个 `tab`,命令继续跑),之后用 `ide_terminal_read` 接着看。终端环境由插件注入:项目 JDK(`PATH`)、Maven home、Node runtime / 包管理器、Go 的 `GOROOT` / `GOPATH` / `GOBIN`、Python SDK / venv(`PATH` + `VIRTUAL_ENV`),用户传的 `env` 最后覆盖 |
453
- | `ide_list_terminals` | 按来源分组列出 MCP tab:`mcp_project_sdk` 一组、每台远程服务器各一组;每组带一个组级 `default`(该来源的默认 tab)和组内 `tabs` 数组。用户手开的 tab 不出现 |
454
- | `ide_terminal_read` | 读已有 tab,**立即返回、不等待**:默认读上次之后的增量,`tail: N` 读最近 N 个命令段(本地带每段 `exitCode`),`full: true` 读整屏,`running` 表示命令还在不在跑 |
455
- | `ide_terminal_interrupt` | 往已有 tab 发**一次 Ctrl-C**。只在命令卡住时用 —— 执行工具会等 shell 空闲,卡住的命令会把它们一直挡住;它不接受任何文本,只能打断,不能拿来跑命令 |
456
- | `ide_execute_in_remote_host` | 通过本项目的一台 Deployment **SFTP** 服务器开真实 SSH 终端。`serverName` 取 `servers[].name`。**默认复用这台服务器的默认 tab**(第一次调用创建,`list_terminals` 该组的 `default` 就是它),传 `tab` 指定 / `newTab: true` 换干净 shell;新 tab 命名 `mcp-<服务器名>-<序号>`(如 `mcp-mbpmiddleware-1`)。`loginShell` 默认 `true`(套 `zsh -lic` / `bash -lc`),`strictHostKey` 默认 `false`(accept-new) |
457
-
458
- 路由:引导里写的是 **"这条命令在哪台机器上、要不要项目运行时"** 两刀切 —— 远程机器(部署机 / 开发机 / 用户点名的主机)
459
- 走 `ide_execute_in_remote_host`(服务器名不确定先 `ide_list_server_deployments`);本机 + 要运行时(IDE 里配好的
460
- JDK / Node / Python / Maven / Go)走 `ide_project_sdk_terminal`;本机 + 不要运行时(`git` / `ls` / `curl` / `docker` /
461
- `ps`)仍走原生 `shell`。**常驻进程**(dev server / watch)有 run configuration 就用它;没有就用终端起在 tab 里,
462
- 跑满等待窗口还没结束会返回 `running: true`,之后用 `ide_terminal_read` 跟日志。
463
-
464
- **等太久会转成异步**:命令跑得久,这次调用先返回 `running: true` + 同一个 tab,命令继续跑;之后用 `ide_terminal_read`
465
- 每隔几秒看一眼进度,直到 `running` 变 false —— 不要因为没拿到结果就重跑一遍。超时不是调用方能设的参数,它是工具自身的
466
- 行为(也没有"主动异步"选项)。引导里也明写了**禁止用 `shell` 的 `sleep` 干等**(实测会话里出现过 `sleep 60` /
467
- `sleep 120` / `sleep 1500`,全是旧版 12 秒上限逼出来的)。
468
-
469
- **终端默认复用**:同一台机器上的连续命令落在同一个 tab —— `cd` / `export` / 后台进程都还在,不必每条重贴 `cd ... &&`,
470
- 也不用自己记 tab 号;要干净 shell 传 `newTab: true`,要指定某条传 `tab`。`ide_terminal_read` / `ide_terminal_interrupt`
471
- 管的是"接着看 / 打断",不是"再跑一条"的替代。这条规则在「命令执行」和「终端」两处都写了,因为它最容易被绕成"每条命令一个 tab"。
472
-
473
- 三条容易读错的语义,引导里都点名了:
474
-
475
- - **每种来源一条默认 tab** —— 本地一条、每台服务器各一条,第一次调用自动创建,`list_terminals` 在该组的 `default` 字段里报出它;
476
- 不传 `tab` 就永远落在它上面(不会随使用历史漂移),默认 tab 被关掉后下次调用重建一条;一条命令要独立环境就传
477
- `newTab: true` / `env`。跨服务器复用会被直接拒绝(`tab_server_mismatch`);
478
- - **远程没有"命令结束"信号** —— `exitCode` 永远 `null`,`running` 也可能 `null`;别等退出码,按输出判断或继续 `ide_terminal_read` 读;
479
- - **tab 只在这次 IDE 会话里有效** —— 关掉就失效(报 `terminal_closed` / 找不到),这时才重开一个;没有"关闭 tab"的工具,
480
- 用完不必主动关,用户可以直接在 IDE 里接手。
481
-
482
- opencode-idea 对它做的仍是**同一套两件事**(透传 / 无条件引导):本地三个工具(Terminal 插件在就有)和
483
- `execute_in_remote_host`(还要 `remote-run`,仅 Ultimate)都**默认齐全**,引导直接点名,不再按工具快照裁剪。
484
- 契约以该仓库的 `TerminalSchemas.kt` 为准。
491
+ | `remote_exec` | 在远程服务器上跑一条命令。参数 `server` / `command` / `workingDirectory?`,返回 `[服务器名] exitCode N` 加输出 |
492
+ | `remote_list_servers` | 列出全部可用服务器,带 `[IDE]` / `[项目]` / `[全局]` 来源标记。名字不确定时先调它 |
493
+
494
+ 认证方式三种都支持:`PASSWORD`(密码)、`KEY_PAIR`(私钥 + 可选口令)、`OPEN_SSH`(ssh-agent /
495
+ `~/.ssh/config`,靠 `SSH_AUTH_SOCK`)。
496
+
497
+ 服务器与凭据有三级来源,同名以高优先级为准:
498
+
499
+ 1. **IDE** —— 配套插件的 `get_deployment_servers`(只返回 SFTP server;凭据由 IDE 进程从 Credentials 直接读出,
500
+ 不经过任何配置文件,也不碰 Keychain)
501
+ 2. **项目级** `<项目>/.opencode/remote-shell/hosts.json`(与全局同名同格式,跟着仓库走)
502
+ 3. **全局** `~/.config/remote-shell/hosts.json`
503
+
504
+ IDE 没开时自动退到 2 / 3,所以 `remote_exec` 在 IDE 之外也能用。列表缓存 60 秒;**名字找不到时会全量刷新一次**
505
+ 再匹配,仍找不到就把全部服务器列给模型 —— 不做模糊猜测(用户说 "dev1"、配置的可能是 "deploy1",猜错比列出来更糟)。
506
+ 命中但连接失败时,会刷新一次凭据再重试(应对"刚在 IDE 里改了密码"),仍失败才报错。
507
+
508
+ **每条命令一条独立 SSH 连接**:`cd` / `export` 不跨命令保留,要目录就传 `workingDirectory`(内部拼
509
+ `cd '<dir>' && <command>`);命令同步返回,没有 tab、没有增量读、没有 Ctrl-C 通道,长任务自己在远程用 `nohup` /
510
+ `tmux`。
511
+
512
+ 上传 / 下载见上一节:同样是本插件的 `remote_upload` / `remote_download`,映射来自同一套三级配置。
513
+
514
+ **项目环境怎么进原生 shell**:连接 IDE 时(以及 `/open-in-ide` 每一次完整连接)调 `get_project_env`,拿到
515
+ `{ PATH, variables }` 后缓存;每条 shell 创建前由 `shell.hook("create.before")` 把 `PATH` **前置**拼上、其余变量直接覆盖。
516
+ `PATH` 里只有五个 provider(Java / Node / Go / Maven / Python)的 bin,IDE 进程自己的 PATH 不掺进来 —— 所以 OpenCode 的
517
+ PATH 不会丢。**env 拉不到 = 连接没做完**:`/open-in-ide` 报 `env-unready`,不会静默降级成"工具有、环境是空的"。
518
+
519
+ `get_project_env` 与 `get_deployment_servers` 都是**隐藏**的(数据通道,不是模型任务),IDE 侧那套远程终端
520
+ (`execute_in_remote_host` / `terminal_read` / `terminal_interrupt` / `list_terminals`)也一并隐藏 —— 本插件不再需要它们。
485
521
 
486
522
  ## 前置条件
487
523
 
488
524
  - **必须安装配套插件 [`idea-mcp-enhance`](https://github.com/syllr/idea-mcp-enhance)(IDEA 2026.2+)**。引导默认它的工具都在
489
- (运行配置启停 / 部署 / 终端),**不做"装没装 / 有没有这个工具"的判断**;部署与远程终端还要求 Ultimate。
525
+ (运行配置启停 / 部署 / 环境变量),**不做"装没装 / 有没有这个工具"的判断**;部署那组还要求 Ultimate。
490
526
  - JetBrains IDE 已开启 MCP 服务 (IDE 设置里的 MCP Server / AI Assistant MCP),版本需 **2026.2+**(提供 Streamable HTTP 端点
491
527
  `/stream`);若关闭,`/open-in-ide` 会立即提示如何重新开启。
492
528
  - IDE 侧需开启 **Brave Mode**(否则需要确认的 MCP 工具调用会停下来等用户确认);MCP 未就绪时通知会同时提醒开启它。
@@ -618,15 +654,16 @@ export { default } from "/Users/yutao/IdeaProjects/opencode-idea/src/index.js";
618
654
  - skill 定义的字段名 **以 schema 为准**,不要照官方文档:`Skill.Info` 需要 `path`(AbsolutePath),文档里写的 `location`
619
655
  不存在 —— 用错会让 `ctx.skill.transform` 抛 `SchemaError`,而**任何 transform 失败都会禁用整个插件**
620
656
  (0.0.6 就是这样丢了 `/open-in-ide`)。完整字段是 `id` / `name` / `description?` / `autoinvoke?` / `path` / `content`。
621
- - 一批用不到的 IDE MCP 工具被硬编码隐藏(`src/plugin.js` 的 `HIDDEN_IDE_TOOL_SUFFIXES`,**共 48 个后缀**):
657
+ - 一批用不到的 IDE MCP 工具被硬编码隐藏(`src/plugin.js` 的 `HIDDEN_IDE_TOOL_SUFFIXES`,**共 58 个后缀**):
622
658
  VCS(`git_status` / `get_repositories`)、Router 派发工具(`execute_tool`)、Debugger(全部 `xdebug_*`)、Dev Kit MCP、
623
- Inspection KTS MCP、解释器环境 MCP、**IDE 内置终端**(`execute_terminal_command`:实测不继承项目环境,已由配套插件的
624
- `project_sdk_terminal` 取代)、
659
+ Inspection KTS MCP、解释器环境 MCP、**IDE 内置终端**(`execute_terminal_command`:实测不继承项目环境)、
660
+ **`get_project_env`**(本插件 shell hook 的数据通道,不是模型任务)、
625
661
  **整个 Database 组**(数据源由用户在 IDE 里配置)、**有原生对应的文件搜索**(`search_text` / `search_regex` / `search_file`)、
626
662
  以及**建文件**(`create_new_file`)。配套插件自带的那个写文件工具同样隐藏。**`apply_patch` 不在隐藏列表里**。
627
663
  存的是**后缀**,清洗时按当前每个项目前缀**各删一遍** —— 只处理 `ide_` 会让子项目那几份原样送到模型面前。
628
- 实测(拿运行中的 IDE MCP 拉 `tools/list`,单个项目):IDE 暴露 **75** 个 → 隐藏 47 → **模型可见 28 个**,
629
- 而且这 28 个**恰好等于引导里点名的 28 个**。多项目就是 N × 28。
664
+ 其中有几个后缀(`execute_in_remote_host` / `terminal_read` / `terminal_interrupt` / `list_terminals`)对应的工具
665
+ 已经从配套插件里删掉了,留着是为了挡住**没升级**的安装。具体数字随 IDE 与配套插件版本变化,每次工具集调整都要重测;
666
+ 判据是 **模型可见的 IDE 工具 = 引导里点名的那批**,不增不减。
630
667
  - **IDE 的「目录包含」语义(实测)**:请求路径落在某个**已打开项目的目录树内**时,IDE 会把它解析到那个项目,而不是报错。
631
668
  所以「子项目与 root 配同一个 IDE」时,只要那个 IDE 打开了 root,子项目就被判成"已打开" —— 它确实是 root 项目的一部分,
632
669
  工具能操作它的文件,但语言支持按 **root 项目**走(例如 Python 子项目被 root 的 Web 模块解析,符号检索与检查会不准)。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-idea",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "description": "OpenCode plugin that connects to JetBrains IDE MCP servers and prefers IDE tools when the current project is open in the IDE",
5
5
  "main": "src/index.js",
6
6
  "type": "module",
@@ -10,6 +10,7 @@
10
10
  "src/plugin.js",
11
11
  "src/template.js",
12
12
  "src/ide-guidance.template.md",
13
+ "src/plugin-tools-guidance.template.md",
13
14
  "src/ide-projects.js",
14
15
  "src/mcp/idea.js",
15
16
  "src/mcp/idea-tool-defaults.js",
@@ -17,6 +18,7 @@
17
18
  "src/project.js",
18
19
  "src/ide-launcher.js",
19
20
  "src/ide-guidance.js",
21
+ "src/remote/",
20
22
  "src/skill/loader.js",
21
23
  "skills",
22
24
  "README.md"
@@ -52,5 +54,8 @@
52
54
  },
53
55
  "engines": {
54
56
  "node": ">=18.0.0"
57
+ },
58
+ "dependencies": {
59
+ "ssh2": "^1.17.0"
55
60
  }
56
61
  }
@@ -72,9 +72,18 @@ import { renderTemplate } from './template.js';
72
72
  /** The prompt document, next to this module so it ships with it. */
73
73
  const TEMPLATE_PATH = new URL('ide-guidance.template.md', import.meta.url);
74
74
 
75
+ /**
76
+ * 远程执行的指引。`remote_*` 是**插件自己**的工具(不带 `<前缀>_`、IDE 关掉也在),
77
+ * 所以这份文本与 IDE 连接状态无关,单独渲染、单独注入。
78
+ */
79
+ const REMOTE_TEMPLATE_PATH = new URL('plugin-tools-guidance.template.md', import.meta.url);
80
+
75
81
  /** Read once: the file is fixed for the life of the process, and this runs per request. */
76
82
  const TEMPLATE = readFileSync(TEMPLATE_PATH, 'utf8');
77
83
 
84
+ /** 同上,只为远程工具那份。 */
85
+ const REMOTE_TEMPLATE = readFileSync(REMOTE_TEMPLATE_PATH, 'utf8');
86
+
78
87
  /**
79
88
  * 「本会话有哪些项目、各自用哪个 MCP 工具前缀」的清单。
80
89
  *
@@ -191,6 +200,29 @@ export function appendIdeGuidance(system, projects) {
191
200
  system.push({ type: 'text', text });
192
201
  }
193
202
 
203
+ /**
204
+ * 远程执行的指引,**与 IDE 连接状态无关**。
205
+ *
206
+ * `remote_*` 是插件常驻注册的工具:IDE 关掉时它们仍然能跑(服务器列表退到 hosts.json)。
207
+ * 所以这段不能跟着 `appendIdeGuidance` 一起在 `serving === false` 时被跳过 —— 否则模型手上有
208
+ * `remote_exec`,却没有任何说明告诉它该用、怎么传参。
209
+ *
210
+ * @returns {string}
211
+ */
212
+ export function buildRemoteGuidanceText() {
213
+ return renderTemplate(REMOTE_TEMPLATE, {});
214
+ }
215
+
216
+ /**
217
+ * @param {unknown} system
218
+ */
219
+ export function appendRemoteGuidance(system) {
220
+ if (!Array.isArray(system)) return;
221
+ const text = buildRemoteGuidanceText();
222
+ if (system.some((part) => part?.text === text)) return;
223
+ system.push({ type: 'text', text });
224
+ }
225
+
194
226
  /**
195
227
  * @param {unknown} system
196
228
  * @param {{ marked?: boolean, serving?: boolean }} [options] `marked` picks the
@@ -7,16 +7,9 @@
7
7
  2. **IDE 工具补自带工具做不到的**:符号与定义用 `<前缀>_search_symbol` + `<前缀>_read_file`;改名用
8
8
  `<前缀>_rename_refactoring`;单文件检查用 `<前缀>_lint_files` / `<前缀>_get_file_problems`;跨模块构建用
9
9
  `<前缀>_build_project`。
10
- 3. **要项目运行时环境的命令用项目终端**:{{cmd_project_sdk_terminal}};本机上 `git` / `ls` / `curl` / `docker` 这类与项目
11
- 无关的仍走 `shell`。远程机器不是这条 —— 见第 4 条。细则见「命令执行」与「终端」。
12
- 4. **远程机器上的命令走 `<前缀>_execute_in_remote_host`**:用户说"去 xxx 上执行""部署机上跑一下""连某台机器看看",
13
- 先 `<前缀>_list_server_deployments` 拿服务器名,再用它在那台机器上跑。凭据、代理、路径映射都在 IDE 的那台
14
- Server 后面 —— `serverName` 就是这些连接信息的唯一入口。
15
- 5. **终端是复用的,不是一次性的**:同一来源(本机 / 每台远程服务器)有一条**默认 tab**,不传 `tab` 的命令都落在它上面。
16
- 细则见「终端」的复用规则。
17
- 6. **校验节奏**:改一处只在收尾跑 `lint_files` (要细节再 `get_file_problems`);改一大片或动了接口 / 依赖就用
10
+ 3. **校验节奏**:改一处只在收尾跑 `lint_files` (要细节再 `get_file_problems`);改一大片或动了接口 / 依赖就用
18
11
  `build_project`;全仓检查只在收尾。
19
- 7. **批量修改**:逐文件用 `edit`,或一次用 `<前缀>_apply_patch`。
12
+ 4. **批量修改**:逐文件用 `edit`,或一次用 `<前缀>_apply_patch`。
20
13
 
21
14
  本会话接入了 {{projectCount}} 个 JetBrains 项目。**每个 IDE 功能在所有项目下都各有一份工具**,命令名是
22
15
  `<项目前缀>_<工具名>`;下文写 `<前缀>` 就是指这一截。
@@ -40,12 +33,9 @@
40
33
  项目外的路径(`/tmp`、别的仓库、用户主目录)不在 IDE 的解析范围内。
41
34
 
42
35
  - **项目内** —— **OpenCode 自带的工具为主**,它们更快。**它们做不了、或者做得很差的,才用 IDE 工具**:
43
- 符号检索、依赖实现、重构、格式化、校验、运行配置、项目终端、跨文件补丁。
36
+ 符号检索、依赖实现、重构、格式化、校验、运行配置、跨文件补丁。
44
37
  **两边都不顺手时,你自己判断用 `shell` 里的命令** —— 那是第三选择,不是第一选择。
45
38
  - **项目外、但还在本机** —— 用 OpenCode 自带的工具;IDE 工具只对项目内路径生效。
46
- - **远程机器(部署机 / 开发机 / 用户点名的那台主机)** —— 它不属于上面两类,是 IDE 里配好的一台 Deployment Server:
47
- 跑命令走 `<前缀>_execute_in_remote_host`,传文件走 `<前缀>_upload_to_deployment` / `<前缀>_download_from_deployment`。
48
- 凭据与路径映射都由这台 Server 提供。
49
39
 
50
40
  ## 总则 (所有项目通用)
51
41
 
@@ -60,29 +50,14 @@
60
50
  - **改文件**:改一个符号用 `<前缀>_rename_refactoring`;改一段文字用 `edit` / `write` 工具;
61
51
  同一段文字铺到多个文件用 `<前缀>_apply_patch`。跑命令的路由见「命令执行」。
62
52
  改代码始终落在具体的那几行上,其余内容保持原样。
63
- - **改完代码自己先查一遍**:`lint_files` / `build_project`,怎么挑见「校验」。
53
+ - **改完代码自己先查一遍**:`lint_files` / `build_project`,怎么挑见「改代码」的校验规则。
64
54
  - **文档类文件 (Markdown / 文档) 改完之后,用 `<前缀>_reformat_file` 过一遍** —— 表格对齐、换行宽度、缩进交给 IDE
65
55
  统一。它从磁盘重读,外部写完直接格式化是安全的。
66
56
  - 某条功能下面没有你正要操作的那个项目的命令,说明那个项目没接上:提示用户执行 `/open-in-ide`。
67
57
 
68
- ## 命令执行 (所有项目通用)
58
+ ## 本地命令
69
59
 
70
- - **按"这条命令在哪台机器上、要不要项目运行时"分流**:
71
- - **远程机器**(部署机 / 开发机 / 用户说了"去 xxx 上"的那台)→ {{cmd_execute_in_remote_host}}。服务器名字不确定,
72
- 就先 {{cmd_list_server_deployments}} —— **它的返回就是"能直接跑命令的机器"清单**,`servers[].name` 直接用。
73
- - **本机 + 要项目运行时**(IDE 里配好的 JDK / Node / Python / Maven / Go,以及依赖它们的构建、脚本、生成、迁移)→
74
- {{cmd_project_sdk_terminal}}。它开的是 IDE 里真正的终端,自动带上项目 SDK 与 Maven / Node / Python 的路径;
75
- `workingDirectory` 默认项目根,`env` 里的值最后覆盖。
76
- - **本机 + 不要项目运行时**(`git` / `ls` / `cat` / `curl` / `docker` / `ps`)→ `shell` 工具。
77
- - **每种来源一条默认 tab,整趟任务复用**:不传 `tab` 的命令永远落在该来源的默认 tab 上(`project_sdk_terminal` 管本机、
78
- `execute_in_remote_host` 管每台服务器)—— `cd` / `export` / 后台进程都留在那个 shell 里,不必每条命令重贴
79
- `cd ... &&` 前缀。
80
- - **等太久会转成异步**:命令跑得久,这次调用先返回 `running: true` 和同一个 `tab`,命令还在里面跑 —— 用
81
- 结果从 {{cmd_terminal_read}} 取,每隔几秒看一眼,直到 `running` 变 false。
82
- - **卡住的命令用 {{cmd_terminal_interrupt}} 打断**:它在命令还跑着的时候发 Ctrl-C —— 执行工具帮不了这个忙
83
- (它们会等 shell 空闲,卡住的命令会把它们一直挡住)。
84
- - **常驻进程**(dev server / watch / 长时间跑的服务)有 run configuration 就用 `rerun` 起它;
85
- 没有就用项目终端起在 tab 里;它跑满等待窗口还没结束会返回 `running: true`,之后用 {{cmd_terminal_read}} 跟日志。
60
+ - **常驻进程**(dev server / watch / 长时间跑的服务)有 run configuration 就用 `rerun` 起它。
86
61
  - **一次性的命令就地跑完,反复发生的流程才固化成 run configuration** —— 配置是**项目资产**,不是"跑命令"
87
62
  的手段。判据只有一条: **这件事以后会不会以同样的形态再发生?** 会 (构建 / 生成 / 迁移 / 起服务 / 部署这类)
88
63
  就 **主动提**一次要不要固化成配置,并把配置名 / 类型 / 命令 / 工作目录 / 为什么值得留摊开;
@@ -196,72 +171,3 @@
196
171
  变体、没有默认版的,就用它自己那个 —— "10 个服务"可以是"3 个 `@dev` + 7 个默认",不必逐条问。
197
172
  - 一条配置同时有 `base` 与 `base@<env>`、又没说走哪个环境 → **问一次走哪个环境**,选定后本会话默认走这套。
198
173
  - 一个环境怎么接上(启动参数 / 环境变量 / 配置文件)是项目自己的事:照现成的同类变体来,或问用户。
199
-
200
- ### 终端 (本机环境 · 远程主机 · 复用同一个 tab)
201
-
202
- - {{cmd_project_sdk_terminal}} **在本项目 SDK 终端里跑一条命令,返回输出与 tab id**。`command` 必填;`workingDirectory`
203
- 默认项目根;`env` 最后覆盖自动注入的环境;`input` 在命令后写一次(自带换行);`maxChars` 只保留最新输出。
204
- **默认复用**:命令打进本项目的默认 tab(第一次调用创建,`list_terminals` 该组的 `default` 就是它),`cd` / `export` /
205
- 后台进程都还在;`workingDirectory` 会在那个 tab 里 `cd` 过去。`env` 只能在新 shell 生效,传了它就会新开一个(不会抢默认);
206
- 要指定某条 tab 传 `tab`,要干净 shell 传 `newTab: true`(同样不抢默认)。命令跑得久时先返回 `running: true`,
207
- 用 {{cmd_terminal_read}} 接着看。
208
- - {{cmd_list_terminals}} **本项目的终端 tab 清单**:按来源分组 —— `mcp_project_sdk` 一组、每台远程服务器各一组;每组带一个
209
- 组级 `default`(该来源的默认 tab)和组内 `tabs` 数组(状态、当前目录、最后一条命令)。用户自己开的 tab 不出现;
210
- 只有 `addressable: true` 的能交给 {{cmd_terminal_read}} / {{cmd_terminal_interrupt}}。
211
- - {{cmd_terminal_read}} **读已有 tab,立即返回、不等待**:`target` 取 `local`(`project_sdk_terminal` 建的)或 `remote`
212
- (`execute_in_remote_host` 建的)。默认读**上次之后的新输出**,`tail: N` 读最近 N 个命令段(本地带每段的 `exitCode`),
213
- `full: true` 读整屏。返回里的 `running` 说明命令还在不在跑。
214
- - {{cmd_terminal_interrupt}} **往已有 tab 发一次 Ctrl-C**:同样传 `target` + `tab`。只在命令卡住时用 —— 执行工具会等
215
- shell 空闲,卡住的命令会把它们一直挡住。它不接受任何文本,只能打断,不能拿来跑命令。
216
- - {{cmd_execute_in_remote_host}} **在远程主机的真实 SSH 终端里跑命令** —— 主机与凭据来自本项目的一台 Deployment
217
- SFTP 服务器,名字传 `serverName`(那台**服务器**的名字,不是 deployment 名)。`loginShell` 默认 `true`(套
218
- `zsh -lic` / `bash -lc`,PATH 与工具链才会加载);`strictHostKey` 默认 `false`(接受并记录新主机密钥)。
219
- **远程命令一律走它** —— 凭据、代理、路径映射都在 IDE 这边。
220
- **默认复用这台服务器的默认 tab**(第一次调用创建,`list_terminals` 该组的 `default` 就是它;整趟任务只重连一次 SSH),
221
- `cd` / `export` / 后台进程都在原地;传 `tab` 指定某条,传 `newTab: true` 换一个干净 shell。
222
- 远程没有"命令结束"信号:**`exitCode` 永远为 `null`,`running` 也可能为 `null`** —— 别等 `exitCode`,看输出,或接着用
223
- {{cmd_terminal_read}} 读。
224
- - **`list_server_deployments` 报出来的服务器就是能直接跑命令的机器**:拿到名字立即用 `execute_in_remote_host`。
225
- `hasCredentials` / `validationIssue` 有问题时把它报给用户,由用户在 IDE 里处理。
226
-
227
- **复用规则 (本地 / 远程一套):每种来源一条默认 tab。**
228
-
229
- 1. 直接调 `project_sdk_terminal`(本机)或 `execute_in_remote_host`(远程),不传 `tab` 就落在该来源的默认 tab 上。
230
- 不用先 `list_terminals`,也不用把 tab id 一路记着。
231
- 2. **不必每条命令重贴 `cd ... &&`**:复用同一个 shell,目录、`export` 的变量、后台进程都还在。要换目录就传
232
- `workingDirectory`(会在那个 tab 里 `cd` 过去),别再用 `cd` 拼在命令前面。
233
- 3. **什么时候要新 tab**:两条命令会互相干扰、要独立环境的 `env`、或想从头来一遍 —— 传 `newTab: true`。
234
- 它不会抢走默认身份;默认 tab 被关掉后,下次调用会重建一条。
235
- 4. 要盯输出用 {{cmd_terminal_read}}:`read` 读增量或 `tail: N` 读最近几段。**它不是"再跑一条"的替代**。
236
- 5. 本地 tab 只跑本机命令,远程 tab 只跑那台机器上的命令 —— 别拿本地 tab 敲远程命令(反之亦然);跨服务器同理。
237
-
238
- **tab 只在这次 IDE 会话里有效**:tab 一关(报 `terminal_closed` / 找不到 tab)才重新开一个;用完不必主动关 —— 用户能看见,
239
- 也能直接在 IDE 里接手。
240
-
241
- ### 服务器文件同步
242
-
243
- 往服务器传文件 / 从服务器取文件,走这一组 —— IDE 的连接、路径映射、排除规则都在它们后面,传的就是 IDE 在管的那一份。
244
-
245
- - {{cmd_list_server_deployments}} **本项目能用的服务器,以及每台服务器上的 deployment**。先分清两层:
246
- **Server 是连接目标,deployment 是挂在它上面的一条路径映射**;一台 Server 可以有 **0 个 deployment** —— 那样它仍能给
247
- `execute_in_remote_host` 用,但**上传 / 下载没有目标**。
248
- - `servers[].name` → **远程终端**的 `serverName`;`servers[].deployments[].name` → **上传 / 下载**的 `deploymentName`
249
- (由本地路径最后一段派生,**全局唯一**)。
250
- - 每台 Server 还带 `level`(项目级 / 应用级)、`accessType`、`host` / `port`、`rootFolder`、`hasCredentials`、
251
- `validationIssue`、`isDefault`;返回里另有**整个项目共用**的 `options` 与 `warnings[]`(**只读 IDE 配置、不联网**)。
252
- - **`hasCredentials: false` 的服务器连不上** —— IDE 会弹模态登录框,MCP 调用会卡死;动手前先看 `warnings[]`。
253
- - {{cmd_upload_to_deployment}} **把一条 deployment(本地映射目录)传到服务器**(等同 IDE 的 Upload to …)。
254
- `deploymentName` 传 `servers[].deployments[].name` —— **不是 `serverName`**。`mode` 默认 `mirror` ——
255
- **会删掉服务器上多出来的文件**,使两边一致;要留住它们就传 `upload`。 **破坏性操作**。
256
- - {{cmd_download_from_deployment}} **把一条 deployment 从服务器拉回本地**(等同 IDE 的 Download from …), **以服务器为准**:
257
- 两边都有的文件会被远端覆盖 (内容相同则不写)。同样传 `deploymentName`。 **没有"保留我的版本"这个选项**。
258
- - {{cmd_get_deployment_task_status}} **查一次传输的状态**:`handle` 用上传 / 下载返回的那个 —— **它自己不启动任何传输**。
259
-
260
- 上传 / 下载默认**同步等结果**:传完立刻返回 `state: "completed"`。只有超过等待窗口(300 秒)还没传完,才会返回
261
- `state: "in_progress"` + `handle` —— 这 **正常**,不是失败(它也可能以 error 结果回来);拿 `handle` 调
262
- `get_deployment_task_status` 接着看 —— 重复调上传 / 下载会再起一次传输。到 `completed` 之后
263
- `counters` 才可信,而且它数的是**操作次数**,不是文件数(删掉整个目录也只算 1)。
264
-
265
- **同步只是上半段**:传完之后在那台 Server 上继续操作(启动刚传上去的二进制、重启服务、看日志)—— 用
266
- `execute_in_remote_host`,`serverName` 取 `servers[].name`。上传下载与远程执行走的是同一台 Server、同一套凭据和
267
- 路径映射 —— 两条路径连的是同一个地方。
package/src/mcp/idea.js CHANGED
@@ -127,7 +127,7 @@ export async function callTool(port, projectPath, name, args = {}, options = {})
127
127
  params: {
128
128
  protocolVersion: PROTOCOL_VERSION,
129
129
  capabilities: {},
130
- clientInfo: { name: 'opencode-idea', version: '0.1.4' },
130
+ clientInfo: { name: 'opencode-idea', version: '0.1.5' },
131
131
  },
132
132
  });
133
133
  // The IDE's Streamable-HTTP endpoint binds follow-up requests to the session
@@ -0,0 +1,18 @@
1
+ # 远程机器
2
+
3
+ ## 远程命令
4
+
5
+ - **部署机 / 开发机 / 用户点名的机器上的命令走 `remote_exec`**,不要自己拼 `ssh` / `scp`。名字不确定就先
6
+ `remote_list_servers`。
7
+ - **每条命令是独立连接**:`cd` / `export` 不跨命令保留,要目录就传 `workingDirectory`。
8
+ - **命令跑完才返回**
9
+
10
+ ## 工具
11
+
12
+ - `remote_list_servers` 列出全部可用服务器(带 `[IDE]` / `[项目]` / `[全局]` 来源)与各自的 mapping。
13
+ - `remote_exec` 在服务器上跑一条命令:`server`、`command`、可选的 `workingDirectory`。
14
+ - `remote_upload` / `remote_download` 按 deployment 名同步目录。默认 `overwrite`;`mirror` 会删掉目标端多出来的
15
+ 文件,只在明确要求镜像时用。
16
+ - **名字传错会返回全部候选**,按列表里的名字重新调用即可。
17
+
18
+ 用户执行 `/persist-remote-config` 后,IDE 的服务器与 mapping 会写进项目里的 hosts.json,IDE 关掉也能用。