cbe41e4f4f
- Gradle + Kotlin + IntelliJ Platform SDK build - JCEF embedded browser tool window with configurable start URL - Settings page (Tools > Harmness Browser) - JS<->Java bridge scaffold (window.harmnessBridge) - Vite + React + TypeScript web scaffold for embedded page - README: build, register, upload to Marketplace, install guide
195 lines
8.7 KiB
Markdown
195 lines
8.7 KiB
Markdown
# Harmness Browser — JetBrains 插件
|
||
|
||
在 JetBrains IDE(IntelliJ IDEA / PyCharm / PhpStorm / WebStorm 等)的侧边栏内嵌一个
|
||
**可配置地址的浏览器窗口**。默认搭配本地 [Harness](https://harness.io/) 这类 AI 助手
|
||
Web 服务使用,让你不用切出 IDE 就能在代码区与 AI 界面之间来回操作。
|
||
|
||
本仓库已初始化:
|
||
|
||
- **JetBrains 插件本体**(Kotlin + Gradle + IntelliJ Platform SDK,`src/`)
|
||
- **TypeScript Web 前端脚手架**(Vite + React + TS,`web/`,用于构建/调试将被嵌入的页面)
|
||
- **JS ↔ 插件双向桥** 示例(页面上直接调用 `window.harmnessBridge`)
|
||
|
||
## 项目结构
|
||
|
||
```
|
||
.
|
||
├── build.gradle.kts # Gradle 构建(IntelliJ Platform plugin build)
|
||
├── settings.gradle.kts
|
||
├── gradle.properties
|
||
├── scripts/
|
||
│ └── setup-toolchain.sh # 一键下载 JDK17 + Gradle(无 root 环境)
|
||
├── src/main/
|
||
│ ├── kotlin/com/harmness/toolwindow/
|
||
│ │ ├── HarmnessBrowserPanel.kt # JCEF 内嵌浏览器 + JS↔Java 桥
|
||
│ │ ├── HarmnessToolWindowFactory.kt # 侧边栏工具窗口
|
||
│ │ ├── HarmnessSettingsConfigurable.kt # 设置页入口
|
||
│ │ ├── HarmnessBrowserConfigurablePanel.kt # 设置 UI(起始地址)
|
||
│ │ ├── SettingsState.kt # 持久化设置存储
|
||
│ │ └── WindowFocusService.kt # 工具窗口焦点广播(预留)
|
||
│ └── resources/
|
||
│ ├── META-INF/plugin.xml # 插件声明(扩展点注册)
|
||
│ └── icons/harmness.svg # 工具窗口图标
|
||
└── web/ # (可选)被嵌入页面的前端脚手架
|
||
├── package.json
|
||
├── vite.config.ts
|
||
└── src/{main.tsx, App.tsx, bridge.ts, ...}
|
||
```
|
||
|
||
## 本地构建
|
||
|
||
### 1. 准备工具链(本机没有 JDK/Gradle 时)
|
||
|
||
```bash
|
||
./scripts/setup-toolchain.sh
|
||
# 会下载 Temurin JDK 17 与 Gradle 8.11.1 到 .tools/
|
||
```
|
||
|
||
若本机已装 JDK 17+ 与 Gradle,可跳过,直接用系统的。
|
||
|
||
### 2. 构建插件 zip
|
||
|
||
```bash
|
||
export JAVA_HOME=/data/project/Plugin/harmness/.tools/jdk-17.0.12+7 # 若用脚本版
|
||
./.tools/gradle-8.11.1/bin/gradle buildPlugin -x test
|
||
```
|
||
|
||
产物:`build/distributions/harmness-toolwindow-0.1.0.zip`
|
||
|
||
> 首次构建会下载 IntelliJ Platform SDK(约 1–2GB),请保持网络畅通。
|
||
|
||
### 3. 在 IDE 里运行/调试
|
||
|
||
在 IDEA(Ultimate 或 Community 均可)中:
|
||
|
||
1. `File → Open` 打开本仓库根目录(Gradle 项目会自动识别)。
|
||
2. `Gradle → Tasks → intellij → runIde`,或运行主类
|
||
`com.intellij.idea.Main`(由 Gradle 任务 `runIde` 提供)。
|
||
3. 等 IDE 启动后,右侧边栏会出现 **Harmness Browser** 工具窗口。
|
||
|
||
### 4. 前端(可选)
|
||
|
||
```bash
|
||
cd web
|
||
npm install
|
||
npm run dev # 起一个位于 http://127.0.0.1:8888 的页面
|
||
```
|
||
|
||
然后在插件设置里把「起始地址」填成 `http://127.0.0.1:8888`,即可在 IDE 侧边栏里看到该页面。
|
||
|
||
## 功能与使用
|
||
|
||
| 功能 | 说明 |
|
||
| --- | --- |
|
||
| 侧边栏浏览器 | 打开 IDE 后右侧出现可停靠/悬浮的工具窗口 |
|
||
| 配置起始地址 | `Settings → Tools → Harmness Browser`(或点工具栏 ⚙) |
|
||
| 地址栏 | 手动输入任意地址回车跳转 |
|
||
| 前进/后退/刷新 | 工具栏 ← → ⟳ |
|
||
| 外部浏览器打开 | 工具栏 ⧉ 把当前地址丢给系统浏览器 |
|
||
| JS↔Java 桥 | 页面加载后注入 `window.harmnessBridge(payload)`,网页可调用插件能力(原型:`ping` / `getUrl` / `openExternal:*`) |
|
||
|
||
### JS↔Java 桥(给 Harness 前端用)
|
||
|
||
`web/src/bridge.ts` 提供类型化封装:
|
||
|
||
```ts
|
||
import { callPlugin, openInExternalBrowser, initBridge } from './bridge'
|
||
|
||
initBridge(( ) => console.log('bridge ready'))
|
||
|
||
const pong = await callPlugin('ping') // -> "pong"
|
||
openInExternalBrowser('https://example.com') // 用系统浏览器打开
|
||
```
|
||
|
||
如果想要 Harness(或其前端)在收到网页请求时把代码插入编辑器、打开文件等,
|
||
需要在 `HarmnessBrowserPanel.setupBridge()` 的 handler 里扩展桥协议,
|
||
并通过 IntelliJ Platform API(`FileDocumentManager`、`EditorFactory`、`CodeInsightUtil` 等)
|
||
实现。IntelliJ 官方插件 SDK 不提供对 JCEF 页面 DOM 的直接访问,双向通信一律走
|
||
`JBCefJSQuery`(本插件已封装)。
|
||
|
||
## 发布到 JetBrains Marketplace
|
||
|
||
### 1. 注册 JetBrains 账号
|
||
|
||
访问 <https://account.jetbrains.com/login> 注册/登录(可用 Google / GitHub 账号)。
|
||
|
||
### 2. 申请插件仓库(只有一次)
|
||
|
||
1. 打开 <https://plugins.jetbrains.com/> 并登录。
|
||
2. 右上角头像 → **Developer Console**(或直接 <https://plugins.jetbrains.com/developer>)。
|
||
3. 点击 **Create New Plugin**(第一次需要填组织/开发者信息 + 同意
|
||
[Plugin Hosting Terms](https://plugins.jetbrains.com/docs/marketplace/plugin-hosting-terms.html))。
|
||
4. 创建后会得到一个 **Plugin ID**,把 `plugin.xml` 里的 `<id>`(当前为
|
||
`com.harmness.toolwindow`)改成该 ID(建议保持相同,便于后续关联)。
|
||
|
||
### 3. 构建并本地验证产物
|
||
|
||
```bash
|
||
./.tools/gradle-8.11.1/bin/gradle buildPlugin -x test
|
||
```
|
||
|
||
生成的 `build/distributions/*.zip` 即发布物。
|
||
|
||
可选(推荐):在 IDE 里用 `Settings → Plugins → ⚙ → Install Plugin from Disk…`
|
||
选这个 zip 验证一次,再上传。
|
||
|
||
### 4. 上传发布
|
||
|
||
1. 进入 <https://plugins.jetbrains.com/developer>,选你的插件。
|
||
2. **Upload Plugin** 上传 zip。
|
||
3. 填写版本信息:
|
||
- **Version**:与 `build.gradle.kts` 的 `version` 一致(如 `0.1.0`)
|
||
- **Since / Until build**:对应 `plugin.xml` 的 `242 / 243.*`
|
||
- **Changelog**:版本变更说明
|
||
- **Compatibility**:勾选目标 IDE(IDEA Community/Ultimate 等)
|
||
4. 提交后,若勾选 **Publish**(或之后手动点 Publish),插件会进入审核,一般几分钟到数小时;
|
||
审核通过后即可在 Marketplace 搜索到。
|
||
|
||
> 之后每次发新版,重复第 3–4 步即可。也可用 CI(GitHub Actions + JetBrains
|
||
> [publish plugin task](https://plugins.jetbrains.com/docs/intellij/publishing-plugin.html),
|
||
> `gradle publishPlugin`)自动化。
|
||
|
||
### 5. 其他人安装使用
|
||
|
||
- **IDE 内**:`Settings → Plugins → Marketplace`,搜索 `Harmness Browser` 安装。
|
||
- **手动**:`Settings → Plugins → ⚙ → Install Plugin from Disk…` 选 zip。
|
||
- **下载**:<https://plugins.jetbrains.com/plugin/xxxx>(你的插件主页)。
|
||
|
||
安装后在右侧栏点开 **Harmness Browser**,到
|
||
`Settings → Tools → Harmness Browser` 把地址配置成你的 Harness 实例即可。
|
||
|
||
## 与 Harness 的适配注意点(重要)
|
||
|
||
1. **嵌入限制**:目标 Web 应用(Harness)必须允许被嵌入渲染:
|
||
- 不能返回 `X-Frame-Options: DENY/SAMEORIGIN`,
|
||
- CSP 里不能有 `frame-ancestors 'none'`。
|
||
若 Harness 有这些限制,需要在其反向代理/HTTP 头里放行,或使用 Harness 专门的无 frame 限制入口。
|
||
2. **登录态**:cookie 与本地存储默认按 JCEF 的浏览器实例隔离,登录 Harness 后一般会保留
|
||
(IDE 重启后缓存仍有效,除非换 IDE/机器)。
|
||
3. **性能与授权**:JCEF 每次都会初始化一个 Chromium 实例,多个 IDE 窗口会占用较多内存;
|
||
老机器上建议只保留最需要的 IDE 窗口。
|
||
4. **桥接协议**:要把「网页请求 → 编辑代码/打开文件」打通,需按前面「JS↔Java 桥」一节扩展插件。
|
||
|
||
## 关于「把 Harness 塞进侧边栏」的可行性评估(给决策用)
|
||
|
||
你的想法是合理的,也是目前社区常见的做法(例如在 IDE 里嵌入 ChatGPT / Copilot 网页版)。
|
||
优点:
|
||
|
||
- 不用在两个窗口之间来回切换,交互摩擦小;
|
||
- 利用 IDE 自带的 JCEF,不需要额外浏览器进程;
|
||
- 可以做双向桥,网页 → 编辑器有原生 IPC 通路。
|
||
|
||
局限(需要接受或规避):
|
||
|
||
- JCEF = 内置 Chromium,内存占用明显(每个 IDE 窗口一份);
|
||
- 官方 SDK 不给页面 DOM 权限,需求超过「纯网页浏览 + 简单桥」就要自己维护桥协议
|
||
(本插件已铺好骨架);
|
||
- 第三方网页的嵌入限制(X-Frame-Options / CSP)可能直接挡掉,需要 Harness 侧配合。
|
||
|
||
结论:**方向可行**。建议先把 `web/` 里替换成 Harness 实际前端,跑通「配置地址 → 侧边栏显示 →
|
||
桥接 ping」这条链路,再决定扩展哪些 IDE 能力。
|
||
|
||
## License / 后续
|
||
|
||
- 当前版本为原型骨架(0.1.0),默认 `sinceBuild=242, untilBuild=243.*`,只覆盖 2024.2–2024.3。
|
||
- 后续可加:多地址书签、地址访问白名单(安全)、按 IDE 主题切换深/浅色、自动重连等。 |