Files
pi-perplexity/README.md
T
Ivan Pereira 76dbc20064 Harden token storage and declare Bun runtime
Enforce 0600 permissions after every auth token write so existing files
with broader modes are corrected.

Add a regression test for the permission hardening path and document the
Bun runtime dependency used by the Node/jiti search subprocess path.
Also declare bun in package dependencies and engines.
2026-02-23 10:47:05 +00:00

137 lines
4.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# pi-perplexity
A [pi](https://github.com/nickarrow/pi-coding-agent) extension that provides web search via a Perplexity Pro/Max subscription. Uses your existing subscription — no API credits consumed.
## Installation
```bash
pi install pi-perplexity
```
## Usage
Once installed, the agent gains a `perplexity_search` tool it can call automatically when it needs to look something up. You can also trigger a search by asking the agent to search for something.
### Tool Parameters
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | yes | Search query |
| `recency` | string | no | Filter by age: `hour`, `day`, `week`, `month`, `year` |
| `limit` | number | no | Max sources to return (150) |
### Slash Command
```
/perplexity-login # Authenticate and save token
/perplexity-login --force # Clear cached token and re-authenticate
```
## Authentication
The extension tries two auth methods in order:
1. **macOS Desktop App** (automatic) — Borrows the JWT from the Perplexity macOS app if installed and signed in. Zero interaction required.
2. **Email OTP** (interactive fallback) — Prompts for your Perplexity email, sends a one-time code, and prompts for the code.
The token is cached at `~/.config/pi-perplexity/auth.json` (permissions `0600`). On HTTP 401/403, the cached token is automatically cleared so the next search re-authenticates.
### Environment Variables
| Variable | Description |
|----------|-------------|
| `PI_AUTH_NO_BORROW=1` | Skip macOS desktop app token extraction |
| `PI_PERPLEXITY_EMAIL` | Email for OTP auth (skips interactive prompt) |
| `PI_PERPLEXITY_OTP` | OTP code for non-interactive auth |
## How It Works
The extension calls Perplexity's internal SSE endpoint (`perplexity_ask`) with your subscription credentials. Responses stream as incremental events that are merged into a final result containing an answer and sources.
All queries use `is_incognito: true` — nothing appears in your Perplexity search history.
### Output Format
The tool returns structured text the agent can reason over:
```
## Answer
<synthesized answer with inline citations>
## Sources
3 sources
[1] Example Article (2d ago)
https://example.com/article
Brief snippet of the source content...
[2] Another Source (5h ago)
https://example.com/other
Another snippet preview...
## Meta
Provider: perplexity (oauth)
Model: pplx_pro_upgraded
```
## Development
### Prerequisites
- [Bun](https://bun.sh) runtime
- pi coding agent (`@mariozechner/pi-coding-agent`)
### Commands
```bash
bun install # Install dev dependencies
bun test # Run tests (30 tests across 6 files)
bunx tsc --noEmit # Type check
```
### Project Structure
```
src/
index.ts # Extension entry — registers tool and commands
auth/
login.ts # macOS app extraction + email OTP flow
storage.ts # Token persistence (~/.config/pi-perplexity/auth.json)
commands/
login.ts # /perplexity-login slash command
search/
types.ts # Type definitions (StreamEvent, SearchResult, errors)
client.ts # HTTP POST to SSE endpoint, event merging, result extraction
stream.ts # SSE line parser + incremental event merging
format.ts # SearchResult → LLM-readable text output
render/
call.ts # TUI component for tool call display
result.ts # TUI component for tool result display
util.ts # Shared render utilities
```
### Runtime Dependencies
This extension depends on the `bun` runtime package at execution time.
Why: when pi loads extensions under Node/jiti, direct `fetch` to Perplexity is Cloudflare-challenged, so searches are executed through a Bun subprocess.
Everything else uses platform globals:
- `fetch` — HTTP requests
- `crypto.randomUUID()` — request IDs
- `ReadableStream` — SSE parsing
- `Intl.DateTimeFormat` — timezone detection
Peer dependencies (`@sinclair/typebox`, `@mariozechner/pi-tui`, `@mariozechner/pi-ai`) are provided by pi at runtime.
## Requirements
- Perplexity **Pro** or **Max** subscription
- Bun installed and available on `PATH` (used by the search client when running under Node/jiti)
- macOS (for desktop app token extraction) or interactive terminal (for email OTP)
## License
Private — not published.