pplx-zero 1.1.5 → 1.1.7
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/README.md +79 -329
- package/dist/index.js +179 -160
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,404 +1,154 @@
|
|
|
1
|
-
# PPLX
|
|
1
|
+
# PPLX‑Zero
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use the Perplexity API straight from the terminal — sub‑1s search API, ideal for coding agents and automation.
|
|
4
|
+
Minimal setup, fast results, and practical flags for files, images, streaming, and batch workflows.
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
<a href="https://bun.sh"><img src="https://img.shields.io/badge/Bun-black?logo=bun&logoColor=white" alt="Bun"></a>
|
|
10
|
-
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
|
|
11
|
-
</p>
|
|
6
|
+
### What you can do
|
|
7
|
+
- Ask, research, and stream answers instantly from the CLI with sensible defaults for rapid iteration.
|
|
8
|
+
- Summarize documents and analyze images using a single command with optional model control.
|
|
9
|
+
- Run batch jobs with concurrency and timeouts for agent pipelines and CI flows.
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
## Features
|
|
16
|
-
|
|
17
|
-
- **⚡ Fast Search** - Concurrent queries with intelligent rate limiting
|
|
18
|
-
- **🎯 Simple Setup** - Works with just an API key, no configuration required
|
|
19
|
-
- **📦 Batch Processing** - Handle multiple searches simultaneously
|
|
20
|
-
- **🔄 Real-time Updates** - JSONL streaming progress events
|
|
21
|
-
- **🖼️ File Analysis** - Process documents and images with AI models
|
|
22
|
-
- **🤖 AI Models** - Sonar, Sonar Pro, Sonar Deep Research, Sonar Reasoning
|
|
23
|
-
- **🛡️ Type Safe** - Full Zod validation and TypeScript support
|
|
24
|
-
- **🌍 Cross-Platform** - Native Bun runtime support
|
|
25
|
-
- **🔄 Auto-Update** - Background update checking to stay current
|
|
26
|
-
|
|
27
|
-
## Quick Start
|
|
28
|
-
|
|
29
|
-
### 1️⃣ Install
|
|
30
|
-
|
|
31
|
-
**📦 Package Manager Installation (Recommended)**
|
|
32
|
-
|
|
33
|
-
<p align="center">
|
|
34
|
-
<a href="https://badge.fury.io/js/pplx-zero"><img src="https://badge.fury.io/js/pplx-zero.svg" alt="npm version"></a>
|
|
35
|
-
<a href="https://aur.archlinux.org/packages/pplx-zero"><img src="https://img.shields.io/aur/version/pplx-zero?style=flat-square" alt="AUR package"></a>
|
|
36
|
-
</p>
|
|
11
|
+
### Install
|
|
12
|
+
Choose one:
|
|
37
13
|
|
|
38
14
|
```bash
|
|
39
|
-
# npm
|
|
15
|
+
# npm or bun (global)
|
|
40
16
|
npm install -g pplx-zero
|
|
17
|
+
pplx --version
|
|
18
|
+
```
|
|
41
19
|
|
|
42
|
-
# AUR (Arch Linux) - Binary package
|
|
43
|
-
yay -S pplx-zero
|
|
44
20
|
|
|
45
|
-
|
|
46
|
-
git clone https://aur.archlinux.org/pplx-zero.git
|
|
47
|
-
cd pplx-zero
|
|
48
|
-
makepkg -si
|
|
21
|
+
or
|
|
49
22
|
|
|
50
|
-
|
|
23
|
+
```bash
|
|
24
|
+
# AUR (Arch Linux)
|
|
25
|
+
yay -S pplx-zero
|
|
51
26
|
pplx --version
|
|
52
27
|
```
|
|
53
28
|
|
|
54
|
-
|
|
29
|
+
|
|
30
|
+
or
|
|
55
31
|
|
|
56
32
|
```bash
|
|
57
|
-
#
|
|
58
|
-
|
|
59
|
-
|
|
33
|
+
# Build from source
|
|
34
|
+
# 1) clone the repository
|
|
35
|
+
# 2) enter the folder
|
|
36
|
+
# 3) build and link the CLI
|
|
60
37
|
bun install && bun run build
|
|
61
|
-
|
|
62
|
-
# Add to PATH
|
|
63
38
|
sudo ln -s "$(pwd)/dist/cli.js" /usr/local/bin/pplx
|
|
64
|
-
|
|
65
|
-
# Verify installation
|
|
66
39
|
pplx --version
|
|
67
40
|
```
|
|
68
41
|
|
|
69
|
-
### 2️⃣ Setup API Key
|
|
70
42
|
|
|
71
|
-
|
|
43
|
+
### Configure
|
|
44
|
+
Set your API key as an environment variable before running commands.
|
|
45
|
+
|
|
46
|
+
Linux/macOS:
|
|
72
47
|
```bash
|
|
73
48
|
export PERPLEXITY_API_KEY="your-api-key"
|
|
74
49
|
```
|
|
75
50
|
|
|
76
|
-
|
|
51
|
+
|
|
52
|
+
Windows:
|
|
77
53
|
```cmd
|
|
78
54
|
setx PERPLEXITY_API_KEY "your-api-key"
|
|
79
55
|
```
|
|
80
56
|
|
|
81
|
-
**Get your API key:** https://www.perplexity.ai/account/api/keys
|
|
82
57
|
|
|
83
|
-
|
|
58
|
+
Get your key from your Perplexity account and keep it private to your machine or CI secrets manager.
|
|
84
59
|
|
|
60
|
+
### Quick examples
|
|
61
|
+
Simple search (default model: sonar)
|
|
85
62
|
```bash
|
|
86
|
-
|
|
87
|
-
pplx "latest AI developments"
|
|
88
|
-
|
|
89
|
-
# Choose model for detailed analysis
|
|
90
|
-
pplx --model sonar-pro "Explain quantum computing"
|
|
91
|
-
|
|
92
|
-
# Analyze document
|
|
93
|
-
pplx --file report.pdf "Summarize this document"
|
|
94
|
-
|
|
95
|
-
# Analyze image
|
|
96
|
-
pplx --image screenshot.png "What does this interface do?"
|
|
97
|
-
|
|
98
|
-
# Document + image analysis
|
|
99
|
-
pplx --file data.csv --image chart.png "Analyze this data"
|
|
100
|
-
|
|
101
|
-
# Advanced AI models
|
|
102
|
-
pplx --model sonar-reasoning "Solve this math problem"
|
|
103
|
-
pplx --model sonar-deep-research "History of artificial intelligence"
|
|
104
|
-
|
|
105
|
-
# See basic help
|
|
106
|
-
pplx --help
|
|
63
|
+
pplx "python type hints best practices"
|
|
107
64
|
```
|
|
108
65
|
|
|
109
|
-
## Auto-Update
|
|
110
|
-
|
|
111
|
-
PPLX-Zero includes intelligent auto-update functionality that runs in the background to keep your CLI current.
|
|
112
|
-
|
|
113
|
-
### How It Works
|
|
114
|
-
|
|
115
|
-
- **Background Checking**: Automatically checks for updates every 24 hours when you run searches
|
|
116
|
-
- **Non-Blocking**: Never slows down your search queries - updates happen in the background
|
|
117
|
-
- **Smart Caching**: Uses intelligent caching to avoid unnecessary network requests
|
|
118
|
-
- **Silent by Default**: Runs quietly without interrupting your workflow
|
|
119
|
-
|
|
120
|
-
### Update Commands
|
|
121
66
|
|
|
67
|
+
Deep research or sonar-pro or reasoning when you need more steps or web context
|
|
122
68
|
```bash
|
|
123
|
-
|
|
124
|
-
pplx
|
|
125
|
-
|
|
126
|
-
# Install available updates automatically
|
|
127
|
-
pplx update --auto
|
|
128
|
-
|
|
129
|
-
# Show version information
|
|
130
|
-
pplx version
|
|
131
|
-
|
|
132
|
-
# Check updates with version command
|
|
133
|
-
pplx version --check-updates
|
|
69
|
+
pplx -m sonar-pro "React 19 Hooks"
|
|
70
|
+
pplx -m sonar-deep-research "best Rust web frameworks 2025"
|
|
71
|
+
pplx -m sonar-reasoning "prove this algorithm runs in O(n log n)"
|
|
134
72
|
```
|
|
135
73
|
|
|
136
|
-
### Update Methods
|
|
137
|
-
|
|
138
|
-
The auto-update system tries multiple package managers in order of preference:
|
|
139
|
-
|
|
140
|
-
1. **npm global** (`npm update -g pplx-zero`)
|
|
141
|
-
2. **bun global** (`bun update -g pplx-zero`)
|
|
142
|
-
3. **yarn global** (`yarn global upgrade pplx-zero`)
|
|
143
|
-
4. **pnpm global** (`pnpm update -g pplx-zero`)
|
|
144
|
-
|
|
145
|
-
If automatic updates fail, you'll get helpful instructions to update manually.
|
|
146
|
-
|
|
147
|
-
### Configuration
|
|
148
|
-
|
|
149
|
-
Auto-update settings are stored in `~/.pplx-zero/update-cache.json`:
|
|
150
|
-
|
|
151
|
-
- **Check Interval**: 24 hours by default
|
|
152
|
-
- **Quiet Mode**: Silent operation to not interrupt workflow
|
|
153
|
-
- **Auto Install**: Disabled by default for safety
|
|
154
|
-
|
|
155
|
-
### Privacy & Performance
|
|
156
74
|
|
|
157
|
-
|
|
158
|
-
- **No Data Collection**: Never sends search queries or personal data
|
|
159
|
-
- **Fast Performance**: Cached results prevent repeated network requests
|
|
160
|
-
- **Local Only**: All update logic runs locally on your machine
|
|
161
|
-
|
|
162
|
-
## Usage Guide
|
|
163
|
-
|
|
164
|
-
### Command Line Options
|
|
165
|
-
|
|
166
|
-
**Quick Reference:**
|
|
75
|
+
Summarize a PDF report quickly
|
|
167
76
|
```bash
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
# File analysis (simplified)
|
|
172
|
-
pplx -f document.pdf "Summarize this"
|
|
77
|
+
pplx -f report.pdf "summarize key findings and risks"
|
|
78
|
+
```
|
|
173
79
|
|
|
174
|
-
# Advanced batch processing
|
|
175
|
-
pplx --input queries.json -c 10 -t 60000
|
|
176
80
|
|
|
177
|
-
|
|
178
|
-
|
|
81
|
+
Understand an interface from a screenshot
|
|
82
|
+
```bash
|
|
83
|
+
pplx -i screenshot.png "what is this UI and what are the next steps?"
|
|
179
84
|
```
|
|
180
85
|
|
|
181
|
-
**Essential Commands:**
|
|
182
|
-
```bash
|
|
183
|
-
# Model selection
|
|
184
|
-
pplx -m sonar-pro "Detailed analysis"
|
|
185
86
|
|
|
186
|
-
|
|
187
|
-
|
|
87
|
+
Combine a doc and an image in one prompt
|
|
88
|
+
```bash
|
|
89
|
+
pplx -f data.csv -i chart.png "spot anomalies and explain the chart"
|
|
90
|
+
```
|
|
188
91
|
|
|
189
|
-
# Output format
|
|
190
|
-
pplx -o jsonl "Get streaming output"
|
|
191
92
|
|
|
192
|
-
|
|
193
|
-
|
|
93
|
+
Stream newline‑delimited JSON for agents or UNIX pipes
|
|
94
|
+
```bash
|
|
95
|
+
pplx -o jsonl "ai trends"
|
|
194
96
|
```
|
|
195
97
|
|
|
196
|
-
### Batch Processing
|
|
197
|
-
|
|
198
|
-
Create `queries.json`:
|
|
199
98
|
|
|
99
|
+
Batch from a JSON file (concurrency and timeout shown)
|
|
200
100
|
```json
|
|
201
101
|
{
|
|
202
102
|
"version": "1.0.0",
|
|
203
103
|
"requests": [
|
|
204
|
-
{"op": "search", "args": {"query": "AI trends", "maxResults": 5}},
|
|
205
|
-
{"op": "search", "args": {"query": "TypeScript patterns", "maxResults": 3}}
|
|
206
|
-
{"op": "search", "args": {"query": "Bun performance", "maxResults": 3}}
|
|
104
|
+
{ "op": "search", "args": { "query": "AI trends", "maxResults": 5 } },
|
|
105
|
+
{ "op": "search", "args": { "query": "TypeScript patterns", "maxResults": 3 } }
|
|
207
106
|
],
|
|
208
|
-
"options": {
|
|
209
|
-
"concurrency": 5,
|
|
210
|
-
"timeoutMs": 30000
|
|
211
|
-
}
|
|
107
|
+
"options": { "concurrency": 5, "timeoutMs": 30000 }
|
|
212
108
|
}
|
|
213
109
|
```
|
|
214
110
|
|
|
215
|
-
Process with:
|
|
216
111
|
|
|
217
112
|
```bash
|
|
218
|
-
pplx
|
|
113
|
+
pplx -I queries.json -o jsonl -c 5 -t 30000
|
|
219
114
|
```
|
|
220
115
|
|
|
221
|
-
### File Attachments
|
|
222
|
-
|
|
223
|
-
Supported file formats for analysis:
|
|
224
116
|
|
|
225
|
-
|
|
226
|
-
- PDF, DOC, DOCX, TXT, RTF, MD
|
|
227
|
-
|
|
228
|
-
**Images (max 50MB):**
|
|
229
|
-
- PNG, JPEG, WebP, HEIF, HEIC, GIF
|
|
230
|
-
|
|
231
|
-
**Examples:**
|
|
117
|
+
Fire‑and‑forget async with a webhook callback (agent workflows)
|
|
232
118
|
```bash
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
119
|
+
pplx --async --webhook http://localhost:3000/callback "long research task"
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
### Flags
|
|
124
|
+
- -m, --model: sonar | sonar-pro | sonar-deep-research | sonar-reasoning (default: sonar)
|
|
125
|
+
- -f, --file: attach a document (PDF, DOC, DOCX, TXT, RTF, MD; up to ~50MB)
|
|
126
|
+
- -i, --image: attach an image (PNG, JPEG, WebP, HEIF/HEIC, GIF; up to ~50MB)
|
|
127
|
+
- -o, --format: json | jsonl (default: json)
|
|
128
|
+
- -I, --input: read batch requests from a JSON file
|
|
129
|
+
- -c, --concurrency: max parallel requests, e.g., 5 (default: 5)
|
|
130
|
+
- -t, --timeout: request timeout in ms, e.g., 30000 (default: 30000)
|
|
131
|
+
- --async: process requests asynchronously
|
|
132
|
+
- --webhook: URL receiving async notifications
|
|
133
|
+
- -h, --help: show help
|
|
134
|
+
- -v, --version: show version
|
|
135
|
+
|
|
136
|
+
### Programmatic use (optional)
|
|
137
|
+
Use the toolkit directly in TypeScript when embedding into agents or services.
|
|
138
|
+
```ts
|
|
246
139
|
import { PerplexitySearchTool } from 'pplx-zero';
|
|
247
140
|
|
|
248
141
|
const tool = new PerplexitySearchTool();
|
|
249
142
|
|
|
250
143
|
const result = await tool.runBatch({
|
|
251
144
|
version: "1.0.0",
|
|
252
|
-
requests: [{
|
|
253
|
-
op: "search",
|
|
254
|
-
args: { query: "TypeScript best practices", maxResults: 5 }
|
|
255
|
-
}]
|
|
145
|
+
requests: [{ op: "search", args: { query: "TypeScript best practices", maxResults: 5 } }]
|
|
256
146
|
});
|
|
257
147
|
|
|
258
148
|
console.log(result);
|
|
259
149
|
```
|
|
260
150
|
|
|
261
|
-
## Configuration
|
|
262
|
-
|
|
263
|
-
### Simplified Options (Everyday Usage)
|
|
264
|
-
|
|
265
|
-
| Option | Short | Type | Default | Description |
|
|
266
|
-
|--------|-------|------|---------|-------------|
|
|
267
|
-
| `--file` | `-f` | string | - | Attach document (PDF, DOC, DOCX, TXT, RTF, MD) |
|
|
268
|
-
| `--image` | `-i` | string | - | Attach image (PNG, JPEG, WebP, HEIF, HEIC, GIF) |
|
|
269
|
-
| `--format` | `-o` | string | json | Output format: json|jsonl |
|
|
270
|
-
| `--model` | `-m` | string | sonar | AI model: sonar, sonar-pro, sonar-deep-research, sonar-reasoning |
|
|
271
|
-
| `--version` | `-v` | boolean | - | Show version |
|
|
272
|
-
| `--help` | `-h` | boolean | - | Show basic help |
|
|
273
|
-
|
|
274
|
-
### Update Commands
|
|
275
|
-
|
|
276
|
-
| Command | Options | Description |
|
|
277
|
-
|---------|---------|-------------|
|
|
278
|
-
| `pplx update` | `--check` | Check for available updates |
|
|
279
|
-
| `pplx update` | `--auto` | Install available updates automatically |
|
|
280
|
-
| `pplx version` | `--check-updates` | Show version and check for updates |
|
|
281
|
-
| `pplx version` | `--verbose` | Show detailed version information |
|
|
282
|
-
|
|
283
|
-
### Advanced Options (Power Users)
|
|
284
|
-
|
|
285
|
-
| Option | Short | Type | Default | Description |
|
|
286
|
-
|--------|-------|------|---------|-------------|
|
|
287
|
-
| `--input` | `-I` | string | - | Read batch requests from JSON file |
|
|
288
|
-
| `--stdin` | `-s` | boolean | false | Read JSONL requests from stdin |
|
|
289
|
-
| `--concurrency` | `-c` | number | 5 | Max concurrent requests (1-20) |
|
|
290
|
-
| `--timeout` | `-t` | number | 30000 | Request timeout in ms (1000-300000) |
|
|
291
|
-
| `--workspace` | `-w` | string | - | Workspace directory for sandboxing |
|
|
292
|
-
| `--attach` | - | string[] | - | Attach document files (multiple) |
|
|
293
|
-
| `--attach-image` | - | string[] | - | Attach image files (multiple) |
|
|
294
|
-
| `--async` | - | boolean | false | Process requests asynchronously |
|
|
295
|
-
| `--webhook` | - | string | - | Webhook URL for async notifications |
|
|
296
|
-
|
|
|
297
|
-
|
|
298
|
-
### Quick Reference
|
|
299
|
-
|
|
300
|
-
```bash
|
|
301
|
-
# Basic usage (simplified)
|
|
302
|
-
pplx -f doc.pdf -m sonar-pro "analyze this"
|
|
303
|
-
|
|
304
|
-
# Advanced usage (full control)
|
|
305
|
-
pplx -I batch.json -c 10 -t 60000 --format jsonl "process all"
|
|
306
|
-
|
|
307
|
-
# See all available options
|
|
308
|
-
pplx --help
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### AI Models
|
|
312
|
-
|
|
313
|
-
- `sonar` - Fast, concise responses (default)
|
|
314
|
-
- `sonar-pro` - Detailed, comprehensive responses
|
|
315
|
-
- `sonar-deep-research` - In-depth research with web search
|
|
316
|
-
- `sonar-reasoning` - Step-by-step logical reasoning
|
|
317
|
-
|
|
318
|
-
## Output Formats
|
|
319
|
-
|
|
320
|
-
### JSON (Default)
|
|
321
|
-
```json
|
|
322
|
-
{
|
|
323
|
-
"version": "1.0.0",
|
|
324
|
-
"ok": true,
|
|
325
|
-
"summary": {
|
|
326
|
-
"total": 1,
|
|
327
|
-
"successful": 1,
|
|
328
|
-
"failed": 0,
|
|
329
|
-
"totalDuration": 572
|
|
330
|
-
},
|
|
331
|
-
"results": [...]
|
|
332
|
-
}
|
|
333
|
-
```
|
|
334
|
-
|
|
335
|
-
### JSONL (Streaming)
|
|
336
|
-
```bash
|
|
337
|
-
pplx --format jsonl "AI trends"
|
|
338
|
-
```
|
|
339
|
-
Each result printed as a separate JSON line for real-time processing.
|
|
340
|
-
|
|
341
|
-
## Development
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
# Clone and build
|
|
345
|
-
git clone https://github.com/codewithkenzo/pplx-zero.git
|
|
346
|
-
cd pplx-zero
|
|
347
|
-
bun install && bun run build
|
|
348
|
-
|
|
349
|
-
# Development mode
|
|
350
|
-
bun run dev
|
|
351
|
-
|
|
352
|
-
# Type checking
|
|
353
|
-
bun run typecheck
|
|
354
|
-
|
|
355
|
-
# Build for production
|
|
356
|
-
bun run build
|
|
357
|
-
|
|
358
|
-
# Create binary
|
|
359
|
-
bun run build:binary
|
|
360
|
-
```
|
|
361
|
-
|
|
362
|
-
## Architecture
|
|
363
|
-
|
|
364
|
-
- **Bun Runtime** - Fast JavaScript runtime
|
|
365
|
-
- **Zod Validation** - Type-safe schema validation
|
|
366
|
-
- **Error Handling** - Resilient error recovery
|
|
367
|
-
- **Concurrency Control** - Semaphore pattern for rate limiting
|
|
368
|
-
- **Streaming Events** - Real-time progress updates
|
|
369
|
-
|
|
370
|
-
## Security Features
|
|
371
|
-
|
|
372
|
-
- Environment variable API key management
|
|
373
|
-
- Input validation and sanitization
|
|
374
|
-
- Request timeout protection
|
|
375
|
-
- Error information filtering
|
|
376
|
-
- No external dependencies beyond core runtime
|
|
377
|
-
|
|
378
|
-
## Error Handling
|
|
379
|
-
|
|
380
|
-
PPLX-Zero provides comprehensive error classification:
|
|
381
|
-
|
|
382
|
-
```typescript
|
|
383
|
-
enum ErrorCode {
|
|
384
|
-
VALIDATION_ERROR = "VALIDATION_ERROR",
|
|
385
|
-
API_KEY_MISSING = "API_KEY_MISSING",
|
|
386
|
-
API_ERROR = "API_ERROR",
|
|
387
|
-
TIMEOUT_ERROR = "TIMEOUT_ERROR",
|
|
388
|
-
NETWORK_ERROR = "NETWORK_ERROR",
|
|
389
|
-
RATE_LIMIT_ERROR = "RATE_LIMIT_ERROR",
|
|
390
|
-
UNEXPECTED_ERROR = "UNEXPECTED_ERROR"
|
|
391
|
-
}
|
|
392
|
-
```
|
|
393
|
-
|
|
394
|
-
## Contributing
|
|
395
|
-
|
|
396
|
-
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
397
|
-
|
|
398
|
-
## License
|
|
399
|
-
|
|
400
|
-
MIT License - see [LICENSE](LICENSE) file for details.
|
|
401
|
-
|
|
402
|
-
---
|
|
403
151
|
|
|
404
|
-
|
|
152
|
+
### Notes
|
|
153
|
+
- Use pplx --help to see all available options and short flags without scanning long docs.
|
|
154
|
+
- Keep output in jsonl for streaming pipelines and agent frameworks that consume line‑by‑line events.*Built with [Bun](https://bun.sh) and [Perplexity AI](https://www.perplexity.ai)**
|
package/dist/index.js
CHANGED
|
@@ -1883,7 +1883,7 @@ __export(exports_version, {
|
|
|
1883
1883
|
getDescription: () => getDescription,
|
|
1884
1884
|
getAuthor: () => getAuthor,
|
|
1885
1885
|
formatVersionInfo: () => formatVersionInfo,
|
|
1886
|
-
compareVersions: () =>
|
|
1886
|
+
compareVersions: () => compareVersions2
|
|
1887
1887
|
});
|
|
1888
1888
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
1889
1889
|
import { join as join6, dirname as dirname3 } from "node:path";
|
|
@@ -1972,7 +1972,7 @@ async function formatVersionInfo(verbose = false) {
|
|
|
1972
1972
|
}
|
|
1973
1973
|
return `${versionInfo.name} v${versionInfo.version}`;
|
|
1974
1974
|
}
|
|
1975
|
-
function
|
|
1975
|
+
function compareVersions2(version1, version2) {
|
|
1976
1976
|
const v1Parts = version1.split(".").map(Number);
|
|
1977
1977
|
const v2Parts = version2.split(".").map(Number);
|
|
1978
1978
|
const maxLength = Math.max(v1Parts.length, v2Parts.length);
|
|
@@ -1987,7 +1987,7 @@ function compareVersions(version1, version2) {
|
|
|
1987
1987
|
return 0;
|
|
1988
1988
|
}
|
|
1989
1989
|
function isNewerVersion(current, latest) {
|
|
1990
|
-
return
|
|
1990
|
+
return compareVersions2(latest, current) > 0;
|
|
1991
1991
|
}
|
|
1992
1992
|
function parseVersion(version) {
|
|
1993
1993
|
const mainVersion = version.split("-")[0];
|
|
@@ -9118,149 +9118,156 @@ class CliFormatter {
|
|
|
9118
9118
|
import { promises as fs3 } from "node:fs";
|
|
9119
9119
|
import { join as join3 } from "node:path";
|
|
9120
9120
|
import { homedir as homedir3 } from "node:os";
|
|
9121
|
-
|
|
9122
|
-
|
|
9123
|
-
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9129
|
-
|
|
9130
|
-
|
|
9131
|
-
|
|
9132
|
-
|
|
9133
|
-
|
|
9134
|
-
}
|
|
9135
|
-
|
|
9136
|
-
if (!this.config.enabled) {
|
|
9137
|
-
return null;
|
|
9138
|
-
}
|
|
9139
|
-
try {
|
|
9140
|
-
await this.loadUpdateCache();
|
|
9141
|
-
const now = new Date;
|
|
9142
|
-
const timeSinceLastCheck = this.updateCache?.lastChecked ? now.getTime() - this.updateCache.lastChecked.getTime() : Infinity;
|
|
9143
|
-
const checkIntervalMs = this.config.checkInterval * 60 * 1000;
|
|
9144
|
-
if (this.updateCache && timeSinceLastCheck < checkIntervalMs) {
|
|
9145
|
-
return this.updateCache;
|
|
9146
|
-
}
|
|
9147
|
-
const updateInfo = await this.fetchUpdateInfo();
|
|
9148
|
-
await this.saveUpdateCache(updateInfo);
|
|
9149
|
-
if (this.config.autoInstall && updateInfo.updateAvailable) {
|
|
9150
|
-
this.performAutoUpdate(updateInfo).catch((error) => {
|
|
9151
|
-
if (!this.config.quietMode) {
|
|
9152
|
-
console.error("Auto-update failed:", error);
|
|
9153
|
-
}
|
|
9154
|
-
});
|
|
9155
|
-
}
|
|
9156
|
-
return updateInfo;
|
|
9157
|
-
} catch (error) {
|
|
9158
|
-
if (!this.config.quietMode) {
|
|
9159
|
-
console.error("Update check failed:", error);
|
|
9160
|
-
}
|
|
9161
|
-
return null;
|
|
9162
|
-
}
|
|
9163
|
-
}
|
|
9164
|
-
async fetchUpdateInfo() {
|
|
9165
|
-
const currentVersion = await this.getCurrentVersion();
|
|
9166
|
-
try {
|
|
9167
|
-
const npmResponse = await fetch("https://registry.npmjs.org/pplx-zero");
|
|
9168
|
-
const npmData = await npmResponse.json();
|
|
9169
|
-
const latestVersion = npmData["dist-tags"]?.latest || currentVersion;
|
|
9170
|
-
const updateAvailable = this.compareVersions(latestVersion, currentVersion) > 0;
|
|
9171
|
-
return {
|
|
9172
|
-
currentVersion,
|
|
9173
|
-
latestVersion,
|
|
9174
|
-
updateAvailable,
|
|
9175
|
-
lastChecked: new Date,
|
|
9176
|
-
updateUrl: npmData.versions?.[latestVersion]?.dist?.tarball,
|
|
9177
|
-
releaseNotes: npmData.versions?.[latestVersion]?.description
|
|
9178
|
-
};
|
|
9179
|
-
} catch (error) {
|
|
9180
|
-
return {
|
|
9181
|
-
currentVersion,
|
|
9182
|
-
latestVersion: currentVersion,
|
|
9183
|
-
updateAvailable: false,
|
|
9184
|
-
lastChecked: new Date
|
|
9185
|
-
};
|
|
9186
|
-
}
|
|
9121
|
+
var UPDATE_CACHE_FILE = join3(homedir3(), ".pplx-zero", "update-cache.json");
|
|
9122
|
+
var CONFIG_FILE = join3(homedir3(), ".pplx-zero", "config.json");
|
|
9123
|
+
var DEFAULT_CONFIG = {
|
|
9124
|
+
enabled: true,
|
|
9125
|
+
checkInterval: 1440,
|
|
9126
|
+
autoInstall: false,
|
|
9127
|
+
quietMode: true
|
|
9128
|
+
};
|
|
9129
|
+
async function loadAutoUpdateConfig() {
|
|
9130
|
+
try {
|
|
9131
|
+
const configContent = await fs3.readFile(CONFIG_FILE, "utf-8");
|
|
9132
|
+
const config = JSON.parse(configContent);
|
|
9133
|
+
return { ...DEFAULT_CONFIG, ...config.autoUpdate };
|
|
9134
|
+
} catch {
|
|
9135
|
+
return DEFAULT_CONFIG;
|
|
9187
9136
|
}
|
|
9188
|
-
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
|
|
9193
|
-
|
|
9194
|
-
|
|
9137
|
+
}
|
|
9138
|
+
async function saveAutoUpdateConfig(config) {
|
|
9139
|
+
try {
|
|
9140
|
+
const configDir = join3(homedir3(), ".pplx-zero");
|
|
9141
|
+
await fs3.mkdir(configDir, { recursive: true });
|
|
9142
|
+
const existingConfig = await loadAutoUpdateConfig();
|
|
9143
|
+
const updatedConfig = { ...existingConfig, ...config };
|
|
9144
|
+
await fs3.writeFile(CONFIG_FILE, JSON.stringify({ autoUpdate: updatedConfig }, null, 2), "utf-8");
|
|
9145
|
+
} catch (error) {
|
|
9146
|
+
if (process.env.PPLX_DEBUG) {
|
|
9147
|
+
console.error("Failed to save auto-update config:", error);
|
|
9195
9148
|
}
|
|
9196
9149
|
}
|
|
9197
|
-
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
const
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
const v2Part = v2Parts[i] || 0;
|
|
9204
|
-
if (v1Part > v2Part)
|
|
9205
|
-
return 1;
|
|
9206
|
-
if (v1Part < v2Part)
|
|
9207
|
-
return -1;
|
|
9150
|
+
}
|
|
9151
|
+
async function checkForUpdatesCached() {
|
|
9152
|
+
try {
|
|
9153
|
+
const config = await loadAutoUpdateConfig();
|
|
9154
|
+
if (!config.enabled) {
|
|
9155
|
+
return null;
|
|
9208
9156
|
}
|
|
9209
|
-
|
|
9210
|
-
}
|
|
9211
|
-
async loadUpdateCache() {
|
|
9157
|
+
let updateCache = null;
|
|
9212
9158
|
try {
|
|
9213
|
-
const cacheData = await fs3.readFile(
|
|
9214
|
-
|
|
9159
|
+
const cacheData = await fs3.readFile(UPDATE_CACHE_FILE, "utf-8");
|
|
9160
|
+
updateCache = JSON.parse(cacheData);
|
|
9215
9161
|
} catch {
|
|
9216
|
-
|
|
9162
|
+
updateCache = null;
|
|
9217
9163
|
}
|
|
9218
|
-
|
|
9219
|
-
|
|
9220
|
-
|
|
9221
|
-
|
|
9222
|
-
|
|
9223
|
-
|
|
9224
|
-
|
|
9225
|
-
|
|
9226
|
-
|
|
9227
|
-
|
|
9164
|
+
const now = new Date;
|
|
9165
|
+
const timeSinceLastCheck = updateCache?.lastChecked ? now.getTime() - new Date(updateCache.lastChecked).getTime() : Infinity;
|
|
9166
|
+
const checkIntervalMs = config.checkInterval * 60 * 1000;
|
|
9167
|
+
if (updateCache && timeSinceLastCheck < checkIntervalMs) {
|
|
9168
|
+
return updateCache;
|
|
9169
|
+
}
|
|
9170
|
+
const updateInfo = await fetchUpdateInfo();
|
|
9171
|
+
await saveUpdateCache(updateInfo);
|
|
9172
|
+
return updateInfo;
|
|
9173
|
+
} catch (error) {
|
|
9174
|
+
if (process.env.PPLX_DEBUG) {
|
|
9175
|
+
console.error("Update check failed:", error);
|
|
9228
9176
|
}
|
|
9177
|
+
return null;
|
|
9229
9178
|
}
|
|
9230
|
-
|
|
9231
|
-
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9236
|
-
|
|
9237
|
-
|
|
9238
|
-
|
|
9239
|
-
|
|
9240
|
-
|
|
9241
|
-
|
|
9242
|
-
|
|
9243
|
-
|
|
9179
|
+
}
|
|
9180
|
+
async function forceUpdateCheck() {
|
|
9181
|
+
try {
|
|
9182
|
+
await fs3.unlink(UPDATE_CACHE_FILE);
|
|
9183
|
+
} catch {}
|
|
9184
|
+
return fetchUpdateInfo();
|
|
9185
|
+
}
|
|
9186
|
+
async function toggleAutoUpdate(enabled, autoInstall = false) {
|
|
9187
|
+
const config = await loadAutoUpdateConfig();
|
|
9188
|
+
const updatedConfig = {
|
|
9189
|
+
...config,
|
|
9190
|
+
enabled,
|
|
9191
|
+
autoInstall
|
|
9192
|
+
};
|
|
9193
|
+
await saveAutoUpdateConfig(updatedConfig);
|
|
9194
|
+
}
|
|
9195
|
+
async function getAutoUpdateStatus() {
|
|
9196
|
+
const config = await loadAutoUpdateConfig();
|
|
9197
|
+
let updateCache = null;
|
|
9198
|
+
try {
|
|
9199
|
+
const cacheData = await fs3.readFile(UPDATE_CACHE_FILE, "utf-8");
|
|
9200
|
+
updateCache = JSON.parse(cacheData);
|
|
9201
|
+
} catch {
|
|
9202
|
+
updateCache = null;
|
|
9244
9203
|
}
|
|
9245
|
-
|
|
9246
|
-
|
|
9204
|
+
return {
|
|
9205
|
+
enabled: config.enabled,
|
|
9206
|
+
autoInstall: config.autoInstall,
|
|
9207
|
+
lastChecked: updateCache?.lastChecked ? new Date(updateCache.lastChecked) : undefined,
|
|
9208
|
+
updateAvailable: updateCache?.updateAvailable,
|
|
9209
|
+
currentVersion: updateCache?.currentVersion,
|
|
9210
|
+
latestVersion: updateCache?.latestVersion
|
|
9211
|
+
};
|
|
9212
|
+
}
|
|
9213
|
+
async function fetchUpdateInfo() {
|
|
9214
|
+
const currentVersion = await getCurrentVersion();
|
|
9215
|
+
try {
|
|
9216
|
+
const npmResponse = await fetch("https://registry.npmjs.org/pplx-zero");
|
|
9217
|
+
const npmData = await npmResponse.json();
|
|
9218
|
+
const latestVersion = npmData["dist-tags"]?.latest || currentVersion;
|
|
9219
|
+
const updateAvailable = compareVersions(latestVersion, currentVersion) > 0;
|
|
9247
9220
|
return {
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
updateAvailable
|
|
9251
|
-
|
|
9252
|
-
|
|
9221
|
+
currentVersion,
|
|
9222
|
+
latestVersion,
|
|
9223
|
+
updateAvailable,
|
|
9224
|
+
lastChecked: new Date,
|
|
9225
|
+
updateUrl: npmData.versions?.[latestVersion]?.dist?.tarball,
|
|
9226
|
+
releaseNotes: npmData.versions?.[latestVersion]?.description
|
|
9227
|
+
};
|
|
9228
|
+
} catch (error) {
|
|
9229
|
+
return {
|
|
9230
|
+
currentVersion,
|
|
9231
|
+
latestVersion: currentVersion,
|
|
9232
|
+
updateAvailable: false,
|
|
9233
|
+
lastChecked: new Date
|
|
9253
9234
|
};
|
|
9254
9235
|
}
|
|
9255
|
-
|
|
9256
|
-
|
|
9257
|
-
|
|
9258
|
-
|
|
9259
|
-
|
|
9260
|
-
return
|
|
9236
|
+
}
|
|
9237
|
+
async function getCurrentVersion() {
|
|
9238
|
+
try {
|
|
9239
|
+
const packageJsonPath = join3(process.cwd(), "package.json");
|
|
9240
|
+
const packageJson = JSON.parse(await fs3.readFile(packageJsonPath, "utf-8"));
|
|
9241
|
+
return packageJson.version || "1.1.7";
|
|
9242
|
+
} catch {
|
|
9243
|
+
return "1.1.7";
|
|
9244
|
+
}
|
|
9245
|
+
}
|
|
9246
|
+
function compareVersions(version1, version2) {
|
|
9247
|
+
const v1Parts = version1.split(".").map(Number);
|
|
9248
|
+
const v2Parts = version2.split(".").map(Number);
|
|
9249
|
+
const maxLength = Math.max(v1Parts.length, v2Parts.length);
|
|
9250
|
+
for (let i = 0;i < maxLength; i++) {
|
|
9251
|
+
const v1Part = v1Parts[i] || 0;
|
|
9252
|
+
const v2Part = v2Parts[i] || 0;
|
|
9253
|
+
if (v1Part > v2Part)
|
|
9254
|
+
return 1;
|
|
9255
|
+
if (v1Part < v2Part)
|
|
9256
|
+
return -1;
|
|
9257
|
+
}
|
|
9258
|
+
return 0;
|
|
9259
|
+
}
|
|
9260
|
+
async function saveUpdateCache(updateInfo) {
|
|
9261
|
+
try {
|
|
9262
|
+
const configDir = join3(homedir3(), ".pplx-zero");
|
|
9263
|
+
await fs3.mkdir(configDir, { recursive: true });
|
|
9264
|
+
await fs3.writeFile(UPDATE_CACHE_FILE, JSON.stringify(updateInfo, null, 2), "utf-8");
|
|
9265
|
+
} catch (error) {
|
|
9266
|
+
if (process.env.PPLX_DEBUG) {
|
|
9267
|
+
console.error("Failed to save update cache:", error);
|
|
9268
|
+
}
|
|
9261
9269
|
}
|
|
9262
9270
|
}
|
|
9263
|
-
var service_default = AutoUpdateService;
|
|
9264
9271
|
|
|
9265
9272
|
// src/cli/commands/search.ts
|
|
9266
9273
|
function parseNumber(value, defaultValue, min, max, name) {
|
|
@@ -9563,13 +9570,7 @@ async function logToHistory(queries, results, metadata, exportPath) {
|
|
|
9563
9570
|
async function handleSearchCommand(options) {
|
|
9564
9571
|
const startTime = Date.now();
|
|
9565
9572
|
const sessionId = randomUUID3();
|
|
9566
|
-
|
|
9567
|
-
enabled: true,
|
|
9568
|
-
checkInterval: 1440,
|
|
9569
|
-
autoInstall: false,
|
|
9570
|
-
quietMode: true
|
|
9571
|
-
});
|
|
9572
|
-
autoUpdateService.checkForUpdates().catch((error) => {
|
|
9573
|
+
checkForUpdatesCached().catch((error) => {
|
|
9573
9574
|
if (process.env.PPLX_DEBUG) {
|
|
9574
9575
|
console.error("Background update check failed:", error);
|
|
9575
9576
|
}
|
|
@@ -9877,7 +9878,9 @@ import { join as join5 } from "node:path";
|
|
|
9877
9878
|
import { homedir as homedir4 } from "node:os";
|
|
9878
9879
|
async function handleUpdateCommand(options) {
|
|
9879
9880
|
try {
|
|
9880
|
-
if (options.check) {
|
|
9881
|
+
if (options.check && options.auto) {
|
|
9882
|
+
return await handleToggleAutoUpdate();
|
|
9883
|
+
} else if (options.check) {
|
|
9881
9884
|
return await handleUpdateCheck(options.silent);
|
|
9882
9885
|
} else if (options.auto) {
|
|
9883
9886
|
return await handleAutoUpdate();
|
|
@@ -9895,14 +9898,8 @@ async function handleUpdateCommand(options) {
|
|
|
9895
9898
|
}
|
|
9896
9899
|
}
|
|
9897
9900
|
async function handleUpdateCheck(silent = false) {
|
|
9898
|
-
const autoUpdateService = new service_default({
|
|
9899
|
-
enabled: true,
|
|
9900
|
-
checkInterval: 0,
|
|
9901
|
-
autoInstall: false,
|
|
9902
|
-
quietMode: silent
|
|
9903
|
-
});
|
|
9904
9901
|
try {
|
|
9905
|
-
const updateInfo = await
|
|
9902
|
+
const updateInfo = await forceUpdateCheck();
|
|
9906
9903
|
if (!updateInfo) {
|
|
9907
9904
|
const errorMessage = "Update check failed";
|
|
9908
9905
|
if (!silent) {
|
|
@@ -9921,7 +9918,16 @@ async function handleUpdateCheck(silent = false) {
|
|
|
9921
9918
|
if (updateInfo.updateAvailable && !silent) {
|
|
9922
9919
|
const updateMessage = CliFormatter.formatUpdateNotification(updateInfo.currentVersion, updateInfo.latestVersion);
|
|
9923
9920
|
console.log(CliFormatter.supportsColors() ? updateMessage : CliFormatter.formatPlainText(updateMessage));
|
|
9924
|
-
|
|
9921
|
+
const status = await getAutoUpdateStatus();
|
|
9922
|
+
if (status.enabled) {
|
|
9923
|
+
console.log("\uD83D\uDCA1 Auto-updates are enabled");
|
|
9924
|
+
if (status.autoInstall) {
|
|
9925
|
+
console.log("\uD83D\uDD04 Auto-install is enabled - updates will install automatically");
|
|
9926
|
+
}
|
|
9927
|
+
} else {
|
|
9928
|
+
console.log('\uD83D\uDCA1 Run "pplx update --auto --check" to enable auto-updates');
|
|
9929
|
+
console.log(' or run "pplx update --auto" to install manually');
|
|
9930
|
+
}
|
|
9925
9931
|
}
|
|
9926
9932
|
return {
|
|
9927
9933
|
exitCode: 0,
|
|
@@ -9958,13 +9964,7 @@ async function handleAutoUpdate() {
|
|
|
9958
9964
|
} catch {}
|
|
9959
9965
|
await writeFile(updateLockFile, currentPid.toString());
|
|
9960
9966
|
try {
|
|
9961
|
-
const
|
|
9962
|
-
enabled: true,
|
|
9963
|
-
checkInterval: 0,
|
|
9964
|
-
autoInstall: false,
|
|
9965
|
-
quietMode: false
|
|
9966
|
-
});
|
|
9967
|
-
const updateInfo = await autoUpdateService.forceUpdateCheck();
|
|
9967
|
+
const updateInfo = await forceUpdateCheck();
|
|
9968
9968
|
if (!updateInfo || !updateInfo.updateAvailable) {
|
|
9969
9969
|
console.log("ℹ️ No updates available. You are running the latest version.");
|
|
9970
9970
|
return {
|
|
@@ -10051,17 +10051,36 @@ async function executeCommand(command, args) {
|
|
|
10051
10051
|
});
|
|
10052
10052
|
});
|
|
10053
10053
|
}
|
|
10054
|
-
function
|
|
10055
|
-
|
|
10054
|
+
async function handleToggleAutoUpdate() {
|
|
10055
|
+
try {
|
|
10056
|
+
const status = await getAutoUpdateStatus();
|
|
10057
|
+
if (status.enabled) {
|
|
10058
|
+
await toggleAutoUpdate(false);
|
|
10059
|
+
return {
|
|
10060
|
+
exitCode: 0,
|
|
10061
|
+
output: "Auto-updates disabled"
|
|
10062
|
+
};
|
|
10063
|
+
} else {
|
|
10064
|
+
await toggleAutoUpdate(true, false);
|
|
10065
|
+
return {
|
|
10066
|
+
exitCode: 0,
|
|
10067
|
+
output: "Auto-updates enabled"
|
|
10068
|
+
};
|
|
10069
|
+
}
|
|
10070
|
+
} catch (error) {
|
|
10071
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10072
|
+
console.error(`❌ Failed to toggle auto-update: ${errorMessage}`);
|
|
10056
10073
|
return {
|
|
10057
|
-
|
|
10058
|
-
error:
|
|
10074
|
+
exitCode: 1,
|
|
10075
|
+
error: errorMessage
|
|
10059
10076
|
};
|
|
10060
10077
|
}
|
|
10061
|
-
|
|
10078
|
+
}
|
|
10079
|
+
function validateUpdateOptions(options) {
|
|
10080
|
+
if (!options.check && !options.auto) {
|
|
10062
10081
|
return {
|
|
10063
10082
|
valid: false,
|
|
10064
|
-
error: "
|
|
10083
|
+
error: "Either --check or --auto must be specified for update command"
|
|
10065
10084
|
};
|
|
10066
10085
|
}
|
|
10067
10086
|
return { valid: true };
|