askpplx 1.2.2 → 1.3.1
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 +22 -4
- package/dist/cli.js +39 -15
- package/dist/collect-stdin-text.d.ts +1 -0
- package/dist/collect-stdin-text.js +15 -0
- package/dist/resolve-cli-prompt.d.ts +1 -0
- package/dist/resolve-cli-prompt.js +9 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -29,6 +29,15 @@ askpplx "Explain Raft vs Paxos in simple terms"
|
|
|
29
29
|
|
|
30
30
|
# web-enabled search with local context
|
|
31
31
|
askpplx "What are breaking changes in React 19 that affect this code? $(cat src/app.tsx)"
|
|
32
|
+
|
|
33
|
+
# read prompt from stdin (filter style)
|
|
34
|
+
cat article.txt | askpplx -S "Summarize this article"
|
|
35
|
+
|
|
36
|
+
# extract plain text from JSON response
|
|
37
|
+
askpplx "Node.js LTS version" --json | jq -r '.text'
|
|
38
|
+
|
|
39
|
+
# list cited source URLs
|
|
40
|
+
askpplx "Latest TypeScript release notes" --json | jq -r '.sources[].url' | sort -u
|
|
32
41
|
```
|
|
33
42
|
|
|
34
43
|
## Agent Rule
|
|
@@ -36,11 +45,20 @@ askpplx "What are breaking changes in React 19 that affect this code? $(cat src/
|
|
|
36
45
|
Add this rule to your `CLAUDE.md` or `AGENTS.md` to enable automatic Perplexity lookups, no need to configure MCPs:
|
|
37
46
|
|
|
38
47
|
```markdown
|
|
39
|
-
# Rule: askpplx CLI Usage
|
|
48
|
+
# Rule: `askpplx` CLI Usage
|
|
49
|
+
|
|
50
|
+
**MANDATORY:** Run `npx -y askpplx --help` at the start of every agent session to learn available options and confirm the tool is working.
|
|
51
|
+
|
|
52
|
+
Use `askpplx` to query Perplexity, an AI search engine combining real-time web search with advanced language models.
|
|
53
|
+
|
|
54
|
+
## Why This Matters
|
|
40
55
|
|
|
41
|
-
|
|
56
|
+
- **Ground your knowledge:** Your training data has a cutoff date. Real-time search ensures you work with current information—correct API signatures, latest versions, up-to-date best practices.
|
|
57
|
+
- **Save time and resources:** A quick lookup is far cheaper than debugging hallucinated code or explaining why an approach failed. When in doubt, verify first.
|
|
58
|
+
- **Reduce false confidence:** Even when you feel certain, external verification catches subtle errors before they compound into larger problems.
|
|
59
|
+
- **Stay current:** Libraries change, APIs deprecate, patterns evolve. What was correct six months ago may be wrong today.
|
|
42
60
|
|
|
43
|
-
|
|
61
|
+
## Usage Guidelines
|
|
44
62
|
|
|
45
|
-
Verification is fast and cheap
|
|
63
|
+
Use concise prompts for quick facts and focused questions for deeper topics. If results are unexpected, refine your query and ask again. Verification is fast and cheap—prefer looking up information over making assumptions.
|
|
46
64
|
```
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command } from "commander";
|
|
2
|
+
import { Command, Option } from "@commander-js/extra-typings";
|
|
3
3
|
import packageJson from "../package.json" with { type: "json" };
|
|
4
4
|
import { clearPerplexityApiKey, getConfigPath, getPerplexityApiKey, maskApiKey, setPerplexityApiKey, } from "./config.js";
|
|
5
5
|
import { runCli } from "./run-cli.js";
|
|
6
|
+
import { collectStdinText } from "./collect-stdin-text.js";
|
|
7
|
+
import { resolveCliPrompt } from "./resolve-cli-prompt.js";
|
|
6
8
|
const usageExamples = `
|
|
7
9
|
About Perplexity:
|
|
8
10
|
Perplexity AI is an AI-powered search engine and answer engine that delivers
|
|
@@ -28,28 +30,51 @@ Examples:
|
|
|
28
30
|
askpplx "Latest news on AI" -c medium
|
|
29
31
|
askpplx "$(cat article.txt)" -s ./summarize.md
|
|
30
32
|
askpplx "$(cat article.txt)" -S "Summarize this article"
|
|
33
|
+
cat article.txt | askpplx -S "Summarize this article"
|
|
31
34
|
askpplx "Node.js LTS version" --json | jq -r '.text'
|
|
32
35
|
askpplx "Show reasoning" --show-thinking`;
|
|
33
36
|
const program = new Command()
|
|
34
|
-
.name(
|
|
37
|
+
.name(packageJson.name)
|
|
35
38
|
.description(packageJson.description)
|
|
36
39
|
.version(packageJson.version)
|
|
40
|
+
.showHelpAfterError("(add --help for additional information)")
|
|
41
|
+
.showSuggestionAfterError()
|
|
37
42
|
.argument("[prompt]", "The prompt to send to Perplexity Sonar")
|
|
38
43
|
.option("-m, --model <model>", "Model to use", "sonar-reasoning-pro")
|
|
39
44
|
.option("-s, --system <path>", "Path to custom system prompt file")
|
|
40
45
|
.option("-S, --system-text <text>", "System prompt text (overrides -s)")
|
|
41
|
-
.
|
|
46
|
+
.addOption(new Option("-c, --context <size>", "Search context size: low, medium, high")
|
|
47
|
+
.choices(["low", "medium", "high"])
|
|
48
|
+
.default("high"))
|
|
42
49
|
.option("--json", "Output full API response as JSON (text, sources, usage)")
|
|
43
50
|
.option("--show-thinking", "Show model thinking/reasoning blocks")
|
|
44
|
-
.option("--no-stream
|
|
51
|
+
.option("--no-stream", "Disable streaming output")
|
|
52
|
+
.addOption(new Option("--no-streaming", "Alias for --no-stream").hideHelp())
|
|
45
53
|
.addHelpText("after", usageExamples)
|
|
46
54
|
.action(async (prompt, options) => {
|
|
47
|
-
if (!prompt) {
|
|
48
|
-
program.help();
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
55
|
try {
|
|
52
|
-
|
|
56
|
+
let stdinText;
|
|
57
|
+
if (!prompt && !process.stdin.isTTY) {
|
|
58
|
+
process.stdin.setEncoding("utf8");
|
|
59
|
+
stdinText = await collectStdinText(process.stdin);
|
|
60
|
+
}
|
|
61
|
+
const effectivePrompt = resolveCliPrompt(prompt, stdinText);
|
|
62
|
+
if (!effectivePrompt) {
|
|
63
|
+
program.error("Missing prompt.\n" +
|
|
64
|
+
'Usage: askpplx <prompt> OR cat <file> | askpplx -S "Summarize this article"\n' +
|
|
65
|
+
"(Note: use -S to provide an instruction with stdin input)", { exitCode: 1 });
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const cliOptions = {
|
|
69
|
+
model: options.model,
|
|
70
|
+
json: Boolean(options.json),
|
|
71
|
+
system: options.system,
|
|
72
|
+
systemText: options.systemText,
|
|
73
|
+
context: options.context,
|
|
74
|
+
showThinking: Boolean(options.showThinking),
|
|
75
|
+
stream: options.stream && options.streaming,
|
|
76
|
+
};
|
|
77
|
+
await runCli(effectivePrompt, cliOptions);
|
|
53
78
|
}
|
|
54
79
|
catch (error) {
|
|
55
80
|
const message = error instanceof Error ? error.message : "An unexpected error occurred";
|
|
@@ -57,7 +82,7 @@ const program = new Command()
|
|
|
57
82
|
process.exitCode = 1;
|
|
58
83
|
}
|
|
59
84
|
});
|
|
60
|
-
program
|
|
85
|
+
const configCommand = program
|
|
61
86
|
.command("config")
|
|
62
87
|
.description("Manage stored configuration")
|
|
63
88
|
.option("--set-api-key <key>", "Store Perplexity API key")
|
|
@@ -68,7 +93,7 @@ program
|
|
|
68
93
|
try {
|
|
69
94
|
if (options.setApiKey) {
|
|
70
95
|
setPerplexityApiKey(options.setApiKey);
|
|
71
|
-
console.
|
|
96
|
+
console.error("API key stored successfully.");
|
|
72
97
|
}
|
|
73
98
|
else if (options.showApiKey) {
|
|
74
99
|
const key = getPerplexityApiKey();
|
|
@@ -77,14 +102,13 @@ program
|
|
|
77
102
|
}
|
|
78
103
|
else if (options.clearApiKey) {
|
|
79
104
|
clearPerplexityApiKey();
|
|
80
|
-
console.
|
|
105
|
+
console.error("API key cleared.");
|
|
81
106
|
}
|
|
82
107
|
else if (options.path) {
|
|
83
108
|
console.log(getConfigPath());
|
|
84
109
|
}
|
|
85
110
|
else {
|
|
86
|
-
|
|
87
|
-
configCmd?.help();
|
|
111
|
+
configCommand.help({ error: true });
|
|
88
112
|
}
|
|
89
113
|
}
|
|
90
114
|
catch (error) {
|
|
@@ -95,4 +119,4 @@ program
|
|
|
95
119
|
process.exitCode = 1;
|
|
96
120
|
}
|
|
97
121
|
});
|
|
98
|
-
program.
|
|
122
|
+
await program.parseAsync();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function collectStdinText(input: AsyncIterable<string>, maxBytes?: number): Promise<string>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Buffer } from "node:buffer";
|
|
2
|
+
const DEFAULT_MAX_STDIN_BYTES = 10 * 1024 * 1024;
|
|
3
|
+
export async function collectStdinText(input, maxBytes = DEFAULT_MAX_STDIN_BYTES) {
|
|
4
|
+
const chunks = [];
|
|
5
|
+
let totalBytes = 0;
|
|
6
|
+
for await (const chunk of input) {
|
|
7
|
+
totalBytes += Buffer.byteLength(chunk, "utf8");
|
|
8
|
+
if (totalBytes > maxBytes) {
|
|
9
|
+
const limitMegabytes = Math.round(maxBytes / 1024 / 1024);
|
|
10
|
+
throw new Error(`Input too large: exceeds ${String(limitMegabytes)}MB limit`);
|
|
11
|
+
}
|
|
12
|
+
chunks.push(chunk);
|
|
13
|
+
}
|
|
14
|
+
return chunks.join("");
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveCliPrompt(promptArgument: string | undefined, stdinText?: string): string | undefined;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export function resolveCliPrompt(promptArgument, stdinText) {
|
|
2
|
+
const candidate = (promptArgument ?? stdinText)?.trimEnd();
|
|
3
|
+
if (candidate === undefined)
|
|
4
|
+
return undefined;
|
|
5
|
+
const trimmedCandidate = candidate.trim();
|
|
6
|
+
if (trimmedCandidate.length === 0)
|
|
7
|
+
return undefined;
|
|
8
|
+
return candidate;
|
|
9
|
+
}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "askpplx",
|
|
3
3
|
"author": "Łukasz Jerciński",
|
|
4
4
|
"license": "MIT",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.3.1",
|
|
6
6
|
"description": "Minimal Unix-style CLI for querying Perplexity Sonar API.",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -42,6 +42,7 @@
|
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"@ai-sdk/perplexity": "^2.0.21",
|
|
45
|
+
"@commander-js/extra-typings": "^14.0.0",
|
|
45
46
|
"ai": "^5.0.108",
|
|
46
47
|
"commander": "^14.0.2",
|
|
47
48
|
"conf": "^15.0.2",
|