Add ext-toggle extension and /ext slash command
extensions/ext-toggle.ts: /ext lists ~/.pi/agent/extensions/ with active/disabled markers and toggles individual extensions by renaming between name.ts and name.ts.off (pi only auto-discovers *.ts). Calls ctx.reload() so the change takes effect without restarting pi. Subdirectory-style extensions (name/index.ts) are listed read-only in v1 — toggling a directory cleanly is more work than the rename trick is worth. install.sh: --uninstall now matches both *.ts and *.ts.off symlinks pointing into this repo, so a disabled extension is still cleaned up. README.md / AGENTS.md: Document ext-toggle alongside the others; AGENTS notes the API surface used (registerCommand, ui.select/confirm/notify, reload) and the rename-not-delete design decision.
This commit is contained in:
@@ -21,6 +21,7 @@ extensions/
|
||||
confirm-destructive.ts # Confirm before dangerous bash commands and session actions
|
||||
git-checkpoint.ts # Git stash checkpoint per turn, restorable on /fork
|
||||
notify.ts # Native terminal notification when agent finishes
|
||||
ext-toggle.ts # /ext slash command — list & toggle extensions at runtime
|
||||
install.sh # Idempotent installer — symlinks extensions/ into ~/.pi/agent/extensions/
|
||||
package.json # pi package manifest — enables `pi install /path` as an alternative
|
||||
README.md # User-facing docs.
|
||||
@@ -159,6 +160,43 @@ Terminal detection order: `KITTY_WINDOW_ID` → OSC 99 (Kitty) →
|
||||
|
||||
Notification text: `Pi — Done (Ns)` where N is the rounded elapsed seconds.
|
||||
|
||||
### `ext-toggle.ts`
|
||||
|
||||
Registers `/ext` slash command. Lists files in `~/.pi/agent/extensions/`,
|
||||
shows `●` (active) / `○` (disabled) plus dir/symlink hints, and lets the
|
||||
user toggle individual extensions by renaming them between `name.ts` and
|
||||
`name.ts.off`. Calls `ctx.reload()` after a toggle so the change takes
|
||||
effect without restarting pi.
|
||||
|
||||
**Key design decisions:**
|
||||
|
||||
- **Rename, not delete.** Disabling a built-in produces a `name.ts.off`
|
||||
symlink/file that's invisible to pi's `*.ts` discovery glob but trivially
|
||||
reversible. No state stored elsewhere.
|
||||
- **Symlink-friendly.** `fs.renameSync` renames the symlink itself; the repo
|
||||
target is untouched. Toggling an extension installed by this repo is
|
||||
reversible without re-running `install.sh`.
|
||||
- **Subdir extensions are read-only in v1.** `name/index.ts` shapes show up in
|
||||
the listing with a `[dir]` tag but cannot be toggled — the cleanest disable
|
||||
for a directory would need a hidden-prefix or move-aside dance that adds
|
||||
more failure modes than it's worth for now.
|
||||
- **`install.sh --uninstall` matches both `*.ts` and `*.ts.off`.** Means a
|
||||
disabled extension is still cleaned up on uninstall, regardless of which
|
||||
state it was left in.
|
||||
- **Listing is recomputed on every `/ext` invocation.** No cache, no event
|
||||
subscription — cheap enough for the tens of files this directory will ever
|
||||
contain.
|
||||
|
||||
**API used:**
|
||||
|
||||
- `pi.registerCommand(name, { description, handler })` — registers `/ext`.
|
||||
- `ctx.ui.select(title, items)` — picker; returns selected string or `undefined`.
|
||||
- `ctx.ui.confirm(title, message)` — yes/no dialog returning `boolean`.
|
||||
- `ctx.ui.notify(message, level)` — transient toast.
|
||||
- `ctx.reload()` — reloads extensions/skills/prompts/themes; same as `/reload`.
|
||||
|
||||
No flags, no `agent_*` event handlers — fully passive until `/ext` is invoked.
|
||||
|
||||
No framework. Manual:
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user