askpplx 1.3.0 → 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 +9 -0
- 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
|
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.3.
|
|
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",
|