pplx-zero 1.1.7 → 1.1.8

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.
Files changed (3) hide show
  1. package/README.md +452 -60
  2. package/dist/index.js +106 -17
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,102 +1,248 @@
1
1
  # PPLX‑Zero
2
2
 
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.
3
+ 🚀 **Lightning-fast Perplexity AI in your terminal** — sub‑1s search responses with multimodal support. Built for developers, coding agents, and automation workflows that demand speed and reliability.
5
4
 
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.
5
+ Perfect for rapid research, document analysis, image understanding, and batch processing with minimal configuration.
10
6
 
11
- ### Install
12
- Choose one:
7
+ ---
8
+
9
+ ## ✨ What Makes PPLX‑Zero Special
10
+
11
+ - **⚡ Blazing Fast**: Get answers in under a second with optimized API calls
12
+ - **🧠 Smart Models**: Choose from Sonar, Sonar‑Pro, Sonar‑Reasoning, and Deep‑Research models
13
+ - **📎 Multimodal**: Analyze documents, images, and combinations seamlessly
14
+ - **🔄 Auto‑Update**: Stay current with simplified update management
15
+ - **⚙️ Developer‑First**: Built for CI/CD, agent pipelines, and programmatic use
16
+ - **🎯 Minimal Setup**: One environment variable and you're ready to go
17
+
18
+ ## 📦 Installation
19
+
20
+ Choose the installation method that works best for you:
21
+
22
+ ### 🚀 Quick Install (Recommended)
13
23
 
14
24
  ```bash
15
25
  # npm or bun (global)
16
26
  npm install -g pplx-zero
27
+ # or
28
+ bun install -g pplx-zero
29
+
30
+ # Verify installation
17
31
  pplx --version
18
32
  ```
19
33
 
34
+ ### 📦 Binary Download (No Node.js required)
20
35
 
21
- or
36
+ ```bash
37
+ # Download the appropriate binary for your platform
38
+ # Linux (x64) - Most servers and desktops
39
+ wget https://github.com/codewithkenzo/pplx-zero/releases/latest/download/pplx-v1.1.7-linux-x64
40
+ chmod +x pplx-v1.1.7-linux-x64
41
+ sudo mv pplx-v1.1.7-linux-x64 /usr/local/bin/pplx
42
+
43
+ # Linux (ARM64) - Raspberry Pi, ARM servers
44
+ wget https://github.com/codewithkenzo/pplx-zero/releases/latest/download/pplx-v1.1.7-linux-arm64
45
+ chmod +x pplx-v1.1.7-linux-arm64
46
+ sudo mv pplx-v1.1.7-linux-arm64 /usr/local/bin/pplx
47
+
48
+ # macOS (Intel) - Macs with Intel processors
49
+ wget https://github.com/codewithkenzo/pplx-zero/releases/latest/download/pplx-v1.1.7-darwin-x64
50
+ chmod +x pplx-v1.1.7-darwin-x64
51
+ sudo mv pplx-v1.1.7-darwin-x64 /usr/local/bin/pplx
52
+
53
+ # macOS (Apple Silicon) - Macs with M1/M2/M3 chips
54
+ wget https://github.com/codewithkenzo/pplx-zero/releases/latest/download/pplx-v1.1.7-darwin-arm64
55
+ chmod +x pplx-v1.1.7-darwin-arm64
56
+ sudo mv pplx-v1.1.7-darwin-arm64 /usr/local/bin/pplx
57
+
58
+ # Windows (x64) - Most Windows computers
59
+ # Download pplx-v1.1.7-windows-x64.exe from GitHub releases
60
+ # Add to your PATH or run directly
61
+ ```
62
+
63
+ **Alternative Installation Script (Linux/macOS):**
22
64
 
23
65
  ```bash
24
- # AUR (Arch Linux)
66
+ # Automated installation script
67
+ curl -sSL https://github.com/codewithkenzo/pplx-zero/releases/latest/download/pplx-v1.1.7-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/x64/') -o pplx
68
+ chmod +x pplx
69
+ sudo mv pplx /usr/local/bin/pplx
70
+ ```
71
+
72
+ ### 🏛️ AUR (Arch Linux)
73
+
74
+ ```bash
75
+ # Using yay (recommended)
25
76
  yay -S pplx-zero
77
+
78
+ # Using paru
79
+ paru -S pplx-zero
80
+
81
+ # Verify installation
26
82
  pplx --version
27
83
  ```
28
84
 
29
-
30
- or
85
+ ### 🔧 Build from Source
31
86
 
32
87
  ```bash
33
- # Build from source
34
- # 1) clone the repository
35
- # 2) enter the folder
36
- # 3) build and link the CLI
88
+ # 1) Clone the repository
89
+ git clone https://github.com/codewithkenzo/pplx-zero.git
90
+ cd pplx-zero
91
+
92
+ # 2) Install dependencies and build
37
93
  bun install && bun run build
38
- sudo ln -s "$(pwd)/dist/cli.js" /usr/local/bin/pplx
94
+
95
+ # 3) Link the CLI (system-wide)
96
+ sudo ln -s "$(pwd)/dist/index.js" /usr/local/bin/pplx
97
+
98
+ # 4) Verify installation
39
99
  pplx --version
40
100
  ```
41
101
 
102
+ ---
42
103
 
43
- ### Configure
44
- Set your API key as an environment variable before running commands.
104
+ ## ⚙️ Configuration
45
105
 
46
- Linux/macOS:
106
+ ### API Key Setup
107
+
108
+ Set your Perplexity API key as an environment variable:
109
+
110
+ **Linux/macOS:**
47
111
  ```bash
112
+ # Temporary (current session)
48
113
  export PERPLEXITY_API_KEY="your-api-key"
114
+
115
+ # Permanent (add to ~/.bashrc, ~/.zshrc, etc.)
116
+ echo 'export PERPLEXITY_API_KEY="your-api-key"' >> ~/.bashrc
117
+ source ~/.bashrc
49
118
  ```
50
119
 
120
+ **Windows (PowerShell):**
121
+ ```powershell
122
+ # Temporary (current session)
123
+ $env:PERPLEXITY_API_KEY = "your-api-key"
124
+
125
+ # Permanent
126
+ [Environment]::SetEnvironmentVariable("PERPLEXITY_API_KEY", "your-api-key", "User")
127
+ ```
51
128
 
52
- Windows:
129
+ **Windows (CMD):**
53
130
  ```cmd
131
+ # Permanent
54
132
  setx PERPLEXITY_API_KEY "your-api-key"
55
133
  ```
56
134
 
135
+ > 🔑 **Get your API key** from your [Perplexity account settings](https://www.perplexity.ai/settings/api) and keep it secure. Never share your API key or commit it to version control.
57
136
 
58
- Get your key from your Perplexity account and keep it private to your machine or CI secrets manager.
137
+ ---
138
+
139
+ ## 🔄 Auto‑Update Management
140
+
141
+ PPLX‑Zero includes a simplified auto‑update system that keeps you current with the latest features and security updates.
142
+
143
+ ### Basic Update Commands
59
144
 
60
- ### Quick examples
61
- Simple search (default model: sonar)
62
145
  ```bash
63
- pplx "python type hints best practices"
146
+ # Check for available updates
147
+ pplx update --check
148
+
149
+ # Install updates and relaunch automatically
150
+ pplx update --auto
64
151
  ```
65
152
 
153
+ ### Update Workflow
154
+
155
+ 1. **Automatic Notifications**: PPLX‑Zero checks for updates once per day and notifies you when a new version is available
156
+ 2. **Smart Installation**: The updater detects your installation method (npm, AUR, binary) and uses the appropriate update mechanism
157
+ 3. **Seamless Relaunch**: When using `--auto`, PPLX‑Zero installs the update and relaunches with your original command
158
+
159
+ ### Advanced Update Options
66
160
 
67
- Deep research or sonar-pro or reasoning when you need more steps or web context
68
161
  ```bash
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)"
162
+ # Force update check (ignores cache)
163
+ pplx update --check
164
+
165
+ # Update during automation without interaction
166
+ pplx update --auto --quiet
72
167
  ```
73
168
 
169
+ ### Troubleshooting Updates
170
+
171
+ | Issue | Solution |
172
+ |-------|----------|
173
+ | **Permission denied** | Run with `sudo` or check installation directory permissions |
174
+ | **Network timeout** | Check internet connection and try again |
175
+ | **Update fails** | Manually install using your original installation method |
176
+ | **Lock file error** | Wait for current update to complete or manually remove `~/.pplx-zero/.updating.lock` |
177
+
178
+ The auto‑update system respects your system configuration and won't modify files without proper permissions.
179
+
180
+ ---
181
+
182
+ ## 🚀 Quick Examples
183
+
184
+ ### Basic Search
74
185
 
75
- Summarize a PDF report quickly
76
186
  ```bash
77
- pplx -f report.pdf "summarize key findings and risks"
187
+ # Simple search (default model: sonar)
188
+ pplx "python type hints best practices"
189
+
190
+ # Multiple queries in one command
191
+ pplx "React hooks tutorial" "TypeScript generics" "Docker best practices"
78
192
  ```
79
193
 
194
+ ### Advanced Models
80
195
 
81
- Understand an interface from a screenshot
82
196
  ```bash
83
- pplx -i screenshot.png "what is this UI and what are the next steps?"
197
+ # Research with Sonar Pro (more detailed analysis)
198
+ pplx -m sonar-pro "React 19 Hooks new features"
199
+
200
+ # Deep research with comprehensive web context
201
+ pplx -m sonar-deep-research "best Rust web frameworks 2025"
202
+
203
+ # Mathematical reasoning and proofs
204
+ pplx -m sonar-reasoning "prove this algorithm runs in O(n log n)"
84
205
  ```
85
206
 
207
+ ### Document & Image Analysis
86
208
 
87
- Combine a doc and an image in one prompt
88
209
  ```bash
210
+ # Summarize a PDF report quickly
211
+ pplx -f report.pdf "summarize key findings and risks"
212
+
213
+ # Understand an interface from a screenshot
214
+ pplx -i screenshot.png "what is this UI and what are the next steps?"
215
+
216
+ # Combine multiple files in one analysis
89
217
  pplx -f data.csv -i chart.png "spot anomalies and explain the chart"
218
+
219
+ # Multiple file attachments
220
+ pplx -f report.pdf --attach data.csv --attach summary.md "analyze all documents"
221
+
222
+ # Multiple documents of same type using --attach
223
+ pplx --attach doc1.pdf --attach doc2.pdf --attach doc3.txt "compare all reports"
224
+
225
+ # Multiple images using --attach-image
226
+ pplx --attach-image screenshot1.png --attach-image screenshot2.png "analyze the UI flow"
227
+
228
+ # Mixed multiple files (documents + images)
229
+ pplx -f main.pdf --attach appendix.md --attach-image chart.png --attach-image diagram.jpg "comprehensive analysis"
230
+
231
+ # Multiple files with positional arguments (all treated as files)
232
+ pplx file1.pdf file2.txt file3.md "what's in these files"
90
233
  ```
91
234
 
235
+ ### Batch Processing
92
236
 
93
- Stream newline‑delimited JSON for agents or UNIX pipes
94
237
  ```bash
95
- pplx -o jsonl "ai trends"
96
- ```
238
+ # Stream newline-delimited JSON for agents or UNIX pipes
239
+ pplx -o jsonl "AI trends"
97
240
 
241
+ # Batch from a JSON file with custom concurrency
242
+ pplx -I queries.json -o jsonl -c 5 -t 30000
243
+ ```
98
244
 
99
- Batch from a JSON file (concurrency and timeout shown)
245
+ **Batch JSON format:**
100
246
  ```json
101
247
  {
102
248
  "version": "1.0.0",
@@ -108,47 +254,293 @@ Batch from a JSON file (concurrency and timeout shown)
108
254
  }
109
255
  ```
110
256
 
257
+ ### Advanced Workflows
111
258
 
112
259
  ```bash
113
- pplx -I queries.json -o jsonl -c 5 -t 30000
260
+ # Fire-and-forget async with webhook callback
261
+ pplx --async --webhook http://localhost:3000/callback "long research task"
262
+
263
+ # Export results to file
264
+ pplx --export results.json "machine learning trends"
265
+
266
+ # Search with custom result limits
267
+ pplx -n 10 "latest web development frameworks"
268
+
269
+ # Query from stdin (for pipelines)
270
+ echo '{"query": "best practices for API design"}' | pplx -s
114
271
  ```
115
272
 
273
+ ### Real‑World Scenarios
116
274
 
117
- Fire‑and‑forget async with a webhook callback (agent workflows)
118
275
  ```bash
119
- pplx --async --webhook http://localhost:3000/callback "long research task"
276
+ # Security researcher: Analyze vulnerability report
277
+ pplx -f vuln_report.pdf --attach screenshots/ "explain security implications"
278
+
279
+ # Data analyst: Extract insights from datasets
280
+ pplx -f sales_data.csv -i revenue_chart.png "identify growth opportunities"
281
+
282
+ # Developer: Code review and optimization
283
+ pplx -f app.py --attach perf_metrics.json "suggest performance improvements"
284
+
285
+ # Product manager: Competitive analysis
286
+ pplx -f competitor_data.pdf "summarize key differentiators and market position"
120
287
  ```
121
288
 
122
289
 
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
290
+ ---
291
+
292
+ ## 📋 Command Reference
293
+
294
+ ### Main Options
295
+
296
+ | Flag | Short | Description | Example |
297
+ |------|-------|-------------|---------|
298
+ | `--model` | `-m` | AI model to use | `-m sonar-pro` |
299
+ | `--max-results` | `-n` | Max results per query (1-20) | `-n 10` |
300
+ | `--file` | `-f` | Attach document for analysis | `-f report.pdf` |
301
+ | `--image` | `-i` | Attach image for analysis | `-i screenshot.png` |
302
+ | `--format` | `-o` | Output format: json/jsonl | `-o jsonl` |
303
+ | `--query` | `-q` | Search query (alternative to positional) | `-q "search term"` |
304
+ | `--export` | | Export results to file | `--export results.json` |
305
+ | `--input` | `-I` | Read queries from JSON file | `-I batch.json` |
306
+ | `--stdin` | `-s` | Read queries from stdin | `cat query.json \| pplx -s` |
307
+ | `--attach` | | Additional file attachments | `--attach file1.pdf --attach file2.txt` |
308
+ | `--attach-image` | | Additional image attachments | `--attach-image img1.png --attach-image img2.jpg` |
309
+ | `--async` | | Enable async mode for advanced models | `--async` |
310
+ | `--webhook` | | Webhook URL for async results | `--webhook http://localhost:3000` |
311
+ | `--workspace` | | Workspace directory for file operations | `--workspace ./project` |
312
+ | `--use-search-api` | | Use search API (default: true) | `--use-search-api` |
313
+ | `--batch-size` | | Batch size for processing (1-100) | `--batch-size 50` |
314
+
315
+ ### Performance & Control
316
+
317
+ | Flag | Description | Default | Range |
318
+ |------|-------------|---------|-------|
319
+ | `--concurrency` | Max parallel requests for batch operations | 5 | 1-20 |
320
+ | `--timeout` | Request timeout in milliseconds | 30000 | 1000-300000 |
321
+
322
+ ### Utility Commands
323
+
324
+ | Command | Description | Example |
325
+ |---------|-------------|---------|
326
+ | `update --check` | Check for available updates | `pplx update --check` |
327
+ | `update --auto` | Install updates and relaunch | `pplx update --auto` |
328
+ | `history [limit]` | Show search history | `pplx history 10` |
329
+ | `version` | Show version information | `pplx version` |
330
+ | `--help` | Show help message | `pplx --help` |
331
+ | `--version` | Show version number | `pplx --version` |
332
+
333
+ ### Supported File Formats
334
+
335
+ **Documents (up to 50MB):**
336
+ - PDF, DOC, DOCX, TXT, RTF, MD
337
+ - CSV, JSON (structured data)
338
+ - XML, YAML (configuration files)
339
+
340
+ **Images (up to 50MB):**
341
+ - PNG, JPEG, WebP, HEIF/HEIC, GIF
342
+ - BMP, TIFF (legacy formats)
343
+
344
+ ### AI Models
345
+
346
+ | Model | Best For | Speed | Detail |
347
+ |-------|----------|-------|--------|
348
+ | `sonar` | Quick answers, general queries | ⚡ Fast | Standard detail |
349
+ | `sonar-pro` | Detailed analysis, research | 🚀 Fast | Enhanced detail |
350
+ | `sonar-reasoning` | Mathematical reasoning, logic | 🐢 Moderate | Step-by-step |
351
+ | `sonar-deep-research` | Comprehensive research with web context | 🐌 Slow | Maximum detail |
352
+
353
+ ---
354
+
355
+ ## 💻 Programmatic Use
356
+
357
+ ### TypeScript API
135
358
 
136
- ### Programmatic use (optional)
137
359
  Use the toolkit directly in TypeScript when embedding into agents or services.
360
+
138
361
  ```ts
139
362
  import { PerplexitySearchTool } from 'pplx-zero';
140
363
 
364
+ // Initialize the search tool
141
365
  const tool = new PerplexitySearchTool();
142
366
 
143
- const result = await tool.runBatch({
144
- version: "1.0.0",
145
- requests: [{ op: "search", args: { query: "TypeScript best practices", maxResults: 5 } }]
367
+ // Single search query
368
+ const result = await tool.search({
369
+ query: "TypeScript best practices",
370
+ model: "sonar-pro",
371
+ maxResults: 5
146
372
  });
147
373
 
148
374
  console.log(result);
149
375
  ```
150
376
 
377
+ ### Batch Processing
378
+
379
+ ```ts
380
+ import { PerplexitySearchTool } from 'pplx-zero';
381
+
382
+ const tool = new PerplexitySearchTool();
383
+
384
+ // Batch search with custom configuration
385
+ const batchResult = await tool.runBatch({
386
+ version: "1.0.0",
387
+ requests: [
388
+ {
389
+ op: "search",
390
+ args: {
391
+ query: "TypeScript best practices",
392
+ maxResults: 5,
393
+ model: "sonar-pro"
394
+ }
395
+ },
396
+ {
397
+ op: "search",
398
+ args: {
399
+ query: "React performance optimization",
400
+ maxResults: 3,
401
+ model: "sonar"
402
+ }
403
+ }
404
+ ],
405
+ options: {
406
+ concurrency: 3,
407
+ timeoutMs: 30000
408
+ }
409
+ });
410
+
411
+ console.log('Batch results:', batchResult);
412
+ ```
413
+
414
+ ### Advanced Usage with Error Handling
415
+
416
+ ```ts
417
+ import { PerplexitySearchTool } from 'pplx-zero';
418
+
419
+ async function searchWithRetry(query: string, maxRetries = 3) {
420
+ const tool = new PerplexitySearchTool();
421
+
422
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
423
+ try {
424
+ const result = await tool.search({
425
+ query,
426
+ model: "sonar-pro",
427
+ maxResults: 5
428
+ });
429
+
430
+ return result;
431
+ } catch (error) {
432
+ if (attempt === maxRetries) {
433
+ throw new Error(`Search failed after ${maxRetries} attempts: ${error}`);
434
+ }
435
+
436
+ // Exponential backoff
437
+ await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
438
+ }
439
+ }
440
+ }
441
+
442
+ // Usage
443
+ searchWithRetry("latest AI trends")
444
+ .then(result => console.log(result))
445
+ .catch(error => console.error(error));
446
+ ```
447
+
448
+ ---
449
+
450
+ ## 🛠️ Troubleshooting
451
+
452
+ ### Common Issues & Solutions
453
+
454
+ #### API Key Problems
455
+ ```bash
456
+ # Error: "API key not found"
457
+ export PERPLEXITY_API_KEY="your-api-key"
458
+
459
+ # Verify key is set
460
+ echo $PERPLEXITY_API_KEY
461
+ ```
462
+
463
+ #### File Attachment Issues
464
+ ```bash
465
+ # Error: "File too large" (files must be < 50MB)
466
+ ls -lh your-file.pdf
467
+
468
+ # Supported formats check
469
+ file your-document.pdf # Should show PDF format
470
+ ```
471
+
472
+ #### Network/Timeout Issues
473
+ ```bash
474
+ # Increase timeout for complex queries
475
+ pplx -t 60000 "complex research question"
476
+
477
+ # Check internet connectivity
478
+ curl -I https://api.perplexity.ai
479
+ ```
480
+
481
+ #### Permission Issues
482
+ ```bash
483
+ # Permission denied during installation
484
+ npm install -g pplx-zero --unsafe-perm
485
+
486
+ # Or use npx to avoid global installation
487
+ npx pplx-zero "your query"
488
+ ```
489
+
490
+ ### Debug Mode
491
+
492
+ ```bash
493
+ # Enable verbose output for debugging
494
+ DEBUG=pplx:* pplx "your query"
495
+
496
+ # Check configuration
497
+ pplx --version
498
+ pplx update --check
499
+ ```
500
+
501
+ ### Performance Tips
502
+
503
+ | Scenario | Recommended Settings |
504
+ |----------|---------------------|
505
+ | **Quick searches** | Default settings (sonar model) |
506
+ | **Deep research** | `-m sonar-deep-research -t 60000` |
507
+ | **Batch processing** | `-c 10 -t 45000` |
508
+ | **File analysis** | `-m sonar-pro -t 60000` |
509
+ | **Real-time queries** | `-m sonar -n 3` |
510
+
511
+ ---
512
+
513
+ ## 📚 Additional Resources
514
+
515
+ - **GitHub Repository**: [github.com/codewithkenzo/pplx-zero](https://github.com/codewithkenzo/pplx-zero)
516
+ - **Bug Reports & Issues**: [GitHub Issues](https://github.com/codewithkenzo/pplx-zero/issues)
517
+ - **Perplexity API Documentation**: [docs.perplexity.ai](https://docs.perplexity.ai)
518
+ - **Model Comparison**: Detailed model comparison in the [AI Models](#ai-models) section above
519
+
520
+ ---
521
+
522
+ ### Quick Reference Commands
523
+
524
+ ```bash
525
+ # Show all available options
526
+ pplx --help
527
+
528
+ # Check for updates
529
+ pplx update --check
530
+
531
+ # Auto-update
532
+ pplx update --auto
533
+
534
+ # Show version
535
+ pplx --version
536
+
537
+ # Search history
538
+ pplx history 10
539
+
540
+ # Quick test
541
+ pplx "test query"
542
+ ```
543
+
544
+ ---
151
545
 
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)**
546
+ *Built with ❤️ using [Bun](https://bun.sh) and powered by [Perplexity AI](https://www.perplexity.ai)*
package/dist/index.js CHANGED
@@ -2008,7 +2008,7 @@ function isValidVersion(version) {
2008
2008
  const semverRegex = /^(\d+)\.(\d+)\.(\d+)(?:-([a-zA-Z0-9.-]+))?(?:\+([a-zA-Z0-9.-]+))?$/;
2009
2009
  return semverRegex.test(version);
2010
2010
  }
2011
- var __filename2, __dirname2, FALLBACK_VERSION = "1.1.4", FALLBACK_PACKAGE_INFO, packageJsonCache = null;
2011
+ var __filename2, __dirname2, FALLBACK_VERSION = "1.1.8", FALLBACK_PACKAGE_INFO, packageJsonCache = null;
2012
2012
  var init_version = __esm(() => {
2013
2013
  __filename2 = fileURLToPath(import.meta.url);
2014
2014
  __dirname2 = dirname3(__filename2);
@@ -7857,7 +7857,7 @@ ${textContent}`
7857
7857
  async executeAdvancedModel(query, options = {}) {
7858
7858
  const startTime = performance.now();
7859
7859
  try {
7860
- const { model, attachments, webhook } = options;
7860
+ const { model, attachments, webhook, timeout } = options;
7861
7861
  if (model === "sonar-pro" || model === "sonar-deep-research" || model === "sonar-reasoning") {
7862
7862
  let messages = [];
7863
7863
  if (attachments && attachments.length > 0) {
@@ -7902,12 +7902,13 @@ ${textContent}`
7902
7902
  { role: "user", content: query }
7903
7903
  ];
7904
7904
  }
7905
+ const effectiveTimeout = model === "sonar-deep-research" ? Math.max(timeout || 300000, 300000) : timeout || this.config.timeout;
7905
7906
  const response = await this.executeWithTimeout(this.client.chat.completions.create({
7906
7907
  model,
7907
7908
  messages,
7908
7909
  max_tokens: options.maxTokens || 4000,
7909
7910
  temperature: options.temperature || 0.1
7910
- }), this.config.timeout);
7911
+ }), effectiveTimeout);
7911
7912
  let content = "";
7912
7913
  if (response && response.choices && response.choices.length > 0) {
7913
7914
  const choice = response.choices[0];
@@ -9238,9 +9239,9 @@ async function getCurrentVersion() {
9238
9239
  try {
9239
9240
  const packageJsonPath = join3(process.cwd(), "package.json");
9240
9241
  const packageJson = JSON.parse(await fs3.readFile(packageJsonPath, "utf-8"));
9241
- return packageJson.version || "1.1.7";
9242
+ return packageJson.version || "1.1.8";
9242
9243
  } catch {
9243
- return "1.1.7";
9244
+ return "1.1.8";
9244
9245
  }
9245
9246
  }
9246
9247
  function compareVersions(version1, version2) {
@@ -9325,7 +9326,13 @@ async function parseQueries(options) {
9325
9326
  metadata = { lineCount };
9326
9327
  } else if (options.input) {
9327
9328
  source = "file";
9328
- const fileContent = await Bun.file(options.input).text();
9329
+ let fileContent;
9330
+ if (typeof Bun !== "undefined") {
9331
+ fileContent = await Bun.file(options.input).text();
9332
+ } else {
9333
+ const fs4 = await import("node:fs");
9334
+ fileContent = await fs4.promises.readFile(options.input, "utf-8");
9335
+ }
9329
9336
  const parsed = JSON.parse(fileContent);
9330
9337
  if (parsed.queries && Array.isArray(parsed.queries)) {
9331
9338
  queries.push(...parsed.queries);
@@ -9358,7 +9365,8 @@ async function executeSearch(query, options, filePaths = []) {
9358
9365
  response = await engine.executeAdvancedModel(query, {
9359
9366
  model: options.model,
9360
9367
  attachments,
9361
- webhook: options.webhook
9368
+ webhook: options.webhook,
9369
+ timeout: options.timeout
9362
9370
  });
9363
9371
  result = {
9364
9372
  success: true,
@@ -9599,14 +9607,58 @@ async function handleSearchCommand(options) {
9599
9607
  positionals: options.positionals
9600
9608
  });
9601
9609
  const filePaths = [];
9602
- if (options.file)
9610
+ const filesToValidate = [];
9611
+ if (options.file) {
9603
9612
  filePaths.push(options.file);
9604
- if (options.image)
9613
+ filesToValidate.push(options.file);
9614
+ }
9615
+ if (options.image) {
9605
9616
  filePaths.push(options.image);
9606
- if (options.attach)
9617
+ filesToValidate.push(options.image);
9618
+ }
9619
+ if (options.attach) {
9607
9620
  filePaths.push(...options.attach);
9608
- if (options.attachImage)
9621
+ filesToValidate.push(...options.attach);
9622
+ }
9623
+ if (options.attachImage) {
9609
9624
  filePaths.push(...options.attachImage);
9625
+ filesToValidate.push(...options.attachImage);
9626
+ }
9627
+ if (filesToValidate.length > 0) {
9628
+ const missingFiles = [];
9629
+ for (const filePath of filesToValidate) {
9630
+ try {
9631
+ if (typeof Bun !== "undefined") {
9632
+ const file = Bun.file(filePath);
9633
+ if (!await file.exists()) {
9634
+ missingFiles.push(filePath);
9635
+ } else if (file.size === 0) {
9636
+ throw new Error(`File is empty: ${filePath}`);
9637
+ }
9638
+ } else {
9639
+ const fs4 = await import("node:fs");
9640
+ const stats = await fs4.promises.stat(filePath);
9641
+ if (!stats.isFile()) {
9642
+ missingFiles.push(filePath);
9643
+ } else if (stats.size === 0) {
9644
+ throw new Error(`File is empty: ${filePath}`);
9645
+ }
9646
+ }
9647
+ } catch (error) {
9648
+ if (error instanceof Error && error.message.includes("File is empty")) {
9649
+ throw error;
9650
+ }
9651
+ missingFiles.push(filePath);
9652
+ }
9653
+ }
9654
+ if (missingFiles.length > 0) {
9655
+ const fileList = missingFiles.length === 1 ? `File "${missingFiles[0]}" does not exist or is not readable` : `Files do not exist or are not readable:
9656
+ ${missingFiles.map((f) => ` - ${f}`).join(`
9657
+ `)}`;
9658
+ throw new Error(`${fileList}
9659
+ Please check the file paths and try again.`);
9660
+ }
9661
+ }
9610
9662
  const searchOptions = {
9611
9663
  maxResults,
9612
9664
  concurrency,
@@ -10104,7 +10156,7 @@ class UpdateChecker {
10104
10156
  return await getVersion2();
10105
10157
  } catch (error) {
10106
10158
  console.error("Failed to read current version:", error);
10107
- return "1.1.4";
10159
+ return "1.1.8";
10108
10160
  }
10109
10161
  }
10110
10162
  async getLatestVersion() {
@@ -10236,7 +10288,7 @@ async function handleVersionCommand(options) {
10236
10288
  }
10237
10289
  } catch (error) {
10238
10290
  const errorMessage = error instanceof Error ? error.message : String(error);
10239
- const fallbackVersion = "pplx-zero v1.1.4";
10291
+ const fallbackVersion = "pplx-zero v1.1.8";
10240
10292
  console.log(fallbackVersion);
10241
10293
  if (!errorMessage.includes("ENOENT") && !errorMessage.includes("package.json")) {
10242
10294
  const formattedError = CliFormatter.formatError(`Warning: ${errorMessage}`);
@@ -10299,8 +10351,8 @@ function validateVersionOptions(options) {
10299
10351
 
10300
10352
  // src/cli/index.ts
10301
10353
  var program2 = new Command;
10302
- program2.name("pplx").description("Fast Perplexity AI search CLI with multi-search, history, and export").version("1.1.4", "-v, --version", "Show version information").helpOption("-h, --help", "Show this help message");
10303
- program2.option("-m, --model <model>", "AI model: sonar, sonar-pro, sonar-reasoning, sonar-deep-research").option("-n, --max-results <n>", "Maximum results per query (default: 5, range: 1-20)", "5").option("-c, --concurrency <n>", "Concurrency for batch searches (default: 5, range: 1-20)", "5").option("-t, --timeout <ms>", "Request timeout in milliseconds (default: 30000, range: 1000-300000)", "30000").option("-f, --file <file>", "Attach document for analysis").option("-i, --image <file>", "Attach image for analysis").option("-o, --format <format>", "Output format: json|jsonl (default: json)", "json").option("-q, --query <query>", "Search query (alternative to positional queries)").option("--export <filename>", "Export results to file").option("-I, --input <file>", "Read queries from JSON file").option("-s, --stdin", "Read queries from stdin (JSON format)").option("--attach <files...>", "Additional file attachments (multiple allowed)").option("--attach-image <files...>", "Additional image attachments (multiple allowed)").option("--async", "Enable async mode for advanced models").option("--webhook <url>", "Webhook URL for async results").option("--workspace <path>", "Workspace directory for file operations").option("--use-search-api", "Use search API (default: true)", true).option("--batch-size <n>", "Batch size for processing (default: 20, range: 1-100)", "20").allowExcessArguments(true).argument("[queries...]", "Search queries (multiple queries enable multi-search)");
10354
+ program2.name("pplx").description("Fast Perplexity AI search CLI with multi-search, history, and export").version("1.1.8", "-v, --version", "Show version information").helpOption("-h, --help", "Show this help message");
10355
+ program2.option("-m, --model <model>", "AI model: sonar, sonar-pro, sonar-reasoning, sonar-deep-research").option("-n, --max-results <n>", "Maximum results per query (default: 5, range: 1-20)", "5").option("-c, --concurrency <n>", "Concurrency for batch searches (default: 5, range: 1-20)", "5").option("-t, --timeout <ms>", "Request timeout in milliseconds (default: 30000, range: 1000-300000)", "30000").option("-f, --file <file>", "Attach document for analysis").option("-i, --image <file>", "Attach image for analysis").option("-o, --format <format>", "Output format: json|jsonl (default: json)", "json").option("-q, --query <query>", "Search query (alternative to positional queries)").option("--export <filename>", "Export results to file").option("-I, --input <file>", "Read queries from JSON file").option("-s, --stdin", "Read queries from stdin (JSON format)").option("--attach <file>", "Additional file attachment (can be used multiple times)").option("--attach-image <file>", "Additional image attachment (can be used multiple times)").option("--async", "Enable async mode for advanced models").option("--webhook <url>", "Webhook URL for async results").option("--workspace <path>", "Workspace directory for file operations").option("--use-search-api", "Use search API (default: true)", true).option("--batch-size <n>", "Batch size for processing (default: 20, range: 1-100)", "20").allowExcessArguments(true).argument("[queries...]", "Search queries (multiple queries enable multi-search)");
10304
10356
  program2.command("history").description("Show search history").argument("[limit]", "Number of recent searches to show (max 50)").option("-f, --files", "Show individual search files with query+date naming").option("--query-pattern <pattern>", "Filter search files by query pattern").action(async (limit, options, command) => {
10305
10357
  const args = command.parent?.args.slice(command.parent.args.indexOf(command.name()) + 1) || [];
10306
10358
  const historyOptions = parseHistoryArgs(args);
@@ -10388,7 +10440,44 @@ program2.hook("preSubcommand", async (thisCommand) => {
10388
10440
  process.exit(result.exitCode);
10389
10441
  }
10390
10442
  });
10443
+ function parseAttachOptions(rawArgs) {
10444
+ const attach = [];
10445
+ const attachImage = [];
10446
+ const remainingArgs = [];
10447
+ let i = 0;
10448
+ while (i < rawArgs.length) {
10449
+ const arg = rawArgs[i];
10450
+ if (arg === "--attach") {
10451
+ if (i + 1 < rawArgs.length && !rawArgs[i + 1].startsWith("-")) {
10452
+ attach.push(rawArgs[i + 1]);
10453
+ i += 2;
10454
+ } else {
10455
+ console.error("Error: --attach requires a file path");
10456
+ process.exit(1);
10457
+ }
10458
+ } else if (arg === "--attach-image") {
10459
+ if (i + 1 < rawArgs.length && !rawArgs[i + 1].startsWith("-")) {
10460
+ attachImage.push(rawArgs[i + 1]);
10461
+ i += 2;
10462
+ } else {
10463
+ console.error("Error: --attach-image requires a file path");
10464
+ process.exit(1);
10465
+ }
10466
+ } else {
10467
+ remainingArgs.push(arg);
10468
+ i += 1;
10469
+ }
10470
+ }
10471
+ return { attach, attachImage, remainingArgs };
10472
+ }
10473
+ var rawArgs = process.argv.slice(2);
10474
+ var { attach: attachFiles, attachImage: attachImages, remainingArgs } = parseAttachOptions(rawArgs);
10475
+ var collectedAttach = attachFiles;
10476
+ var collectedAttachImages = attachImages;
10477
+ var originalArgv = process.argv;
10478
+ process.argv = ["node", originalArgv[1], ...remainingArgs];
10391
10479
  program2.action(async (queries, options) => {
10480
+ process.argv = originalArgv;
10392
10481
  const result = await handleSearchCommand({
10393
10482
  query: options.query,
10394
10483
  file: options.file,
@@ -10402,8 +10491,8 @@ program2.action(async (queries, options) => {
10402
10491
  useSearchAPI: options.useSearchApi,
10403
10492
  stdin: options.stdin,
10404
10493
  input: options.input,
10405
- attach: options.attach || [],
10406
- attachImage: options.attachImage || [],
10494
+ attach: collectedAttach,
10495
+ attachImage: collectedAttachImages,
10407
10496
  export: options.export,
10408
10497
  async: options.async,
10409
10498
  webhook: options.webhook,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pplx-zero",
3
- "version": "1.1.7",
3
+ "version": "1.1.8",
4
4
  "description": "Fast Perplexity AI search CLI with multimodal support - minimal setup, maximal results",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",