Initialize Harmness Browser JetBrains plugin skeleton

- 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
This commit is contained in:
harmness
2026-09-10 13:27:43 +08:00
commit cbe41e4f4f
23 changed files with 1125 additions and 0 deletions
+195
View File
@@ -0,0 +1,195 @@
# Harmness Browser — JetBrains 插件
在 JetBrains IDEIntelliJ 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(约 12GB),请保持网络畅通。
### 3. 在 IDE 里运行/调试
在 IDEAUltimate 或 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**:勾选目标 IDEIDEA Community/Ultimate 等)
4. 提交后,若勾选 **Publish**(或之后手动点 Publish),插件会进入审核,一般几分钟到数小时;
审核通过后即可在 Marketplace 搜索到。
> 之后每次发新版,重复第 3–4 步即可。也可用 CIGitHub 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.22024.3。
- 后续可加:多地址书签、地址访问白名单(安全)、按 IDE 主题切换深/浅色、自动重连等。