# pi-extmgr

![pi-extmgr banner](https://i.imgur.com/Ce513Br.png)

[![CI](https://github.com/ayagmar/pi-extmgr/actions/workflows/ci.yml/badge.svg)](https://github.com/ayagmar/pi-extmgr/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A better way to manage Pi extensions. Browse, install, enable/disable, and remove extensions from one place.
Built on top of Pi's native package install, update, and config flows, so extmgr stays aligned with current upstream behavior.

**🌐 [pi-extmgr landing page](https://ayagmar.github.io/pi-extmgr)**

## Install

```bash
pi install npm:pi-extmgr
```

If Pi is already running, use `/reload`.

Requires Node.js `>=22.20.0`.

### npm prefix permissions

Pi global package installs use `npm install -g`. If `npm_config_prefix` points at an
unwritable prefix such as `/usr/local`, install or reload can fail with `EACCES`.
Use a writable npm prefix, configure Pi's `npmCommand` setting for your Node
version manager, or install project-local with `pi install npm:pi-extmgr -l`.

`npmCommand` examples for `~/.pi/agent/settings.json`:

```jsonc
{
  // mise: run npm through Node 22
  // "npmCommand": ["mise", "exec", "node@22", "--", "npm"]

  // bun: use Bun as Pi's package-manager command
  // "npmCommand": ["bun"]

  // nvm: start Pi from an nvm-enabled shell and use npm on PATH
  // "npmCommand": ["npm"]
}
```

## Features

- **Unified manager UI**
  - Local extensions (`~/.pi/agent/extensions`, `.pi/extensions`) and installed packages in one list
  - Grouped sections for local extensions vs installed packages
  - Responsive master/detail layout on wide terminals, with a compact stacked fallback on narrow terminals
  - Focused primary filters and contextual one-line controls; secondary actions remain available through the command palette and help
  - Built-in search and filter shortcuts for large extension sets
  - Scope indicators (global/project), status indicators, update badges, and package sizes when known
- **Package extension configuration panel**
  - Configure individual extension entrypoints inside an installed package (`c` on package row)
  - Works with manifest-declared entrypoints and conventional `extensions/` package layouts
  - Persists to package filters in `settings.json` (no manual JSON editing)
- **Safe staged local extension toggles**
  - Toggle with `Space`, apply with `S`
  - Unsaved-change guard when leaving (save/discard/stay)
- **Package management**
  - Install, update, remove from UI and command line
  - Quick actions (`A`, `u`, `X`) and coordinated bulk package actions (`B`)
- **Remote discovery and install**
  - npm search/browse with server-side pagination, inline browse search, keyboard page navigation, and rate-limit-aware retries
  - Weekly npm downloads in browse rows/details plus popularity sorting (`o` cycles sort modes)
  - Path- and git-like queries are handled explicitly instead of surfacing unrelated npm results
  - Install by source (`npm:`, `git:`, `https://`, `ssh://`, `git@...`, local path)
  - Supports direct GitHub `.ts` installs and standalone local install for self-contained packages
  - Search results render immediately; weekly download metrics hydrate in the background and update the visible rows
  - Long-running discovery/detail screens now show dedicated loading UI, and cancellable reads can be aborted with `Esc`
- **Scheduled update checks**
  - Interactive wizard (`t` in manager, or `/extensions auto-update`)
  - Persistent schedule restored on startup and session switch
  - Background checks + status bar updates for installed npm + git packages
- **Task-oriented workspaces**
  - Installed: local extensions, packages, updates, and staged changes
  - Discover: community npm search, package inspection, downloads, and popularity sorting
  - Profiles: inline current-vs-target diffs (scope, version, ref, filters, checksum); applying always passes through the review screen
  - Health: runtime conflicts, compatibility, reload state, recoverable trash, conflict remediation, and a conservative “fix all safe issues” action (never removes packages)
- **Operational visibility**
  - Session history (`/extensions history`)
  - Cache controls (`/extensions clear-cache` clears persistent + runtime extmgr caches)
  - Status line summary (`pkg count • scheduled update checks • known updates`)
  - History now records local extension deletions and scheduled update checks configuration changes
- **Overlay-first output**
  - Help, item details, bulk summaries, doctor, history, trash lists, and profile check/import reports open in a floating scrollable panel instead of the chat transcript
  - Reference peeks (help, details) float beside the list; standalone reports (doctor, history, summaries) center on screen
  - Package updates show progress in a corner overlay while the session stays visible
  - A one-line attention widget above the editor appears when updates are known or a reload is pending, and clears once handled
  - The terminal title reflects the active workspace while the manager is open
- **Interactive + non-interactive support**
  - Works in TUI and non-UI modes
  - Non-UI modes receive the same report content as plain notifications
  - Non-interactive commands for list/install/remove/update/scheduled update checks (checks discover updates; package updates remain explicit)

## Usage

Open the manager:

```
/extensions
```

Or press `Ctrl+Alt+E` from anywhere in the pi TUI.

### In the manager

| Key           | Action                                                |
| ------------- | ----------------------------------------------------- |
| `Tab` / `Shift+Tab` | Next / previous workspace: Installed / Discover / Profiles / Health |
| `↑↓`          | Navigate                                              |
| `PageUp/Down` | Jump through longer lists                             |
| `Home/End`    | Jump to top or bottom                                 |
| `Space`       | Toggle selected local extension on/off                |
| `S`           | Save local extension changes                          |
| `Enter` / `A` | Actions on selected item                              |
| `/` / `Ctrl+F`| Search visible items                                  |
| `1-7`         | Filter: All / Local / Packages / Updates / Disabled / Favorites / Recent |
| `c`           | Configure selected package extensions                 |
| `u`           | Update selected package directly                      |
| `V`           | View full details for selected item                   |
| `X`           | Remove selected item (package/local extension)        |
| `i`           | Quick install by source                               |
| `f`           | Remote package search                                 |
| `B`           | Bulk actions for selected packages                    |
| `W` / `L` / `D` | Save / load / delete manager views                  |
| `*`           | Toggle favorite for selected item                     |
| `U`           | Update all packages                                   |
| `t`           | Scheduled update checks wizard                                    |
| `P` / `M`     | Workspace screens and actions                         |
| `R`           | Browse remote packages                                |
| `?` / `H`     | Help                                                  |
| `Esc`         | Clear search or exit                                  |

### Commands

```bash
/extensions                      # Open interactive manager (default)
/extensions local                # Alias: open interactive manager
/extensions list                 # List local extensions
/extensions remote               # Open remote package browser
/extensions packages             # Alias: remote browser
/extensions installed            # Installed packages view (legacy alias to unified flow)
/extensions search <query>       # Search npm packages
/extensions install <source> [--project|--global]  # Install package
/extensions remove [source]      # Remove package
/extensions uninstall [source]   # Alias: remove
/extensions update [source]      # Update one package (or all when omitted)
/extensions auto-update [every]  # No arg opens wizard in UI; accepts 1d, 1w, 1mo, never, etc.
/extensions doctor                # Inspect ownership and package compatibility
/extensions profile list              # List named profiles
/extensions profile save <name> [--force] # Save the current package profile
/extensions profile export <path>     # Export; refuses to overwrite an existing file
/extensions profile apply <name|path> # Safely apply a profile
/extensions profile rename <from> <to> # Rename a named profile
/extensions profile duplicate <from> <to> # Duplicate a named profile
/extensions profile delete <name>     # Delete a named profile
/extensions trash <list|restore|purge> # Manage local extension trash
/extensions history [options]    # View change history (supports filters)
/extensions clear-cache          # Clear persistent + runtime extmgr caches
```

### Non-interactive mode

When Pi is running without UI, extmgr still supports command-driven workflows:

- `/extensions list`
- `/extensions installed`
- `/extensions install <source> [--project|--global]`
- `/extensions remove <source>`
- `/extensions update [source]`
- `/extensions history [options]`
- `/extensions auto-update <duration>`
  - Use `1mo` for monthly schedules (`/extensions history --since <duration>` also accepts `1mo`; `30m`/`24h` are just lookback examples)

Remote browsing/search menus require the full interactive TUI.

### RPC / limited-UI mode

In RPC mode, dialog-based commands still work, but the custom TUI panels do not:

- `/extensions` falls back to read-only local/package lists
- `/extensions installed` lists packages directly
- remote browsing/search panels require the full interactive TUI
- package extension configuration requires the full interactive TUI

History options (works in non-interactive mode too):

- `--limit <n>`
- `--action <extension_toggle|extension_delete|package_install|package_update|package_remove|cache_clear|auto_update_config>`
- `--success` / `--failed`
- `--package <query>`
- `--since <duration>` (e.g. `30m`, `24h`, `7d`, `1mo`; `1mo` is supported for monthly lookbacks)
- `--global` (non-interactive mode only; reads all persisted sessions under `~/.pi/agent/sessions`)

Examples:

- `/extensions history --failed --limit 50`
- `/extensions history --action package_update --since 7d`
- `/extensions history --global --package extmgr --since 1mo`

### Install sources

```bash
/extensions install npm:package-name
/extensions install @scope/package
/extensions install git:https://github.com/user/repo.git
/extensions install git:git@github.com:user/repo.git
/extensions install ssh://git@github.com/user/repo.git
/extensions install https://github.com/user/repo/blob/main/extension.ts
/extensions install /path/to/extension.ts
/extensions install ./local-folder/
```

## Tips

- **Staged local changes**: Toggle local extensions on/off, then press `S` to apply all at once.
- **Package extension config**: Select a package and press `c` (or Enter/A → Configure) to enable/disable individual package entrypoints.
  - After saving package extension config, run /reload to apply changes.
- **Two install modes**:
  - **Managed** (npm): uses explicit `pi update` updates, stored in pi's package cache, supports Pi package manifest/convention loading
  - **Local** (standalone): Copies to `~/.pi/agent/extensions/{package}/`, so it only accepts runnable standalone layouts (manifest-declared/root entrypoints), requires `tar` on `PATH`, and rejects packages whose runtime `dependencies` are not already bundled with the package contents
- **Scheduled update-check schedule is persistent**: `/extensions auto-update 1d` stays active across future Pi sessions and is restored when switching sessions.
- **Scheduled update-check badges cover npm + git packages**: extmgr now uses pi's package manager APIs for structured update detection instead of parsing `pi list` output.
- **Settings/cache writes are hardened**: extmgr serializes writes and uses safe file replacement to reduce JSON corruption issues.
- **Invalid JSON is handled safely**: malformed `auto-update.json` / metadata cache files are backed up and reset; invalid `.pi/settings.json` is not overwritten during package-extension toggles.
- **Reload is built-in**: When extmgr asks to reload, it calls `ctx.reload()` directly. Successful mutations persist a versioned reload-required marker; cancellation and failure do not. The marker survives reopening the manager and clears after a successful reload.
- **Saved manager state**: Views, favorites, recent items, and bulk selections are stored atomically in `~/.pi/agent/.extmgr-cache/views-<project>.json`. Named profiles are stored in `profiles.json`; project policies load from `.pi/extmgr-policy.json`.
- **Trash lifecycle**: Local removals move to `~/.pi/agent/.extmgr-trash/` with persistent records. Undo refuses to overwrite a replacement file, and expired or missing records are cleaned up.
- **Metadata safety**: Missing compatibility, provenance, checksum, or target-version metadata is reported as `unknown`, never `safe`. Target-version previews, exact target badges, and update-policy/maintenance-window enforcement are intentionally deferred because Pi does not expose structured target metadata.

## License

MIT
