pi-x-ide 1.4.3 → 1.5.1

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
@@ -46,11 +46,16 @@ See [Configuration Reference](#pi-side-environment-variables) for all available
46
46
 
47
47
  No extension installation is needed. Pi automatically detects Zed when running inside a Zed terminal (`ZED_TERM=true` or `TERM_PROGRAM=zed`). Pi reads Zed's local state database to discover the active editor file and selection.
48
48
 
49
- Requires Node.js ≥ 26 and Zed running on the same machine.
50
-
51
49
  #### Neovim
52
50
 
53
- Neovim support uses a Lua plugin plus a bundled Node.js sidecar. Pi can run from any terminal matching the Neovim workspace — it does not need to run inside Neovim.
51
+ Neovim support uses a Lua plugin plus a sidecar process. On first start the
52
+ plugin downloads a standalone binary for your platform (Linux / macOS / Windows,
53
+ x64 or arm64) from GitHub Releases. If the download fails, or no binary matches
54
+ your platform, the plugin falls back to the bundled Node.js sidecar — Node.js is
55
+ then required on PATH.
56
+
57
+ The binary is cached under `stdpath("cache")/pi-x-ide/` and reused on subsequent
58
+ starts. Plugin updates trigger a one-time re-download.
54
59
 
55
60
  **lazy.nvim:**
56
61
 
@@ -151,11 +156,14 @@ require("pi_x_ide").setup({
151
156
  range_format = "comma", -- or "dash"
152
157
  debounce_ms = 150,
153
158
  -- sidecar_cmd = { "node", "/absolute/path/to/pi-x-ide-nvim-sidecar.cjs" },
159
+ -- (defaults to the platform binary; falls back to node + cjs if no binary found)
154
160
  -- workspace_folders = { "/path/to/project" },
155
161
  })
156
162
  ```
157
163
 
158
- If the sidecar does not start, run `:PiXIdeStatus`, confirm Node.js is available on Neovim's `PATH`, or set `sidecar_cmd` to an absolute Node command.
164
+ If the sidecar does not start, run `:PiXIdeStatus`, or set `sidecar_cmd` to a
165
+ custom command. The plugin prefers the platform binary but falls back to Node.js
166
+ when no binary matches.
159
167
 
160
168
  **Commands:**
161
169
 
@@ -203,7 +211,7 @@ See [docs/specs/ide-protocol.md](docs/specs/ide-protocol.md) for protocol detail
203
211
  ### Prerequisites
204
212
 
205
213
  - Node.js ≥ 26
206
- - pnpm11 (`packageManager` declared as `pnpm@11.5.2`)
214
+ - bun1.3 (`packageManager` declared as `bun@1.3.14`)
207
215
  - VS Code ≥ 1.90 (VS Code extension only)
208
216
  - Neovim ≥ 0.9 (Neovim plugin only)
209
217
 
@@ -214,8 +222,8 @@ Clone the repository, then build:
214
222
  ```bash
215
223
  git clone https://github.com/balaenis/pi-x-ide.git
216
224
  cd pi-x-ide
217
- pnpm install
218
- pnpm build
225
+ bun install
226
+ bun run build
219
227
  ```
220
228
 
221
229
  To load the local build without installing globally:
@@ -226,13 +234,13 @@ pi -e ./src/pi/index.ts
226
234
 
227
235
  Common commands:
228
236
 
229
- | Command | Description |
230
- | --------------------- | -------------------------------------------------------------------------------------------------- |
231
- | `pnpm build` | Build Pi-side TypeScript → `dist/` + Neovim sidecar → `nvim/bin/` + VS Code bundle → `vscode/out/` |
232
- | `pnpm typecheck` | Type-check only (no output files) |
233
- | `pnpm test` | Build + run unit tests |
234
- | `pnpm package:vscode` | Package VS Code extension as VSIX |
235
- | `pnpm vsix` | Alias for `pnpm package:vscode` |
237
+ | Command | Description |
238
+ | ------------------------ | -------------------------------------------------------------------------------------------------- |
239
+ | `bun run build` | Build Pi-side TypeScript → `dist/` + Neovim sidecar → `nvim/bin/` + VS Code bundle → `vscode/out/` |
240
+ | `bun run typecheck` | Type-check only (no output files) |
241
+ | `bun run test` | Build + run unit tests |
242
+ | `bun run package:vscode` | Package VS Code extension as VSIX |
243
+ | `bun run vsix` | Alias for `bun run package:vscode` |
236
244
 
237
245
  ### Testing the VS Code Extension Locally
238
246
 
@@ -242,13 +250,13 @@ Common commands:
242
250
  2. Go to the **Run and Debug** panel (`Ctrl+Shift+D`).
243
251
  3. Select **Run Pi x IDE VS Code Extension**.
244
252
  4. Press **F5**:
245
- - The `preLaunchTask` automatically runs `pnpm build`.
253
+ - The `preLaunchTask` automatically runs `bun run build`.
246
254
  - A new VS Code window titled `[Extension Development Host]` opens.
247
255
 
248
256
  #### Option 2: Package VSIX and Install
249
257
 
250
258
  ```bash
251
- pnpm package:vscode
259
+ bun run package:vscode
252
260
  code --install-extension './vscode'-0.1.0.vsix
253
261
  ```
254
262
 
package/README.zh.md CHANGED
@@ -46,11 +46,15 @@ PI_X_IDE_AUTO_INSTALL=0
46
46
 
47
47
  无需安装任何扩展。Pi 在 Zed 终端中运行时(`ZED_TERM=true` 或 `TERM_PROGRAM=zed`)会自动检测并连接。Pi 通过读取 Zed 本地状态数据库获取活跃编辑器和选区信息。
48
48
 
49
- 需要 Node.js ≥ 26,Zed 在同一台机器上运行。
50
-
51
49
  #### Neovim
52
50
 
53
- Neovim 支持由一个 Lua 插件和一个内置的 Node.js sidecar 组成。只要当前目录匹配 Neovim workspace,Pi 可以从任意终端启动,不要求在 Neovim 内部运行。
51
+ Neovim 支持由一个 Lua 插件和一个 sidecar 进程组成。首次启动时插件会自动从
52
+ GitHub Releases 下载适合当前平台的独立二进制文件(Linux/macOS/Windows,
53
+ x64 或 arm64)。下载失败或无匹配二进制时,插件降级到内置的 Node.js sidecar —
54
+ 此时需要 PATH 中有 Node.js。
55
+
56
+ 二进制文件缓存在 `stdpath("cache")/pi-x-ide/` 目录,后续启动直接复用。插件
57
+ 更新后会触发一次重新下载。
54
58
 
55
59
  **lazy.nvim:**
56
60
 
@@ -151,11 +155,13 @@ require("pi_x_ide").setup({
151
155
  range_format = "comma", -- 或 "dash"
152
156
  debounce_ms = 150,
153
157
  -- sidecar_cmd = { "node", "/absolute/path/to/pi-x-ide-nvim-sidecar.cjs" },
158
+ -- (默认使用平台二进制文件;找不到时降级到 node + cjs)
154
159
  -- workspace_folders = { "/path/to/project" },
155
160
  })
156
161
  ```
157
162
 
158
- 如果 sidecar 无法启动,请运行 `:PiXIdeStatus`,确认 Neovim 的 `PATH` 中可以找到 Node.js,或将 `sidecar_cmd` 设置为绝对 Node 命令。
163
+ 如果 sidecar 无法启动,请运行 `:PiXIdeStatus`,或设置 `sidecar_cmd` 为自定义
164
+ 命令。插件优先使用平台二进制文件,找不到匹配项时降级到 Node.js。
159
165
 
160
166
  **命令:**
161
167
 
@@ -203,7 +209,7 @@ Pi 通过 `ctx.cwd` 与 lock file 中的 `workspaceFolders` 做最长路径匹
203
209
  ### 环境依赖
204
210
 
205
211
  - Node.js ≥ 26
206
- - pnpm11(`packageManager` 声明为 `pnpm@11.5.2`)
212
+ - bun1.3(`packageManager` 声明为 `bun@1.3.14`)
207
213
  - VS Code ≥ 1.90(仅 VS Code 扩展需要)
208
214
  - Neovim ≥ 0.9(仅 Neovim 插件需要)
209
215
 
@@ -214,8 +220,8 @@ Clone 仓库后构建:
214
220
  ```bash
215
221
  git clone https://github.com/balaenis/pi-x-ide.git
216
222
  cd pi-x-ide
217
- pnpm install
218
- pnpm build
223
+ bun install
224
+ bun run build
219
225
  ```
220
226
 
221
227
  加载本地构建(无需全局安装):
@@ -226,13 +232,13 @@ pi -e ./src/pi/index.ts
226
232
 
227
233
  常用命令:
228
234
 
229
- | 命令 | 说明 |
230
- | --------------------- | ----------------------------------------------------------------------------------------------- |
231
- | `pnpm build` | 编译 Pi 侧 TypeScript → `dist/` + Neovim sidecar → `nvim/bin/` + VS Code bundle → `vscode/out/` |
232
- | `pnpm typecheck` | 类型检查(不产出文件) |
233
- | `pnpm test` | 编译 + 运行单元测试 |
234
- | `pnpm package:vscode` | 打包 VS Code 扩展为 VSIX |
235
- | `pnpm vsix` | `pnpm package:vscode` 的别名 |
235
+ | 命令 | 说明 |
236
+ | ------------------------ | ----------------------------------------------------------------------------------------------- |
237
+ | `bun run build` | 编译 Pi 侧 TypeScript → `dist/` + Neovim sidecar → `nvim/bin/` + VS Code bundle → `vscode/out/` |
238
+ | `bun run typecheck` | 类型检查(不产出文件) |
239
+ | `bun run test` | 编译 + 运行单元测试 |
240
+ | `bun run package:vscode` | 打包 VS Code 扩展为 VSIX |
241
+ | `bun run vsix` | `bun run package:vscode` 的别名 |
236
242
 
237
243
  ### 本地测试 VS Code 扩展
238
244
 
@@ -242,13 +248,13 @@ pi -e ./src/pi/index.ts
242
248
  2. 进入 **Run and Debug** 面板(`Ctrl+Shift+D`)。
243
249
  3. 选择 **Run Pi x IDE VS Code Extension**。
244
250
  4. 按 **F5**:
245
- - preLaunchTask 会自动执行 `pnpm build`。
251
+ - preLaunchTask 会自动执行 `bun run build`。
246
252
  - 打开一个标题包含 `[Extension Development Host]` 的新 VS Code 窗口。
247
253
 
248
254
  #### 方式二:打包 VSIX 后安装
249
255
 
250
256
  ```bash
251
- pnpm package:vscode
257
+ bun run package:vscode
252
258
  code --install-extension './vscode'-0.1.0.vsix
253
259
  ```
254
260
 
package/dist/package.json CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "name": "pi-x-ide",
3
- "version": "1.4.3",
3
+ "version": "1.5.1",
4
4
  "description": "Pi extension package for IDE selection context integration.",
5
5
  "files": [
6
6
  "dist",
7
7
  "schemas",
8
- "src",
9
- "nvim/lua",
10
- "nvim/plugin",
11
- "nvim/doc",
12
- "nvim/bin"
8
+ "src"
13
9
  ],
14
10
  "keywords": [
15
11
  "pi-package",
@@ -23,52 +19,61 @@
23
19
  "license": "Apache-2.0",
24
20
  "repository": {
25
21
  "type": "git",
26
- "url": "https://github.com/balaenis/pi-x-ide"
22
+ "url": "git+https://github.com/balaenis/pi-x-ide.git"
27
23
  },
28
24
  "bugs": {
29
25
  "url": "https://github.com/balaenis/pi-x-ide/issues"
30
26
  },
31
27
  "homepage": "https://github.com/balaenis/pi-x-ide#readme",
32
- "packageManager": "pnpm@11.5.2",
28
+ "workspaces": [
29
+ "vscode"
30
+ ],
31
+ "packageManager": "bun@1.3.14",
33
32
  "engines": {
34
33
  "node": ">=26"
35
34
  },
36
35
  "type": "commonjs",
37
36
  "main": "./dist/src/pi/index.js",
38
37
  "scripts": {
39
- "build": "tsc -p tsconfig.json && node scripts/build-nvim-sidecar.mjs --production && pnpm --filter './vscode' compile",
40
- "typecheck": "tsc -p tsconfig.json --noEmit && pnpm --filter './vscode' typecheck",
41
- "generate:config-schema": "node scripts/generate-config-schema.cjs",
42
- "check:config-schema": "node scripts/generate-config-schema.cjs --check",
43
- "test": "pnpm check:config-schema && pnpm build && node --test dist/test/*.test.js",
38
+ "typecheck": "tsc -p tsconfig.json --noEmit && bun run --filter './vscode' typecheck",
39
+ "generate:config-schema": "bun run scripts/generate-config-schema.cjs",
40
+ "check:config-schema": "bun run scripts/generate-config-schema.cjs --check",
41
+ "test": "bun run check:config-schema && bun run compile && node --test dist/test/*.test.js",
44
42
  "lint": "eslint .",
45
43
  "lint:fix": "eslint . --fix",
46
44
  "format": "prettier --write .",
47
45
  "format:check": "prettier --check .",
48
- "compile:vscode": "pnpm --filter './vscode' compile",
49
- "sync:vscode-assets": "pnpm --filter './vscode' sync:assets",
50
- "package:vscode": "pnpm --filter './vscode' package",
51
- "vsix": "pnpm package:vscode"
46
+ "compile": "tsc -p tsconfig.json",
47
+ "compile:vsix": "bun run --filter './vscode' compile",
48
+ "sync:vsix-assets": "bun run --filter './vscode' sync:assets",
49
+ "package:vsix": "bun run --filter './vscode' package",
50
+ "package:nvim-sidecar": "bun run scripts/build-nvim-sidecar.mjs --production",
51
+ "package:nvim-sidecar:all": "bun run scripts/build-nvim-sidecar.mjs --production --target=all",
52
+ "build": "bun run compile && bun run compile:vsix && bun run package:nvim-sidecar",
53
+ "build:all": "bun run compile && bun run compile:vsix && bun run package:nvim-sidecar:all"
52
54
  },
53
55
  "dependencies": {
54
- "ws": "^8.18.0"
56
+ "ws": "^8.21.0"
55
57
  },
56
58
  "peerDependencies": {
57
59
  "@earendil-works/pi-coding-agent": "*"
58
60
  },
59
61
  "devDependencies": {
60
- "@earendil-works/pi-coding-agent": "^0.79.0",
62
+ "@earendil-works/pi-coding-agent": "^0.79.1",
61
63
  "@eslint/js": "^10.0.1",
62
- "@types/node": "^25.9.2",
63
- "@types/ws": "^8.5.13",
64
- "@vscode/vsce": "^3.2.2",
65
- "esbuild": "^0.27.0",
64
+ "@types/node": "^25.9.3",
65
+ "@types/ws": "^8.18.1",
66
+ "@vscode/vsce": "^3.9.2",
67
+ "esbuild": "^0.28.0",
66
68
  "eslint": "^10.4.1",
67
69
  "eslint-config-prettier": "^10.1.8",
68
- "prettier": "^3.8.3",
69
- "typescript": "^5.7.2",
70
- "typescript-eslint": "^8.60.1"
70
+ "prettier": "^3.8.4",
71
+ "typescript": "^6.0.3",
72
+ "typescript-eslint": "^8.61.0"
71
73
  },
74
+ "trustedDependencies": [
75
+ "esbuild"
76
+ ],
72
77
  "pi": {
73
78
  "image": "https://fastly.jsdelivr.net/gh/balaenis/pi-x-ide@main/assets/icons/pi-x-ide.png",
74
79
  "extensions": [
package/package.json CHANGED
@@ -1,15 +1,11 @@
1
1
  {
2
2
  "name": "pi-x-ide",
3
- "version": "1.4.3",
3
+ "version": "1.5.1",
4
4
  "description": "Pi extension package for IDE selection context integration.",
5
5
  "files": [
6
6
  "dist",
7
7
  "schemas",
8
- "src",
9
- "nvim/lua",
10
- "nvim/plugin",
11
- "nvim/doc",
12
- "nvim/bin"
8
+ "src"
13
9
  ],
14
10
  "keywords": [
15
11
  "pi-package",
@@ -23,55 +19,65 @@
23
19
  "license": "Apache-2.0",
24
20
  "repository": {
25
21
  "type": "git",
26
- "url": "https://github.com/balaenis/pi-x-ide"
22
+ "url": "git+https://github.com/balaenis/pi-x-ide.git"
27
23
  },
28
24
  "bugs": {
29
25
  "url": "https://github.com/balaenis/pi-x-ide/issues"
30
26
  },
31
27
  "homepage": "https://github.com/balaenis/pi-x-ide#readme",
28
+ "workspaces": [
29
+ "vscode"
30
+ ],
31
+ "packageManager": "bun@1.3.14",
32
32
  "engines": {
33
33
  "node": ">=26"
34
34
  },
35
35
  "type": "commonjs",
36
36
  "main": "./dist/src/pi/index.js",
37
+ "scripts": {
38
+ "typecheck": "tsc -p tsconfig.json --noEmit && bun run --filter './vscode' typecheck",
39
+ "generate:config-schema": "bun run scripts/generate-config-schema.cjs",
40
+ "check:config-schema": "bun run scripts/generate-config-schema.cjs --check",
41
+ "test": "bun run check:config-schema && bun run compile && node --test dist/test/*.test.js",
42
+ "lint": "eslint .",
43
+ "lint:fix": "eslint . --fix",
44
+ "format": "prettier --write .",
45
+ "format:check": "prettier --check .",
46
+ "compile": "tsc -p tsconfig.json",
47
+ "compile:vsix": "bun run --filter './vscode' compile",
48
+ "sync:vsix-assets": "bun run --filter './vscode' sync:assets",
49
+ "package:vsix": "bun run --filter './vscode' package",
50
+ "package:nvim-sidecar": "bun run scripts/build-nvim-sidecar.mjs --production",
51
+ "package:nvim-sidecar:all": "bun run scripts/build-nvim-sidecar.mjs --production --target=all",
52
+ "build": "bun run compile && bun run compile:vsix && bun run package:nvim-sidecar",
53
+ "build:all": "bun run compile && bun run compile:vsix && bun run package:nvim-sidecar:all"
54
+ },
37
55
  "dependencies": {
38
- "ws": "^8.18.0"
56
+ "ws": "^8.21.0"
39
57
  },
40
58
  "peerDependencies": {
41
59
  "@earendil-works/pi-coding-agent": "*"
42
60
  },
43
61
  "devDependencies": {
44
- "@earendil-works/pi-coding-agent": "^0.79.0",
62
+ "@earendil-works/pi-coding-agent": "^0.79.1",
45
63
  "@eslint/js": "^10.0.1",
46
- "@types/node": "^25.9.2",
47
- "@types/ws": "^8.5.13",
48
- "@vscode/vsce": "^3.2.2",
49
- "esbuild": "^0.27.0",
64
+ "@types/node": "^25.9.3",
65
+ "@types/ws": "^8.18.1",
66
+ "@vscode/vsce": "^3.9.2",
67
+ "esbuild": "^0.28.0",
50
68
  "eslint": "^10.4.1",
51
69
  "eslint-config-prettier": "^10.1.8",
52
- "prettier": "^3.8.3",
53
- "typescript": "^5.7.2",
54
- "typescript-eslint": "^8.60.1"
70
+ "prettier": "^3.8.4",
71
+ "typescript": "^6.0.3",
72
+ "typescript-eslint": "^8.61.0"
55
73
  },
74
+ "trustedDependencies": [
75
+ "esbuild"
76
+ ],
56
77
  "pi": {
57
78
  "image": "https://fastly.jsdelivr.net/gh/balaenis/pi-x-ide@main/assets/icons/pi-x-ide.png",
58
79
  "extensions": [
59
80
  "./src/pi/index.ts"
60
81
  ]
61
- },
62
- "scripts": {
63
- "build": "tsc -p tsconfig.json && node scripts/build-nvim-sidecar.mjs --production && pnpm --filter './vscode' compile",
64
- "typecheck": "tsc -p tsconfig.json --noEmit && pnpm --filter './vscode' typecheck",
65
- "generate:config-schema": "node scripts/generate-config-schema.cjs",
66
- "check:config-schema": "node scripts/generate-config-schema.cjs --check",
67
- "test": "pnpm check:config-schema && pnpm build && node --test dist/test/*.test.js",
68
- "lint": "eslint .",
69
- "lint:fix": "eslint . --fix",
70
- "format": "prettier --write .",
71
- "format:check": "prettier --check .",
72
- "compile:vscode": "pnpm --filter './vscode' compile",
73
- "sync:vscode-assets": "pnpm --filter './vscode' sync:assets",
74
- "package:vscode": "pnpm --filter './vscode' package",
75
- "vsix": "pnpm package:vscode"
76
82
  }
77
- }
83
+ }
@@ -1,21 +0,0 @@
1
- #!/usr/bin/env node
2
- "use strict";var qr=Object.create;var ce=Object.defineProperty;var Gr=Object.getOwnPropertyDescriptor;var zr=Object.getOwnPropertyNames;var Hr=Object.getPrototypeOf,Jr=Object.prototype.hasOwnProperty;var y=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports),Yr=(t,e)=>{for(var r in e)ce(t,r,{get:e[r],enumerable:!0})},nt=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of zr(e))!Jr.call(t,s)&&s!==r&&ce(t,s,{get:()=>e[s],enumerable:!(n=Gr(e,s))||n.enumerable});return t};var N=(t,e,r)=>(r=t!=null?qr(Hr(t)):{},nt(e||!t||!t.__esModule?ce(r,"default",{value:t,enumerable:!0}):r,t)),Kr=t=>nt(ce({},"__esModule",{value:!0}),t);var C=y((Hs,gt)=>{"use strict";var mt=["nodebuffer","arraybuffer","fragments"],_t=typeof Blob<"u";_t&&mt.push("blob");gt.exports={BINARY_TYPES:mt,CLOSE_TIMEOUT:3e4,EMPTY_BUFFER:Buffer.alloc(0),GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",hasBlob:_t,kForOnEventAttribute:Symbol("kIsForOnEventAttribute"),kListener:Symbol("kListener"),kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),NOOP:()=>{}}});var ee=y((Js,le)=>{"use strict";var{EMPTY_BUFFER:sn}=C(),Te=Buffer[Symbol.species];function on(t,e){if(t.length===0)return sn;if(t.length===1)return t[0];let r=Buffer.allocUnsafe(e),n=0;for(let s=0;s<t.length;s++){let i=t[s];r.set(i,n),n+=i.length}return n<e?new Te(r.buffer,r.byteOffset,n):r}function St(t,e,r,n,s){for(let i=0;i<s;i++)r[n+i]=t[i]^e[i&3]}function yt(t,e){for(let r=0;r<t.length;r++)t[r]^=e[r&3]}function an(t){return t.length===t.buffer.byteLength?t.buffer:t.buffer.slice(t.byteOffset,t.byteOffset+t.length)}function Pe(t){if(Pe.readOnly=!0,Buffer.isBuffer(t))return t;let e;return t instanceof ArrayBuffer?e=new Te(t):ArrayBuffer.isView(t)?e=new Te(t.buffer,t.byteOffset,t.byteLength):(e=Buffer.from(t),Pe.readOnly=!1),e}le.exports={concat:on,mask:St,toArrayBuffer:an,toBuffer:Pe,unmask:yt};if(!process.env.WS_NO_BUFFER_UTIL)try{let t=require("bufferutil");le.exports.mask=function(e,r,n,s,i){i<48?St(e,r,n,s,i):t.mask(e,r,n,s,i)},le.exports.unmask=function(e,r){e.length<32?yt(e,r):t.unmask(e,r)}}catch{}});var kt=y((Ys,Et)=>{"use strict";var xt=Symbol("kDone"),Le=Symbol("kRun"),Ne=class{constructor(e){this[xt]=()=>{this.pending--,this[Le]()},this.concurrency=e||1/0,this.jobs=[],this.pending=0}add(e){this.jobs.push(e),this[Le]()}[Le](){if(this.pending!==this.concurrency&&this.jobs.length){let e=this.jobs.shift();this.pending++,e(this[xt])}}};Et.exports=Ne});var q=y((Ks,Ot)=>{"use strict";var te=require("zlib"),wt=ee(),cn=kt(),{kStatusCode:vt}=C(),ln=Buffer[Symbol.species],fn=Buffer.from([0,0,255,255]),de=Symbol("permessage-deflate"),T=Symbol("total-length"),V=Symbol("callback"),I=Symbol("buffers"),j=Symbol("error"),fe,Ie=class{constructor(e){if(this._options=e||{},this._threshold=this._options.threshold!==void 0?this._options.threshold:1024,this._maxPayload=this._options.maxPayload|0,this._isServer=!!this._options.isServer,this._deflate=null,this._inflate=null,this.params=null,!fe){let r=this._options.concurrencyLimit!==void 0?this._options.concurrencyLimit:10;fe=new cn(r)}}static get extensionName(){return"permessage-deflate"}offer(){let e={};return this._options.serverNoContextTakeover&&(e.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(e.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(e.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?e.client_max_window_bits=this._options.clientMaxWindowBits:this._options.clientMaxWindowBits==null&&(e.client_max_window_bits=!0),e}accept(e){return e=this.normalizeParams(e),this.params=this._isServer?this.acceptAsServer(e):this.acceptAsClient(e),this.params}cleanup(){if(this._inflate&&(this._inflate.close(),this._inflate=null),this._deflate){let e=this._deflate[V];this._deflate.close(),this._deflate=null,e&&e(new Error("The deflate stream was closed while data was being processed"))}}acceptAsServer(e){let r=this._options,n=e.find(s=>!(r.serverNoContextTakeover===!1&&s.server_no_context_takeover||s.server_max_window_bits&&(r.serverMaxWindowBits===!1||typeof r.serverMaxWindowBits=="number"&&r.serverMaxWindowBits>s.server_max_window_bits)||typeof r.clientMaxWindowBits=="number"&&!s.client_max_window_bits));if(!n)throw new Error("None of the extension offers can be accepted");return r.serverNoContextTakeover&&(n.server_no_context_takeover=!0),r.clientNoContextTakeover&&(n.client_no_context_takeover=!0),typeof r.serverMaxWindowBits=="number"&&(n.server_max_window_bits=r.serverMaxWindowBits),typeof r.clientMaxWindowBits=="number"?n.client_max_window_bits=r.clientMaxWindowBits:(n.client_max_window_bits===!0||r.clientMaxWindowBits===!1)&&delete n.client_max_window_bits,n}acceptAsClient(e){let r=e[0];if(this._options.clientNoContextTakeover===!1&&r.client_no_context_takeover)throw new Error('Unexpected parameter "client_no_context_takeover"');if(!r.client_max_window_bits)typeof this._options.clientMaxWindowBits=="number"&&(r.client_max_window_bits=this._options.clientMaxWindowBits);else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits=="number"&&r.client_max_window_bits>this._options.clientMaxWindowBits)throw new Error('Unexpected or invalid parameter "client_max_window_bits"');return r}normalizeParams(e){return e.forEach(r=>{Object.keys(r).forEach(n=>{let s=r[n];if(s.length>1)throw new Error(`Parameter "${n}" must have only a single value`);if(s=s[0],n==="client_max_window_bits"){if(s!==!0){let i=+s;if(!Number.isInteger(i)||i<8||i>15)throw new TypeError(`Invalid value for parameter "${n}": ${s}`);s=i}else if(!this._isServer)throw new TypeError(`Invalid value for parameter "${n}": ${s}`)}else if(n==="server_max_window_bits"){let i=+s;if(!Number.isInteger(i)||i<8||i>15)throw new TypeError(`Invalid value for parameter "${n}": ${s}`);s=i}else if(n==="client_no_context_takeover"||n==="server_no_context_takeover"){if(s!==!0)throw new TypeError(`Invalid value for parameter "${n}": ${s}`)}else throw new Error(`Unknown parameter "${n}"`);r[n]=s})}),e}decompress(e,r,n){fe.add(s=>{this._decompress(e,r,(i,o)=>{s(),n(i,o)})})}compress(e,r,n){fe.add(s=>{this._compress(e,r,(i,o)=>{s(),n(i,o)})})}_decompress(e,r,n){let s=this._isServer?"client":"server";if(!this._inflate){let i=`${s}_max_window_bits`,o=typeof this.params[i]!="number"?te.Z_DEFAULT_WINDOWBITS:this.params[i];this._inflate=te.createInflateRaw({...this._options.zlibInflateOptions,windowBits:o}),this._inflate[de]=this,this._inflate[T]=0,this._inflate[I]=[],this._inflate.on("error",hn),this._inflate.on("data",bt)}this._inflate[V]=n,this._inflate.write(e),r&&this._inflate.write(fn),this._inflate.flush(()=>{let i=this._inflate[j];if(i){this._inflate.close(),this._inflate=null,n(i);return}let o=wt.concat(this._inflate[I],this._inflate[T]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[T]=0,this._inflate[I]=[],r&&this.params[`${s}_no_context_takeover`]&&this._inflate.reset()),n(null,o)})}_compress(e,r,n){let s=this._isServer?"server":"client";if(!this._deflate){let i=`${s}_max_window_bits`,o=typeof this.params[i]!="number"?te.Z_DEFAULT_WINDOWBITS:this.params[i];this._deflate=te.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:o}),this._deflate[T]=0,this._deflate[I]=[],this._deflate.on("data",dn)}this._deflate[V]=n,this._deflate.write(e),this._deflate.flush(te.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let i=wt.concat(this._deflate[I],this._deflate[T]);r&&(i=new ln(i.buffer,i.byteOffset,i.length-4)),this._deflate[V]=null,this._deflate[T]=0,this._deflate[I]=[],r&&this.params[`${s}_no_context_takeover`]&&this._deflate.reset(),n(null,i)})}};Ot.exports=Ie;function dn(t){this[I].push(t),this[T]+=t.length}function bt(t){if(this[T]+=t.length,this[de]._maxPayload<1||this[T]<=this[de]._maxPayload){this[I].push(t);return}this[j]=new RangeError("Max payload size exceeded"),this[j].code="WS_ERR_UNSUPPORTED_MESSAGE_LENGTH",this[j][vt]=1009,this.removeListener("data",bt),this.reset()}function hn(t){if(this[de]._inflate=null,this[j]){this[V](this[j]);return}t[vt]=1007,this[V](t)}});var G=y((Zs,he)=>{"use strict";var{isUtf8:Ct}=require("buffer"),{hasBlob:un}=C(),pn=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function mn(t){return t>=1e3&&t<=1014&&t!==1004&&t!==1005&&t!==1006||t>=3e3&&t<=4999}function Re(t){let e=t.length,r=0;for(;r<e;)if((t[r]&128)===0)r++;else if((t[r]&224)===192){if(r+1===e||(t[r+1]&192)!==128||(t[r]&254)===192)return!1;r+=2}else if((t[r]&240)===224){if(r+2>=e||(t[r+1]&192)!==128||(t[r+2]&192)!==128||t[r]===224&&(t[r+1]&224)===128||t[r]===237&&(t[r+1]&224)===160)return!1;r+=3}else if((t[r]&248)===240){if(r+3>=e||(t[r+1]&192)!==128||(t[r+2]&192)!==128||(t[r+3]&192)!==128||t[r]===240&&(t[r+1]&240)===128||t[r]===244&&t[r+1]>143||t[r]>244)return!1;r+=4}else return!1;return!0}function _n(t){return un&&typeof t=="object"&&typeof t.arrayBuffer=="function"&&typeof t.type=="string"&&typeof t.stream=="function"&&(t[Symbol.toStringTag]==="Blob"||t[Symbol.toStringTag]==="File")}he.exports={isBlob:_n,isValidStatusCode:mn,isValidUTF8:Re,tokenChars:pn};if(Ct)he.exports.isValidUTF8=function(t){return t.length<24?Re(t):Ct(t)};else if(!process.env.WS_NO_UTF_8_VALIDATE)try{let t=require("utf-8-validate");he.exports.isValidUTF8=function(e){return e.length<32?Re(e):t(e)}}catch{}});var Me=y((Xs,Ft)=>{"use strict";var{Writable:gn}=require("stream"),Tt=q(),{BINARY_TYPES:Sn,EMPTY_BUFFER:Pt,kStatusCode:yn,kWebSocket:xn}=C(),{concat:Fe,toArrayBuffer:En,unmask:kn}=ee(),{isValidStatusCode:wn,isValidUTF8:Lt}=G(),ue=Buffer[Symbol.species],E=0,Nt=1,It=2,Rt=3,De=4,Ae=5,pe=6,Be=class extends gn{constructor(e={}){super(),this._allowSynchronousEvents=e.allowSynchronousEvents!==void 0?e.allowSynchronousEvents:!0,this._binaryType=e.binaryType||Sn[0],this._extensions=e.extensions||{},this._isServer=!!e.isServer,this._maxBufferedChunks=e.maxBufferedChunks|0,this._maxFragments=e.maxFragments|0,this._maxPayload=e.maxPayload|0,this._skipUTF8Validation=!!e.skipUTF8Validation,this[xn]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._fragments=[],this._errored=!1,this._loop=!1,this._state=E}_write(e,r,n){if(this._opcode===8&&this._state==E)return n();if(this._maxBufferedChunks>0&&this._buffers.length>=this._maxBufferedChunks){n(this.createError(RangeError,"Too many buffered chunks",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS"));return}this._bufferedBytes+=e.length,this._buffers.push(e),this.startLoop(n)}consume(e){if(this._bufferedBytes-=e,e===this._buffers[0].length)return this._buffers.shift();if(e<this._buffers[0].length){let n=this._buffers[0];return this._buffers[0]=new ue(n.buffer,n.byteOffset+e,n.length-e),new ue(n.buffer,n.byteOffset,e)}let r=Buffer.allocUnsafe(e);do{let n=this._buffers[0],s=r.length-e;e>=n.length?r.set(this._buffers.shift(),s):(r.set(new Uint8Array(n.buffer,n.byteOffset,e),s),this._buffers[0]=new ue(n.buffer,n.byteOffset+e,n.length-e)),e-=n.length}while(e>0);return r}startLoop(e){this._loop=!0;do switch(this._state){case E:this.getInfo(e);break;case Nt:this.getPayloadLength16(e);break;case It:this.getPayloadLength64(e);break;case Rt:this.getMask();break;case De:this.getData(e);break;case Ae:case pe:this._loop=!1;return}while(this._loop);this._errored||e()}getInfo(e){if(this._bufferedBytes<2){this._loop=!1;return}let r=this.consume(2);if((r[0]&48)!==0){let s=this.createError(RangeError,"RSV2 and RSV3 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_2_3");e(s);return}let n=(r[0]&64)===64;if(n&&!this._extensions[Tt.extensionName]){let s=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(s);return}if(this._fin=(r[0]&128)===128,this._opcode=r[0]&15,this._payloadLength=r[1]&127,this._opcode===0){if(n){let s=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(s);return}if(!this._fragmented){let s=this.createError(RangeError,"invalid opcode 0",!0,1002,"WS_ERR_INVALID_OPCODE");e(s);return}this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented){let s=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");e(s);return}this._compressed=n}else if(this._opcode>7&&this._opcode<11){if(!this._fin){let s=this.createError(RangeError,"FIN must be set",!0,1002,"WS_ERR_EXPECTED_FIN");e(s);return}if(n){let s=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");e(s);return}if(this._payloadLength>125||this._opcode===8&&this._payloadLength===1){let s=this.createError(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH");e(s);return}}else{let s=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");e(s);return}if(!this._fin&&!this._fragmented&&(this._fragmented=this._opcode),this._masked=(r[1]&128)===128,this._isServer){if(!this._masked){let s=this.createError(RangeError,"MASK must be set",!0,1002,"WS_ERR_EXPECTED_MASK");e(s);return}}else if(this._masked){let s=this.createError(RangeError,"MASK must be clear",!0,1002,"WS_ERR_UNEXPECTED_MASK");e(s);return}this._payloadLength===126?this._state=Nt:this._payloadLength===127?this._state=It:this.haveLength(e)}getPayloadLength16(e){if(this._bufferedBytes<2){this._loop=!1;return}this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength(e)}getPayloadLength64(e){if(this._bufferedBytes<8){this._loop=!1;return}let r=this.consume(8),n=r.readUInt32BE(0);if(n>Math.pow(2,21)-1){let s=this.createError(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009,"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH");e(s);return}this._payloadLength=n*Math.pow(2,32)+r.readUInt32BE(4),this.haveLength(e)}haveLength(e){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0)){let r=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");e(r);return}this._masked?this._state=Rt:this._state=De}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=De}getData(e){let r=Pt;if(this._payloadLength){if(this._bufferedBytes<this._payloadLength){this._loop=!1;return}r=this.consume(this._payloadLength),this._masked&&(this._mask[0]|this._mask[1]|this._mask[2]|this._mask[3])!==0&&kn(r,this._mask)}if(this._opcode>7){this.controlMessage(r,e);return}if(this._compressed){this._state=Ae,this.decompress(r,e);return}if(r.length){if(this._maxFragments>0&&this._fragments.length>=this._maxFragments){let n=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");e(n);return}this._messageLength=this._totalPayloadLength,this._fragments.push(r)}this.dataMessage(e)}decompress(e,r){this._extensions[Tt.extensionName].decompress(e,this._fin,(s,i)=>{if(s)return r(s);if(i.length){if(this._messageLength+=i.length,this._messageLength>this._maxPayload&&this._maxPayload>0){let o=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");r(o);return}if(this._maxFragments>0&&this._fragments.length>=this._maxFragments){let o=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");r(o);return}this._fragments.push(i)}this.dataMessage(r),this._state===E&&this.startLoop(r)})}dataMessage(e){if(!this._fin){this._state=E;return}let r=this._messageLength,n=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._fragments=[],this._opcode===2){let s;this._binaryType==="nodebuffer"?s=Fe(n,r):this._binaryType==="arraybuffer"?s=En(Fe(n,r)):this._binaryType==="blob"?s=new Blob(n):s=n,this._allowSynchronousEvents?(this.emit("message",s,!0),this._state=E):(this._state=pe,setImmediate(()=>{this.emit("message",s,!0),this._state=E,this.startLoop(e)}))}else{let s=Fe(n,r);if(!this._skipUTF8Validation&&!Lt(s)){let i=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");e(i);return}this._state===Ae||this._allowSynchronousEvents?(this.emit("message",s,!1),this._state=E):(this._state=pe,setImmediate(()=>{this.emit("message",s,!1),this._state=E,this.startLoop(e)}))}}controlMessage(e,r){if(this._opcode===8){if(e.length===0)this._loop=!1,this.emit("conclude",1005,Pt),this.end();else{let n=e.readUInt16BE(0);if(!wn(n)){let i=this.createError(RangeError,`invalid status code ${n}`,!0,1002,"WS_ERR_INVALID_CLOSE_CODE");r(i);return}let s=new ue(e.buffer,e.byteOffset+2,e.length-2);if(!this._skipUTF8Validation&&!Lt(s)){let i=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");r(i);return}this._loop=!1,this.emit("conclude",n,s),this.end()}this._state=E;return}this._allowSynchronousEvents?(this.emit(this._opcode===9?"ping":"pong",e),this._state=E):(this._state=pe,setImmediate(()=>{this.emit(this._opcode===9?"ping":"pong",e),this._state=E,this.startLoop(r)}))}createError(e,r,n,s,i){this._loop=!1,this._errored=!0;let o=new e(n?`Invalid WebSocket frame: ${r}`:r);return Error.captureStackTrace(o,this.createError),o.code=i,o[yn]=s,o}};Ft.exports=Be});var $e=y((ei,Bt)=>{"use strict";var{Duplex:Qs}=require("stream"),{randomFillSync:vn}=require("crypto"),{types:{isUint8Array:bn}}=require("util"),Dt=q(),{EMPTY_BUFFER:On,kWebSocket:Cn,NOOP:Tn}=C(),{isBlob:z,isValidStatusCode:Pn}=G(),{mask:At,toBuffer:D}=ee(),k=Symbol("kByteLength"),Ln=Buffer.alloc(4),me=8*1024,A,H=me,v=0,Nn=1,In=2,Ue=class t{constructor(e,r,n){this._extensions=r||{},n&&(this._generateMask=n,this._maskBuffer=Buffer.alloc(4)),this._socket=e,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._queue=[],this._state=v,this.onerror=Tn,this[Cn]=void 0}static frame(e,r){let n,s=!1,i=2,o=!1;r.mask&&(n=r.maskBuffer||Ln,r.generateMask?r.generateMask(n):(H===me&&(A===void 0&&(A=Buffer.alloc(me)),vn(A,0,me),H=0),n[0]=A[H++],n[1]=A[H++],n[2]=A[H++],n[3]=A[H++]),o=(n[0]|n[1]|n[2]|n[3])===0,i=6);let c;typeof e=="string"?(!r.mask||o)&&r[k]!==void 0?c=r[k]:(e=Buffer.from(e),c=e.length):(c=e.length,s=r.mask&&r.readOnly&&!o);let l=c;c>=65536?(i+=8,l=127):c>125&&(i+=2,l=126);let a=Buffer.allocUnsafe(s?c+i:i);return a[0]=r.fin?r.opcode|128:r.opcode,r.rsv1&&(a[0]|=64),a[1]=l,l===126?a.writeUInt16BE(c,2):l===127&&(a[2]=a[3]=0,a.writeUIntBE(c,4,6)),r.mask?(a[1]|=128,a[i-4]=n[0],a[i-3]=n[1],a[i-2]=n[2],a[i-1]=n[3],o?[a,e]:s?(At(e,n,a,i,c),[a]):(At(e,n,e,0,c),[a,e])):[a,e]}close(e,r,n,s){let i;if(e===void 0)i=On;else{if(typeof e!="number"||!Pn(e))throw new TypeError("First argument must be a valid error code number");if(r===void 0||!r.length)i=Buffer.allocUnsafe(2),i.writeUInt16BE(e,0);else{let c=Buffer.byteLength(r);if(c>123)throw new RangeError("The message must not be greater than 123 bytes");if(i=Buffer.allocUnsafe(2+c),i.writeUInt16BE(e,0),typeof r=="string")i.write(r,2);else if(bn(r))i.set(r,2);else throw new TypeError("Second argument must be a string or a Uint8Array")}}let o={[k]:i.length,fin:!0,generateMask:this._generateMask,mask:n,maskBuffer:this._maskBuffer,opcode:8,readOnly:!1,rsv1:!1};this._state!==v?this.enqueue([this.dispatch,i,!1,o,s]):this.sendFrame(t.frame(i,o),s)}ping(e,r,n){let s,i;if(typeof e=="string"?(s=Buffer.byteLength(e),i=!1):z(e)?(s=e.size,i=!1):(e=D(e),s=e.length,i=D.readOnly),s>125)throw new RangeError("The data size must not be greater than 125 bytes");let o={[k]:s,fin:!0,generateMask:this._generateMask,mask:r,maskBuffer:this._maskBuffer,opcode:9,readOnly:i,rsv1:!1};z(e)?this._state!==v?this.enqueue([this.getBlobData,e,!1,o,n]):this.getBlobData(e,!1,o,n):this._state!==v?this.enqueue([this.dispatch,e,!1,o,n]):this.sendFrame(t.frame(e,o),n)}pong(e,r,n){let s,i;if(typeof e=="string"?(s=Buffer.byteLength(e),i=!1):z(e)?(s=e.size,i=!1):(e=D(e),s=e.length,i=D.readOnly),s>125)throw new RangeError("The data size must not be greater than 125 bytes");let o={[k]:s,fin:!0,generateMask:this._generateMask,mask:r,maskBuffer:this._maskBuffer,opcode:10,readOnly:i,rsv1:!1};z(e)?this._state!==v?this.enqueue([this.getBlobData,e,!1,o,n]):this.getBlobData(e,!1,o,n):this._state!==v?this.enqueue([this.dispatch,e,!1,o,n]):this.sendFrame(t.frame(e,o),n)}send(e,r,n){let s=this._extensions[Dt.extensionName],i=r.binary?2:1,o=r.compress,c,l;typeof e=="string"?(c=Buffer.byteLength(e),l=!1):z(e)?(c=e.size,l=!1):(e=D(e),c=e.length,l=D.readOnly),this._firstFragment?(this._firstFragment=!1,o&&s&&s.params[s._isServer?"server_no_context_takeover":"client_no_context_takeover"]&&(o=c>=s._threshold),this._compress=o):(o=!1,i=0),r.fin&&(this._firstFragment=!0);let a={[k]:c,fin:r.fin,generateMask:this._generateMask,mask:r.mask,maskBuffer:this._maskBuffer,opcode:i,readOnly:l,rsv1:o};z(e)?this._state!==v?this.enqueue([this.getBlobData,e,this._compress,a,n]):this.getBlobData(e,this._compress,a,n):this._state!==v?this.enqueue([this.dispatch,e,this._compress,a,n]):this.dispatch(e,this._compress,a,n)}getBlobData(e,r,n,s){this._bufferedBytes+=n[k],this._state=In,e.arrayBuffer().then(i=>{if(this._socket.destroyed){let c=new Error("The socket was closed while the blob was being read");process.nextTick(We,this,c,s);return}this._bufferedBytes-=n[k];let o=D(i);r?this.dispatch(o,r,n,s):(this._state=v,this.sendFrame(t.frame(o,n),s),this.dequeue())}).catch(i=>{process.nextTick(Rn,this,i,s)})}dispatch(e,r,n,s){if(!r){this.sendFrame(t.frame(e,n),s);return}let i=this._extensions[Dt.extensionName];this._bufferedBytes+=n[k],this._state=Nn,i.compress(e,n.fin,(o,c)=>{if(this._socket.destroyed){let l=new Error("The socket was closed while data was being compressed");We(this,l,s);return}this._bufferedBytes-=n[k],this._state=v,n.readOnly=!1,this.sendFrame(t.frame(c,n),s),this.dequeue()})}dequeue(){for(;this._state===v&&this._queue.length;){let e=this._queue.shift();this._bufferedBytes-=e[3][k],Reflect.apply(e[0],this,e.slice(1))}}enqueue(e){this._bufferedBytes+=e[3][k],this._queue.push(e)}sendFrame(e,r){e.length===2?(this._socket.cork(),this._socket.write(e[0]),this._socket.write(e[1],r),this._socket.uncork()):this._socket.write(e[0],r)}};Bt.exports=Ue;function We(t,e,r){typeof r=="function"&&r(e);for(let n=0;n<t._queue.length;n++){let s=t._queue[n],i=s[s.length-1];typeof i=="function"&&i(e)}}function Rn(t,e,r){We(t,e,r),t.onerror(e)}});var zt=y((ti,Gt)=>{"use strict";var{kForOnEventAttribute:re,kListener:Ve}=C(),Mt=Symbol("kCode"),Ut=Symbol("kData"),Wt=Symbol("kError"),$t=Symbol("kMessage"),Vt=Symbol("kReason"),J=Symbol("kTarget"),jt=Symbol("kType"),qt=Symbol("kWasClean"),P=class{constructor(e){this[J]=null,this[jt]=e}get target(){return this[J]}get type(){return this[jt]}};Object.defineProperty(P.prototype,"target",{enumerable:!0});Object.defineProperty(P.prototype,"type",{enumerable:!0});var B=class extends P{constructor(e,r={}){super(e),this[Mt]=r.code===void 0?0:r.code,this[Vt]=r.reason===void 0?"":r.reason,this[qt]=r.wasClean===void 0?!1:r.wasClean}get code(){return this[Mt]}get reason(){return this[Vt]}get wasClean(){return this[qt]}};Object.defineProperty(B.prototype,"code",{enumerable:!0});Object.defineProperty(B.prototype,"reason",{enumerable:!0});Object.defineProperty(B.prototype,"wasClean",{enumerable:!0});var Y=class extends P{constructor(e,r={}){super(e),this[Wt]=r.error===void 0?null:r.error,this[$t]=r.message===void 0?"":r.message}get error(){return this[Wt]}get message(){return this[$t]}};Object.defineProperty(Y.prototype,"error",{enumerable:!0});Object.defineProperty(Y.prototype,"message",{enumerable:!0});var ne=class extends P{constructor(e,r={}){super(e),this[Ut]=r.data===void 0?null:r.data}get data(){return this[Ut]}};Object.defineProperty(ne.prototype,"data",{enumerable:!0});var Fn={addEventListener(t,e,r={}){for(let s of this.listeners(t))if(!r[re]&&s[Ve]===e&&!s[re])return;let n;if(t==="message")n=function(i,o){let c=new ne("message",{data:o?i:i.toString()});c[J]=this,_e(e,this,c)};else if(t==="close")n=function(i,o){let c=new B("close",{code:i,reason:o.toString(),wasClean:this._closeFrameReceived&&this._closeFrameSent});c[J]=this,_e(e,this,c)};else if(t==="error")n=function(i){let o=new Y("error",{error:i,message:i.message});o[J]=this,_e(e,this,o)};else if(t==="open")n=function(){let i=new P("open");i[J]=this,_e(e,this,i)};else return;n[re]=!!r[re],n[Ve]=e,r.once?this.once(t,n):this.on(t,n)},removeEventListener(t,e){for(let r of this.listeners(t))if(r[Ve]===e&&!r[re]){this.removeListener(t,r);break}}};Gt.exports={CloseEvent:B,ErrorEvent:Y,Event:P,EventTarget:Fn,MessageEvent:ne};function _e(t,e,r){typeof t=="object"&&t.handleEvent?t.handleEvent.call(t,r):t.call(e,r)}});var ge=y((ri,Ht)=>{"use strict";var{tokenChars:se}=G();function b(t,e,r){t[e]===void 0?t[e]=[r]:t[e].push(r)}function Dn(t){let e=Object.create(null),r=Object.create(null),n=!1,s=!1,i=!1,o,c,l=-1,a=-1,f=-1,d=0;for(;d<t.length;d++)if(a=t.charCodeAt(d),o===void 0)if(f===-1&&se[a]===1)l===-1&&(l=d);else if(d!==0&&(a===32||a===9))f===-1&&l!==-1&&(f=d);else if(a===59||a===44){if(l===-1)throw new SyntaxError(`Unexpected character at index ${d}`);f===-1&&(f=d);let _=t.slice(l,f);a===44?(b(e,_,r),r=Object.create(null)):o=_,l=f=-1}else throw new SyntaxError(`Unexpected character at index ${d}`);else if(c===void 0)if(f===-1&&se[a]===1)l===-1&&(l=d);else if(a===32||a===9)f===-1&&l!==-1&&(f=d);else if(a===59||a===44){if(l===-1)throw new SyntaxError(`Unexpected character at index ${d}`);f===-1&&(f=d),b(r,t.slice(l,f),!0),a===44&&(b(e,o,r),r=Object.create(null),o=void 0),l=f=-1}else if(a===61&&l!==-1&&f===-1)c=t.slice(l,d),l=f=-1;else throw new SyntaxError(`Unexpected character at index ${d}`);else if(s){if(se[a]!==1)throw new SyntaxError(`Unexpected character at index ${d}`);l===-1?l=d:n||(n=!0),s=!1}else if(i)if(se[a]===1)l===-1&&(l=d);else if(a===34&&l!==-1)i=!1,f=d;else if(a===92)s=!0;else throw new SyntaxError(`Unexpected character at index ${d}`);else if(a===34&&t.charCodeAt(d-1)===61)i=!0;else if(f===-1&&se[a]===1)l===-1&&(l=d);else if(l!==-1&&(a===32||a===9))f===-1&&(f=d);else if(a===59||a===44){if(l===-1)throw new SyntaxError(`Unexpected character at index ${d}`);f===-1&&(f=d);let _=t.slice(l,f);n&&(_=_.replace(/\\/g,""),n=!1),b(r,c,_),a===44&&(b(e,o,r),r=Object.create(null),o=void 0),c=void 0,l=f=-1}else throw new SyntaxError(`Unexpected character at index ${d}`);if(l===-1||i||a===32||a===9)throw new SyntaxError("Unexpected end of input");f===-1&&(f=d);let u=t.slice(l,f);return o===void 0?b(e,u,r):(c===void 0?b(r,u,!0):n?b(r,c,u.replace(/\\/g,"")):b(r,c,u),b(e,o,r)),e}function An(t){return Object.keys(t).map(e=>{let r=t[e];return Array.isArray(r)||(r=[r]),r.map(n=>[e].concat(Object.keys(n).map(s=>{let i=n[s];return Array.isArray(i)||(i=[i]),i.map(o=>o===!0?s:`${s}=${o}`).join("; ")})).join("; ")).join(", ")}).join(", ")}Ht.exports={format:An,parse:Dn}});var Ee=y((ii,ir)=>{"use strict";var Bn=require("events"),Mn=require("https"),Un=require("http"),Kt=require("net"),Wn=require("tls"),{randomBytes:$n,createHash:Vn}=require("crypto"),{Duplex:ni,Readable:si}=require("stream"),{URL:je}=require("url"),R=q(),jn=Me(),qn=$e(),{isBlob:Gn}=G(),{BINARY_TYPES:Jt,CLOSE_TIMEOUT:zn,EMPTY_BUFFER:Se,GUID:Hn,kForOnEventAttribute:qe,kListener:Jn,kStatusCode:Yn,kWebSocket:S,NOOP:Zt}=C(),{EventTarget:{addEventListener:Kn,removeEventListener:Zn}}=zt(),{format:Xn,parse:Qn}=ge(),{toBuffer:es}=ee(),Xt=Symbol("kAborted"),Ge=[8,13],L=["CONNECTING","OPEN","CLOSING","CLOSED"],ts=/^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/,m=class t extends Bn{constructor(e,r,n){super(),this._binaryType=Jt[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage=Se,this._closeTimer=null,this._errorEmitted=!1,this._extensions={},this._paused=!1,this._protocol="",this._readyState=t.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,e!==null?(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,r===void 0?r=[]:Array.isArray(r)||(typeof r=="object"&&r!==null?(n=r,r=[]):r=[r]),Qt(this,e,r,n)):(this._autoPong=n.autoPong,this._closeTimeout=n.closeTimeout,this._isServer=!0)}get binaryType(){return this._binaryType}set binaryType(e){Jt.includes(e)&&(this._binaryType=e,this._receiver&&(this._receiver._binaryType=e))}get bufferedAmount(){return this._socket?this._socket._writableState.length+this._sender._bufferedBytes:this._bufferedAmount}get extensions(){return Object.keys(this._extensions).join()}get isPaused(){return this._paused}get onclose(){return null}get onerror(){return null}get onopen(){return null}get onmessage(){return null}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket(e,r,n){let s=new jn({allowSynchronousEvents:n.allowSynchronousEvents,binaryType:this.binaryType,extensions:this._extensions,isServer:this._isServer,maxBufferedChunks:n.maxBufferedChunks,maxFragments:n.maxFragments,maxPayload:n.maxPayload,skipUTF8Validation:n.skipUTF8Validation}),i=new qn(e,this._extensions,n.generateMask);this._receiver=s,this._sender=i,this._socket=e,s[S]=this,i[S]=this,e[S]=this,s.on("conclude",ss),s.on("drain",is),s.on("error",os),s.on("message",as),s.on("ping",cs),s.on("pong",ls),i.onerror=fs,e.setTimeout&&e.setTimeout(0),e.setNoDelay&&e.setNoDelay(),r.length>0&&e.unshift(r),e.on("close",rr),e.on("data",xe),e.on("end",nr),e.on("error",sr),this._readyState=t.OPEN,this.emit("open")}emitClose(){if(!this._socket){this._readyState=t.CLOSED,this.emit("close",this._closeCode,this._closeMessage);return}this._extensions[R.extensionName]&&this._extensions[R.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=t.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close(e,r){if(this.readyState!==t.CLOSED){if(this.readyState===t.CONNECTING){x(this,this._req,"WebSocket was closed before the connection was established");return}if(this.readyState===t.CLOSING){this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end();return}this._readyState=t.CLOSING,this._sender.close(e,r,!this._isServer,n=>{n||(this._closeFrameSent=!0,(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end())}),tr(this)}}pause(){this.readyState===t.CONNECTING||this.readyState===t.CLOSED||(this._paused=!0,this._socket.pause())}ping(e,r,n){if(this.readyState===t.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"?(n=e,e=r=void 0):typeof r=="function"&&(n=r,r=void 0),typeof e=="number"&&(e=e.toString()),this.readyState!==t.OPEN){ze(this,e,n);return}r===void 0&&(r=!this._isServer),this._sender.ping(e||Se,r,n)}pong(e,r,n){if(this.readyState===t.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof e=="function"?(n=e,e=r=void 0):typeof r=="function"&&(n=r,r=void 0),typeof e=="number"&&(e=e.toString()),this.readyState!==t.OPEN){ze(this,e,n);return}r===void 0&&(r=!this._isServer),this._sender.pong(e||Se,r,n)}resume(){this.readyState===t.CONNECTING||this.readyState===t.CLOSED||(this._paused=!1,this._receiver._writableState.needDrain||this._socket.resume())}send(e,r,n){if(this.readyState===t.CONNECTING)throw new Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof r=="function"&&(n=r,r={}),typeof e=="number"&&(e=e.toString()),this.readyState!==t.OPEN){ze(this,e,n);return}let s={binary:typeof e!="string",mask:!this._isServer,compress:!0,fin:!0,...r};this._extensions[R.extensionName]||(s.compress=!1),this._sender.send(e||Se,s,n)}terminate(){if(this.readyState!==t.CLOSED){if(this.readyState===t.CONNECTING){x(this,this._req,"WebSocket was closed before the connection was established");return}this._socket&&(this._readyState=t.CLOSING,this._socket.destroy())}}};Object.defineProperty(m,"CONNECTING",{enumerable:!0,value:L.indexOf("CONNECTING")});Object.defineProperty(m.prototype,"CONNECTING",{enumerable:!0,value:L.indexOf("CONNECTING")});Object.defineProperty(m,"OPEN",{enumerable:!0,value:L.indexOf("OPEN")});Object.defineProperty(m.prototype,"OPEN",{enumerable:!0,value:L.indexOf("OPEN")});Object.defineProperty(m,"CLOSING",{enumerable:!0,value:L.indexOf("CLOSING")});Object.defineProperty(m.prototype,"CLOSING",{enumerable:!0,value:L.indexOf("CLOSING")});Object.defineProperty(m,"CLOSED",{enumerable:!0,value:L.indexOf("CLOSED")});Object.defineProperty(m.prototype,"CLOSED",{enumerable:!0,value:L.indexOf("CLOSED")});["binaryType","bufferedAmount","extensions","isPaused","protocol","readyState","url"].forEach(t=>{Object.defineProperty(m.prototype,t,{enumerable:!0})});["open","error","close","message"].forEach(t=>{Object.defineProperty(m.prototype,`on${t}`,{enumerable:!0,get(){for(let e of this.listeners(t))if(e[qe])return e[Jn];return null},set(e){for(let r of this.listeners(t))if(r[qe]){this.removeListener(t,r);break}typeof e=="function"&&this.addEventListener(t,e,{[qe]:!0})}})});m.prototype.addEventListener=Kn;m.prototype.removeEventListener=Zn;ir.exports=m;function Qt(t,e,r,n){let s={allowSynchronousEvents:!0,autoPong:!0,closeTimeout:zn,protocolVersion:Ge[1],maxBufferedChunks:1048576,maxFragments:131072,maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...n,socketPath:void 0,hostname:void 0,protocol:void 0,timeout:void 0,method:"GET",host:void 0,path:void 0,port:void 0};if(t._autoPong=s.autoPong,t._closeTimeout=s.closeTimeout,!Ge.includes(s.protocolVersion))throw new RangeError(`Unsupported protocol version: ${s.protocolVersion} (supported versions: ${Ge.join(", ")})`);let i;if(e instanceof je)i=e;else try{i=new je(e)}catch{throw new SyntaxError(`Invalid URL: ${e}`)}i.protocol==="http:"?i.protocol="ws:":i.protocol==="https:"&&(i.protocol="wss:"),t._url=i.href;let o=i.protocol==="wss:",c=i.protocol==="ws+unix:",l;if(i.protocol!=="ws:"&&!o&&!c?l=`The URL's protocol must be one of "ws:", "wss:", "http:", "https:", or "ws+unix:"`:c&&!i.pathname?l="The URL's pathname is empty":i.hash&&(l="The URL contains a fragment identifier"),l){let h=new SyntaxError(l);if(t._redirects===0)throw h;ye(t,h);return}let a=o?443:80,f=$n(16).toString("base64"),d=o?Mn.request:Un.request,u=new Set,_;if(s.createConnection=s.createConnection||(o?ns:rs),s.defaultPort=s.defaultPort||a,s.port=i.port||a,s.host=i.hostname.startsWith("[")?i.hostname.slice(1,-1):i.hostname,s.headers={...s.headers,"Sec-WebSocket-Version":s.protocolVersion,"Sec-WebSocket-Key":f,Connection:"Upgrade",Upgrade:"websocket"},s.path=i.pathname+i.search,s.timeout=s.handshakeTimeout,s.perMessageDeflate&&(_=new R({...s.perMessageDeflate,isServer:!1,maxPayload:s.maxPayload}),s.headers["Sec-WebSocket-Extensions"]=Xn({[R.extensionName]:_.offer()})),r.length){for(let h of r){if(typeof h!="string"||!ts.test(h)||u.has(h))throw new SyntaxError("An invalid or duplicated subprotocol was specified");u.add(h)}s.headers["Sec-WebSocket-Protocol"]=r.join(",")}if(s.origin&&(s.protocolVersion<13?s.headers["Sec-WebSocket-Origin"]=s.origin:s.headers.Origin=s.origin),(i.username||i.password)&&(s.auth=`${i.username}:${i.password}`),c){let h=s.path.split(":");s.socketPath=h[0],s.path=h[1]}let p;if(s.followRedirects){if(t._redirects===0){t._originalIpc=c,t._originalSecure=o,t._originalHostOrSocketPath=c?s.socketPath:i.host;let h=n&&n.headers;if(n={...n,headers:{}},h)for(let[g,W]of Object.entries(h))n.headers[g.toLowerCase()]=W}else if(t.listenerCount("redirect")===0){let h=c?t._originalIpc?s.socketPath===t._originalHostOrSocketPath:!1:t._originalIpc?!1:i.host===t._originalHostOrSocketPath;(!h||t._originalSecure&&!o)&&(delete s.headers.authorization,delete s.headers.cookie,h||delete s.headers.host,s.auth=void 0)}s.auth&&!n.headers.authorization&&(n.headers.authorization="Basic "+Buffer.from(s.auth).toString("base64")),p=t._req=d(s),t._redirects&&t.emit("redirect",t.url,p)}else p=t._req=d(s);s.timeout&&p.on("timeout",()=>{x(t,p,"Opening handshake has timed out")}),p.on("error",h=>{p===null||p[Xt]||(p=t._req=null,ye(t,h))}),p.on("response",h=>{let g=h.headers.location,W=h.statusCode;if(g&&s.followRedirects&&W>=300&&W<400){if(++t._redirects>s.maxRedirects){x(t,p,"Maximum redirects exceeded");return}p.abort();let X;try{X=new je(g,e)}catch{let $=new SyntaxError(`Invalid URL: ${g}`);ye(t,$);return}Qt(t,X,r,n)}else t.emit("unexpected-response",p,h)||x(t,p,`Unexpected server response: ${h.statusCode}`)}),p.on("upgrade",(h,g,W)=>{if(t.emit("upgrade",h),t.readyState!==m.CONNECTING)return;p=t._req=null;let X=h.headers.upgrade;if(X===void 0||X.toLowerCase()!=="websocket"){x(t,g,"Invalid Upgrade header");return}let et=Vn("sha1").update(f+Hn).digest("base64");if(h.headers["sec-websocket-accept"]!==et){x(t,g,"Invalid Sec-WebSocket-Accept header");return}let $=h.headers["sec-websocket-protocol"],Q;if($!==void 0?u.size?u.has($)||(Q="Server sent an invalid subprotocol"):Q="Server sent a subprotocol but none was requested":u.size&&(Q="Server sent no subprotocol"),Q){x(t,g,Q);return}$&&(t._protocol=$);let tt=h.headers["sec-websocket-extensions"];if(tt!==void 0){if(!_){x(t,g,"Server sent a Sec-WebSocket-Extensions header but no extension was requested");return}let be;try{be=Qn(tt)}catch{x(t,g,"Invalid Sec-WebSocket-Extensions header");return}let rt=Object.keys(be);if(rt.length!==1||rt[0]!==R.extensionName){x(t,g,"Server indicated an extension that was not requested");return}try{_.accept(be[R.extensionName])}catch{x(t,g,"Invalid Sec-WebSocket-Extensions header");return}t._extensions[R.extensionName]=_}t.setSocket(g,W,{allowSynchronousEvents:s.allowSynchronousEvents,generateMask:s.generateMask,maxBufferedChunks:s.maxBufferedChunks,maxFragments:s.maxFragments,maxPayload:s.maxPayload,skipUTF8Validation:s.skipUTF8Validation})}),s.finishRequest?s.finishRequest(p,t):p.end()}function ye(t,e){t._readyState=m.CLOSING,t._errorEmitted=!0,t.emit("error",e),t.emitClose()}function rs(t){return t.path=t.socketPath,Kt.connect(t)}function ns(t){return t.path=void 0,!t.servername&&t.servername!==""&&(t.servername=Kt.isIP(t.host)?"":t.host),Wn.connect(t)}function x(t,e,r){t._readyState=m.CLOSING;let n=new Error(r);Error.captureStackTrace(n,x),e.setHeader?(e[Xt]=!0,e.abort(),e.socket&&!e.socket.destroyed&&e.socket.destroy(),process.nextTick(ye,t,n)):(e.destroy(n),e.once("error",t.emit.bind(t,"error")),e.once("close",t.emitClose.bind(t)))}function ze(t,e,r){if(e){let n=Gn(e)?e.size:es(e).length;t._socket?t._sender._bufferedBytes+=n:t._bufferedAmount+=n}if(r){let n=new Error(`WebSocket is not open: readyState ${t.readyState} (${L[t.readyState]})`);process.nextTick(r,n)}}function ss(t,e){let r=this[S];r._closeFrameReceived=!0,r._closeMessage=e,r._closeCode=t,r._socket[S]!==void 0&&(r._socket.removeListener("data",xe),process.nextTick(er,r._socket),t===1005?r.close():r.close(t,e))}function is(){let t=this[S];t.isPaused||t._socket.resume()}function os(t){let e=this[S];e._socket[S]!==void 0&&(e._socket.removeListener("data",xe),process.nextTick(er,e._socket),e.close(t[Yn])),e._errorEmitted||(e._errorEmitted=!0,e.emit("error",t))}function Yt(){this[S].emitClose()}function as(t,e){this[S].emit("message",t,e)}function cs(t){let e=this[S];e._autoPong&&e.pong(t,!this._isServer,Zt),e.emit("ping",t)}function ls(t){this[S].emit("pong",t)}function er(t){t.resume()}function fs(t){let e=this[S];e.readyState!==m.CLOSED&&(e.readyState===m.OPEN&&(e._readyState=m.CLOSING,tr(e)),this._socket.end(),e._errorEmitted||(e._errorEmitted=!0,e.emit("error",t)))}function tr(t){t._closeTimer=setTimeout(t._socket.destroy.bind(t._socket),t._closeTimeout)}function rr(){let t=this[S];if(this.removeListener("close",rr),this.removeListener("data",xe),this.removeListener("end",nr),t._readyState=m.CLOSING,!this._readableState.endEmitted&&!t._closeFrameReceived&&!t._receiver._writableState.errorEmitted&&this._readableState.length!==0){let e=this.read(this._readableState.length);t._receiver.write(e)}t._receiver.end(),this[S]=void 0,clearTimeout(t._closeTimer),t._receiver._writableState.finished||t._receiver._writableState.errorEmitted?t.emitClose():(t._receiver.on("error",Yt),t._receiver.on("finish",Yt))}function xe(t){this[S]._receiver.write(t)||this.pause()}function nr(){let t=this[S];t._readyState=m.CLOSING,t._receiver.end(),this.end()}function sr(){let t=this[S];this.removeListener("error",sr),this.on("error",Zt),t&&(t._readyState=m.CLOSING,this.destroy())}});var lr=y((ai,cr)=>{"use strict";var oi=Ee(),{Duplex:ds}=require("stream");function or(t){t.emit("close")}function hs(){!this.destroyed&&this._writableState.finished&&this.destroy()}function ar(t){this.removeListener("error",ar),this.destroy(),this.listenerCount("error")===0&&this.emit("error",t)}function us(t,e){let r=!0,n=new ds({...e,autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1});return t.on("message",function(i,o){let c=!o&&n._readableState.objectMode?i.toString():i;n.push(c)||t.pause()}),t.once("error",function(i){n.destroyed||(r=!1,n.destroy(i))}),t.once("close",function(){n.destroyed||n.push(null)}),n._destroy=function(s,i){if(t.readyState===t.CLOSED){i(s),process.nextTick(or,n);return}let o=!1;t.once("error",function(l){o=!0,i(l)}),t.once("close",function(){o||i(s),process.nextTick(or,n)}),r&&t.terminate()},n._final=function(s){if(t.readyState===t.CONNECTING){t.once("open",function(){n._final(s)});return}t._socket!==null&&(t._socket._writableState.finished?(s(),n._readableState.endEmitted&&n.destroy()):(t._socket.once("finish",function(){s()}),t.close()))},n._read=function(){t.isPaused&&t.resume()},n._write=function(s,i,o){if(t.readyState===t.CONNECTING){t.once("open",function(){n._write(s,i,o)});return}t.send(s,o)},n.on("end",hs),n.on("error",ar),n}cr.exports=us});var He=y((ci,fr)=>{"use strict";var{tokenChars:ps}=G();function ms(t){let e=new Set,r=-1,n=-1,s=0;for(s;s<t.length;s++){let o=t.charCodeAt(s);if(n===-1&&ps[o]===1)r===-1&&(r=s);else if(s!==0&&(o===32||o===9))n===-1&&r!==-1&&(n=s);else if(o===44){if(r===-1)throw new SyntaxError(`Unexpected character at index ${s}`);n===-1&&(n=s);let c=t.slice(r,n);if(e.has(c))throw new SyntaxError(`The "${c}" subprotocol is duplicated`);e.add(c),r=n=-1}else throw new SyntaxError(`Unexpected character at index ${s}`)}if(r===-1||n!==-1)throw new SyntaxError("Unexpected end of input");let i=t.slice(r,s);if(e.has(i))throw new SyntaxError(`The "${i}" subprotocol is duplicated`);return e.add(i),e}fr.exports={parse:ms}});var gr=y((fi,_r)=>{"use strict";var _s=require("events"),ke=require("http"),{Duplex:li}=require("stream"),{createHash:gs}=require("crypto"),dr=ge(),M=q(),Ss=He(),ys=Ee(),{CLOSE_TIMEOUT:xs,GUID:Es,kWebSocket:ks}=C(),ws=/^[+/0-9A-Za-z]{22}==$/,hr=0,ur=1,mr=2,Je=class extends _s{constructor(e,r){if(super(),e={allowSynchronousEvents:!0,autoPong:!0,maxBufferedChunks:1024*1024,maxFragments:128*1024,maxPayload:100*1024*1024,skipUTF8Validation:!1,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,closeTimeout:xs,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null,WebSocket:ys,...e},e.port==null&&!e.server&&!e.noServer||e.port!=null&&(e.server||e.noServer)||e.server&&e.noServer)throw new TypeError('One and only one of the "port", "server", or "noServer" options must be specified');if(e.port!=null?(this._server=ke.createServer((n,s)=>{let i=ke.STATUS_CODES[426];s.writeHead(426,{"Content-Length":i.length,"Content-Type":"text/plain"}),s.end(i)}),this._server.listen(e.port,e.host,e.backlog,r)):e.server&&(this._server=e.server),this._server){let n=this.emit.bind(this,"connection");this._removeListeners=vs(this._server,{listening:this.emit.bind(this,"listening"),error:this.emit.bind(this,"error"),upgrade:(s,i,o)=>{this.handleUpgrade(s,i,o,n)}})}e.perMessageDeflate===!0&&(e.perMessageDeflate={}),e.clientTracking&&(this.clients=new Set,this._shouldEmitClose=!1),this.options=e,this._state=hr}address(){if(this.options.noServer)throw new Error('The server is operating in "noServer" mode');return this._server?this._server.address():null}close(e){if(this._state===mr){e&&this.once("close",()=>{e(new Error("The server is not running"))}),process.nextTick(ie,this);return}if(e&&this.once("close",e),this._state!==ur)if(this._state=ur,this.options.noServer||this.options.server)this._server&&(this._removeListeners(),this._removeListeners=this._server=null),this.clients?this.clients.size?this._shouldEmitClose=!0:process.nextTick(ie,this):process.nextTick(ie,this);else{let r=this._server;this._removeListeners(),this._removeListeners=this._server=null,r.close(()=>{ie(this)})}}shouldHandle(e){if(this.options.path){let r=e.url.indexOf("?");if((r!==-1?e.url.slice(0,r):e.url)!==this.options.path)return!1}return!0}handleUpgrade(e,r,n,s){r.on("error",pr);let i=e.headers["sec-websocket-key"],o=e.headers.upgrade,c=+e.headers["sec-websocket-version"];if(e.method!=="GET"){U(this,e,r,405,"Invalid HTTP method");return}if(o===void 0||o.toLowerCase()!=="websocket"){U(this,e,r,400,"Invalid Upgrade header");return}if(i===void 0||!ws.test(i)){U(this,e,r,400,"Missing or invalid Sec-WebSocket-Key header");return}if(c!==13&&c!==8){U(this,e,r,400,"Missing or invalid Sec-WebSocket-Version header",{"Sec-WebSocket-Version":"13, 8"});return}if(!this.shouldHandle(e)){oe(r,400);return}let l=e.headers["sec-websocket-protocol"],a=new Set;if(l!==void 0)try{a=Ss.parse(l)}catch{U(this,e,r,400,"Invalid Sec-WebSocket-Protocol header");return}let f=e.headers["sec-websocket-extensions"],d={};if(this.options.perMessageDeflate&&f!==void 0){let u=new M({...this.options.perMessageDeflate,isServer:!0,maxPayload:this.options.maxPayload});try{let _=dr.parse(f);_[M.extensionName]&&(u.accept(_[M.extensionName]),d[M.extensionName]=u)}catch{U(this,e,r,400,"Invalid or unacceptable Sec-WebSocket-Extensions header");return}}if(this.options.verifyClient){let u={origin:e.headers[`${c===8?"sec-websocket-origin":"origin"}`],secure:!!(e.socket.authorized||e.socket.encrypted),req:e};if(this.options.verifyClient.length===2){this.options.verifyClient(u,(_,p,h,g)=>{if(!_)return oe(r,p||401,h,g);this.completeUpgrade(d,i,a,e,r,n,s)});return}if(!this.options.verifyClient(u))return oe(r,401)}this.completeUpgrade(d,i,a,e,r,n,s)}completeUpgrade(e,r,n,s,i,o,c){if(!i.readable||!i.writable)return i.destroy();if(i[ks])throw new Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");if(this._state>hr)return oe(i,503);let a=["HTTP/1.1 101 Switching Protocols","Upgrade: websocket","Connection: Upgrade",`Sec-WebSocket-Accept: ${gs("sha1").update(r+Es).digest("base64")}`],f=new this.options.WebSocket(null,void 0,this.options);if(n.size){let d=this.options.handleProtocols?this.options.handleProtocols(n,s):n.values().next().value;d&&(a.push(`Sec-WebSocket-Protocol: ${d}`),f._protocol=d)}if(e[M.extensionName]){let d=e[M.extensionName].params,u=dr.format({[M.extensionName]:[d]});a.push(`Sec-WebSocket-Extensions: ${u}`),f._extensions=e}this.emit("headers",a,s),i.write(a.concat(`\r
3
- `).join(`\r
4
- `)),i.removeListener("error",pr),f.setSocket(i,o,{allowSynchronousEvents:this.options.allowSynchronousEvents,maxBufferedChunks:this.options.maxBufferedChunks,maxFragments:this.options.maxFragments,maxPayload:this.options.maxPayload,skipUTF8Validation:this.options.skipUTF8Validation}),this.clients&&(this.clients.add(f),f.on("close",()=>{this.clients.delete(f),this._shouldEmitClose&&!this.clients.size&&process.nextTick(ie,this)})),c(f,s)}};_r.exports=Je;function vs(t,e){for(let r of Object.keys(e))t.on(r,e[r]);return function(){for(let n of Object.keys(e))t.removeListener(n,e[n])}}function ie(t){t._state=mr,t.emit("close")}function pr(){this.destroy()}function oe(t,e,r,n){r=r||ke.STATUS_CODES[e],n={Connection:"close","Content-Type":"text/html","Content-Length":Buffer.byteLength(r),...n},t.once("finish",t.destroy),t.end(`HTTP/1.1 ${e} ${ke.STATUS_CODES[e]}\r
5
- `+Object.keys(n).map(s=>`${s}: ${n[s]}`).join(`\r
6
- `)+`\r
7
- \r
8
- `+r)}function U(t,e,r,n,s,i){if(t.listenerCount("wsClientError")){let o=new Error(s);Error.captureStackTrace(o,U),t.emit("wsClientError",o,r,e)}else oe(r,n,s,i)}});var As={};Yr(As,{startNvimSidecar:()=>Ur});module.exports=Kr(As);var Mr=require("node:readline");var F="PI_X_IDE_LOCK_DIR",st="x-pi-x-ide-authorization",it=".lock";var ht=require("node:os"),O=require("node:path");var ct=require("node:fs"),lt=require("node:os"),ft=require("node:path");var Zr=["string","number","boolean"];function ot(t){return Zr.some(e=>typeof t===e)}var Xr="config.json",Qr=new WeakSet;function en(t=(0,lt.homedir)()){return(0,ft.resolve)(t,".pi",Xr)}function tn(t=en()){let e;try{e=JSON.parse((0,ct.readFileSync)(t,"utf8"))}catch{return{}}return!at(e)||!at(e.env)?{}:Object.fromEntries(Object.entries(e.env).filter(r=>{let[n,s]=r;return n.length>0&&ot(s)}).map(([r,n])=>[r,String(n)]))}function dt(t=process.env,e={}){if(t!==process.env&&!e.configPath)return t;let r=tn(e.configPath);if(Object.keys(r).length===0)return t;let n={...r,...t};return t===process.env&&Qr.add(n),n}function at(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Ce(t=process.env){let r=dt(t)[F]?.trim();return r?(0,O.resolve)(r):(0,O.resolve)((0,ht.homedir)(),".pi","pi-x-ide","lock")}function ut(t,e,r){let n=e??r;if(!n)return t;let s=(0,O.relative)(n,t);return!s||s.startsWith("..")||(0,O.isAbsolute)(s)?t:s.split(O.sep).join("/")}function rn(t){return{startLine:t.selection.start.line+1,endLine:t.selection.end.line+1}}function nn(t,e="comma"){let{startLine:r,endLine:n}=rn(t);return r===n?`#L${r}`:e==="dash"?`#L${r}-L${n}`:`#L${r},${n}`}function pt(t,e={}){let r=ut(t.filePath,t.workspaceFolder,e.cwd),n=t.ranges[0];return n?`@${r}${nn(n,e.format)}`:`@${r}`}var Or=require("node:http");var bs=N(lr(),1),Os=N(ge(),1),Cs=N(q(),1),Ts=N(Me(),1),Ps=N($e(),1),Ls=N(He(),1),Sr=N(Ee(),1),Ye=N(gr(),1);var yr=Sr.default;function K(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Z(t){return typeof t=="string"}function ae(t){return typeof t=="number"&&Number.isFinite(t)}function Er(t){return t==="vscode"||t==="zed"||t==="nvim"||t==="unknown"}function xr(t){return K(t)&&ae(t.line)&&ae(t.character)&&t.line>=0&&t.character>=0}function Ns(t){return!K(t)||!Z(t.text)||!K(t.selection)?!1:xr(t.selection.start)&&xr(t.selection.end)}function Ke(t){return K(t)?Er(t.source)&&Z(t.filePath)&&(t.workspaceFolder===void 0||Z(t.workspaceFolder))&&Array.isArray(t.ranges)&&t.ranges.every(Ns)&&(t.receivedAt===void 0||ae(t.receivedAt)):!1}function kr(t){return K(t)&&Er(t.source)&&t.reason==="no-active-editor"&&(t.receivedAt===void 0||ae(t.receivedAt))}function wr(t){return Ke(t)&&Z(t.rangeText)}function vr(t){return K(t)&&t.jsonrpc==="2.0"&&(Z(t.id)||ae(t.id))&&Z(t.method)}var we=require("node:buffer");function br(t){return Array.isArray(t)?we.Buffer.concat(t).toString("utf8"):we.Buffer.isBuffer(t)?t.toString("utf8"):we.Buffer.from(t).toString("utf8")}var ve=class{constructor(e,r,n){this.authToken=e;this.serverInfo=r;this.getInitialSelection=n}authToken;serverInfo;getInitialSelection;httpServer;wss;sockets=new Set;get port(){let e=this.httpServer?.address();return!e||typeof e=="string"?0:e.port}get clientCount(){return this.sockets.size}async start(){return this.httpServer=(0,Or.createServer)(),this.wss=new Ye.default({server:this.httpServer,verifyClient:({req:e},r)=>{let n=e.headers[st],s=Array.isArray(n)?n[0]:n;r(s===this.authToken,s===this.authToken?void 0:401,"Unauthorized")}}),this.wss.on("connection",e=>{this.sockets.add(e),e.on("close",()=>this.sockets.delete(e)),e.on("error",()=>this.sockets.delete(e)),e.on("message",r=>this.handleMessage(e,br(r)))}),await new Promise((e,r)=>{this.httpServer.once("error",r),this.httpServer.listen(0,"127.0.0.1",()=>{this.httpServer.off("error",r),e()})}),this.port}broadcast(e){let r=JSON.stringify(e);for(let n of this.sockets)n.readyState===yr.OPEN&&n.send(r)}async stop(){for(let e of this.sockets)e.close();this.sockets.clear(),await Promise.all([new Promise(e=>this.wss?.close(()=>e())??e()),new Promise(e=>this.httpServer?.close(()=>e())??e())])}handleMessage(e,r){let n;try{n=JSON.parse(r)}catch{return}if(!vr(n)||n.method!=="initialize")return;let s=this.serverInfo.ide??"vscode",i={protocolVersion:1,server:{name:this.serverInfo.name,version:this.serverInfo.version,ide:s}};e.send(JSON.stringify({jsonrpc:"2.0",id:n.id,result:i}));let o=this.getInitialSelection?.();e.send(JSON.stringify({jsonrpc:"2.0",method:o?"selection_changed":"selection_cleared",params:o?{...o,receivedAt:Date.now()}:{source:s,reason:"no-active-editor",receivedAt:Date.now()}}))}};var Cr=require("node:crypto"),w=require("node:fs/promises"),Tr=require("node:path");function Pr(){return(0,Cr.randomBytes)(32).toString("hex")}function Lr(t,e,r=process.pid){return(0,Tr.join)(Ce(),`${t}-${r}-${e}${it}`)}function Nr(t){let e=(t.now??new Date).toISOString();return{version:1,ide:t.ide,name:t.name,transport:"ws",host:"127.0.0.1",port:t.port,authToken:t.authToken,workspaceFolders:t.workspaceFolders,pid:t.pid??process.pid,createdAt:e,updatedAt:e}}async function Ze(t,e){let r=Ce();await(0,w.mkdir)(r,{recursive:!0,mode:448}),await(0,w.chmod)(r,448).catch(()=>{});let n=`${t}.${process.pid}.${Date.now()}.tmp`;await(0,w.writeFile)(n,`${JSON.stringify(e,null,2)}
9
- `,{encoding:"utf8",mode:384}),await(0,w.chmod)(n,384).catch(()=>{}),await(0,w.rename)(n,t),await(0,w.chmod)(t,384).catch(()=>{})}async function Ir(t){t&&await(0,w.rm)(t,{force:!0}).catch(()=>{})}function Rr(t,e,r=new Date){return{...t,workspaceFolders:e,updatedAt:r.toISOString()}}function Fr(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Dr(t){return Array.isArray(t)&&t.every(e=>typeof e=="string")}function Xe(t){if(!Fr(t))return;let e=t.workspaceFolders,r=t.name,n=t.lockDir;if(!(e!==void 0&&!Dr(e))&&!(r!==void 0&&typeof r!="string")&&!(n!==void 0&&typeof n!="string"))return{workspaceFolders:e,name:r,lockDir:n}}function Ar(t){if(!(!Fr(t)||typeof t.type!="string"))switch(t.type){case"selection_changed":return Ke(t.snapshot)?{type:"selection_changed",snapshot:t.snapshot}:void 0;case"selection_cleared":{let e={source:"nvim",reason:t.reason??"no-active-editor"};return kr(e)?{type:"selection_cleared",reason:e.reason}:void 0}case"at_mentioned":{let e=t.snapshot;if(!wr(e))return;let r=typeof t.rangeText=="string"?t.rangeText:e.rangeText;return{type:"at_mentioned",snapshot:e,rangeText:r}}case"workspace_changed":return Dr(t.workspaceFolders)?{type:"workspace_changed",workspaceFolders:t.workspaceFolders}:void 0;case"shutdown":return{type:"shutdown"};default:return}}function Qe(t){try{return JSON.parse(t)}catch{return}}async function Ur(t={}){let e=process.env[F];t.lockDir&&(process.env[F]=t.lockDir);let r={workspaceFolders:$r(t.workspaceFolders),stopped:!1},n=Pr(),s=new ve(n,{name:t.name??"Neovim",ide:"nvim"},()=>r.latestSelection),i=await s.start();r.lockFilePath=Lr("nvim",i),r.lockFile=Nr({ide:"nvim",name:t.name??"Neovim",port:i,authToken:n,workspaceFolders:r.workspaceFolders}),await Ze(r.lockFilePath,r.lockFile),(t.stdout??process.stdout).write(JSON.stringify({type:"ready",port:i,lockFilePath:r.lockFilePath})+`
10
- `);let c=async()=>{r.stopped||(r.stopped=!0,await Ir(r.lockFilePath),await s.stop(),t.lockDir&&(e===void 0?delete process.env[F]:process.env[F]=e))},l=t.stdin??process.stdin,a=t.stderr??process.stderr,f=(0,Mr.createInterface)({input:l});f.on("line",u=>{let _=u.trim();if(!_)return;let p=Qe(_),h=Xe(p);if(h&&!("type"in p)){Wr(r,h,a);return}let g=Ar(p);if(!g){a.write(`pi-x-ide nvim sidecar: ignored malformed message: ${_}
11
- `);return}Rs(r,s,g,a,c)}),f.on("close",()=>{c()});let d=()=>{c()};return process.once("SIGINT",d),process.once("SIGTERM",d),process.once("beforeExit",d),{server:s,lockFilePath:r.lockFilePath,stop:c}}async function Wr(t,e,r){if(e.workspaceFolders&&(t.workspaceFolders=$r(e.workspaceFolders)),!(!t.lockFilePath||!t.lockFile)){t.lockFile=Rr(t.lockFile,t.workspaceFolders);try{await Ze(t.lockFilePath,t.lockFile)}catch(n){r.write(`pi-x-ide nvim sidecar: failed to refresh lock file: ${Vr(n)}
12
- `)}}}async function Rs(t,e,r,n,s){switch(r.type){case"selection_changed":{let i=Br(r.snapshot);t.latestSelection=i,e.broadcast({jsonrpc:"2.0",method:"selection_changed",params:{...i,receivedAt:i.receivedAt??Date.now()}});return}case"selection_cleared":t.latestSelection=void 0,e.broadcast({jsonrpc:"2.0",method:"selection_cleared",params:{source:"nvim",reason:r.reason??"no-active-editor",receivedAt:Date.now()}});return;case"at_mentioned":{let i=Br(r.snapshot);t.latestSelection=i;let o=r.rangeText||pt(i);e.broadcast({jsonrpc:"2.0",method:"at_mentioned",params:{...i,rangeText:o,receivedAt:i.receivedAt??Date.now()}});return}case"workspace_changed":await Wr(t,{workspaceFolders:r.workspaceFolders},n);return;case"shutdown":await s();return}}function Br(t){return{...t,source:"nvim"}}function $r(t){let e=t?.filter(r=>r.length>0)??[];return e.length>0?e:[process.cwd()]}function Vr(t){return t instanceof Error?t.message:String(t)}function Fs(t){let e={};for(let r=0;r<t.length;r+=1){let n=t[r];if(n==="--help"||n==="-h")return"help";if(n==="--name")e.name=t[++r];else if(n==="--lock-dir")e.lockDir=t[++r];else if(n==="--workspace-folder")e.workspaceFolders=[...e.workspaceFolders??[],t[++r]].filter(Boolean);else if(n==="--workspace-folders"){let s=t[++r],i=Qe(s??""),o=Xe({workspaceFolders:i});o?.workspaceFolders&&(e.workspaceFolders=o.workspaceFolders)}}return e}function Ds(){process.stdout.write(`Usage: pi-x-ide-nvim-sidecar [options]
13
-
14
- Options:
15
- --workspace-folder <path> Add a workspace folder. May be repeated.
16
- --workspace-folders <json> JSON array of workspace folders.
17
- --lock-dir <path> Override PI_X_IDE_LOCK_DIR for tests.
18
- --name <name> Display name reported to Pi.
19
- --help Show this help.
20
- `)}if(require.main===module){let t=Fs(process.argv.slice(2));t==="help"?Ds():Ur(t).catch(e=>{process.stderr.write(`pi-x-ide nvim sidecar: ${Vr(e)}
21
- `),process.exitCode=1})}0&&(module.exports={startNvimSidecar});
@@ -1,112 +0,0 @@
1
- *pi-x-ide.txt* Neovim support for Pi x IDE
2
-
3
- ===============================================================================
4
- CONTENTS *pi-x-ide*
5
-
6
- 1. Setup |pi-x-ide-setup|
7
- 2. Commands |pi-x-ide-commands|
8
- 3. Options |pi-x-ide-options|
9
- 4. Troubleshooting |pi-x-ide-troubleshooting|
10
-
11
- ===============================================================================
12
- SETUP *pi-x-ide-setup*
13
-
14
- With lazy.nvim:
15
- >
16
- {
17
- "balaenis/pi-x-ide",
18
- init = function()
19
- vim.opt.rtp:prepend(vim.fn.stdpath("data") .. "/lazy/pi-x-ide/nvim")
20
- end,
21
- config = function()
22
- require("pi_x_ide").setup({
23
- keymap = "<leader>pa",
24
- })
25
- end,
26
- }
27
- <
28
-
29
- Note: The `init` block manually adds the `nvim/` subdirectory to the runtime
30
- path. This avoids a Lua module resolution issue with lazy.nvim's `rtp` option
31
- on some versions.
32
-
33
- With native packages, clone the repository into a `pack/*/start` directory and
34
- add the `nvim` subdirectory to your runtime path before setup:
35
- >
36
- set runtimepath+=/path/to/pi-x-ide/nvim
37
- lua require("pi_x_ide").setup({ keymap = "<leader>pa" })
38
- <
39
-
40
- The plugin starts a bundled Node.js sidecar. The sidecar writes a lock file to
41
- `~/.pi/pi-x-ide/`, and Pi connects through the same `/ide` flow used by VS Code.
42
- Pi may run in any terminal whose current directory matches the Neovim workspace.
43
-
44
- ===============================================================================
45
- COMMANDS *pi-x-ide-commands*
46
-
47
- :PiXIdeStart
48
- Start the Neovim sidecar.
49
-
50
- :PiXIdeStop
51
- Stop the Neovim sidecar and remove its lock file.
52
-
53
- :PiXIdeStatus
54
- Show whether the sidecar is running.
55
-
56
- :PiXIdeAttach
57
- Attach the current file or selection to connected Pi clients. In Pi this
58
- inserts an `@relative/path#Lx,y` reference, matching the VS Code attach flow.
59
-
60
- ===============================================================================
61
- OPTIONS *pi-x-ide-options*
62
-
63
- Pass options to `require("pi_x_ide").setup({ ... })`.
64
-
65
- `enabled` (boolean, default true)
66
- Start the sidecar during setup.
67
-
68
- `sidecar_cmd` (string[]|nil)
69
- Command used to start the sidecar. Defaults to:
70
- `node <plugin-root>/bin/pi-x-ide-nvim-sidecar.cjs`.
71
-
72
- `debounce_ms` (number, default 150)
73
- Delay for high-frequency cursor and text-change updates.
74
-
75
- `range_format` ("comma"|"dash", default "comma")
76
- Format for manual attach references: `#L10,20` or `#L10-L20`.
77
-
78
- `keymap` (string|nil)
79
- Optional normal/visual mode mapping for `:PiXIdeAttach` behavior.
80
-
81
- `workspace_folders` (string[]|nil)
82
- Explicit workspace folder list. Defaults to current working directory plus
83
- active LSP workspace folders when available.
84
-
85
- ===============================================================================
86
- TROUBLESHOOTING *pi-x-ide-troubleshooting*
87
-
88
- No `nvim-*.lock` file appears under `~/.pi/pi-x-ide/`:
89
- Run `:PiXIdeStatus`, confirm Node.js is on PATH, or set `sidecar_cmd` to an
90
- absolute Node command.
91
-
92
- Pi shows no IDE connection:
93
- Start Pi in the same project directory and run `/ide auto`. If the project
94
- layout is unusual, run `/ide` and choose the Neovim connection manually.
95
-
96
- The keymap does not work:
97
- Choose a different `keymap` value in setup. The plugin does not install a
98
- default keymap to avoid conflicts with existing Neovim configs.
99
-
100
- Selection is not attached:
101
- Use visual mode and invoke the configured keymap or `:PiXIdeAttach`. The
102
- plugin sends file context for normal cursor movement and selection context
103
- for active or recently completed visual selections.
104
-
105
- module 'pi_x_ide' not found with lazy.nvim:
106
- Some lazy.nvim versions fail to update Lua's package.path when `rtp` is
107
- used. Replace `rtp = "nvim"` with an `init` block that prepends the path:
108
- >
109
- init = function()
110
- vim.opt.rtp:prepend(vim.fn.stdpath("data") .. "/lazy/pi-x-ide/nvim")
111
- end,
112
- <
@@ -1,442 +0,0 @@
1
- local M = {}
2
-
3
- local state = {
4
- config = nil,
5
- job_id = nil,
6
- timer = nil,
7
- augroup = nil,
8
- latest_snapshot = nil,
9
- visual_mark_valid = false,
10
- }
11
-
12
- local defaults = {
13
- enabled = true,
14
- sidecar_cmd = nil,
15
- debounce_ms = 150,
16
- range_format = "comma",
17
- keymap = nil,
18
- workspace_folders = nil,
19
- }
20
-
21
- local function notify(message, level)
22
- vim.notify("Pi x IDE: " .. message, level or vim.log.levels.INFO)
23
- end
24
-
25
- local function plugin_root()
26
- local source = debug.getinfo(1, "S").source
27
- if source:sub(1, 1) == "@" then
28
- source = source:sub(2)
29
- end
30
- return vim.fn.fnamemodify(source, ":p:h:h:h")
31
- end
32
-
33
- local function default_sidecar_cmd()
34
- return { "node", plugin_root() .. "/bin/pi-x-ide-nvim-sidecar.cjs" }
35
- end
36
-
37
- local function encode(value)
38
- return vim.json and vim.json.encode(value) or vim.fn.json_encode(value)
39
- end
40
-
41
- local function send(value)
42
- if not state.job_id then
43
- return false
44
- end
45
- local ok = vim.fn.chansend(state.job_id, encode(value) .. "\n")
46
- return ok == 1
47
- end
48
-
49
- local function normalize_config(opts)
50
- local config = vim.tbl_deep_extend("force", defaults, opts or {})
51
- if config.range_format ~= "dash" then
52
- config.range_format = "comma"
53
- end
54
- return config
55
- end
56
-
57
- local function workspace_folders()
58
- local configured = state.config and state.config.workspace_folders
59
- if type(configured) == "table" and #configured > 0 then
60
- return configured
61
- end
62
-
63
- local folders = { vim.fn.getcwd() }
64
- for _, client in pairs(vim.lsp.get_clients and vim.lsp.get_clients() or {}) do
65
- for _, folder in ipairs(client.workspace_folders or {}) do
66
- if folder.name and folder.name ~= "" then
67
- table.insert(folders, folder.name)
68
- elseif folder.uri then
69
- local path = vim.uri_to_fname(folder.uri)
70
- if path and path ~= "" then
71
- table.insert(folders, path)
72
- end
73
- end
74
- end
75
- end
76
-
77
- local seen = {}
78
- local result = {}
79
- for _, folder in ipairs(folders) do
80
- local normalized = vim.fn.fnamemodify(folder, ":p"):gsub("/$", "")
81
- if normalized ~= "" and not seen[normalized] then
82
- seen[normalized] = true
83
- table.insert(result, normalized)
84
- end
85
- end
86
- return result
87
- end
88
-
89
- local function is_path_inside(parent, child)
90
- parent = vim.fn.fnamemodify(parent, ":p"):gsub("/$", "")
91
- child = vim.fn.fnamemodify(child, ":p")
92
- if child:gsub("/$", "") == parent then
93
- return true
94
- end
95
- return child:sub(1, #parent + 1) == parent .. "/"
96
- end
97
-
98
- local function best_workspace(file_path)
99
- local best = nil
100
- for _, folder in ipairs(workspace_folders()) do
101
- if is_path_inside(folder, file_path) and (not best or #folder > #best) then
102
- best = folder
103
- end
104
- end
105
- return best or workspace_folders()[1]
106
- end
107
-
108
- local function byte_to_utf16(line, byte_col)
109
- return vim.str_utfindex(line or "", "utf-16", math.max(0, byte_col), false)
110
- end
111
-
112
- local function byte_after_char(line, byte_col)
113
- line = line or ""
114
- if byte_col >= #line then
115
- return #line
116
- end
117
- local utf16 = byte_to_utf16(line, byte_col)
118
- return math.min(#line, vim.str_byteindex(line, "utf-16", utf16 + 1, false))
119
- end
120
-
121
- local function compare_positions(a, b)
122
- if a.line ~= b.line then
123
- return a.line < b.line
124
- end
125
- return a.col <= b.col
126
- end
127
-
128
- local function sorted_positions(a, b)
129
- if compare_positions(a, b) then
130
- return a, b
131
- end
132
- return b, a
133
- end
134
-
135
- local function get_lines(buf, start_row, end_row)
136
- return vim.api.nvim_buf_get_lines(buf, start_row, end_row + 1, false)
137
- end
138
-
139
- local function text_from_range(buf, start_row, start_col, end_row, end_col)
140
- return table.concat(vim.api.nvim_buf_get_text(buf, start_row, start_col, end_row, end_col, {}), "\n")
141
- end
142
-
143
- local function range_from_bytes(buf, start_row, start_col, end_row, end_col)
144
- local lines = get_lines(buf, start_row, end_row)
145
- local start_line = lines[1] or ""
146
- local end_line = lines[#lines] or ""
147
- return {
148
- text = text_from_range(buf, start_row, start_col, end_row, end_col),
149
- selection = {
150
- start = { line = start_row, character = byte_to_utf16(start_line, start_col) },
151
- ["end"] = { line = end_row, character = byte_to_utf16(end_line, end_col) },
152
- },
153
- }
154
- end
155
-
156
- local function pos_from_getpos(pos)
157
- return { line = math.max(0, pos[2] - 1), col = math.max(0, pos[3] - 1), bufnr = pos[1] }
158
- end
159
-
160
- local function active_visual_range(buf, mode)
161
- local start_pos = pos_from_getpos(vim.fn.getpos("v"))
162
- local end_pos = pos_from_getpos(vim.fn.getpos("."))
163
- if start_pos.bufnr ~= 0 and start_pos.bufnr ~= buf then
164
- return {}
165
- end
166
- if end_pos.bufnr ~= 0 and end_pos.bufnr ~= buf then
167
- return {}
168
- end
169
-
170
- start_pos, end_pos = sorted_positions(start_pos, end_pos)
171
-
172
- if mode == "V" then
173
- local lines = get_lines(buf, start_pos.line, end_pos.line)
174
- return { range_from_bytes(buf, start_pos.line, 0, end_pos.line, #(lines[#lines] or "")) }
175
- end
176
-
177
- if mode == "\022" then
178
- local start_col = math.min(start_pos.col, end_pos.col)
179
- local end_col = math.max(start_pos.col, end_pos.col)
180
- local ranges = {}
181
- local lines = get_lines(buf, start_pos.line, end_pos.line)
182
- for offset, line in ipairs(lines) do
183
- local row = start_pos.line + offset - 1
184
- local col_start = math.min(start_col, #line)
185
- local col_end = byte_after_char(line, math.min(end_col, #line))
186
- if col_start < col_end then
187
- table.insert(ranges, range_from_bytes(buf, row, col_start, row, col_end))
188
- end
189
- end
190
- return ranges
191
- end
192
-
193
- local end_line = get_lines(buf, end_pos.line, end_pos.line)[1] or ""
194
- return { range_from_bytes(buf, start_pos.line, start_pos.col, end_pos.line, byte_after_char(end_line, end_pos.col)) }
195
- end
196
-
197
- local function marked_visual_range(buf)
198
- if not state.visual_mark_valid then
199
- return {}
200
- end
201
- local start_mark = vim.api.nvim_buf_get_mark(buf, "<")
202
- local end_mark = vim.api.nvim_buf_get_mark(buf, ">")
203
- if start_mark[1] == 0 or end_mark[1] == 0 then
204
- return {}
205
- end
206
- local start_pos = { line = start_mark[1] - 1, col = start_mark[2], bufnr = buf }
207
- local end_pos = { line = end_mark[1] - 1, col = end_mark[2], bufnr = buf }
208
- start_pos, end_pos = sorted_positions(start_pos, end_pos)
209
- local end_line = get_lines(buf, end_pos.line, end_pos.line)[1] or ""
210
- return { range_from_bytes(buf, start_pos.line, start_pos.col, end_pos.line, byte_after_char(end_line, end_pos.col)) }
211
- end
212
-
213
- function M.snapshot(opts)
214
- opts = opts or {}
215
- local buf = vim.api.nvim_get_current_buf()
216
- if vim.bo[buf].buftype ~= "" then
217
- return state.latest_snapshot
218
- end
219
-
220
- local file_path = vim.api.nvim_buf_get_name(buf)
221
- if file_path == "" then
222
- return nil
223
- end
224
- file_path = vim.fn.fnamemodify(file_path, ":p")
225
-
226
- local mode = vim.fn.mode()
227
- local ranges = {}
228
- if mode == "v" or mode == "V" or mode == "\022" then
229
- ranges = active_visual_range(buf, mode)
230
- elseif opts.prefer_marks then
231
- ranges = marked_visual_range(buf)
232
- end
233
-
234
- local snapshot = {
235
- source = "nvim",
236
- filePath = file_path,
237
- workspaceFolder = best_workspace(file_path),
238
- ranges = ranges,
239
- }
240
- state.latest_snapshot = snapshot
241
- return snapshot
242
- end
243
-
244
- local function relative_path(snapshot)
245
- local base = snapshot.workspaceFolder or vim.fn.getcwd()
246
- local rel = vim.fn.fnamemodify(snapshot.filePath, ":p")
247
- if vim.fs and vim.fs.relpath then
248
- local ok, value = pcall(vim.fs.relpath, base, snapshot.filePath)
249
- if ok and value and value ~= "" then
250
- return value
251
- end
252
- end
253
- local prefix = vim.fn.fnamemodify(base, ":p"):gsub("/$", "") .. "/"
254
- if rel:sub(1, #prefix) == prefix then
255
- return rel:sub(#prefix + 1)
256
- end
257
- return snapshot.filePath
258
- end
259
-
260
- local function line_span(range)
261
- local start_line = range.selection.start.line + 1
262
- local end_line = range.selection["end"].line + 1
263
- if start_line == end_line then
264
- return "#L" .. start_line
265
- end
266
- if state.config and state.config.range_format == "dash" then
267
- return "#L" .. start_line .. "-L" .. end_line
268
- end
269
- return "#L" .. start_line .. "," .. end_line
270
- end
271
-
272
- function M.format_range_mention(snapshot)
273
- local rel = relative_path(snapshot)
274
- if not snapshot.ranges or #snapshot.ranges == 0 then
275
- return "@" .. rel
276
- end
277
- return "@" .. rel .. line_span(snapshot.ranges[1])
278
- end
279
-
280
- local function publish_snapshot()
281
- if not state.job_id then
282
- return
283
- end
284
- local snapshot = M.snapshot()
285
- if not snapshot then
286
- send({ type = "selection_cleared", reason = "no-active-editor" })
287
- return
288
- end
289
- send({ type = "selection_changed", snapshot = snapshot })
290
- end
291
-
292
- local function schedule_publish(delay)
293
- delay = delay or (state.config and state.config.debounce_ms or defaults.debounce_ms)
294
- if state.timer then
295
- pcall(state.timer.stop, state.timer)
296
- pcall(state.timer.close, state.timer)
297
- end
298
- state.timer = vim.defer_fn(publish_snapshot, delay)
299
- end
300
-
301
- function M.start()
302
- if state.job_id then
303
- return true
304
- end
305
- state.config = state.config or normalize_config()
306
- local cmd = state.config.sidecar_cmd or default_sidecar_cmd()
307
- state.job_id = vim.fn.jobstart(cmd, {
308
- stdin = "pipe",
309
- detach = false,
310
- on_exit = function(_, code)
311
- state.job_id = nil
312
- if code ~= 0 then
313
- notify("sidecar exited with code " .. tostring(code), vim.log.levels.WARN)
314
- end
315
- end,
316
- on_stderr = function(_, data)
317
- for _, line in ipairs(data or {}) do
318
- if line ~= "" then
319
- vim.schedule(function()
320
- notify(line, vim.log.levels.WARN)
321
- end)
322
- end
323
- end
324
- end,
325
- })
326
-
327
- if state.job_id <= 0 then
328
- state.job_id = nil
329
- notify("failed to start sidecar", vim.log.levels.ERROR)
330
- return false
331
- end
332
-
333
- send({ workspaceFolders = workspace_folders(), name = "Neovim" })
334
- schedule_publish(0)
335
- return true
336
- end
337
-
338
- function M.stop()
339
- if state.timer then
340
- pcall(state.timer.stop, state.timer)
341
- pcall(state.timer.close, state.timer)
342
- state.timer = nil
343
- end
344
- if state.job_id then
345
- send({ type = "shutdown" })
346
- vim.fn.chanclose(state.job_id, "stdin")
347
- state.job_id = nil
348
- end
349
- end
350
-
351
- function M.attach()
352
- if not state.job_id and not M.start() then
353
- return
354
- end
355
- local snapshot = M.snapshot({ prefer_marks = true })
356
- if not snapshot then
357
- notify("no active file to attach", vim.log.levels.WARN)
358
- return
359
- end
360
- local range_text = M.format_range_mention(snapshot)
361
- send({ type = "at_mentioned", snapshot = vim.tbl_extend("force", snapshot, { rangeText = range_text }), rangeText = range_text })
362
- notify("attached " .. range_text)
363
- end
364
-
365
- function M.status()
366
- notify(state.job_id and "sidecar running" or "sidecar stopped")
367
- end
368
-
369
- local function setup_autocmds()
370
- if state.augroup then
371
- pcall(vim.api.nvim_del_augroup_by_id, state.augroup)
372
- end
373
- state.augroup = vim.api.nvim_create_augroup("PiXIde", { clear = true })
374
- vim.api.nvim_create_autocmd({ "BufEnter", "WinEnter", "CursorMoved", "CursorMovedI", "TextChanged", "TextChangedI", "DirChanged" }, {
375
- group = state.augroup,
376
- callback = function(event)
377
- if event.event == "DirChanged" then
378
- send({ type = "workspace_changed", workspaceFolders = workspace_folders() })
379
- end
380
- schedule_publish()
381
- end,
382
- })
383
- vim.api.nvim_create_autocmd("ModeChanged", {
384
- group = state.augroup,
385
- callback = function(event)
386
- if event.match and event.match:match("^[vV\022].*:n$") then
387
- state.visual_mark_valid = true
388
- end
389
- schedule_publish(0)
390
- end,
391
- })
392
- vim.api.nvim_create_autocmd("VimLeavePre", {
393
- group = state.augroup,
394
- callback = function()
395
- M.stop()
396
- end,
397
- })
398
- end
399
-
400
- local function setup_commands()
401
- local commands = {
402
- PiXIdeStart = M.start,
403
- PiXIdeStop = M.stop,
404
- PiXIdeStatus = M.status,
405
- PiXIdeAttach = M.attach,
406
- }
407
- for name, fn in pairs(commands) do
408
- pcall(vim.api.nvim_create_user_command, name, fn, {})
409
- end
410
- end
411
-
412
- local function setup_keymap()
413
- if not state.config.keymap then
414
- return
415
- end
416
- vim.keymap.set({ "n", "v" }, state.config.keymap, M.attach, { desc = "Pi x IDE: attach selection" })
417
- end
418
-
419
- function M.setup(opts)
420
- state.config = normalize_config(opts)
421
- setup_commands()
422
- setup_autocmds()
423
- setup_keymap()
424
- if state.config.enabled then
425
- M.start()
426
- end
427
- end
428
-
429
- function M._test_set_visual_mark_valid(value)
430
- state.visual_mark_valid = value
431
- end
432
-
433
- function M._test_reset()
434
- M.stop()
435
- state.config = normalize_config({ enabled = false })
436
- state.latest_snapshot = nil
437
- state.visual_mark_valid = false
438
- end
439
-
440
- setup_commands()
441
-
442
- return M
@@ -1,15 +0,0 @@
1
- if vim.g.loaded_pi_x_ide == 1 then
2
- return
3
- end
4
- vim.g.loaded_pi_x_ide = 1
5
-
6
- local function command(name, fn)
7
- pcall(vim.api.nvim_create_user_command, name, function()
8
- require("pi_x_ide")[fn]()
9
- end, {})
10
- end
11
-
12
- command("PiXIdeStart", "start")
13
- command("PiXIdeStop", "stop")
14
- command("PiXIdeStatus", "status")
15
- command("PiXIdeAttach", "attach")