@saifymatteo/pi-x-ide 0.0.0-stage → 1.20.2
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/CHANGELOG.md +328 -0
- package/CONTRIBUTING.md +119 -0
- package/CONTRIBUTING.zh-CN.md +106 -0
- package/LICENSE +201 -0
- package/README.md +33 -2
- package/README.zh-CN.md +34 -0
- package/RELEASE.md +213 -0
- package/config.example.json +9 -0
- package/dist/src/pi/chunks/chunk-4RHJAL4S.js +200 -0
- package/dist/src/pi/chunks/chunk-UUXVCTOS.js +819 -0
- package/dist/src/pi/chunks/config-ui-LO3DVQFC.js +8073 -0
- package/dist/src/pi/chunks/runtime-services-BVQBAAWT.js +19569 -0
- package/dist/src/pi/commands.js +126 -0
- package/dist/src/pi/config-ui.js +127 -0
- package/dist/src/pi/connection.js +237 -0
- package/dist/src/pi/context.js +30 -0
- package/dist/src/pi/diagnostic-renderer.js +326 -0
- package/dist/src/pi/diagnostic-types.js +1 -0
- package/dist/src/pi/diagnostics.js +104 -0
- package/dist/src/pi/discovery.js +135 -0
- package/dist/src/pi/effect-boundary.js +5 -0
- package/dist/src/pi/ide-host.js +68 -0
- package/dist/src/pi/index.js +636 -0
- package/dist/src/pi/install.js +308 -0
- package/dist/src/pi/reconnect.js +57 -0
- package/dist/src/pi/runtime-loader.js +38 -0
- package/dist/src/pi/runtime-services.js +356 -0
- package/dist/src/pi/safety.js +61 -0
- package/dist/src/pi/selection.js +18 -0
- package/dist/src/pi/state.js +13 -0
- package/dist/src/pi/ui.js +304 -0
- package/dist/src/pi/zed.js +409 -0
- package/dist/src/shared/config-options.js +45 -0
- package/dist/src/shared/config.js +183 -0
- package/dist/src/shared/display-width.js +99 -0
- package/dist/src/shared/effect-errors.js +36 -0
- package/dist/src/shared/effect-runtime.js +36 -0
- package/dist/src/shared/effect-schema.js +120 -0
- package/dist/src/shared/errors.js +48 -0
- package/dist/src/shared/format.js +92 -0
- package/dist/src/shared/ide-server.js +167 -0
- package/dist/src/shared/jsonrpc-guard.js +12 -0
- package/dist/src/shared/lock-file-heartbeat.js +58 -0
- package/dist/src/shared/lock-file.js +50 -0
- package/dist/src/shared/paths.js +79 -0
- package/dist/src/shared/platform.js +57 -0
- package/dist/src/shared/protocol.js +3 -0
- package/dist/src/shared/schema.js +37 -0
- package/dist/src/shared/version.js +1 -0
- package/dist/src/shared/ws.js +8 -0
- package/docs/explanation/architecture.md +123 -0
- package/docs/explanation/discovery.md +113 -0
- package/docs/explanation/effect.md +127 -0
- package/docs/how-to/install-jetbrains.md +58 -0
- package/docs/how-to/install-neovim.md +138 -0
- package/docs/how-to/install-vscode.md +75 -0
- package/docs/how-to/install-zed.md +70 -0
- package/docs/how-to/troubleshoot-connection.md +103 -0
- package/docs/how-to/use-wsl2.md +90 -0
- package/docs/reference/commands.md +59 -0
- package/docs/reference/configuration.md +101 -0
- package/docs/reference/feature-parity.md +26 -0
- package/docs/reference/protocol.md +71 -0
- package/docs/specs/ide-protocol.md +215 -0
- package/docs/tutorials/get-started.md +133 -0
- package/docs/zh-CN/explanation/architecture.md +93 -0
- package/docs/zh-CN/explanation/discovery.md +71 -0
- package/docs/zh-CN/explanation/effect.md +90 -0
- package/docs/zh-CN/how-to/install-jetbrains.md +49 -0
- package/docs/zh-CN/how-to/install-neovim.md +126 -0
- package/docs/zh-CN/how-to/install-vscode.md +67 -0
- package/docs/zh-CN/how-to/install-zed.md +56 -0
- package/docs/zh-CN/how-to/troubleshoot-connection.md +85 -0
- package/docs/zh-CN/how-to/use-wsl2.md +75 -0
- package/docs/zh-CN/reference/commands.md +54 -0
- package/docs/zh-CN/reference/configuration.md +94 -0
- package/docs/zh-CN/reference/feature-parity.md +21 -0
- package/docs/zh-CN/reference/protocol.md +54 -0
- package/docs/zh-CN/tutorials/get-started.md +101 -0
- package/package.json +86 -4
- package/schemas/config.json +77 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Protocol reference
|
|
2
|
+
|
|
3
|
+
Pi × IDE connects Pi to an IDE through a local WebSocket discovered by lock files.
|
|
4
|
+
This page is a quick reference; for exact field semantics, message shapes, and the
|
|
5
|
+
full specification, see [`docs/specs/ide-protocol.md`](../specs/ide-protocol.md).
|
|
6
|
+
|
|
7
|
+
## Lock files
|
|
8
|
+
|
|
9
|
+
- **Directory:** `~/.pi/pi-x-ide/lock/` (mode `0700`)
|
|
10
|
+
- **Naming:** `<ide>-<pid>-<port>.lock` - for example `vscode-12345-48123.lock`,
|
|
11
|
+
`nvim-98765-50001.lock`, `jetbrains-4242-51234.lock`
|
|
12
|
+
- **Permissions:** files are mode `0600`, written atomically (temp file + rename)
|
|
13
|
+
|
|
14
|
+
A lock file advertises the WebSocket endpoint, an auth token, workspace folders,
|
|
15
|
+
and timestamps.
|
|
16
|
+
|
|
17
|
+
## Transport
|
|
18
|
+
|
|
19
|
+
- **Protocol:** WebSocket (`ws://host:port`)
|
|
20
|
+
- **Wire format:** JSON-RPC 2.0
|
|
21
|
+
|
|
22
|
+
## Authentication
|
|
23
|
+
|
|
24
|
+
Pi connects with the header:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
x-pi-x-ide-authorization: <authToken>
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The token is a 64-character hex string (`randomBytes(32)`) generated per IDE
|
|
31
|
+
session and written to the lock file. The server rejects connections with missing
|
|
32
|
+
or invalid tokens.
|
|
33
|
+
|
|
34
|
+
## Handshake
|
|
35
|
+
|
|
36
|
+
Pi sends an `initialize` request with its `cwd`; the IDE responds with server info
|
|
37
|
+
and immediately sends an initial `selection_changed` or `selection_cleared`
|
|
38
|
+
notification.
|
|
39
|
+
|
|
40
|
+
## Notifications
|
|
41
|
+
|
|
42
|
+
| Method | Sent when |
|
|
43
|
+
| -------------------------- | -------------------------------------------------------------------- |
|
|
44
|
+
| `selection_changed` | The active editor or selection changes. |
|
|
45
|
+
| `selection_cleared` | There is no active local text editor (JetBrains). |
|
|
46
|
+
| `at_mentioned` | The user invokes an IDE attach-selection command. |
|
|
47
|
+
| `diagnostic_fix_requested` | The user picks a Pi Quick Fix on a diagnostic (VS Code-family only). |
|
|
48
|
+
|
|
49
|
+
Line and character offsets are zero-based, matching VS Code/LSP. Neovim converts
|
|
50
|
+
byte columns to UTF-16 character offsets; JetBrains derives character offsets from
|
|
51
|
+
UTF-16 code-unit counts.
|
|
52
|
+
|
|
53
|
+
## TUI behavior
|
|
54
|
+
|
|
55
|
+
When connected, Pi shows IDE connection status in one place, selected by
|
|
56
|
+
`status_display` (project config overrides global; set via `/ide settings`):
|
|
57
|
+
|
|
58
|
+
- `widget` (default): an above-editor widget via `ctx.ui.setWidget("pi-x-ide", ...)`.
|
|
59
|
+
- `statusline`: the default footer status line via `ctx.ui.setStatus("pi-x-ide", ...)`.
|
|
60
|
+
|
|
61
|
+
Both placements show the compact connection/selection state (IDE icon, spinner or
|
|
62
|
+
status mark, file, range, and `pending` / `sent` attach state). Selected text
|
|
63
|
+
content is intentionally omitted. See
|
|
64
|
+
[Configuration](configuration.md#top-level-options).
|
|
65
|
+
|
|
66
|
+
## Full specification
|
|
67
|
+
|
|
68
|
+
See [`docs/specs/ide-protocol.md`](../specs/ide-protocol.md) for the complete
|
|
69
|
+
lock file schema, the WSL2 discovery and host-resolution rules, and the exact
|
|
70
|
+
JSON for every notification. For the design rationale behind the per-editor
|
|
71
|
+
transports, see [Architecture](../explanation/architecture.md).
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Pi x IDE Protocol
|
|
2
|
+
|
|
3
|
+
Pi x IDE connects Pi to an IDE through a local WebSocket discovered by lock files.
|
|
4
|
+
|
|
5
|
+
## Lock files
|
|
6
|
+
|
|
7
|
+
Directory: `~/.pi/pi-x-ide/lock`.
|
|
8
|
+
|
|
9
|
+
Example file: `vscode-12345-48123.lock`
|
|
10
|
+
|
|
11
|
+
Neovim uses the same protocol version and writes files named `nvim-<pid>-<port>.lock`. JetBrains IDEs use the same protocol version and write files named `jetbrains-<pid>-<port>.lock`.
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"version": 1,
|
|
16
|
+
"ide": "vscode",
|
|
17
|
+
"name": "Visual Studio Code",
|
|
18
|
+
"transport": "ws",
|
|
19
|
+
"host": "127.0.0.1",
|
|
20
|
+
"port": 48123,
|
|
21
|
+
"authToken": "random-hex-token",
|
|
22
|
+
"workspaceFolders": ["/home/user/project"],
|
|
23
|
+
"pid": 12345,
|
|
24
|
+
"runningInWindows": false,
|
|
25
|
+
"createdAt": "2026-06-09T00:00:00.000Z",
|
|
26
|
+
"updatedAt": "2026-06-09T00:00:00.000Z"
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Rules:
|
|
31
|
+
|
|
32
|
+
- Lock directory should be mode `0700`.
|
|
33
|
+
- Lock files should be mode `0600`.
|
|
34
|
+
- Writers should write a temp file and rename it into place.
|
|
35
|
+
- `host` remains required for compatibility, but Pi may resolve a different connection host before opening the WebSocket.
|
|
36
|
+
- `runningInWindows` is optional and backward-compatible. When present and `true`, it declares that the IDE server process is running on native Windows.
|
|
37
|
+
- A consumer must not remove a lock only because of age after it proves the producer is live.
|
|
38
|
+
- A usable local PID is a positive safe integer. When PID checking is enabled, keep a lock with a live usable PID at any age, and remove a lock with a dead usable PID at any age.
|
|
39
|
+
- If the PID is missing or unusable, or if PID checking is disabled, use age-only cleanup.
|
|
40
|
+
- When Pi runs in WSL and a lock has `runningInWindows: true`, TCP reachability is authoritative while PID checking is enabled. Keep the lock if the host and port are reachable. Remove the lock if the probe fails or throws.
|
|
41
|
+
- Malformed lock files remain removable.
|
|
42
|
+
- Repository lock producers for VS Code, Neovim, and JetBrains refresh owned locks every 15 minutes while active. Refresh preserves endpoint identity and the auth token, updates freshness data, and can recreate an externally deleted owned lock.
|
|
43
|
+
- TypeScript producers drain every accepted refresh before they remove the lock. JetBrains stops its EDT timer synchronously before cleanup.
|
|
44
|
+
|
|
45
|
+
## WSL2 discovery and host resolution
|
|
46
|
+
|
|
47
|
+
The primary lock directory is always `~/.pi/pi-x-ide/lock`. When Pi runs inside WSL, it also scans Windows user lock directories such as `/mnt/c/Users/<user>/.pi/pi-x-ide/lock`, skipping Windows system profiles.
|
|
48
|
+
|
|
49
|
+
For connection hosts, Pi resolves in this order:
|
|
50
|
+
|
|
51
|
+
1. `PI_X_IDE_HOST_OVERRIDE`, either from the real environment or `~/.pi/pi-x-ide/config.json` `env`.
|
|
52
|
+
2. If Pi runs in WSL and the lock has `runningInWindows: true`, parse the WSL default gateway from `ip route show` and use it only if a short TCP probe to `<gateway>:<port>` succeeds.
|
|
53
|
+
3. The lock file `host` value.
|
|
54
|
+
4. `127.0.0.1` if `host` is empty.
|
|
55
|
+
|
|
56
|
+
Incoming editor paths are normalized to the Pi host before workspace matching, UI display, `@file#Lx-Ly` mention formatting, and prompt context formatting. Matching WSL UNC paths such as `\\wsl.localhost\Ubuntu\home\user\project` become `/home/user/project` when Pi is running in the `Ubuntu` distro.
|
|
57
|
+
|
|
58
|
+
## Authentication
|
|
59
|
+
|
|
60
|
+
Pi connects to `ws://host:port` with the header:
|
|
61
|
+
|
|
62
|
+
```text
|
|
63
|
+
x-pi-x-ide-authorization: <authToken>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
The IDE server rejects connections with missing or invalid tokens.
|
|
67
|
+
|
|
68
|
+
## Handshake
|
|
69
|
+
|
|
70
|
+
Pi sends:
|
|
71
|
+
|
|
72
|
+
```json
|
|
73
|
+
{
|
|
74
|
+
"jsonrpc": "2.0",
|
|
75
|
+
"id": 1,
|
|
76
|
+
"method": "initialize",
|
|
77
|
+
"params": {
|
|
78
|
+
"protocolVersion": 1,
|
|
79
|
+
"client": { "name": "pi-x-ide", "version": "0.1.0" },
|
|
80
|
+
"cwd": "/home/user/project"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
IDE responds:
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{
|
|
89
|
+
"jsonrpc": "2.0",
|
|
90
|
+
"id": 1,
|
|
91
|
+
"result": {
|
|
92
|
+
"protocolVersion": 1,
|
|
93
|
+
"server": {
|
|
94
|
+
"name": "Pi x IDE VS Code",
|
|
95
|
+
"version": "0.1.0",
|
|
96
|
+
"ide": "vscode"
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Notifications
|
|
103
|
+
|
|
104
|
+
### `selection_changed`
|
|
105
|
+
|
|
106
|
+
Sent whenever the active editor or selection changes.
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"jsonrpc": "2.0",
|
|
111
|
+
"method": "selection_changed",
|
|
112
|
+
"params": {
|
|
113
|
+
"source": "vscode",
|
|
114
|
+
"filePath": "/home/user/project/src/main.ts",
|
|
115
|
+
"workspaceFolder": "/home/user/project",
|
|
116
|
+
"ranges": [
|
|
117
|
+
{
|
|
118
|
+
"text": "const x = 1;",
|
|
119
|
+
"selection": {
|
|
120
|
+
"start": { "line": 9, "character": 0 },
|
|
121
|
+
"end": { "line": 9, "character": 12 }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
"receivedAt": 1780963200000
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`source` is one of `vscode`, `zed`, `nvim`, `jetbrains`, or `unknown`. `line` and `character` are zero-based, matching VS Code/LSP. Neovim converts byte columns to UTF-16 character offsets before sending snapshots. JetBrains derives `character` from document offsets and line-start offsets, which are UTF-16 code-unit counts.
|
|
131
|
+
|
|
132
|
+
JetBrains sends `selection_changed` both for non-empty selections and for an active local file with no selected text (`ranges: []`). It sends `selection_cleared` when there is no active local text editor.
|
|
133
|
+
|
|
134
|
+
### `at_mentioned`
|
|
135
|
+
|
|
136
|
+
Sent when the user invokes an IDE attach-selection command, such as VS Code's command, Neovim's `:PiXIdeAttach`, or the JetBrains **Pi x IDE: Attach Selection** action.
|
|
137
|
+
|
|
138
|
+
```json
|
|
139
|
+
{
|
|
140
|
+
"jsonrpc": "2.0",
|
|
141
|
+
"method": "at_mentioned",
|
|
142
|
+
"params": {
|
|
143
|
+
"source": "vscode",
|
|
144
|
+
"filePath": "/home/user/project/src/main.ts",
|
|
145
|
+
"workspaceFolder": "/home/user/project",
|
|
146
|
+
"rangeText": "@src/main.ts#L10-L20",
|
|
147
|
+
"ranges": [
|
|
148
|
+
{
|
|
149
|
+
"text": "selected text",
|
|
150
|
+
"selection": {
|
|
151
|
+
"start": { "line": 9, "character": 0 },
|
|
152
|
+
"end": { "line": 19, "character": 3 }
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
]
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Pi inserts `rangeText` into the TUI editor and caches the corresponding selection text for context injection. JetBrains sends selection and attach notifications in the MVP; it does not send diagnostic Quick Fix notifications.
|
|
161
|
+
|
|
162
|
+
### `diagnostic_fix_requested`
|
|
163
|
+
|
|
164
|
+
Sent by the VS Code-family extension when the user selects **Pi: Fix it** or **Pi: Send diagnostic** from Quick Fix on an error or warning diagnostic. This notification is additive under protocol version `1`; clients that do not understand it may ignore it.
|
|
165
|
+
|
|
166
|
+
```json
|
|
167
|
+
{
|
|
168
|
+
"jsonrpc": "2.0",
|
|
169
|
+
"method": "diagnostic_fix_requested",
|
|
170
|
+
"params": {
|
|
171
|
+
"action": "fix",
|
|
172
|
+
"source": "vscode",
|
|
173
|
+
"filePath": "/home/user/project/src/main.ts",
|
|
174
|
+
"workspaceFolder": "/home/user/project",
|
|
175
|
+
"documentVersion": 7,
|
|
176
|
+
"triggerRange": {
|
|
177
|
+
"start": { "line": 9, "character": 4 },
|
|
178
|
+
"end": { "line": 9, "character": 10 }
|
|
179
|
+
},
|
|
180
|
+
"diagnostics": [
|
|
181
|
+
{
|
|
182
|
+
"severity": "error",
|
|
183
|
+
"message": "Type 'string' is not assignable to type 'number'.",
|
|
184
|
+
"source": "ts",
|
|
185
|
+
"code": 2322,
|
|
186
|
+
"range": {
|
|
187
|
+
"start": { "line": 9, "character": 4 },
|
|
188
|
+
"end": { "line": 9, "character": 10 }
|
|
189
|
+
},
|
|
190
|
+
"selectedText": "value",
|
|
191
|
+
"contextLines": [
|
|
192
|
+
{ "line": 8, "text": "const value = getValue();", "isPrimary": false },
|
|
193
|
+
{ "line": 9, "text": "const count: number = value;", "isPrimary": true },
|
|
194
|
+
{ "line": 10, "text": "console.log(count);", "isPrimary": false }
|
|
195
|
+
]
|
|
196
|
+
}
|
|
197
|
+
],
|
|
198
|
+
"receivedAt": 1780963200000
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
When `action` is `"fix"` or omitted, Pi formats the diagnostics into a prompt and sends it as a user message. If the agent is busy, Pi queues the diagnostic prompt as a follow-up. When `action` is `"send-diagnostic"`, Pi formats only the diagnostic context and pastes it into the TUI input box without starting an agent turn.
|
|
204
|
+
|
|
205
|
+
## TUI behavior
|
|
206
|
+
|
|
207
|
+
When connected, Pi displays IDE connection status in one place, selected by
|
|
208
|
+
`status_display` (project config overrides global; set via `/ide settings`):
|
|
209
|
+
|
|
210
|
+
- `widget` (default): above-editor widget via `ctx.ui.setWidget("pi-x-ide", ...)`.
|
|
211
|
+
- `statusline`: default footer status line via `ctx.ui.setStatus("pi-x-ide", ...)`.
|
|
212
|
+
|
|
213
|
+
Both placements show the compact connection/selection state (IDE icon, spinner or
|
|
214
|
+
status mark, file, range, and `pending` / `sent` attach state). Selected text
|
|
215
|
+
content is intentionally omitted.
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Get started with Pi × IDE
|
|
2
|
+
|
|
3
|
+
This tutorial walks you from a fresh install to your first IDE selection flowing
|
|
4
|
+
into an LLM conversation in Pi. It takes about five minutes and uses VS Code as
|
|
5
|
+
the vehicle — the same flow works for Cursor and Windsurf.
|
|
6
|
+
|
|
7
|
+
> Already set up and just want to attach a selection? Jump to
|
|
8
|
+
> [Attach the selection](#step-5-attach-the-selection-and-chat).
|
|
9
|
+
> Using a different editor? See the [How-to guides](../how-to/) for Zed, Neovim,
|
|
10
|
+
> and JetBrains.
|
|
11
|
+
|
|
12
|
+
## What you will learn
|
|
13
|
+
|
|
14
|
+
- How to install the Pi extension package and the VS Code extension.
|
|
15
|
+
- How to start Pi so it discovers your IDE automatically.
|
|
16
|
+
- How a text selection becomes LLM context.
|
|
17
|
+
|
|
18
|
+
## Before you begin
|
|
19
|
+
|
|
20
|
+
You need:
|
|
21
|
+
|
|
22
|
+
- The [`pi`](https://github.com/earendil-works/pi-coding-agent) CLI installed and
|
|
23
|
+
on your `PATH`.
|
|
24
|
+
- VS Code, Cursor, or Windsurf installed.
|
|
25
|
+
- A project folder with at least one source file you can open.
|
|
26
|
+
|
|
27
|
+
## Step 1: Install the Pi extension package
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pi install npm:pi-x-ide
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This adds the `pi-x-ide` package to Pi. It is loaded automatically the next time
|
|
34
|
+
Pi starts — no extra wiring required.
|
|
35
|
+
|
|
36
|
+
## Step 2: Install the VS Code extension
|
|
37
|
+
|
|
38
|
+
Open your IDE's **Extensions** panel and search for
|
|
39
|
+
[`balaenis.pi-x-ide`](https://marketplace.visualstudio.com/items?itemName=balaenis.pi-x-ide),
|
|
40
|
+
then install it.
|
|
41
|
+
|
|
42
|
+
> Alternatively, run `/ide install` inside Pi's TUI — it auto-detects `code`,
|
|
43
|
+
> `cursor`, or `windsurf` and installs the extension for you. On startup, Pi also
|
|
44
|
+
> tries to auto-install the extension when it detects a supported VS Code
|
|
45
|
+
> integrated terminal.
|
|
46
|
+
|
|
47
|
+
Reload the IDE window after installing so the extension activates.
|
|
48
|
+
|
|
49
|
+
## Step 3: Start Pi in your project
|
|
50
|
+
|
|
51
|
+
Open a terminal **inside your IDE** (Terminal → New Terminal), then start Pi from
|
|
52
|
+
the same project directory your IDE workspace is using:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pi
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Pi loads `pi-x-ide` and looks for an IDE connection. When your terminal's working
|
|
59
|
+
directory is inside one of the IDE's workspace folders, Pi connects automatically.
|
|
60
|
+
A widget appears above the Pi input box showing the connection and selection
|
|
61
|
+
state.
|
|
62
|
+
|
|
63
|
+
## Step 4: Open a file and select some text
|
|
64
|
+
|
|
65
|
+
Back in your IDE, open a source file and select a few lines. The Pi widget should
|
|
66
|
+
update in real time:
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
⧉ ⇡ foo.ts#L10-L20
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The `⇡` marker means a selection is **pending** — Pi has noticed it but has not
|
|
73
|
+
attached it to a message yet.
|
|
74
|
+
|
|
75
|
+
If the widget does not appear, see
|
|
76
|
+
[Troubleshoot a missing connection](../how-to/troubleshoot-connection.md).
|
|
77
|
+
|
|
78
|
+
## Step 5: Attach the selection and chat
|
|
79
|
+
|
|
80
|
+
With text selected in your IDE, focus the Pi TUI and press `Ctrl+Alt+K`
|
|
81
|
+
(macOS: `Ctrl+Option+K`). Pi inserts a mention into the input box:
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
@src/foo.ts#L10-L20
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Now type a question and submit it. The selected text is injected into the LLM
|
|
88
|
+
context for that turn. After submission, the widget marker changes to `✓`:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
⧉ ✓ foo.ts#L10-L20
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The transcript keeps your prompt and IDE context separate. Pi displays the IDE
|
|
95
|
+
metadata as a purple custom message and sends that same metadata to the agent:
|
|
96
|
+
|
|
97
|
+
```text
|
|
98
|
+
Your prompt
|
|
99
|
+
### IDE Context
|
|
100
|
+
- **IDE**: vscode
|
|
101
|
+
- **File**: `src/foo.ts`
|
|
102
|
+
- **Selection**: L10-L20
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Only IDE, file, and selection-range metadata are attached—not selected source
|
|
106
|
+
contents. This lets the agent inspect the file itself when it needs more context.
|
|
107
|
+
For an open file with no selection, the `Selection` line is omitted. The user's
|
|
108
|
+
blue prompt remains unchanged.
|
|
109
|
+
|
|
110
|
+
You can press `Ctrl+Alt+K` repeatedly to append several ranges to the same
|
|
111
|
+
message, or select new text between turns to attach fresh context each time.
|
|
112
|
+
|
|
113
|
+
## What just happened
|
|
114
|
+
|
|
115
|
+
When you select text, the IDE broadcasts a `selection_changed` notification
|
|
116
|
+
over a local WebSocket to Pi. Pi caches the latest selection and marks it
|
|
117
|
+
pending. When you press the attach shortcut, Pi inserts the `@file#Lx-Ly` mention
|
|
118
|
+
into your input. When you submit the message, Pi adds the IDE name, file path,
|
|
119
|
+
and selected line range as a separate purple custom message. The selected source
|
|
120
|
+
text is not sent automatically.
|
|
121
|
+
|
|
122
|
+
For the full mechanism — lock files, host resolution, the Neovim sidecar, and why
|
|
123
|
+
Zed is polled differently — read [How discovery works](../explanation/discovery.md)
|
|
124
|
+
and [Architecture](../explanation/architecture.md).
|
|
125
|
+
|
|
126
|
+
## Where to go next
|
|
127
|
+
|
|
128
|
+
- [Install another editor](../how-to/) — Zed, Neovim, or JetBrains.
|
|
129
|
+
- [Use Pi × IDE over WSL2](../how-to/use-wsl2.md) — Pi in WSL, IDE on Windows.
|
|
130
|
+
- [Configuration reference](../reference/configuration.md) — env vars, keymaps,
|
|
131
|
+
`fixPrompt`, and `status_display`.
|
|
132
|
+
- [`/ide` command reference](../reference/commands.md) — manage connections from
|
|
133
|
+
the TUI.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# 架构
|
|
2
|
+
|
|
3
|
+
Pi × IDE 在两个通常互不感知的进程之间搭桥:你的 IDE 和 Pi TUI。本页解释各组件、数据流,以及为什么不同编辑器的连接方式不同。这是面向理解的文档 - 确切的消息结构和字段语义见 [协议规范](../../specs/ide-protocol.md)。
|
|
4
|
+
|
|
5
|
+
## 三个角色
|
|
6
|
+
|
|
7
|
+
| 角色 | 谁 | 职责 |
|
|
8
|
+
| ------------- | ------------------------------------------------------- | ------------------------------------------------------------------ |
|
|
9
|
+
| **IDE 插件** | VS Code 扩展、JetBrains 插件、Neovim Lua 插件 + sidecar | 观察活跃编辑器和选区,通过本地 WebSocket 暴露它们。 |
|
|
10
|
+
| **Lock file** | IDE 插件写入,Pi 读取 | 广播 WebSocket 端点(host、port、auth token)和 workspace 文件夹。 |
|
|
11
|
+
| **Pi 扩展** | 加载到 Pi TUI 的 `pi-x-ide` | 发现 lock file、建立连接、接收选区、注入为 LLM 上下文。 |
|
|
12
|
+
|
|
13
|
+
Zed 是例外:它没有插件,Pi 直接读取 Zed 的本地状态数据库。见 [为什么不同编辑器连接方式不同](#为什么不同编辑器连接方式不同)。
|
|
14
|
+
|
|
15
|
+
## 数据流
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
用户在 IDE 中选中文本
|
|
19
|
+
│
|
|
20
|
+
▼
|
|
21
|
+
┌──────────────────────────────────────────────────────────┐
|
|
22
|
+
│ IDE 插件(VS Code / JetBrains / Neovim sidecar) │
|
|
23
|
+
│ │
|
|
24
|
+
│ 捕获编辑器 + 选区,广播一条 │
|
|
25
|
+
│ JSON-RPC "selection_changed" 通知。 │
|
|
26
|
+
└──────────────────────┬───────────────────────────────────┘
|
|
27
|
+
│ WebSocket ws://127.0.0.1:<port>
|
|
28
|
+
│ 认证:x-pi-x-ide-authorization 头
|
|
29
|
+
▼
|
|
30
|
+
┌──────────────────────────────────────────────────────────┐
|
|
31
|
+
│ Pi 扩展 (src/pi/connection.ts) │
|
|
32
|
+
│ │
|
|
33
|
+
│ 接收通知,缓存为 runtime.latestSelection, │
|
|
34
|
+
│ 置 attachState = "pending",更新 TUI widget(⇡ 标记)。 │
|
|
35
|
+
└──────────────────────┬───────────────────────────────────┘
|
|
36
|
+
│ 下一条用户消息时
|
|
37
|
+
▼
|
|
38
|
+
┌──────────────────────────────────────────────────────────┐
|
|
39
|
+
│ Pi prompt 生命周期 (src/pi/context.ts) │
|
|
40
|
+
│ │
|
|
41
|
+
│ before_agent_start:快照 pending 的选区。 │
|
|
42
|
+
│ 添加一条可见的自定义消息,仅包含 IDE、文件和选区行范围。│
|
|
43
|
+
│ 用户 prompt 保持不变;代理可按需自行读取源文件。 │
|
|
44
|
+
│ attachState = "sent"。 │
|
|
45
|
+
└──────────────────────────────────────────────────────────┘
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
附加快捷键(TUI 中的 `Ctrl+Alt+K`,或 IDE 的 attach 命令)发送的是 `at_mentioned` 通知。它把 `@file#Lx-Ly` mention 插入 Pi 输入框,并缓存选中文本,为下一轮做好准备。
|
|
49
|
+
|
|
50
|
+
## 为什么不同编辑器连接方式不同
|
|
51
|
+
|
|
52
|
+
每个 IDE 的扩展 API 决定了传输方式。
|
|
53
|
+
|
|
54
|
+
| 编辑器 | 机制 | 原因 |
|
|
55
|
+
| ------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
56
|
+
| **VS Code** | 扩展宿主内的 WebSocket 服务器 | 扩展 API 丰富:`onDidChangeTextEditorSelection`、文件系统访问、终端创建。轻量服务器在进程内运行,无需独立进程。 |
|
|
57
|
+
| **JetBrains** | IDE 进程内的 WebSocket 服务器 | 同理:`com.intellij` API 提供编辑器监听和 project service 生命周期。Kotlin 插件在进程内运行服务器。 |
|
|
58
|
+
| **Neovim** | 独立的 **sidecar** 进程 | Lua 无法原生运行 WebSocket 服务器。sidecar 是独立进程,通过 stdin/stdout(JSON lines)与 Neovim 通信,并向 Pi 暴露 WebSocket。 |
|
|
59
|
+
| **Zed** | **Pi 侧 SQLite 轮询** | Zed 没有扩展 API,把编辑器状态存在本地 SQLite 数据库中,Pi 每秒直接读取。轮询在 Pi 侧进行,不在 Zed 侧。 |
|
|
60
|
+
|
|
61
|
+
### Neovim sidecar
|
|
62
|
+
|
|
63
|
+
由于 Neovim 无法承载 WebSocket 服务器,Lua 插件会 spawn 一个 sidecar 进程(`src/nvim/sidecar.ts`),由它持有服务器和 lock file。插件通过 Neovim autocmd(`CursorMoved`、`BufEnter`、visual 模式 mark)捕获选区,去抖后把 JSON 消息写入 sidecar 的 stdin。sidecar 再以 JSON-RPC 通知广播给 Pi。
|
|
64
|
+
|
|
65
|
+
sidecar 的解析顺序(`ide-plugins/nvim/lua/pi_x_ide/download.lua`):
|
|
66
|
+
|
|
67
|
+
1. `ide-plugins/nvim/bin/` 中的平台二进制。
|
|
68
|
+
2. 从 GitHub Releases 下载并缓存、经 SHA256 校验的二进制。
|
|
69
|
+
3. 回退到 Node.js 脚本(`pi-x-ide-nvim-sidecar.cjs`)。
|
|
70
|
+
|
|
71
|
+
这就是 Neovim 插件首次启动"开箱即用"的原因:它为你的平台下载合适的二进制,下载失败时回退到 Node。
|
|
72
|
+
|
|
73
|
+
### Zed 轮询
|
|
74
|
+
|
|
75
|
+
Pi 直接读取 Zed 的状态数据库(`src/pi/zed.ts`)。每次轮询(默认 1000 ms,可通过 `PI_X_IDE_ZED_POLL_INTERVAL_MS` 限制在 100–2000 ms):
|
|
76
|
+
|
|
77
|
+
1. 检查 SQLite WAL 文件的 mtime - 未变化则跳过昂贵的读取(在 WSL 下尤为重要,否则每次都要拷贝完整快照)。
|
|
78
|
+
2. 通过 join Zed 的 `items`、`panes`、`workspaces`、`editors` 表查询活跃编辑器。
|
|
79
|
+
3. 按 workspace 匹配度打分,选出最佳。
|
|
80
|
+
4. 把 UTF-8 字节偏移转换为 VS Code/LSP 风格的 line/character 位置。
|
|
81
|
+
|
|
82
|
+
## 认证模型
|
|
83
|
+
|
|
84
|
+
每个 IDE 进程每次会话用 `randomBytes(32).toString("hex")` 生成新 token - 64 字符的十六进制串(`src/shared/lock-file.ts`)。JetBrains 用 `SecureRandom` 生成等价 token。token 写入 lock file(mode `0600`),仅在 WebSocket 升级握手时通过 `x-pi-x-ide-authorization` 头发送。服务器的 `verifyClient` 回调会拒绝头不匹配的连接(`src/shared/ide-server.ts`)。
|
|
85
|
+
|
|
86
|
+
token 除了跨越 WSL 边界外不会离开 localhost - 此时 WebSocket 仍指向解析出的 Windows host。
|
|
87
|
+
|
|
88
|
+
## 相关
|
|
89
|
+
|
|
90
|
+
- [发现机制](discovery.md) - Pi 如何找到 lock file 并选择连接。
|
|
91
|
+
- [Effect 采用说明](effect.md) - Pi 侧 TypeScript 如何在内部用 Effect 处理错误、Schema 校验与 IO 边界。
|
|
92
|
+
- [协议规范](../../specs/ide-protocol.md) - 确切的消息结构、握手和通知。
|
|
93
|
+
- [功能对比](../reference/feature-parity.md) - 各编辑器支持的能力。
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# 发现机制
|
|
2
|
+
|
|
3
|
+
Pi 通过 **lock file** 发现 IDE 连接:每个运行中的 IDE 插件写入的小型 JSON 文件,用来广播自己的 WebSocket 端点。本页解释它们的位置、Pi 如何选择正确的连接,以及如何跨越 WSL 边界。确切的文件 schema 见 [协议规范](../../specs/ide-protocol.md)。
|
|
4
|
+
|
|
5
|
+
## lock 目录
|
|
6
|
+
|
|
7
|
+
主 lock 目录始终是:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
~/.pi/pi-x-ide/lock/
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
每个文件命名为 `<ide>-<pid>-<port>.lock`,例如:
|
|
14
|
+
|
|
15
|
+
- `vscode-12345-48123.lock`
|
|
16
|
+
- `nvim-98765-50001.lock`
|
|
17
|
+
- `jetbrains-4242-51234.lock`
|
|
18
|
+
|
|
19
|
+
lock file 包含 IDE 来源、WebSocket host 和 port、auth token、workspace 文件夹、进程 PID 和时间戳。写入方先写临时文件再原子 rename;目录权限 `0700`,文件权限 `0600`。
|
|
20
|
+
|
|
21
|
+
## Pi 如何选择连接
|
|
22
|
+
|
|
23
|
+
Pi 启动时扫描它知道的所有 lock 目录,解析每个文件并为候选排序。排序优先 workspace **包含**终端当前工作目录的连接(`src/shared/paths.ts` 中的 `relationshipMatchLength`):
|
|
24
|
+
|
|
25
|
+
1. 包含你 `cwd` 的 workspace 文件夹得分最高。
|
|
26
|
+
2. 被你 `cwd` **包含**的 workspace 文件夹(你在父目录启动了 Pi)得分较低。
|
|
27
|
+
3. 无关系得分为零。
|
|
28
|
+
|
|
29
|
+
这就是为什么推荐工作流是 **在项目目录内** 启动 Pi:匹配精确,Pi 自动连接。如果 `cwd` 只是父目录(例如 `~/`),没有候选胜出 - 运行 `/ide` 手动选择,或 `/ide auto` 重新匹配。
|
|
30
|
+
|
|
31
|
+
## lock file 生命周期
|
|
32
|
+
|
|
33
|
+
lock file 是临时的。Pi 先解析每个 lock,再应用过期策略。当 Pi 能证明生产者仍在运行时,会在任何年龄保留该 lock。
|
|
34
|
+
|
|
35
|
+
- **活的本地 PID:** 可用的本地 PID 是正的安全整数。活的可用 PID 会保留 lock。死的可用 PID 会删除 lock。
|
|
36
|
+
- **仅按年龄清理:** 若 PID 缺失或不可用,或禁用了 PID 检查,Pi 按年龄处理。超过 24 小时的文件随后会被删除。
|
|
37
|
+
- **WSL Windows lock:** 当 lock 为 `runningInWindows: true` 且 Pi 在 WSL 中运行时,TCP 可达性是权威依据。可达则保留,不可达则删除。
|
|
38
|
+
- **格式错误:** 无法解析的文件会被删除。
|
|
39
|
+
|
|
40
|
+
VS Code、Neovim 和 JetBrains 在活动期间每 15 分钟刷新自己拥有的 lock。刷新会保留端点身份和 auth token,并更新新鲜度数据。若生产者仍在运行时文件被删除,lock 可能直到下一次心跳才重新出现。
|
|
41
|
+
|
|
42
|
+
Zed 不写入这种 lock file。Pi 从 SQLite 读取 Zed 状态。
|
|
43
|
+
|
|
44
|
+
关闭 IDE 时插件会移除自己的 lock file。IDE 崩溃时,Pi 在下次扫描中于活性检查失败或仅按年龄清理时回收该文件。
|
|
45
|
+
|
|
46
|
+
## WSL2:发现 Windows 上的 IDE
|
|
47
|
+
|
|
48
|
+
当 Pi 运行在 WSL 内、IDE 运行在原生 Windows 上时,IDE 把 lock file 写到 Windows 用户目录。Pi 同时扫描 Linux home 的 lock 目录 **和** Windows 用户目录(如 `/mnt/c/Users/<user>/.pi/pi-x-ide/lock/`),跳过 Windows 系统配置文件。
|
|
49
|
+
|
|
50
|
+
Windows lock file 设置 `runningInWindows: true`。当 Pi 在 WSL 中运行时,到 Windows 生产者的 TCP 可达性是权威依据。Pi 不把 Windows PID 当作 Linux 进程活性证据。
|
|
51
|
+
|
|
52
|
+
### 解析连接 host
|
|
53
|
+
|
|
54
|
+
lock file 的 `host` 始终是 `127.0.0.1`,对 IDE 进程正确,但 **从 WSL 内部不可达**。Pi 按以下顺序解析可用 host(`src/pi/ide-host.ts`):
|
|
55
|
+
|
|
56
|
+
1. **`PI_X_IDE_HOST_OVERRIDE`** - 若设置(环境变量或 `~/.pi/pi-x-ide/config.json` 的 `env`),直接使用。
|
|
57
|
+
2. **WSL 默认网关** - 若 lock 有 `runningInWindows: true` 且 Pi 在 WSL 中,从 `ip route show` 解析网关,仅当对 `<gateway>:<port>` 的短 TCP 探测成功(500 ms 超时)时使用。
|
|
58
|
+
3. **lock file 的 `host` 值** - 同主机连接用 `127.0.0.1`。
|
|
59
|
+
4. **`127.0.0.1`** - `host` 为空时。
|
|
60
|
+
|
|
61
|
+
大多数 WSL 配置无需任何设置:第 2 步会自动处理。如果你的 WSL 网络模式、防火墙或终端安全策略阻止探测,显式设置 `PI_X_IDE_HOST_OVERRIDE`。见 [在 WSL2 中使用](../how-to/use-wsl2.md)。
|
|
62
|
+
|
|
63
|
+
## 路径规范化
|
|
64
|
+
|
|
65
|
+
来自 Windows IDE 的编辑器路径是 Windows 风格。Pi 在 workspace 匹配、UI 显示、`@file#Lx-Ly` mention 格式化和 prompt 上下文格式化之前,把它们规范化为 Linux host 路径。例如 WSL UNC 路径 `\\wsl.localhost\Ubuntu\home\user\project` 在 Pi 运行于 `Ubuntu` 发行版时变为 `/home/user/project`(`src/shared/platform.ts`)。
|
|
66
|
+
|
|
67
|
+
## 相关
|
|
68
|
+
|
|
69
|
+
- [架构](architecture.md) - 端到端数据流和各编辑器传输方式。
|
|
70
|
+
- [协议规范](../../specs/ide-protocol.md) - lock file schema、握手和通知语义。
|
|
71
|
+
- [排查连接问题](../how-to/troubleshoot-connection.md) - 发现未能连接时怎么办。
|