@vibemastery/zurf 0.1.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/LICENSE +21 -0
- package/README.md +541 -0
- package/bin/dev.cmd +3 -0
- package/bin/dev.js +28 -0
- package/bin/run.cmd +3 -0
- package/bin/run.js +17 -0
- package/dist/commands/config/which.d.ts +10 -0
- package/dist/commands/config/which.js +61 -0
- package/dist/commands/fetch/index.d.ts +17 -0
- package/dist/commands/fetch/index.js +111 -0
- package/dist/commands/init/index.d.ts +15 -0
- package/dist/commands/init/index.js +95 -0
- package/dist/commands/search/index.d.ts +14 -0
- package/dist/commands/search/index.js +59 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/lib/browserbase-client.d.ts +12 -0
- package/dist/lib/browserbase-client.js +16 -0
- package/dist/lib/browserbase-command.d.ts +8 -0
- package/dist/lib/browserbase-command.js +16 -0
- package/dist/lib/cli-errors.d.ts +19 -0
- package/dist/lib/cli-errors.js +36 -0
- package/dist/lib/config.d.ts +34 -0
- package/dist/lib/config.js +66 -0
- package/dist/lib/fetch-output.d.ts +20 -0
- package/dist/lib/fetch-output.js +23 -0
- package/dist/lib/flags.d.ts +6 -0
- package/dist/lib/flags.js +10 -0
- package/dist/lib/gitignore-zurf.d.ts +5 -0
- package/dist/lib/gitignore-zurf.js +45 -0
- package/dist/lib/init-input.d.ts +2 -0
- package/dist/lib/init-input.js +26 -0
- package/dist/lib/json-output.d.ts +3 -0
- package/dist/lib/json-output.js +11 -0
- package/dist/lib/search-output.d.ts +16 -0
- package/dist/lib/search-output.js +20 -0
- package/dist/lib/zurf-browserbase-command.d.ts +8 -0
- package/dist/lib/zurf-browserbase-command.js +36 -0
- package/oclif.manifest.json +213 -0
- package/package.json +90 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import * as readline from 'node:readline';
|
|
2
|
+
export async function readStdinIfPiped() {
|
|
3
|
+
if (process.stdin.isTTY) {
|
|
4
|
+
return undefined;
|
|
5
|
+
}
|
|
6
|
+
try {
|
|
7
|
+
const chunks = [];
|
|
8
|
+
for await (const chunk of process.stdin) {
|
|
9
|
+
chunks.push(chunk);
|
|
10
|
+
}
|
|
11
|
+
const s = Buffer.concat(chunks).toString('utf8').trim();
|
|
12
|
+
return s.length > 0 ? s : undefined;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function promptLine(question) {
|
|
19
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
20
|
+
return new Promise((resolve) => {
|
|
21
|
+
rl.question(question, (answer) => {
|
|
22
|
+
rl.close();
|
|
23
|
+
resolve(answer.trim());
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function printJson(value) {
|
|
2
|
+
process.stdout.write(`${JSON.stringify(value)}\n`);
|
|
3
|
+
}
|
|
4
|
+
/** JSON errors use stdout on purpose so `--json` callers get a single stream for piping/parsing. */
|
|
5
|
+
export function printErrorJson(message, code) {
|
|
6
|
+
const payload = { error: { message } };
|
|
7
|
+
if (code !== undefined) {
|
|
8
|
+
payload.error.code = code;
|
|
9
|
+
}
|
|
10
|
+
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
|
11
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export type SearchResultRow = {
|
|
2
|
+
author?: string;
|
|
3
|
+
title: string;
|
|
4
|
+
url: string;
|
|
5
|
+
};
|
|
6
|
+
export type SearchResponseForDisplay = {
|
|
7
|
+
query: string;
|
|
8
|
+
requestId: string;
|
|
9
|
+
results: SearchResultRow[];
|
|
10
|
+
};
|
|
11
|
+
export declare function buildSearchJsonPayload(response: SearchResponseForDisplay): {
|
|
12
|
+
query: string;
|
|
13
|
+
requestId: string;
|
|
14
|
+
results: SearchResultRow[];
|
|
15
|
+
};
|
|
16
|
+
export declare function linesForHumanSearch(response: SearchResponseForDisplay): string[];
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function buildSearchJsonPayload(response) {
|
|
2
|
+
return {
|
|
3
|
+
query: response.query,
|
|
4
|
+
requestId: response.requestId,
|
|
5
|
+
results: response.results,
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function linesForHumanSearch(response) {
|
|
9
|
+
const lines = [`requestId: ${response.requestId}`, ''];
|
|
10
|
+
for (const [i, r] of response.results.entries()) {
|
|
11
|
+
const block = [
|
|
12
|
+
`${i + 1}. ${r.title}`,
|
|
13
|
+
` ${r.url}`,
|
|
14
|
+
...(r.author ? [` author: ${r.author}`] : []),
|
|
15
|
+
'',
|
|
16
|
+
];
|
|
17
|
+
lines.push(...block);
|
|
18
|
+
}
|
|
19
|
+
return lines;
|
|
20
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { Browserbase } from '@browserbasehq/sdk';
|
|
2
|
+
import { Command } from '@oclif/core';
|
|
3
|
+
/** Shared behavior for commands that call Browserbase: client resolution, optional spinner, unified API error handling. */
|
|
4
|
+
export declare abstract class ZurfBrowserbaseCommand extends Command {
|
|
5
|
+
protected runWithBrowserbase(flags: {
|
|
6
|
+
json: boolean;
|
|
7
|
+
}, spinnerLabel: string, work: (client: Browserbase) => Promise<void>): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Command, ux } from '@oclif/core';
|
|
2
|
+
import { getBrowserbaseClientOrExit } from './browserbase-command.js';
|
|
3
|
+
import { cliError, errorMessage, errorStatus } from './cli-errors.js';
|
|
4
|
+
/** Shared behavior for commands that call Browserbase: client resolution, optional spinner, unified API error handling. */
|
|
5
|
+
export class ZurfBrowserbaseCommand extends Command {
|
|
6
|
+
async runWithBrowserbase(flags, spinnerLabel, work) {
|
|
7
|
+
const { client } = await getBrowserbaseClientOrExit(this, flags, {
|
|
8
|
+
globalConfigDir: this.config.configDir,
|
|
9
|
+
});
|
|
10
|
+
const run = async () => {
|
|
11
|
+
try {
|
|
12
|
+
await work(client);
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
cliError({
|
|
16
|
+
command: this,
|
|
17
|
+
exitCode: 1,
|
|
18
|
+
json: flags.json,
|
|
19
|
+
message: errorMessage(error),
|
|
20
|
+
statusCode: errorStatus(error),
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
if (flags.json) {
|
|
25
|
+
await run();
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
ux.action.start(spinnerLabel);
|
|
29
|
+
try {
|
|
30
|
+
await run();
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
ux.action.stop();
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
{
|
|
2
|
+
"commands": {
|
|
3
|
+
"config:which": {
|
|
4
|
+
"aliases": [],
|
|
5
|
+
"args": {},
|
|
6
|
+
"description": "Show where the Browserbase API key would be loaded from (no secret printed).\nResolution order: BROWSERBASE_API_KEY, then project .zurf/config.json (walk-up), then global config in the CLI config directory.",
|
|
7
|
+
"examples": [
|
|
8
|
+
"<%= config.bin %> config which",
|
|
9
|
+
"<%= config.bin %> config which --json"
|
|
10
|
+
],
|
|
11
|
+
"flags": {
|
|
12
|
+
"json": {
|
|
13
|
+
"description": "Print machine-readable JSON to stdout",
|
|
14
|
+
"env": "ZURF_JSON",
|
|
15
|
+
"name": "json",
|
|
16
|
+
"allowNo": false,
|
|
17
|
+
"type": "boolean"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"hasDynamicHelp": false,
|
|
21
|
+
"hiddenAliases": [],
|
|
22
|
+
"id": "config:which",
|
|
23
|
+
"pluginAlias": "@vibemastery/zurf",
|
|
24
|
+
"pluginName": "@vibemastery/zurf",
|
|
25
|
+
"pluginType": "core",
|
|
26
|
+
"strict": true,
|
|
27
|
+
"summary": "Show where the API key is loaded from",
|
|
28
|
+
"enableJsonFlag": false,
|
|
29
|
+
"isESM": true,
|
|
30
|
+
"relativePath": [
|
|
31
|
+
"dist",
|
|
32
|
+
"commands",
|
|
33
|
+
"config",
|
|
34
|
+
"which.js"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"fetch": {
|
|
38
|
+
"aliases": [],
|
|
39
|
+
"args": {
|
|
40
|
+
"url": {
|
|
41
|
+
"description": "URL to fetch",
|
|
42
|
+
"name": "url",
|
|
43
|
+
"required": true
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
"description": "Fetch a URL via Browserbase (no browser session; static HTML, 1 MB max).\nRequires authentication. Run `zurf init --global` or use a project key before first use.",
|
|
47
|
+
"examples": [
|
|
48
|
+
"<%= config.bin %> <%= command.id %> https://example.com",
|
|
49
|
+
"<%= config.bin %> <%= command.id %> https://example.com --json",
|
|
50
|
+
"<%= config.bin %> <%= command.id %> https://example.com -o page.html --proxies"
|
|
51
|
+
],
|
|
52
|
+
"flags": {
|
|
53
|
+
"json": {
|
|
54
|
+
"description": "Print machine-readable JSON to stdout",
|
|
55
|
+
"env": "ZURF_JSON",
|
|
56
|
+
"name": "json",
|
|
57
|
+
"allowNo": false,
|
|
58
|
+
"type": "boolean"
|
|
59
|
+
},
|
|
60
|
+
"allow-insecure-ssl": {
|
|
61
|
+
"description": "Disable TLS certificate verification (use only if you trust the target)",
|
|
62
|
+
"name": "allow-insecure-ssl",
|
|
63
|
+
"allowNo": false,
|
|
64
|
+
"type": "boolean"
|
|
65
|
+
},
|
|
66
|
+
"allow-redirects": {
|
|
67
|
+
"description": "Follow HTTP redirects",
|
|
68
|
+
"name": "allow-redirects",
|
|
69
|
+
"allowNo": false,
|
|
70
|
+
"type": "boolean"
|
|
71
|
+
},
|
|
72
|
+
"output": {
|
|
73
|
+
"char": "o",
|
|
74
|
+
"description": "Write response body to this file (full content); otherwise human mode prints a truncated preview to stdout",
|
|
75
|
+
"name": "output",
|
|
76
|
+
"hasDynamicHelp": false,
|
|
77
|
+
"multiple": false,
|
|
78
|
+
"type": "option"
|
|
79
|
+
},
|
|
80
|
+
"proxies": {
|
|
81
|
+
"description": "Route through Browserbase proxies (helps with some blocked sites)",
|
|
82
|
+
"name": "proxies",
|
|
83
|
+
"allowNo": false,
|
|
84
|
+
"type": "boolean"
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
"hasDynamicHelp": false,
|
|
88
|
+
"hiddenAliases": [],
|
|
89
|
+
"id": "fetch",
|
|
90
|
+
"pluginAlias": "@vibemastery/zurf",
|
|
91
|
+
"pluginName": "@vibemastery/zurf",
|
|
92
|
+
"pluginType": "core",
|
|
93
|
+
"strict": true,
|
|
94
|
+
"summary": "Fetch a URL via Browserbase",
|
|
95
|
+
"isESM": true,
|
|
96
|
+
"relativePath": [
|
|
97
|
+
"dist",
|
|
98
|
+
"commands",
|
|
99
|
+
"fetch",
|
|
100
|
+
"index.js"
|
|
101
|
+
]
|
|
102
|
+
},
|
|
103
|
+
"search": {
|
|
104
|
+
"aliases": [],
|
|
105
|
+
"args": {
|
|
106
|
+
"query": {
|
|
107
|
+
"description": "Search query, max 200 characters (quote for multiple words)",
|
|
108
|
+
"name": "query",
|
|
109
|
+
"required": true
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"description": "Search the web via Browserbase (Exa-powered).\nRequires authentication. Run `zurf init --global` or use a project key before first use.",
|
|
113
|
+
"examples": [
|
|
114
|
+
"<%= config.bin %> <%= command.id %> \"browserbase documentation\"",
|
|
115
|
+
"<%= config.bin %> <%= command.id %> \"laravel inertia\" --num-results 5 --json"
|
|
116
|
+
],
|
|
117
|
+
"flags": {
|
|
118
|
+
"json": {
|
|
119
|
+
"description": "Print machine-readable JSON to stdout",
|
|
120
|
+
"env": "ZURF_JSON",
|
|
121
|
+
"name": "json",
|
|
122
|
+
"allowNo": false,
|
|
123
|
+
"type": "boolean"
|
|
124
|
+
},
|
|
125
|
+
"num-results": {
|
|
126
|
+
"char": "n",
|
|
127
|
+
"description": "Number of results (1–25)",
|
|
128
|
+
"name": "num-results",
|
|
129
|
+
"default": 10,
|
|
130
|
+
"hasDynamicHelp": false,
|
|
131
|
+
"multiple": false,
|
|
132
|
+
"type": "option"
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
"hasDynamicHelp": false,
|
|
136
|
+
"hiddenAliases": [],
|
|
137
|
+
"id": "search",
|
|
138
|
+
"pluginAlias": "@vibemastery/zurf",
|
|
139
|
+
"pluginName": "@vibemastery/zurf",
|
|
140
|
+
"pluginType": "core",
|
|
141
|
+
"strict": true,
|
|
142
|
+
"summary": "Search the web via Browserbase",
|
|
143
|
+
"isESM": true,
|
|
144
|
+
"relativePath": [
|
|
145
|
+
"dist",
|
|
146
|
+
"commands",
|
|
147
|
+
"search",
|
|
148
|
+
"index.js"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
"init": {
|
|
152
|
+
"aliases": [],
|
|
153
|
+
"args": {},
|
|
154
|
+
"description": "Save your Browserbase API key to global or project config.\nGlobal path follows oclif config (same as `zurf config which`).",
|
|
155
|
+
"examples": [
|
|
156
|
+
"<%= config.bin %> <%= command.id %> --global",
|
|
157
|
+
"<%= config.bin %> <%= command.id %> --local",
|
|
158
|
+
"printenv BROWSERBASE_API_KEY | <%= config.bin %> <%= command.id %> --global"
|
|
159
|
+
],
|
|
160
|
+
"flags": {
|
|
161
|
+
"json": {
|
|
162
|
+
"description": "Print machine-readable JSON to stdout",
|
|
163
|
+
"env": "ZURF_JSON",
|
|
164
|
+
"name": "json",
|
|
165
|
+
"allowNo": false,
|
|
166
|
+
"type": "boolean"
|
|
167
|
+
},
|
|
168
|
+
"api-key": {
|
|
169
|
+
"description": "API key for non-interactive use. Prefer piping stdin or using a TTY prompt — values on the command line are visible in shell history and process listings.",
|
|
170
|
+
"name": "api-key",
|
|
171
|
+
"hasDynamicHelp": false,
|
|
172
|
+
"multiple": false,
|
|
173
|
+
"type": "option"
|
|
174
|
+
},
|
|
175
|
+
"gitignore": {
|
|
176
|
+
"description": "Append .zurf/ to ./.gitignore if that entry is missing",
|
|
177
|
+
"name": "gitignore",
|
|
178
|
+
"allowNo": false,
|
|
179
|
+
"type": "boolean"
|
|
180
|
+
},
|
|
181
|
+
"global": {
|
|
182
|
+
"description": "Store API key in user config (oclif config dir for this CLI)",
|
|
183
|
+
"name": "global",
|
|
184
|
+
"allowNo": false,
|
|
185
|
+
"type": "boolean"
|
|
186
|
+
},
|
|
187
|
+
"local": {
|
|
188
|
+
"description": "Store API key in ./.zurf/config.json for this directory",
|
|
189
|
+
"name": "local",
|
|
190
|
+
"allowNo": false,
|
|
191
|
+
"type": "boolean"
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
"hasDynamicHelp": false,
|
|
195
|
+
"hiddenAliases": [],
|
|
196
|
+
"id": "init",
|
|
197
|
+
"pluginAlias": "@vibemastery/zurf",
|
|
198
|
+
"pluginName": "@vibemastery/zurf",
|
|
199
|
+
"pluginType": "core",
|
|
200
|
+
"strict": true,
|
|
201
|
+
"summary": "Configure Browserbase API key storage",
|
|
202
|
+
"enableJsonFlag": false,
|
|
203
|
+
"isESM": true,
|
|
204
|
+
"relativePath": [
|
|
205
|
+
"dist",
|
|
206
|
+
"commands",
|
|
207
|
+
"init",
|
|
208
|
+
"index.js"
|
|
209
|
+
]
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
"version": "0.1.0"
|
|
213
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@vibemastery/zurf",
|
|
3
|
+
"description": "A lightweight CLI for searching and fetching web pages, powered by Browserbase.",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": "Luis Güette",
|
|
6
|
+
"bin": {
|
|
7
|
+
"zurf": "./bin/run.js"
|
|
8
|
+
},
|
|
9
|
+
"bugs": "https://github.com/vibemastery/zurf/issues",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@browserbasehq/sdk": "^2.9.0",
|
|
12
|
+
"@oclif/core": "^4",
|
|
13
|
+
"@oclif/plugin-autocomplete": "^3.2.42",
|
|
14
|
+
"@oclif/plugin-help": "^6",
|
|
15
|
+
"@oclif/plugin-not-found": "^3.2.77",
|
|
16
|
+
"@oclif/plugin-plugins": "^5",
|
|
17
|
+
"@oclif/plugin-warn-if-update-available": "^3.1.57"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@eslint/compat": "^1",
|
|
21
|
+
"@oclif/prettier-config": "^0.2.1",
|
|
22
|
+
"@oclif/test": "^4",
|
|
23
|
+
"@types/chai": "^4",
|
|
24
|
+
"@types/mocha": "^10",
|
|
25
|
+
"@types/node": "^18",
|
|
26
|
+
"chai": "^4",
|
|
27
|
+
"eslint": "^9",
|
|
28
|
+
"eslint-config-oclif": "^6",
|
|
29
|
+
"eslint-config-prettier": "^10",
|
|
30
|
+
"mocha": "^11",
|
|
31
|
+
"oclif": "^4",
|
|
32
|
+
"shx": "^0.3.3",
|
|
33
|
+
"ts-node": "^10",
|
|
34
|
+
"typescript": "^5"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=18.0.0"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"./bin",
|
|
41
|
+
"./dist",
|
|
42
|
+
"./oclif.manifest.json"
|
|
43
|
+
],
|
|
44
|
+
"homepage": "https://github.com/vibemastery/zurf",
|
|
45
|
+
"keywords": [
|
|
46
|
+
"oclif",
|
|
47
|
+
"browserbase",
|
|
48
|
+
"web-search",
|
|
49
|
+
"cli"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"main": "dist/index.js",
|
|
53
|
+
"type": "module",
|
|
54
|
+
"oclif": {
|
|
55
|
+
"bin": "zurf",
|
|
56
|
+
"dirname": "zurf",
|
|
57
|
+
"commands": "./dist/commands",
|
|
58
|
+
"plugins": [
|
|
59
|
+
"@oclif/plugin-autocomplete",
|
|
60
|
+
"@oclif/plugin-help",
|
|
61
|
+
"@oclif/plugin-not-found",
|
|
62
|
+
"@oclif/plugin-plugins",
|
|
63
|
+
"@oclif/plugin-warn-if-update-available"
|
|
64
|
+
],
|
|
65
|
+
"macos": {
|
|
66
|
+
"identifier": "ai.vibemastery.zurf"
|
|
67
|
+
},
|
|
68
|
+
"topicSeparator": " ",
|
|
69
|
+
"topics": {
|
|
70
|
+
"config": {
|
|
71
|
+
"description": "Inspect zurf configuration"
|
|
72
|
+
},
|
|
73
|
+
"init": {
|
|
74
|
+
"description": "Configure Browserbase API key storage"
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
"repository": "vibemastery/zurf",
|
|
79
|
+
"scripts": {
|
|
80
|
+
"build": "shx rm -rf dist && tsc -b",
|
|
81
|
+
"lint": "eslint",
|
|
82
|
+
"postpack": "shx rm -f oclif.manifest.json",
|
|
83
|
+
"posttest": "pnpm run lint",
|
|
84
|
+
"prepack": "oclif manifest && oclif readme",
|
|
85
|
+
"pretest": "pnpm run build",
|
|
86
|
+
"test": "mocha --forbid-only \"test/**/*.test.ts\"",
|
|
87
|
+
"version": "oclif readme && git add README.md"
|
|
88
|
+
},
|
|
89
|
+
"types": "dist/index.d.ts"
|
|
90
|
+
}
|