npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@ldelossa/pi-ide

v0.2.5

Published

Pi extension that connects to a running editor (Neovim today, more later) over a local WebSocket. Adds ambient editor context to the agent and routes write/edit tool calls through interactive diffs in the editor.

Downloads

294

Readme

pi-ide

Connects a Pi coding-agent session to a running editor over a local WebSocket MCP server. Provides ambient editor context (current file, cursor, selection), routes write/edit tool calls through the editor as interactive diffs, and serves inline code completions (often called "suggestions") to editors that request them. The wireformat is compatible with Claude Code's editor integration.

Install

pi install npm:@ldelossa/pi-ide

That writes to ~/.pi/agent/settings.json and loads pi-ide on every pi session. To scope it to one project instead of globally, add -l:

pi install -l npm:@ldelossa/pi-ide

Project installs land in ./.pi/settings.json and can be checked in so teammates pick the extension up automatically.

To try it without installing permanently:

pi -e npm:@ldelossa/pi-ide

To remove:

pi remove npm:@ldelossa/pi-ide

Git installs also work if you prefer pinning to a tag:

pi install git:github.com/ldelossa/[email protected]

You also need an editor that speaks the protocol. The reference Neovim implementation is at https://github.com/ldelossa/pi-ide.nvim.

Once both are running, use /ide inside pi to connect to the editor.

Architecture

  1. Editor starts a loopback MCP server on a free TCP port. Writes a lockfile to $PI_IDE_LOCK_DIR (default ~/.pi/ide/<port>.lock). Removes it on exit.
  2. On startup, if pi-ide.autoconnect is not false and exactly one valid lockfile matches cwd, the extension connects automatically. A sticky reconnect target is remembered across /new sessions, keeping the same IDE when multiple editors are open. Use /ide to manually connect, switch IDEs, or disconnect.
  3. Extension opens ws://127.0.0.1:<port>/ with header x-pi-ide-authorization: <authToken> and runs MCP initialize.
  4. While connected:
    • Editor pushes selection_changed notifications. Extension caches filePath, cursor, selection. Renders a status widget.
    • Before each agent run, cached state is injected into the system prompt as an <editor> block.
    • On every write or edit tool call, extension calls openDiff. The call blocks until the editor returns FILE_SAVED (accept) or DIFF_REJECTED (reject). On reject, the tool call is blocked and the rejection is surfaced to the agent.
  5. Session shutdown closes the socket.

Autoconnect

Autoconnect saves a manual /ide step by connecting to the IDE automatically. It is enabled by default.

Connections are made on two occasions:

On start

  1. pi-ide.autoconnect is not false
  2. Exactly one valid IDE lockfile exists for the current working directory

On session replacement (/new, /resume, /reload) If the previous session was connected to an IDE, pi-ide tries to reconnect to that same IDE. This sticky reconnect bypasses the single-candidate rule, which means it can reconnect even when a second IDE has since started in the same directory. If the sticky IDE is no longer valid (closed, stopped, connection fails, or its project changed), autoconnect falls back to the cold-start rule.

Disabling

Add to any Pi settings file:

{
  "pi-ide": {
    "autoconnect": false
  }
}

| Scope | File | |-------|------| | Global | ~/.pi/agent/settings.json | | Project | .pi/settings.json |

Project settings override global settings. A missing setting is treated as enabled.

Lockfile

Path: $PI_IDE_LOCK_DIR/<port>.lock (default ~/.pi/ide/<port>.lock).

{
  "pid": <int>,
  "workspaceFolders": ["<abs path>", ...],
  "ideName": "<display name>",
  "transport": "ws",
  "authToken": "<uuid>"
}

Transport

  • WebSocket on 127.0.0.1:<port>, path /.
  • Required header: x-pi-ide-authorization: <authToken>. Mismatches must be rejected before upgrade.
  • Framing: JSON-RPC 2.0 in text frames. One message per frame.
  • Protocol: MCP 2024-11-05. Subset only. resources/*, prompts/*, logging/*, and sampling are not used. Server-reported capabilities are ignored by the client. Four methods carry the protocol: initialize, notifications/initialized, tools/list, tools/call.

Editor-side contract

The editor must:

  1. Serve MCP on loopback. Write the lockfile on start, remove on shutdown.
  2. Authenticate the upgrade header against the lockfile's authToken.
  3. Implement initialize, tools/list, tools/call.
  4. Implement the tools below.
  5. Emit the notifications below.

Tool: openDiff

Input:

| field | type | description | | ------------------- | ------ | ------------------------------------------ | | old_file_path | string | absolute path of the existing file | | new_file_path | string | destination path (typically same as old) | | new_file_contents | string | proposed contents | | tab_name | string | stable id for this diff invocation |

Behavior: open a two-pane diff between on-disk content and proposed content. Block (suspend the JSON-RPC response) until the user accepts or rejects.

Response on accept:

{ "content": [
  { "type": "text", "text": "FILE_SAVED" },
  { "type": "text", "text": "<final contents>" }
]}

Final contents may differ from new_file_contents if the user edited the diff before saving.

Response on reject:

{ "content": [
  { "type": "text", "text": "DIFF_REJECTED" },
  { "type": "text", "text": "<tab_name>" }
]}

Tool: close_tab

Input: tab_name (string). Close the named diff if open. No-op otherwise.

Response:

{ "content": [ { "type": "text", "text": "TAB_CLOSED" } ] }

Notification: selection_changed

JSON-RPC notification (no id). Sent on cursor move, mode change, buffer enter, and text change. Debounce locally (~100ms recommended).

{
  "text": "<selected text, empty when no selection>",
  "filePath": "<abs path>",
  "fileUrl": "file://<abs path>",
  "selection": {
    "start": { "line": <0-based>, "character": <0-based> },
    "end":   { "line": <0-based>, "character": <0-based> },
    "isEmpty": <bool>
  }
}

Lines and characters are zero-based. The extension renders line numbers as 1-based.

Editor-initiated requests

The editor may send JSON-RPC requests to the extension over the same WebSocket. The extension processes them and returns responses.

Request: getSuggestions

Returns inline code completions for the editor to render as ghost text or equivalent. The extension calls the configured model (current session model by default; see model precedence below), parses up to 3 <SUGGESTION>...</SUGGESTION> blocks from the response, and returns them.

Input:

| field | type | description | | ----------------- | ------ | -------------------------------------------- | | filePath | string | optional. absolute path of the cursor file | | language | string | optional. filetype or language id | | outline | string | optional. structural sketch of the file | | enclosingScope | string | optional. surrounding function or class | | cursorBefore | string | text before cursor (typically ~20 lines) | | cursorAfter | string | text after cursor (typically ~10 lines) | | suggestionCount | int | optional. cap on returned alternatives. Max 3. | | cursorInComment | bool | optional. cursor is inside a comment | | model | string | optional. preferred model "provider/id". CLI flag wins if set. |

outline is an optional compact declaration summary produced with the editor's native source-analysis tool — treesitter declarations (Neovim), document symbols from LSP (VS Code), PSI symbols (JetBrains), or omitted entirely. Local cursorBefore and cursorAfter context remains the most important input; a large raw syntax tree is usually slower and less useful.

Response:

{ "suggestions": ["<text>", ...] }

Empty suggestions is valid and means the model declined to complete. Each returned string is inserted at the cursor exactly as provided after model newlines are canonicalized to LF; leading spaces and newlines are meaningful and must not be trimmed by the editor. A multi-line candidate is discarded when non-whitespace text remains on the cursor line because the reference editor cannot preview that suffix relocation exactly.

Cancellation: editor sends request_cancelled notification with { "id": <request id> }. The extension aborts the in-flight model call.

Model precedence: the CLI flag (--pi-ide-suggestion-model <provider>/<id>) wins. Otherwise the editor-provided model field is used. If neither is set, the current session's model is used.

To find valid provider/id strings, run pi --list-models and join the provider and model columns with a / (e.g., openai/gpt-4o).

For suggestions, prefer low-latency models. Large reasoning models often feel too slow for inline completion; smaller coding-capable models such as openai-codex/gpt-5.4-mini or deepseek/deepseek-v4-flash usually provide a better interactive experience.

For prompt evaluation, --pi-ide-suggestion-debug-log <path> appends the request context, rendered prompt, raw model output, parsed/returned candidates, latency, stop reason, and usage for each successful request. The log contains source code and should be stored and shared accordingly.

Request: listSuggestionModels

Returns models available to the current pi session for runtime suggestion model selection in editors. The extension is the source of truth for model discovery; editors should not read pi config files directly.

Input: none.

Response:

{
  "cliOverride": "<provider/id>",       // optional. --pi-ide-suggestion-model is active
  "currentModel": "<provider/id>",      // optional. current pi session model
  "models": [
    { "provider": "openai", "id": "gpt-4o", "name": "GPT-4o", "model": "openai/gpt-4o" }
  ]
}

If cliOverride is present, editor-provided model selections are still accepted by the editor but will not affect suggestions because the CLI flag has higher precedence.

Reference editor implementation

Neovim: pi-ide.nvim. Implements both the editor-side contract (diffs, diagnostics, selection notifications) and the getSuggestions client. Suggestions work without treesitter; when available, the Neovim reference client uses standardized treesitter locals query captures plus a compact generic top-level fallback. Language-specific declaration knowledge remains in the installed treesitter queries rather than the editor client.

Development

npm test
npm run check

The suggestion tests cover the exact insertion contract, whitespace, comment continuations, response parsing, candidate deduplication, and prompt shape.