opencode-idea 0.0.26 → 0.0.27

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
@@ -169,9 +169,11 @@ IDE MCP 可用时,插件通过 **系统提示注入**告诉模型 **哪些事该
169
169
  `ide_download_from_deployment` / `ide_get_deployment_task_status`
170
170
  - **读、找文本、找文件用原生工具**(`read` / `grep` / `glob`)—— 这几件事走 IDE 只是多一跳,
171
171
  所以映射表里 **不出现** `ide_search_text` / `ide_search_regex` / `ide_search_file`,也不再禁止它们的原生对应物。
172
- - **写文件反过来走 IDE**(`ide_apply_patch` / `ide_create_new_file`):原生 `write` / `edit` 是 **进程外**写,
173
- IDE 对编辑器里开着的文件留着一份内存副本,要等 VFS 刷新才重读 —— 这期间 IDE 侧工具读到的是旧内容,
174
- `reformat_file` 还会把旧副本存回磁盘把刚写的代码冲掉。走 IDE 写,内存与磁盘才是同一份。
172
+ - **写文件一律用原生 `write` / `edit`**:IDE 的 `apply_patch` / `create_new_file` 已收起 —— 补丁工具按上下文精确匹配,
173
+ 标点被规范化就整块对不上(`Hunk context not found`),而原生写没有这层限制。IDE 侧只留 **重构**与**格式化**。
174
+ **`ide_reformat_file` 会从磁盘重读**,所以外部写完直接格式化是安全的(实测:新增 / 删除 / 改文本都不会被旧副本
175
+ 冲掉);会丢内容的只有 **用户在编辑器里正改着的那份脏 buffer**,别对它跑 formatter。
176
+ **读**是另一回事:`ide_read_file` 可能给出旧快照,要它跟上得先跑一次 `ide_get_file_problems`。
175
177
  - **唯一例外是 `ide_read_file`**:它是读 **包内文件**的唯一手段 (`<jar>!/<entry>` 的依赖 jar 内文件、`jrt://` 的
176
178
  JDK 镜像),引导只在这个用途上点名它,并写明普通文件一律用 `read`。
177
179
 
@@ -429,9 +431,8 @@ loader 读的是 OpenCode 文档里的那个嵌套写法 (它自己的读取器
429
431
  `ShConfigurationType`
430
432
  (`<option>` 子元素)、`NodeJSConfigurationType`(全属性)三种写法并存,套错就是静默失效。
431
433
 
432
- **先过滤,再建档**:**服务化的配置不进这个块** —— 它们已经登记在 `AGENTS.md` 的 `idea-standalone` 块里 (端口 /
433
- 热重载也写在那里),
434
- 所以建档第一步是读那个块、把它登记过的名字记下来并排除, **剩下的**才是本块内容。
434
+ **先过滤,再建档**:**服务化 / 常驻应用的配置一律不进这个块**(它们归 `idea-standalone`,端口与热重载写在那边的块里);
435
+ 有那个块时,再把它登记过的名字一并排除 —— **剩下的**才是本块内容。
435
436
 
436
437
  这个档案块 **以带前缀的工具为准**,不围绕 IDE 界面说话:各项目各有自己的前缀 (root 是 `ide`,子项目是它的目录名),枚举与执行都用
437
438
  **它自己那个前缀**的
@@ -442,20 +443,14 @@ loader 读的是 OpenCode 文档里的那个嵌套写法 (它自己的读取器
442
443
  删除 / 修改**
443
444
  (无论谁做的:工具建的、用户自己建的、用户删掉的)都要在文档里同步 **加条目 / 删条目 / 改条目**,否则它就开始骗人。
444
445
 
445
- **别的文档都指向这里**:引导文本与 `idea-standalone` skill 碰到"要建 / 删 / 改一个配置",不再让用户自己去 IDE 里摸,而是让用户调本
446
- skill ——
447
- 增 / 删 / 改的流程入口只有这一个,而它只由用户触发。
446
+ **别的文档都指向这里**:引导文本碰到"要建 / 删 / 改一个配置",不再让模型现编流程,而是让它加载本 skill ——
447
+ 增 / 删 / 改的流程与档案规则只有这一处。
448
448
 
449
- **它绕着"新建配置"这件事写**(新建只有配套插件 `idea-mcp-enhance` 能做),但 **这不影响它出不出现** —— 两个 skill
450
- 都在插件加载时注册,
451
- 不缺任何工具也照样在列表里;缺工具时由正文把流程交回用户 (`idea-standalone` 只要 `rerun_run_configuration`,门更松)
452
- 。这是刻意的:
453
- 一个只教模型"去建配置"、却没给建配置工具的 skill,只会把用户拖进一次注定失败的调用。
449
+ **两个 skill 都是模型可自取的**(frontmatter 不带 `metadata: opencode/autoinvoke: false`):模型判断到场景就加载。
450
+ 「该不该建」的判断留在引导文本里(它每次请求都在),skill 负责动手时的流程与写法。
454
451
 
455
- **而且只能用户调**:它的 frontmatter 带 `metadata: opencode/autoinvoke: false`,loader 翻成定义的 `autoinvoke: false` ——
456
- skill 照常注册,但 **不进模型的可选列表**,模型不会自己挑上它,只有用户显式指定 (`@idea-run-config-manager`)才会加载。
457
- 理由是它 **直接动手改项目文件与项目资产**:运行配置与 `AGENTS.md` 都由用户自己按这个 skill 的流程来改,模型不主动挑上它。
458
- 「该不该建」的时机判断仍在引导文本的判据里 (那是模型该管的事), **动手权**留给人。
452
+ **它绕着"新建配置"这件事写**,但不影响它出不出现 —— 两个 skill 都在插件加载时注册,缺工具时由正文把流程交回用户
453
+ (`idea-standalone` 只要 `rerun_run_configuration`,门更松)。
459
454
 
460
455
  ## Deployment 全套 (配套插件 `idea-mcp-enhance`)
461
456
 
@@ -667,19 +662,19 @@ export { default } from "/Users/yutao/Projects/opencode-idea/src/index.js";
667
662
  不存在 —— 用错会让 `ctx.skill.transform` 抛 `SchemaError`,而 **任何 transform 失败都会禁用整个插件**(0.0.6 就是这样丢了
668
663
  `/open-in-ide`)。同理,`Skill.Info` 的完整字段是 `id` / `name` / `description?` / `autoinvoke?` / `path` / `content`。
669
664
  - 需要项目环境的命令走 `ide_execute_run_configuration`(run configuration 要先在 IDEA 里配好),不用原生 shell。
670
- - 一批用不到的 IDE MCP 工具被硬编码隐藏 (`src/plugin.js` 的 `HIDDEN_IDE_TOOL_SUFFIXES`, **共 47 个后缀**):
665
+ - 一批用不到的 IDE MCP 工具被硬编码隐藏 (`src/plugin.js` 的 `HIDDEN_IDE_TOOL_SUFFIXES`, **共 49 个后缀**):
671
666
  VCS (`git_status` / `get_repositories`,版本控制走原生 `git`)、Router 派发工具 (`execute_tool`,未启用 router-only
672
667
  时冗余)、
673
668
  Debugger (全部 `xdebug_*`)、Dev Kit MCP、Inspection KTS MCP、解释器环境 MCP、 **IDE 内置终端 (`execute_terminal_command`:
674
669
  实测不继承项目环境,对原生 shell 没有优势)**、 **整个 Database 组**(数据源由用户在
675
- IDE 里配置,而 IDE 也不是本插件设想的数据库客户端),以及 **有原生对应的文件搜索**
676
- (`search_text` / `search_regex` / `search_file` 分别对应 `grep` / `grep -E` / `glob`)。 **文件"写"(`apply_patch` /
677
- `create_new_file`)刻意不隐藏** —— 走 IDE 写才有"内存与磁盘是同一份"这件事 (见上面
678
- 「写文件反过来走 IDE」);配套插件自带的那个写文件工具则隐藏,同一个活儿不摆两个工具。
670
+ IDE 里配置,而 IDE 也不是本插件设想的数据库客户端)、 **有原生对应的文件搜索**
671
+ (`search_text` / `search_regex` / `search_file` 分别对应 `grep` / `grep -E` / `glob`),以及 **文件写**
672
+ (`apply_patch` / `create_new_file`:原生 `write` / `edit` 就够,补丁工具的上下文精确匹配反而脆 —— 见上面
673
+ 「写文件一律用原生」)。配套插件自带的那个写文件工具同样隐藏。
679
674
 
680
675
  存的是 **后缀**,清洗时按当前每个项目前缀 **各删一遍** —— 只处理 `ide_` 会让子项目那几份原样送到模型面前。
681
- 实测数字 (拿运行中的 IDE MCP 拉 `tools/list`,单个项目):IDE 暴露 **76** 个 → 隐藏 47 → **模型可见 29 个**,
682
- 而且这 29 个 **恰好等于引导里点名的 29 个** —— 没有"能看见但没人告诉它用途"的残留。多项目就是 N × 29:
676
+ 实测数字 (拿运行中的 IDE MCP 拉 `tools/list`,单个项目):IDE 暴露 **76** 个 → 隐藏 49 → **模型可见 27 个**,
677
+ 而且这 27 个 **恰好等于引导里点名的 27 个** —— 没有"能看见但没人告诉它用途"的残留。多项目就是 N × 29:
683
678
  暴露面完全由插件决定,不需要 OpenCode 提供任何白名单能力,也不需要惰性注册。
684
679
 
685
680
  - **部署工具只在 Ultimate 上出现**:`ide_list_deployment_servers` / `ide_upload_to_deployment` /
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-idea",
3
- "version": "0.0.26",
3
+ "version": "0.0.27",
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",
@@ -43,6 +43,5 @@ description: "为项目固化 standalone(启动收口只有 IDEA run configurati
43
43
  3. **新增**(文件里还没有标记块):在 `AGENTS.md` **末尾追加**标记块,文件既有内容原样保留;文件不存在则创建它。
44
44
  只替换标记内内容、不动标记外 —— 尤其 **不要触碰**其他 skill 的标记块 (例如 `project-scaffold`)。
45
45
  4. **更新**(已有标记块):只替换 `<!-- idea-standalone:begin -->` 与 `<!-- idea-standalone:end -->` 之间的内容,块外一字不动。
46
- 5. 改文件用 **IDE 的编辑命令** `<前缀>_apply_patch`(新建用 `<前缀>_create_new_file`),不要用原生 `write` / `edit`。
47
- **不要整文件重写**。
46
+ 5. 改文件用原生 `edit` 替换标记块里那一段; **不要整文件重写**。
48
47
  6. 复读并核对:标记块内逐段与模板一致,块外内容与改动前逐字一致,报告产物清单。
@@ -23,8 +23,11 @@
23
23
  也不要用 Code Mode 的 `search` 去找 (它们不在那份目录里,搜不到)。
24
24
  - **只有 IDE 才有的能力才用它们**:符号级检索、项目模型、检查与构建、重构与格式化、run configuration。
25
25
  - **读与搜索用原生工具**(`read` / `grep` / `glob`):不要为读一个文件、搜一段文本去绕 IDE 工具。
26
- - **改项目代码用 IDE 的编辑命令**(`<前缀>_apply_patch`,新建文件用 `<前缀>_create_new_file`),不要用原生 `write` / `edit` ——
27
- 那两个在进程外写,IDE 手里可能还是旧内容,紧接着的 IDE 侧工具会基于旧代码干活。项目目录之外的文件才用原生那两个。
26
+ - **改文件一律用原生 `write` / `edit`** —— 不受补丁上下文匹配的限制(IDE 那个补丁工具按上下文精确匹配,标点被规范化就
27
+ 整块对不上,已经收起不用)。IDE 侧的写操作只留 **重构**与**格式化**两件事。
28
+ - **`reformat_file` 会从磁盘重读**,外部写完直接格式化是安全的(实测:新增 / 删除 / 改文本都不会被冲掉)。
29
+ - **文档类文件 (Markdown / 文档) 改完之后,用 `<前缀>_reformat_file` 过一遍** —— 表格对齐、换行宽度、缩进都交给 IDE
30
+ 统一,别手搓空格。
28
31
  - **改完代码自己先查一遍**:用 `lint_files` / `build_project`,怎么挑见下面「校验」。
29
32
  - 某条功能下面没有你正要操作的那个项目的命令,就是那个项目没接上:提示用户执行 `/open-in-ide`,不要重试,也不要去别处找。
30
33
 
@@ -79,13 +82,8 @@
79
82
  - {{cmd_get_all_open_file_paths}} **用户在 IDE 里打开了哪些文件**(含当前激活的那个)。
80
83
  - {{cmd_open_file_in_editor}} **把文件在 IDE 里打开并激活**,给用户看。
81
84
 
82
- ### 改代码 (编辑 · 重构 · 校验)
85
+ ### 改代码 (重构 · 格式化 · 校验)
83
86
 
84
- - {{cmd_apply_patch}} **走 IDE 改文件**:`input` 传补丁 (两种格式都行 —— Codex 的 `*** Begin Patch` /
85
- `*** Update File: <路径>` / `@@` / `*** End Patch`,或 unified git diff)。一个补丁里可混着 **Add / Update / Delete**
86
- 多个操作,`Update` 还能带 `*** Move to: <新路径>` 改名; **按上下文匹配**,`@@` 不用写行号。返回
87
- `N out of M operations applied`,对不上的 hunk 会报 `Hunk context not found`。路径必须在项目内。
88
- - {{cmd_create_new_file}} **新建文件**:`pathInProject` + `text`;父目录自动建,`overwrite` 默认关 (文件已存在会报错)。
89
87
  - {{cmd_rename_refactoring}} **按符号改名**,项目内的引用一并更新。
90
88
  - {{cmd_reformat_file}} **按 IDE 的代码风格重排**。
91
89
  - {{cmd_lint_files}} **批量检查**:`files` 传数组;只列有问题的文件。
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.0.26' },
130
+ clientInfo: { name: 'opencode-idea', version: '0.0.27' },
131
131
  },
132
132
  });
133
133
  // The IDE's Streamable-HTTP endpoint binds follow-up requests to the session
package/src/plugin.js CHANGED
@@ -151,16 +151,18 @@ const PLUGIN_TOOL_NAMES = new Set(['configure_ide_project']);
151
151
  * it is the only way to read a file inside a jar (`<jar>!/<entry>`) or the
152
152
  * JDK's `jrt://` image, so the guidance keeps it for exactly that and sends
153
153
  * ordinary reads to the native tool.
154
- * - Plain file **write**: `apply_patch` / `create_new_file` are **kept**, and
155
- * they are the ones the guidance sends writes to. The native `write` / `edit`
156
- * write from **outside** the IDE, and the IDE keeps an in-memory copy of every
157
- * file it has open — that copy is only re-read when the VFS refreshes, so
158
- * between the write and the refresh the IDE still sees the OLD text. Measured
159
- * against a real IDE: after an external write, `read_file` still returned the
160
- * old content; after `apply_patch` it returned the new one immediately. That
161
- * gap is not cosmetic — `reformat_file` formats the in-memory copy and
162
- * **writes it back**, silently discarding whatever was just written. Writing
163
- * through the IDE (`apply_patch`) keeps the two copies the same thing.
154
+ * - Plain file **write**: `apply_patch` / `create_new_file` are **hidden** too.
155
+ * Writes go through the native `write` / `edit`: they are simpler, and the
156
+ * IDE's patch tool is brittle in a way that costs real time — it matches hunks
157
+ * by exact context text, so a quote or a corner bracket normalised somewhere
158
+ * on the way in fails the whole hunk (`Hunk context not found`).
159
+ * Measured against a real IDE, the stale-copy concern does not justify keeping
160
+ * them: `reformat_file` re-reads from disk (append / delete / edit all survived
161
+ * it), and `apply_patch` is not what made the in-memory copy fresh — only
162
+ * `ide_read_file` lags behind an external write, and the guidance tells the
163
+ * model to read ordinary files with the native `read` anyway.
164
+ * `rename_refactoring` and `reformat_file` stay: both are capabilities the
165
+ * native tools do not have.
164
166
  * - IDE terminal: `execute_terminal_command` does NOT inherit the project's
165
167
  * environment. It was exposed on the assumption that it ran with the SDKs the
166
168
  * user configured in the IDE (JDK, Node, Python, ...), but measured against a
@@ -232,11 +234,12 @@ export const HIDDEN_IDE_TOOL_SUFFIXES = [
232
234
  'search_text',
233
235
  'search_regex',
234
236
  'search_file',
235
- // The companion plugin's own write tool. The IDE's built-in `apply_patch` /
236
- // `create_new_file` already cover writing through the IDE, so this one is
237
- // hidden: two tools for the same job is a worse answer than one. The plugin
238
- // has dropped it as well — this line only hides the copies still served by
239
- // the plugin version installed before that.
237
+ // File WRITE: the native `write` / `edit` do the job, and the IDE's patch
238
+ // tool matches hunks by exact context text (a normalised quote fails the
239
+ // hunk). `edit_file` is the companion plugin's own writer, dropped by the
240
+ // plugin itself — hiding it only covers the older installed copies.
241
+ 'apply_patch',
242
+ 'create_new_file',
240
243
  'edit_file',
241
244
  ];
242
245