opencode-idea 0.1.3 → 0.1.4

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
@@ -168,7 +168,7 @@ IDE MCP 可用时,插件通过 **系统提示注入**告诉模型 **哪些事该
168
168
  | 批量改文件 | `ide_apply_patch` |
169
169
  | 校验 | `ide_lint_files` / `ide_get_file_problems` / `ide_build_project` |
170
170
  | 运行配置 | `ide_get_run_configurations` / `ide_execute_run_configuration`(+ 配套插件的启停工具) |
171
- | 终端 | `ide_project_sdk_terminal` / `ide_terminal_io` / `ide_list_terminals` / `ide_execute_in_remote_host`(远程执行还要求 Ultimate + Deployment SFTP) |
171
+ | 终端 | `ide_project_sdk_terminal` / `ide_terminal_read` / `ide_terminal_interrupt` / `ide_list_terminals` / `ide_execute_in_remote_host`(远程执行还要求 Ultimate + Deployment SFTP) |
172
172
  | 部署 | `ide_list_server_deployments` / `ide_upload_to_deployment` / `ide_download_from_deployment` / `ide_get_deployment_task_status`(要求 Ultimate) |
173
173
 
174
174
  **读、找文本、找文件、改单个文件一律用 OpenCode 自带的工具**(`read` / `grep` / `glob` / `write` / `edit`):
@@ -423,17 +423,20 @@ opencode-idea 对它做的是**同一套两件事**(透传 / 无条件引导),
423
423
  所以「服务器文件同步」节始终出现;Community 上调用这些工具会失败 —— 这属于配套环境没装全,不做兼容判断;
424
424
  - **契约**:`DeploymentSchemas.kt` 就是这组工具的对外形状(参数名、返回字段),引导按它写,不再单独维护工具名清单。
425
425
 
426
- 这节存在的理由是 **一条路由规则**:往服务器传 / 取文件要走这些工具, **不要自己拼 `ssh` / `rsync` / `scp`** ——
427
- IDE 的连接、路径映射、排除规则都在它后面,自己拼的那份与 IDE 看到、管理的不是同一份。文案里同时点明两件容易读错的事:
426
+ 这节存在的理由是 **一条路由规则**:往服务器传 / 取文件要走这些工具 —— IDE 的连接、路径映射、排除规则都在它后面,
427
+ 手工拼的那份与 IDE 看到、管理的不是同一份。文案里同时点明两件容易读错的事:
428
428
  `mirror` 是 **默认值**且 **会删远端文件**(而 MCP 路径上没有确认步骤),下载 **以远端为准**、没有"保留我的版本"。
429
429
 
430
430
  **同步只是上半段**:每条 deployment 都属于某台 Server,传完之后在那台 Server 上启动刚传上去的二进制、重启服务、看日志,
431
- 走 `execute_in_remote_host`(`serverName` 用服务器名,不是 deployment 名)。
431
+ 走 `execute_in_remote_host`(`serverName` 用服务器名,不是 deployment 名)。**这两步都不要用 `scp` / `rsync` / `ssh`
432
+ 手工顶替** —— 手工那条路既没有 IDE 的路径映射,也常常根本没有权限(实测过一次:模型拿到服务器名之后转去读
433
+ `~/.ssh/config`、逐个试用户名,失败后回头找用户要密码,而 `execute_in_remote_host` 一直都在工具表里)。
432
434
 
433
- 还有一个语义必须写明,否则模型会把正常的中间态当失败去重试:上传 / 下载都在 IDE 后台跑,单次调用只等到 `waitMs`
434
- (默认 10 秒,上限 12 秒)为止,返回 `state: "in_progress"` 是 **正常**的(它可能以 **error 结果**回来)—— 拿 `handle`
435
- 调 `get_deployment_task_status` 接着看,**不要用重复调上传 / 下载来代替**(那样会再起一次传输)。`completed` 之后
436
- `counters` 才可信,而且数的是**操作次数**,不是文件数(删掉整个目录也只算 1)。
435
+ 还有一个语义必须写明,否则模型会把正常的中间态当失败去重试:上传 / 下载默认**同步等结果**,传完立刻返回
436
+ `state: "completed"`;只有超过 300 秒等待窗口还没传完,才返回 `state: "in_progress"` + `handle`,这是 **正常**的
437
+ (它也可能以 **error 结果**回来)—— 拿 `handle` 调 `get_deployment_task_status` 接着看,**不要用重复调上传 / 下载
438
+ 来代替**(那样会再起一次传输)。`completed` 之后 `counters` 才可信,而且数的是**操作次数**,不是文件数
439
+ (删掉整个目录也只算 1)。
437
440
 
438
441
  > **这一组没有 skill,和 run configuration 不同。** run configuration 要 skill 是因为"某种类型怎么写"是一批得逐类型实测的
439
442
  > 模板 (`assets/types/`);部署没有这层知识 —— 四个工具的 schema 已经说清 `serverName` / `deploymentName` / `mode` 怎么填,
@@ -446,20 +449,33 @@ IDE 内置的 `execute_terminal_command` **不继承项目环境**(实测拿不
446
449
 
447
450
  | 工具 (OpenCode 里叫 `ide_*`) | 作用 |
448
451
  | --- | --- |
449
- | `ide_project_sdk_terminal` | 在本项目 SDK 终端里跑**一条**命令,返回输出 + `tab`。每次调用 **新开一个 tab**;`timeoutMs` 默认 10000(`0` = 发出去就返回,上限 12000)。终端环境由插件注入:项目 JDK(`PATH`)、Maven home、Node runtime / 包管理器、Go 的 `GOROOT` / `GOPATH` / `GOBIN`、Python SDK / venv(`PATH` + `VIRTUAL_ENV`),用户传的 `env` 最后覆盖 |
450
- | `ide_list_terminals` | 列出 `mcp_project_sdk` / `mcp_remote` / `user` 三类 tab(状态、当前目录、最后一条命令、`lastUsedAt`)。**只有 `tab` 非空且 `addressable: true` 的能交给 `terminal_io`**;用户手开的 tab 只能看 |
451
- | `ide_terminal_io` | 对已有 tab 读 / 写。`read`:默认读上次之后的增量,`tail: N` 读最近 N 个命令段(本地带每段 `exitCode`),`full: true` 读整屏,`timeoutMs > 0` 等输出稳定;`write`:原样写进当前命令(自带换行) |
452
- | `ide_execute_in_remote_host` | 通过本项目的一台 Deployment **SFTP** 服务器开真实 SSH 终端。`loginShell` 默认 `true`(套 `zsh -lic` / `bash -lc`),`strictHostKey` 默认 `false`(accept-new) |
453
-
454
- 路由:引导里写的是 **"这条命令要不要项目运行时"** 一刀切 —— 要(IDE 里配好的 JDK / Node / Python / Maven / Go)走
455
- `ide_project_sdk_terminal`,不要(`git` / `ls` / `curl` / `docker` / `ps`)仍走原生 `shell`。**常驻进程**(dev server / watch)
456
- 有 run configuration 就用它;没有就在终端里以 `timeoutMs: 0` 起,之后用 `terminal_io` 跟日志、回答提示。
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"。
457
472
 
458
473
  三条容易读错的语义,引导里都点名了:
459
474
 
460
- - **每次调用都新开 tab** —— 同一件事的后续(看日志、回答提示、再敲一条)必须 `list_terminals` → `terminal_io`,不能反复
461
- `project_sdk_terminal` 把 tab 堆起来;
462
- - **远程没有"命令结束"信号** —— `exitCode` 永远 `null`,`running` 也可能 `null`;别等退出码,按输出判断或继续 `terminal_io` 读;
475
+ - **每种来源一条默认 tab** —— 本地一条、每台服务器各一条,第一次调用自动创建,`list_terminals` 在该组的 `default` 字段里报出它;
476
+ 不传 `tab` 就永远落在它上面(不会随使用历史漂移),默认 tab 被关掉后下次调用重建一条;一条命令要独立环境就传
477
+ `newTab: true` / `env`。跨服务器复用会被直接拒绝(`tab_server_mismatch`);
478
+ - **远程没有"命令结束"信号** —— `exitCode` 永远 `null`,`running` 也可能 `null`;别等退出码,按输出判断或继续 `ide_terminal_read` 读;
463
479
  - **tab 只在这次 IDE 会话里有效** —— 关掉就失效(报 `terminal_closed` / 找不到),这时才重开一个;没有"关闭 tab"的工具,
464
480
  用完不必主动关,用户可以直接在 IDE 里接手。
465
481
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-idea",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
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",
@@ -7,11 +7,16 @@
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`。细则见「命令执行」与「终端」。
12
- 4. **校验节奏**:改一处只在收尾跑 `lint_files` (要细节再 `get_file_problems`);改一大片或动了接口 / 依赖就用
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`);改一大片或动了接口 / 依赖就用
13
18
  `build_project`;全仓检查只在收尾。
14
- 5. **批量修改**:逐文件用 `edit`,或一次用 `<前缀>_apply_patch`。
19
+ 7. **批量修改**:逐文件用 `edit`,或一次用 `<前缀>_apply_patch`。
15
20
 
16
21
  本会话接入了 {{projectCount}} 个 JetBrains 项目。**每个 IDE 功能在所有项目下都各有一份工具**,命令名是
17
22
  `<项目前缀>_<工具名>`;下文写 `<前缀>` 就是指这一截。
@@ -37,7 +42,10 @@
37
42
  - **项目内** —— **OpenCode 自带的工具为主**,它们更快。**它们做不了、或者做得很差的,才用 IDE 工具**:
38
43
  符号检索、依赖实现、重构、格式化、校验、运行配置、项目终端、跨文件补丁。
39
44
  **两边都不顺手时,你自己判断用 `shell` 里的命令** —— 那是第三选择,不是第一选择。
40
- - **项目外** —— 用 OpenCode 自带的工具;IDE 工具只对项目内路径生效。
45
+ - **项目外、但还在本机** —— 用 OpenCode 自带的工具;IDE 工具只对项目内路径生效。
46
+ - **远程机器(部署机 / 开发机 / 用户点名的那台主机)** —— 它不属于上面两类,是 IDE 里配好的一台 Deployment Server:
47
+ 跑命令走 `<前缀>_execute_in_remote_host`,传文件走 `<前缀>_upload_to_deployment` / `<前缀>_download_from_deployment`。
48
+ 凭据与路径映射都由这台 Server 提供。
41
49
 
42
50
  ## 总则 (所有项目通用)
43
51
 
@@ -59,13 +67,22 @@
59
67
 
60
68
  ## 命令执行 (所有项目通用)
61
69
 
62
- - **按"这条命令要不要项目运行时"分流**:
63
- - **要**(IDE 里配好的 JDK / Node / Python / Maven / Go,以及依赖它们的构建、脚本、生成、迁移)→
70
+ - **按"这条命令在哪台机器上、要不要项目运行时"分流**:
71
+ - **远程机器**(部署机 / 开发机 / 用户说了"去 xxx 上"的那台)→ {{cmd_execute_in_remote_host}}。服务器名字不确定,
72
+ 就先 {{cmd_list_server_deployments}} —— **它的返回就是"能直接跑命令的机器"清单**,`servers[].name` 直接用。
73
+ - **本机 + 要项目运行时**(IDE 里配好的 JDK / Node / Python / Maven / Go,以及依赖它们的构建、脚本、生成、迁移)→
64
74
  {{cmd_project_sdk_terminal}}。它开的是 IDE 里真正的终端,自动带上项目 SDK 与 Maven / Node / Python 的路径;
65
75
  `workingDirectory` 默认项目根,`env` 里的值最后覆盖。
66
- - **不要**(`git` / `ls` / `cat` / `curl` / `docker` / `ps`)→ `shell` 工具。
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 空闲,卡住的命令会把它们一直挡住)。
67
84
  - **常驻进程**(dev server / watch / 长时间跑的服务)有 run configuration 就用 `rerun` 起它;
68
- 没有就用项目终端传 `timeoutMs: 0` 起在 tab 里,之后用 {{cmd_terminal_io}} 跟日志、回答提示。
85
+ 没有就用项目终端起在 tab 里;它跑满等待窗口还没结束会返回 `running: true`,之后用 {{cmd_terminal_read}} 跟日志。
69
86
  - **一次性的命令就地跑完,反复发生的流程才固化成 run configuration** —— 配置是**项目资产**,不是"跑命令"
70
87
  的手段。判据只有一条: **这件事以后会不会以同样的形态再发生?** 会 (构建 / 生成 / 迁移 / 起服务 / 部署这类)
71
88
  就 **主动提**一次要不要固化成配置,并把配置名 / 类型 / 命令 / 工作目录 / 为什么值得留摊开;
@@ -168,6 +185,8 @@
168
185
  - {{cmd_rerun_run_configuration}} **启动 / 重启常驻进程**:在跑就重启、没在跑就启动 —— 改完代码要重启就直接用它,
169
186
  有没有热重载都一样;读 `started` 判断新进程是否真的起来了。这次运行的输出在 `output`,完整日志文件路径在
170
187
  `fullOutputPath`。启停都走这个工具,IDE 的 Run 窗口状态才会跟着更新。
188
+ **before-launch 很久**(要先构建 / 跑另一个配置)时,调用会一直等到它结束;等不起就传 `waitForStart: false`,
189
+ 提交后自己查 {{cmd_list_running_configurations}}。
171
190
 
172
191
  **配置名怎么读**:`[os@]base[@env]`,`@` 分割、最多三段 —— `os` = `win`(缺省 macOS / Linux)、`base` = 配置本体(必填)、
173
192
  `env` = 环境名(缺省 = 默认环境)。`win@base`(换平台)与 `base@env`(换环境)都是 `base` 的 **变体**,跑哪一个:
@@ -178,25 +197,43 @@
178
197
  - 一条配置同时有 `base` 与 `base@<env>`、又没说走哪个环境 → **问一次走哪个环境**,选定后本会话默认走这套。
179
198
  - 一个环境怎么接上(启动参数 / 环境变量 / 配置文件)是项目自己的事:照现成的同类变体来,或问用户。
180
199
 
181
- ### 终端 (项目环境 · 交互 · 远程)
182
-
183
- - {{cmd_project_sdk_terminal}} **在本项目 SDK 终端里跑一条命令,返回输出与 tab id**。`command` 必填;`timeoutMs` 默认
184
- 10000(`0` = 发出去就返回,最长 12000);`workingDirectory` 默认项目根;`env` 最后覆盖自动注入的环境;`input` 在命令后
185
- 写一次(自带换行);`maxChars` 只保留最新输出。 **每次调用都新开一个 tab** —— 同一件事的后续改用 `list_terminals` /
186
- `terminal_io`,别再调它。
187
- - {{cmd_list_terminals}} **本项目的终端 tab 清单**:`kind`(`mcp_project_sdk` / `mcp_remote` / `user`)、`status`、
188
- `workingDirectory` / `currentDirectory`、`lastCommand`、`lastUsedAt`。 **只有 `tab` 非空且 `addressable: true` 的能交给
189
- `terminal_io`**;用户自己开的 tab 只用于认位置,不可控制;`title` 不是 id。
190
- - {{cmd_terminal_io}} **对已有 tab 读 / 写**:`target` 取 `local`(`project_sdk_terminal` 建的)或 `remote`。
191
- - `action: "read"` —— 默认读**上次之后的新输出**;`tail: N` 读最近 N 个命令段(本地还带每段的 `exitCode`);`full: true`
192
- 读整屏;`timeoutMs > 0` 先等输出稳定再读(最长 12000)。
193
- - `action: "write"` —— `text` **原样**送进当前命令(自带换行),不是新开一条命令。
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 空闲,卡住的命令会把它们一直挡住。它不接受任何文本,只能打断,不能拿来跑命令。
194
216
  - {{cmd_execute_in_remote_host}} **在远程主机的真实 SSH 终端里跑命令** —— 主机与凭据来自本项目的一台 Deployment
195
217
  SFTP 服务器,名字传 `serverName`(那台**服务器**的名字,不是 deployment 名)。`loginShell` 默认 `true`(套
196
218
  `zsh -lic` / `bash -lc`,PATH 与工具链才会加载);`strictHostKey` 默认 `false`(接受并记录新主机密钥)。
197
- **远程命令一律走它,不要自己拼 `ssh` / `scp`** —— 凭据、代理、路径映射都在 IDE 这边。
219
+ **远程命令一律走它** —— 凭据、代理、路径映射都在 IDE 这边。
220
+ **默认复用这台服务器的默认 tab**(第一次调用创建,`list_terminals` 该组的 `default` 就是它;整趟任务只重连一次 SSH),
221
+ `cd` / `export` / 后台进程都在原地;传 `tab` 指定某条,传 `newTab: true` 换一个干净 shell。
198
222
  远程没有"命令结束"信号:**`exitCode` 永远为 `null`,`running` 也可能为 `null`** —— 别等 `exitCode`,看输出,或接着用
199
- `terminal_io` 读。
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 敲远程命令(反之亦然);跨服务器同理。
200
237
 
201
238
  **tab 只在这次 IDE 会话里有效**:tab 一关(报 `terminal_closed` / 找不到 tab)才重新开一个;用完不必主动关 —— 用户能看见,
202
239
  也能直接在 IDE 里接手。
@@ -212,7 +249,7 @@
212
249
  (由本地路径最后一段派生,**全局唯一**)。
213
250
  - 每台 Server 还带 `level`(项目级 / 应用级)、`accessType`、`host` / `port`、`rootFolder`、`hasCredentials`、
214
251
  `validationIssue`、`isDefault`;返回里另有**整个项目共用**的 `options` 与 `warnings[]`(**只读 IDE 配置、不联网**)。
215
- - **`hasCredentials: false` 时不要连接** —— IDE 会弹模态登录框,MCP 调用会卡死;动手前先看 `warnings[]`。
252
+ - **`hasCredentials: false` 的服务器连不上** —— IDE 会弹模态登录框,MCP 调用会卡死;动手前先看 `warnings[]`。
216
253
  - {{cmd_upload_to_deployment}} **把一条 deployment(本地映射目录)传到服务器**(等同 IDE 的 Upload to …)。
217
254
  `deploymentName` 传 `servers[].deployments[].name` —— **不是 `serverName`**。`mode` 默认 `mirror` ——
218
255
  **会删掉服务器上多出来的文件**,使两边一致;要留住它们就传 `upload`。 **破坏性操作**。
@@ -220,9 +257,11 @@
220
257
  两边都有的文件会被远端覆盖 (内容相同则不写)。同样传 `deploymentName`。 **没有"保留我的版本"这个选项**。
221
258
  - {{cmd_get_deployment_task_status}} **查一次传输的状态**:`handle` 用上传 / 下载返回的那个 —— **它自己不启动任何传输**。
222
259
 
223
- 上传 / 下载都在 IDE 后台跑,单次调用只等到 `waitMs`(默认 10 秒,上限 12 秒)为止。返回 `state: "in_progress"` 是 **正常**的,
224
- 不是失败 (它可能以 error 结果回来) —— 拿 `handle` 调 `get_deployment_task_status` 接着看; **不要用重复调上传 / 下载来代替**
225
- (那样会再起一次传输)。到 `completed` 之后 `counters` 才可信,而且它数的是**操作次数**,不是文件数(删掉整个目录也只算 1)。
260
+ 上传 / 下载默认**同步等结果**:传完立刻返回 `state: "completed"`。只有超过等待窗口(300 秒)还没传完,才会返回
261
+ `state: "in_progress"` + `handle` —— 这 **正常**,不是失败(它也可能以 error 结果回来);拿 `handle` 调
262
+ `get_deployment_task_status` 接着看 —— 重复调上传 / 下载会再起一次传输。到 `completed` 之后
263
+ `counters` 才可信,而且它数的是**操作次数**,不是文件数(删掉整个目录也只算 1)。
226
264
 
227
265
  **同步只是上半段**:传完之后在那台 Server 上继续操作(启动刚传上去的二进制、重启服务、看日志)—— 用
228
- `execute_in_remote_host`,`serverName` 取 `servers[].name`。
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.3' },
130
+ clientInfo: { name: 'opencode-idea', version: '0.1.4' },
131
131
  },
132
132
  });
133
133
  // The IDE's Streamable-HTTP endpoint binds follow-up requests to the session