@vinitngr/serper-v 1.0.0
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/SKILL.md +20 -0
- package/dist/index.js +105 -0
- package/package.json +38 -0
package/SKILL.md
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: serperV
|
|
3
|
+
description: Real-time web search (news, places, organic) via Serper API.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Serper Search
|
|
7
|
+
|
|
8
|
+
## Usage
|
|
9
|
+
```bash
|
|
10
|
+
serperV search --query "Term" --type search --limit 5
|
|
11
|
+
```
|
|
12
|
+
- **Auth**: `serperV auth <key>` (saves to `~/.vinit/credentials.json`) or `export SERPER_API_KEY=key`.
|
|
13
|
+
- **Types**: `search`, `news`, `places`, `images`, `scholar`, `videos`.
|
|
14
|
+
- **Flags**: `-q` (query), `-l` (limit), `-t` (type), `-g` (country), `-h` (language).
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
`npm install -g @vinitngr/serper-v`
|
|
18
|
+
|
|
19
|
+
## Errors
|
|
20
|
+
If 401/403: Run `serperV auth <new_key>`.
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
3
|
+
import axios from 'axios';
|
|
4
|
+
import fs from 'fs';
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import os from 'os';
|
|
7
|
+
const CONFIG_DIR = path.join(os.homedir(), '.vinit');
|
|
8
|
+
const CONFIG_FILE = path.join(CONFIG_DIR, 'credentials.json');
|
|
9
|
+
function getStoredApiKey() {
|
|
10
|
+
try {
|
|
11
|
+
if (fs.existsSync(CONFIG_FILE)) {
|
|
12
|
+
const config = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'));
|
|
13
|
+
return config.serperV || null;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch (error) {
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const program = new Command();
|
|
21
|
+
program
|
|
22
|
+
.name('serperV')
|
|
23
|
+
.description('Optimal Serper search for AI agents (TypeScript)')
|
|
24
|
+
.version('2.1.0');
|
|
25
|
+
program
|
|
26
|
+
.command('auth')
|
|
27
|
+
.description('Store Serper API key persistently')
|
|
28
|
+
.argument('<key>', 'Your Serper API key')
|
|
29
|
+
.action((key) => {
|
|
30
|
+
try {
|
|
31
|
+
if (!fs.existsSync(CONFIG_DIR)) {
|
|
32
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
33
|
+
}
|
|
34
|
+
const config = fs.existsSync(CONFIG_FILE)
|
|
35
|
+
? JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf-8'))
|
|
36
|
+
: {};
|
|
37
|
+
config.serperV = key;
|
|
38
|
+
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
39
|
+
console.log('\nā
API Key stored successfully in ~/.vinit/credentials.json\n');
|
|
40
|
+
}
|
|
41
|
+
catch (error) {
|
|
42
|
+
console.error('\nā Failed to store API key:', error.message, '\n');
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
program
|
|
47
|
+
.command('search')
|
|
48
|
+
.description('Search the web using Serper API')
|
|
49
|
+
.requiredOption('-q, --query <string>', 'Search query')
|
|
50
|
+
.option('-l, --limit <number>', 'Number of results', (val) => parseInt(val), 10)
|
|
51
|
+
.option('-t, --type <string>', 'Search type (search, news, places, images, scholar, videos, shopping)', 'search')
|
|
52
|
+
.option('-g, --gl <string>', 'Country code (e.g., us, in)', 'us')
|
|
53
|
+
.option('-h, --hl <string>', 'Language code (e.g., en, hi)', 'en')
|
|
54
|
+
.option('-p, --page <number>', 'Page number', (val) => parseInt(val), 1)
|
|
55
|
+
.option('-a, --autocorrect <boolean>', 'Enable/disable autocorrect', (val) => val === 'true', true)
|
|
56
|
+
.action(async (options) => {
|
|
57
|
+
const apiKey = process.env.SERPER_API_KEY || getStoredApiKey();
|
|
58
|
+
if (!apiKey) {
|
|
59
|
+
console.error('\nā Error: Serper API key not found.');
|
|
60
|
+
console.error('š” Please set it using: serperV auth <your_key>');
|
|
61
|
+
console.error('š ļø Or via environment: export SERPER_API_KEY="your_key_here"\n');
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
const config = {
|
|
65
|
+
method: 'post',
|
|
66
|
+
url: `https://google.serper.dev/${options.type}`,
|
|
67
|
+
headers: {
|
|
68
|
+
'X-API-KEY': apiKey,
|
|
69
|
+
'Content-Type': 'application/json'
|
|
70
|
+
},
|
|
71
|
+
data: {
|
|
72
|
+
q: options.query,
|
|
73
|
+
num: options.limit,
|
|
74
|
+
gl: options.gl,
|
|
75
|
+
hl: options.hl,
|
|
76
|
+
page: options.page,
|
|
77
|
+
autocorrect: options.autocorrect
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
try {
|
|
81
|
+
const response = await axios(config);
|
|
82
|
+
console.log(JSON.stringify(response.data, null, 2));
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (axios.isAxiosError(error)) {
|
|
86
|
+
const axiosError = error;
|
|
87
|
+
if (axiosError.response?.status === 401 || axiosError.response?.status === 403) {
|
|
88
|
+
console.error('\nā Error: Unauthorized. Your Serper API key is invalid or expired.');
|
|
89
|
+
console.error('š” Update it using: serperV auth <new_key>\n');
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
console.error('\nā Search failed:', axiosError.response?.data?.message || axiosError.message);
|
|
93
|
+
if (axiosError.response?.data) {
|
|
94
|
+
console.error('Details:', JSON.stringify(axiosError.response.data, null, 2));
|
|
95
|
+
}
|
|
96
|
+
console.error('');
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
console.error('\nā An unexpected error occurred:', error.message, '\n');
|
|
101
|
+
}
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vinitngr/serper-v",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Optimal Serper Search CLI for AI Agents",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"serperV": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"SKILL.md"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc && chmod +x dist/index.js",
|
|
16
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
17
|
+
"test:search": "node test-serper.js"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"serper",
|
|
21
|
+
"search",
|
|
22
|
+
"cli",
|
|
23
|
+
"ai",
|
|
24
|
+
"agent"
|
|
25
|
+
],
|
|
26
|
+
"author": "vinitngr",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"commander": "^11.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/commander": "^2.12.0",
|
|
33
|
+
"@types/node": "^25.2.1",
|
|
34
|
+
"axios": "^1.13.4",
|
|
35
|
+
"ts-node": "^10.9.2",
|
|
36
|
+
"typescript": "^5.9.3"
|
|
37
|
+
}
|
|
38
|
+
}
|