@vibemastery/zurf 0.2.3 → 0.3.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/README.md +69 -17
- package/dist/commands/ask/index.d.ts +17 -0
- package/dist/commands/ask/index.js +102 -0
- package/dist/commands/browse/index.js +2 -2
- package/dist/commands/config/which.js +51 -44
- package/dist/commands/fetch/index.js +1 -1
- package/dist/commands/search/index.js +1 -1
- package/dist/commands/setup/index.d.ts +14 -0
- package/dist/commands/setup/index.js +123 -0
- package/dist/lib/browserbase-client.js +1 -1
- package/dist/lib/config.d.ts +22 -1
- package/dist/lib/config.js +91 -19
- package/dist/lib/perplexity-client.d.ts +33 -0
- package/dist/lib/perplexity-client.js +59 -0
- package/dist/lib/setup-prompts.d.ts +10 -0
- package/dist/lib/setup-prompts.js +34 -0
- package/oclif.manifest.json +157 -102
- package/package.json +4 -3
- package/dist/commands/init/index.d.ts +0 -18
- package/dist/commands/init/index.js +0 -116
package/dist/lib/config.js
CHANGED
|
@@ -26,29 +26,56 @@ export function findLocalConfigPath(startDir = process.cwd()) {
|
|
|
26
26
|
}
|
|
27
27
|
return undefined;
|
|
28
28
|
}
|
|
29
|
-
|
|
29
|
+
/**
|
|
30
|
+
* Detect whether a parsed config object uses the old flat shape (has `apiKey` at root, no `providers` key).
|
|
31
|
+
*/
|
|
32
|
+
function isLegacyConfig(raw) {
|
|
33
|
+
if (raw === null || typeof raw !== 'object')
|
|
34
|
+
return false;
|
|
35
|
+
const obj = raw;
|
|
36
|
+
return ('apiKey' in obj || 'projectId' in obj) && !('providers' in obj);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Migrate a legacy flat config to the new nested shape.
|
|
40
|
+
*/
|
|
41
|
+
function migrateLegacyConfig(legacy) {
|
|
42
|
+
const config = {};
|
|
43
|
+
if (legacy.apiKey || legacy.projectId) {
|
|
44
|
+
config.providers = {
|
|
45
|
+
browserbase: {},
|
|
46
|
+
};
|
|
47
|
+
if (legacy.apiKey)
|
|
48
|
+
config.providers.browserbase.apiKey = legacy.apiKey;
|
|
49
|
+
if (legacy.projectId)
|
|
50
|
+
config.providers.browserbase.projectId = legacy.projectId;
|
|
51
|
+
}
|
|
52
|
+
if (legacy.format)
|
|
53
|
+
config.format = legacy.format;
|
|
54
|
+
return config;
|
|
55
|
+
}
|
|
56
|
+
export function readConfigFile(filePath) {
|
|
30
57
|
try {
|
|
31
58
|
const raw = fs.readFileSync(filePath, 'utf8');
|
|
32
|
-
|
|
59
|
+
const parsed = JSON.parse(raw);
|
|
60
|
+
if (isLegacyConfig(parsed)) {
|
|
61
|
+
return migrateLegacyConfig(parsed);
|
|
62
|
+
}
|
|
63
|
+
return parsed;
|
|
33
64
|
}
|
|
34
65
|
catch {
|
|
35
66
|
return undefined;
|
|
36
67
|
}
|
|
37
68
|
}
|
|
38
|
-
function
|
|
69
|
+
function readStringField(filePath, getter) {
|
|
39
70
|
const parsed = readConfigFile(filePath);
|
|
40
71
|
if (!parsed)
|
|
41
72
|
return undefined;
|
|
42
|
-
const
|
|
43
|
-
return
|
|
44
|
-
}
|
|
45
|
-
function readProjectIdFromFile(filePath) {
|
|
46
|
-
const parsed = readConfigFile(filePath);
|
|
47
|
-
if (!parsed)
|
|
48
|
-
return undefined;
|
|
49
|
-
const id = typeof parsed.projectId === 'string' ? parsed.projectId.trim() : '';
|
|
50
|
-
return id.length > 0 ? id : undefined;
|
|
73
|
+
const val = getter(parsed)?.trim() ?? '';
|
|
74
|
+
return val.length > 0 ? val : undefined;
|
|
51
75
|
}
|
|
76
|
+
const readBrowserbaseApiKeyFromFile = (f) => readStringField(f, (c) => c.providers?.browserbase?.apiKey);
|
|
77
|
+
const readBrowserbaseProjectIdFromFile = (f) => readStringField(f, (c) => c.providers?.browserbase?.projectId);
|
|
78
|
+
const readPerplexityApiKeyFromFile = (f) => readStringField(f, (c) => c.providers?.perplexity?.apiKey);
|
|
52
79
|
function readFormatFromFile(filePath) {
|
|
53
80
|
const parsed = readConfigFile(filePath);
|
|
54
81
|
if (!parsed)
|
|
@@ -85,13 +112,13 @@ export function resolveApiKey(options) {
|
|
|
85
112
|
}
|
|
86
113
|
const localPath = findLocalConfigPath(cwd);
|
|
87
114
|
if (localPath) {
|
|
88
|
-
const key =
|
|
115
|
+
const key = readBrowserbaseApiKeyFromFile(localPath);
|
|
89
116
|
if (key) {
|
|
90
117
|
return { apiKey: key, path: localPath, source: 'local' };
|
|
91
118
|
}
|
|
92
119
|
}
|
|
93
120
|
const gPath = globalConfigFilePath(options.globalConfigDir);
|
|
94
|
-
const globalKey =
|
|
121
|
+
const globalKey = readBrowserbaseApiKeyFromFile(gPath);
|
|
95
122
|
if (globalKey) {
|
|
96
123
|
return { apiKey: globalKey, path: gPath, source: 'global' };
|
|
97
124
|
}
|
|
@@ -105,20 +132,40 @@ export function resolveProjectId(options) {
|
|
|
105
132
|
}
|
|
106
133
|
const localPath = findLocalConfigPath(cwd);
|
|
107
134
|
if (localPath) {
|
|
108
|
-
const id =
|
|
135
|
+
const id = readBrowserbaseProjectIdFromFile(localPath);
|
|
109
136
|
if (id) {
|
|
110
137
|
return { path: localPath, projectId: id, source: 'local' };
|
|
111
138
|
}
|
|
112
139
|
}
|
|
113
140
|
const gPath = globalConfigFilePath(options.globalConfigDir);
|
|
114
|
-
const globalId =
|
|
141
|
+
const globalId = readBrowserbaseProjectIdFromFile(gPath);
|
|
115
142
|
if (globalId) {
|
|
116
143
|
return { path: gPath, projectId: globalId, source: 'global' };
|
|
117
144
|
}
|
|
118
145
|
return { source: 'none' };
|
|
119
146
|
}
|
|
147
|
+
export function resolvePerplexityApiKey(options) {
|
|
148
|
+
const cwd = options.cwd ?? process.cwd();
|
|
149
|
+
const envKey = process.env.PERPLEXITY_API_KEY?.trim();
|
|
150
|
+
if (envKey) {
|
|
151
|
+
return { apiKey: envKey, source: 'env' };
|
|
152
|
+
}
|
|
153
|
+
const localPath = findLocalConfigPath(cwd);
|
|
154
|
+
if (localPath) {
|
|
155
|
+
const key = readPerplexityApiKeyFromFile(localPath);
|
|
156
|
+
if (key) {
|
|
157
|
+
return { apiKey: key, path: localPath, source: 'local' };
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const gPath = globalConfigFilePath(options.globalConfigDir);
|
|
161
|
+
const globalKey = readPerplexityApiKeyFromFile(gPath);
|
|
162
|
+
if (globalKey) {
|
|
163
|
+
return { apiKey: globalKey, path: gPath, source: 'global' };
|
|
164
|
+
}
|
|
165
|
+
return { source: 'none' };
|
|
166
|
+
}
|
|
120
167
|
export async function writeApiKeyConfig(targetPath, apiKey) {
|
|
121
|
-
await writeConfig(targetPath, { apiKey: apiKey.trim() });
|
|
168
|
+
await writeConfig(targetPath, { providers: { browserbase: { apiKey: apiKey.trim() } } });
|
|
122
169
|
}
|
|
123
170
|
export async function writeConfig(targetPath, fields) {
|
|
124
171
|
const dir = path.dirname(targetPath);
|
|
@@ -126,12 +173,37 @@ export async function writeConfig(targetPath, fields) {
|
|
|
126
173
|
let existing = {};
|
|
127
174
|
try {
|
|
128
175
|
const raw = await fs.promises.readFile(targetPath, 'utf8');
|
|
129
|
-
|
|
176
|
+
const parsed = JSON.parse(raw);
|
|
177
|
+
existing = isLegacyConfig(parsed) ? migrateLegacyConfig(parsed) : parsed;
|
|
130
178
|
}
|
|
131
179
|
catch {
|
|
132
180
|
// file doesn't exist yet — start fresh
|
|
133
181
|
}
|
|
134
|
-
const merged = {
|
|
182
|
+
const merged = {
|
|
183
|
+
...existing,
|
|
184
|
+
...fields,
|
|
185
|
+
providers: {
|
|
186
|
+
...existing.providers,
|
|
187
|
+
...fields.providers,
|
|
188
|
+
browserbase: {
|
|
189
|
+
...existing.providers?.browserbase,
|
|
190
|
+
...fields.providers?.browserbase,
|
|
191
|
+
},
|
|
192
|
+
perplexity: {
|
|
193
|
+
...existing.providers?.perplexity,
|
|
194
|
+
...fields.providers?.perplexity,
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
if (merged.providers?.browserbase && Object.keys(merged.providers.browserbase).length === 0) {
|
|
199
|
+
delete merged.providers.browserbase;
|
|
200
|
+
}
|
|
201
|
+
if (merged.providers?.perplexity && Object.keys(merged.providers.perplexity).length === 0) {
|
|
202
|
+
delete merged.providers.perplexity;
|
|
203
|
+
}
|
|
204
|
+
if (merged.providers && Object.keys(merged.providers).length === 0) {
|
|
205
|
+
delete merged.providers;
|
|
206
|
+
}
|
|
135
207
|
const body = `${JSON.stringify(merged, null, 2)}\n`;
|
|
136
208
|
await fs.promises.writeFile(targetPath, body, { encoding: 'utf8', mode: 0o600 });
|
|
137
209
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { resolvePerplexityApiKey } from './config.js';
|
|
2
|
+
export type PerplexityDepth = 'deep' | 'quick';
|
|
3
|
+
export type PerplexityRecency = 'day' | 'hour' | 'month' | 'week' | 'year';
|
|
4
|
+
export interface PerplexityAskOptions {
|
|
5
|
+
depth?: PerplexityDepth;
|
|
6
|
+
domains?: string[];
|
|
7
|
+
question: string;
|
|
8
|
+
recency?: PerplexityRecency;
|
|
9
|
+
}
|
|
10
|
+
export interface PerplexityAskResult {
|
|
11
|
+
answer: string;
|
|
12
|
+
citations: string[];
|
|
13
|
+
model: string;
|
|
14
|
+
}
|
|
15
|
+
export declare class PerplexityClient {
|
|
16
|
+
private readonly apiKey;
|
|
17
|
+
constructor(apiKey: string);
|
|
18
|
+
ask(options: PerplexityAskOptions): Promise<PerplexityAskResult>;
|
|
19
|
+
}
|
|
20
|
+
export declare class MissingPerplexityKeyError extends Error {
|
|
21
|
+
code: string;
|
|
22
|
+
suggestions: string[];
|
|
23
|
+
constructor();
|
|
24
|
+
}
|
|
25
|
+
export declare function createPerplexityClient(options: {
|
|
26
|
+
cwd?: string;
|
|
27
|
+
globalConfigDir: string;
|
|
28
|
+
}): {
|
|
29
|
+
client: PerplexityClient;
|
|
30
|
+
resolution: Extract<ReturnType<typeof resolvePerplexityApiKey>, {
|
|
31
|
+
apiKey: string;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { resolvePerplexityApiKey } from './config.js';
|
|
2
|
+
function buildRequestBody(options) {
|
|
3
|
+
const model = options.depth === 'deep' ? 'sonar-pro' : 'sonar';
|
|
4
|
+
const body = {
|
|
5
|
+
messages: [{ content: options.question, role: 'user' }],
|
|
6
|
+
model,
|
|
7
|
+
};
|
|
8
|
+
if (options.recency) {
|
|
9
|
+
body.search_recency_filter = options.recency; // eslint-disable-line camelcase
|
|
10
|
+
}
|
|
11
|
+
if (options.domains && options.domains.length > 0) {
|
|
12
|
+
body.search_domain_filter = options.domains; // eslint-disable-line camelcase
|
|
13
|
+
}
|
|
14
|
+
return body;
|
|
15
|
+
}
|
|
16
|
+
export class PerplexityClient {
|
|
17
|
+
apiKey;
|
|
18
|
+
constructor(apiKey) {
|
|
19
|
+
this.apiKey = apiKey;
|
|
20
|
+
}
|
|
21
|
+
async ask(options) {
|
|
22
|
+
const body = buildRequestBody(options);
|
|
23
|
+
const response = await fetch('https://api.perplexity.ai/chat/completions', {
|
|
24
|
+
body: JSON.stringify(body),
|
|
25
|
+
headers: {
|
|
26
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
method: 'POST',
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
const text = await response.text().catch(() => '');
|
|
33
|
+
throw new Error(`Perplexity API error (${response.status}): ${text || response.statusText}`);
|
|
34
|
+
}
|
|
35
|
+
const data = (await response.json());
|
|
36
|
+
const answer = data.choices?.[0]?.message?.content ?? '';
|
|
37
|
+
const citations = data.citations ?? [];
|
|
38
|
+
return { answer, citations, model: data.model };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export class MissingPerplexityKeyError extends Error {
|
|
42
|
+
code = 'MISSING_PERPLEXITY_KEY';
|
|
43
|
+
suggestions = [
|
|
44
|
+
'Run `zurf setup` to configure your Perplexity API key',
|
|
45
|
+
'Or set the PERPLEXITY_API_KEY environment variable',
|
|
46
|
+
];
|
|
47
|
+
constructor() {
|
|
48
|
+
super('No Perplexity API key found.');
|
|
49
|
+
this.name = 'MissingPerplexityKeyError';
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function createPerplexityClient(options) {
|
|
53
|
+
const resolution = resolvePerplexityApiKey({ cwd: options.cwd, globalConfigDir: options.globalConfigDir });
|
|
54
|
+
if (resolution.source === 'none') {
|
|
55
|
+
throw new MissingPerplexityKeyError();
|
|
56
|
+
}
|
|
57
|
+
const client = new PerplexityClient(resolution.apiKey);
|
|
58
|
+
return { client, resolution };
|
|
59
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export type ConfigScope = 'global' | 'local';
|
|
2
|
+
export interface ProviderChoice {
|
|
3
|
+
configured: boolean;
|
|
4
|
+
name: string;
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function selectScope(): Promise<ConfigScope>;
|
|
8
|
+
export declare function selectProviders(providers: ProviderChoice[]): Promise<string[]>;
|
|
9
|
+
export declare function promptApiKey(label: string): Promise<string>;
|
|
10
|
+
export declare function promptProjectId(): Promise<string>;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { checkbox, input, password, select } from '@inquirer/prompts';
|
|
2
|
+
export async function selectScope() {
|
|
3
|
+
return select({
|
|
4
|
+
choices: [
|
|
5
|
+
{ name: 'Global (user-wide, recommended)', value: 'global' },
|
|
6
|
+
{ name: 'Local (this project only)', value: 'local' },
|
|
7
|
+
],
|
|
8
|
+
message: 'Where should zurf store your config?',
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
export async function selectProviders(providers) {
|
|
12
|
+
const choices = providers.map((p) => ({
|
|
13
|
+
checked: p.configured,
|
|
14
|
+
name: p.configured ? `${p.name} [configured]` : p.name,
|
|
15
|
+
value: p.value,
|
|
16
|
+
}));
|
|
17
|
+
return checkbox({
|
|
18
|
+
choices,
|
|
19
|
+
message: 'Which providers do you want to configure?',
|
|
20
|
+
required: true,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
export async function promptApiKey(label) {
|
|
24
|
+
return password({
|
|
25
|
+
mask: '*',
|
|
26
|
+
message: `${label} API key:`,
|
|
27
|
+
validate: (value) => (value.trim().length > 0 ? true : 'API key cannot be empty'),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
export async function promptProjectId() {
|
|
31
|
+
return input({
|
|
32
|
+
message: 'Browserbase Project ID (optional, press Enter to skip):',
|
|
33
|
+
});
|
|
34
|
+
}
|
package/oclif.manifest.json
CHANGED
|
@@ -1,29 +1,49 @@
|
|
|
1
1
|
{
|
|
2
2
|
"commands": {
|
|
3
|
-
"
|
|
3
|
+
"ask": {
|
|
4
4
|
"aliases": [],
|
|
5
5
|
"args": {
|
|
6
|
-
"
|
|
7
|
-
"description": "
|
|
8
|
-
"name": "
|
|
6
|
+
"question": {
|
|
7
|
+
"description": "The question to ask Perplexity",
|
|
8
|
+
"name": "question",
|
|
9
9
|
"required": true
|
|
10
10
|
}
|
|
11
11
|
},
|
|
12
|
-
"description": "
|
|
12
|
+
"description": "Ask a question and get an AI-powered answer with web citations via Perplexity Sonar.\nReturns an answer with inline citations and a sources list. Use --depth deep for more thorough research.",
|
|
13
13
|
"examples": [
|
|
14
|
-
"<%= config.bin %> <%= command.id %>
|
|
15
|
-
"<%= config.bin %> <%= command.id %>
|
|
16
|
-
"<%= config.bin %> <%= command.id %>
|
|
17
|
-
"<%= config.bin %> <%= command.id %>
|
|
14
|
+
"<%= config.bin %> <%= command.id %> \"What is Browserbase?\"",
|
|
15
|
+
"<%= config.bin %> <%= command.id %> \"latest tech news\" --recency day",
|
|
16
|
+
"<%= config.bin %> <%= command.id %> \"search reddit for best CLI tools\" --domains reddit.com",
|
|
17
|
+
"<%= config.bin %> <%= command.id %> \"explain quantum computing\" --depth deep",
|
|
18
|
+
"<%= config.bin %> <%= command.id %> \"What is Node.js?\" --json",
|
|
19
|
+
"<%= config.bin %> <%= command.id %> \"What is oclif?\" --no-citations"
|
|
18
20
|
],
|
|
19
21
|
"flags": {
|
|
20
|
-
"
|
|
21
|
-
"description": "
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"allowNo": false,
|
|
22
|
+
"citations": {
|
|
23
|
+
"description": "Show sources list after the answer (use --no-citations to hide)",
|
|
24
|
+
"name": "citations",
|
|
25
|
+
"allowNo": true,
|
|
25
26
|
"type": "boolean"
|
|
26
27
|
},
|
|
28
|
+
"depth": {
|
|
29
|
+
"description": "Search depth: quick (sonar) or deep (sonar-pro)",
|
|
30
|
+
"name": "depth",
|
|
31
|
+
"default": "quick",
|
|
32
|
+
"hasDynamicHelp": false,
|
|
33
|
+
"multiple": false,
|
|
34
|
+
"options": [
|
|
35
|
+
"quick",
|
|
36
|
+
"deep"
|
|
37
|
+
],
|
|
38
|
+
"type": "option"
|
|
39
|
+
},
|
|
40
|
+
"domains": {
|
|
41
|
+
"description": "Restrict search to these domains (comma-separated)",
|
|
42
|
+
"name": "domains",
|
|
43
|
+
"hasDynamicHelp": false,
|
|
44
|
+
"multiple": false,
|
|
45
|
+
"type": "option"
|
|
46
|
+
},
|
|
27
47
|
"json": {
|
|
28
48
|
"description": "Print machine-readable JSON to stdout",
|
|
29
49
|
"env": "ZURF_JSON",
|
|
@@ -31,81 +51,53 @@
|
|
|
31
51
|
"allowNo": false,
|
|
32
52
|
"type": "boolean"
|
|
33
53
|
},
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"name": "output",
|
|
54
|
+
"recency": {
|
|
55
|
+
"description": "Filter sources by recency",
|
|
56
|
+
"name": "recency",
|
|
38
57
|
"hasDynamicHelp": false,
|
|
39
58
|
"multiple": false,
|
|
59
|
+
"options": [
|
|
60
|
+
"hour",
|
|
61
|
+
"day",
|
|
62
|
+
"week",
|
|
63
|
+
"month",
|
|
64
|
+
"year"
|
|
65
|
+
],
|
|
40
66
|
"type": "option"
|
|
41
67
|
}
|
|
42
68
|
},
|
|
43
69
|
"hasDynamicHelp": false,
|
|
44
70
|
"hiddenAliases": [],
|
|
45
|
-
"id": "
|
|
71
|
+
"id": "ask",
|
|
46
72
|
"pluginAlias": "@vibemastery/zurf",
|
|
47
73
|
"pluginName": "@vibemastery/zurf",
|
|
48
74
|
"pluginType": "core",
|
|
49
75
|
"strict": true,
|
|
50
|
-
"summary": "
|
|
76
|
+
"summary": "Ask a question via Perplexity Sonar",
|
|
77
|
+
"enableJsonFlag": false,
|
|
51
78
|
"isESM": true,
|
|
52
79
|
"relativePath": [
|
|
53
80
|
"dist",
|
|
54
81
|
"commands",
|
|
55
|
-
"
|
|
82
|
+
"ask",
|
|
56
83
|
"index.js"
|
|
57
84
|
]
|
|
58
85
|
},
|
|
59
|
-
"
|
|
86
|
+
"browse": {
|
|
60
87
|
"aliases": [],
|
|
61
|
-
"args": {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
],
|
|
67
|
-
"flags": {
|
|
68
|
-
"html": {
|
|
69
|
-
"description": "Output raw HTML instead of markdown",
|
|
70
|
-
"env": "ZURF_HTML",
|
|
71
|
-
"name": "html",
|
|
72
|
-
"allowNo": false,
|
|
73
|
-
"type": "boolean"
|
|
74
|
-
},
|
|
75
|
-
"json": {
|
|
76
|
-
"description": "Print machine-readable JSON to stdout",
|
|
77
|
-
"env": "ZURF_JSON",
|
|
78
|
-
"name": "json",
|
|
79
|
-
"allowNo": false,
|
|
80
|
-
"type": "boolean"
|
|
88
|
+
"args": {
|
|
89
|
+
"url": {
|
|
90
|
+
"description": "URL to browse",
|
|
91
|
+
"name": "url",
|
|
92
|
+
"required": true
|
|
81
93
|
}
|
|
82
94
|
},
|
|
83
|
-
"
|
|
84
|
-
"hiddenAliases": [],
|
|
85
|
-
"id": "config:which",
|
|
86
|
-
"pluginAlias": "@vibemastery/zurf",
|
|
87
|
-
"pluginName": "@vibemastery/zurf",
|
|
88
|
-
"pluginType": "core",
|
|
89
|
-
"strict": true,
|
|
90
|
-
"summary": "Show where the API key is loaded from",
|
|
91
|
-
"enableJsonFlag": false,
|
|
92
|
-
"isESM": true,
|
|
93
|
-
"relativePath": [
|
|
94
|
-
"dist",
|
|
95
|
-
"commands",
|
|
96
|
-
"config",
|
|
97
|
-
"which.js"
|
|
98
|
-
]
|
|
99
|
-
},
|
|
100
|
-
"init": {
|
|
101
|
-
"aliases": [],
|
|
102
|
-
"args": {},
|
|
103
|
-
"description": "Save your Browserbase API key and optional Project ID to global or project config.\nGlobal path follows oclif config (same as `zurf config which`).",
|
|
95
|
+
"description": "Browse a URL in a cloud browser and return the rendered content as markdown (default) or raw HTML.\nUses a real Chromium browser via Browserbase, so JavaScript-heavy pages are fully rendered.\nRequires authentication and a Project ID. Run `zurf setup` before first use.",
|
|
104
96
|
"examples": [
|
|
105
|
-
"<%= config.bin %> <%= command.id %>
|
|
106
|
-
"<%= config.bin %> <%= command.id %> --
|
|
107
|
-
"<%= config.bin %> <%= command.id %>
|
|
108
|
-
"
|
|
97
|
+
"<%= config.bin %> <%= command.id %> https://example.com",
|
|
98
|
+
"<%= config.bin %> <%= command.id %> https://example.com --html",
|
|
99
|
+
"<%= config.bin %> <%= command.id %> https://example.com --json",
|
|
100
|
+
"<%= config.bin %> <%= command.id %> https://example.com -o page.md"
|
|
109
101
|
],
|
|
110
102
|
"flags": {
|
|
111
103
|
"html": {
|
|
@@ -122,34 +114,10 @@
|
|
|
122
114
|
"allowNo": false,
|
|
123
115
|
"type": "boolean"
|
|
124
116
|
},
|
|
125
|
-
"
|
|
126
|
-
"
|
|
127
|
-
"
|
|
128
|
-
"
|
|
129
|
-
"multiple": false,
|
|
130
|
-
"type": "option"
|
|
131
|
-
},
|
|
132
|
-
"gitignore": {
|
|
133
|
-
"description": "Append .zurf/ to ./.gitignore if that entry is missing",
|
|
134
|
-
"name": "gitignore",
|
|
135
|
-
"allowNo": false,
|
|
136
|
-
"type": "boolean"
|
|
137
|
-
},
|
|
138
|
-
"global": {
|
|
139
|
-
"description": "Store API key in user config (oclif config dir for this CLI)",
|
|
140
|
-
"name": "global",
|
|
141
|
-
"allowNo": false,
|
|
142
|
-
"type": "boolean"
|
|
143
|
-
},
|
|
144
|
-
"local": {
|
|
145
|
-
"description": "Store API key in ./.zurf/config.json for this directory",
|
|
146
|
-
"name": "local",
|
|
147
|
-
"allowNo": false,
|
|
148
|
-
"type": "boolean"
|
|
149
|
-
},
|
|
150
|
-
"project-id": {
|
|
151
|
-
"description": "Browserbase Project ID (optional; needed for browse, screenshot, pdf commands)",
|
|
152
|
-
"name": "project-id",
|
|
117
|
+
"output": {
|
|
118
|
+
"char": "o",
|
|
119
|
+
"description": "Write rendered content to this file (full content); otherwise human mode prints a truncated preview to stdout",
|
|
120
|
+
"name": "output",
|
|
153
121
|
"hasDynamicHelp": false,
|
|
154
122
|
"multiple": false,
|
|
155
123
|
"type": "option"
|
|
@@ -157,18 +125,17 @@
|
|
|
157
125
|
},
|
|
158
126
|
"hasDynamicHelp": false,
|
|
159
127
|
"hiddenAliases": [],
|
|
160
|
-
"id": "
|
|
128
|
+
"id": "browse",
|
|
161
129
|
"pluginAlias": "@vibemastery/zurf",
|
|
162
130
|
"pluginName": "@vibemastery/zurf",
|
|
163
131
|
"pluginType": "core",
|
|
164
132
|
"strict": true,
|
|
165
|
-
"summary": "
|
|
166
|
-
"enableJsonFlag": false,
|
|
133
|
+
"summary": "Browse a URL in a cloud browser and return rendered content as markdown",
|
|
167
134
|
"isESM": true,
|
|
168
135
|
"relativePath": [
|
|
169
136
|
"dist",
|
|
170
137
|
"commands",
|
|
171
|
-
"
|
|
138
|
+
"browse",
|
|
172
139
|
"index.js"
|
|
173
140
|
]
|
|
174
141
|
},
|
|
@@ -181,7 +148,7 @@
|
|
|
181
148
|
"required": true
|
|
182
149
|
}
|
|
183
150
|
},
|
|
184
|
-
"description": "Fetch a URL via Browserbase and return content as markdown (default) or raw HTML (no browser session; static HTML, 1 MB max).\nRequires authentication. Run `zurf
|
|
151
|
+
"description": "Fetch a URL via Browserbase and return content as markdown (default) or raw HTML (no browser session; static HTML, 1 MB max).\nRequires authentication. Run `zurf setup` or use a project key before first use.",
|
|
185
152
|
"examples": [
|
|
186
153
|
"<%= config.bin %> <%= command.id %> https://example.com",
|
|
187
154
|
"<%= config.bin %> <%= command.id %> https://example.com --html",
|
|
@@ -246,6 +213,47 @@
|
|
|
246
213
|
"index.js"
|
|
247
214
|
]
|
|
248
215
|
},
|
|
216
|
+
"config:which": {
|
|
217
|
+
"aliases": [],
|
|
218
|
+
"args": {},
|
|
219
|
+
"description": "Show where API keys would be loaded from (no secrets printed).\nResolution order: env var → project .zurf/config.json (walk-up) → global config.",
|
|
220
|
+
"examples": [
|
|
221
|
+
"<%= config.bin %> config which",
|
|
222
|
+
"<%= config.bin %> config which --json"
|
|
223
|
+
],
|
|
224
|
+
"flags": {
|
|
225
|
+
"html": {
|
|
226
|
+
"description": "Output raw HTML instead of markdown",
|
|
227
|
+
"env": "ZURF_HTML",
|
|
228
|
+
"name": "html",
|
|
229
|
+
"allowNo": false,
|
|
230
|
+
"type": "boolean"
|
|
231
|
+
},
|
|
232
|
+
"json": {
|
|
233
|
+
"description": "Print machine-readable JSON to stdout",
|
|
234
|
+
"env": "ZURF_JSON",
|
|
235
|
+
"name": "json",
|
|
236
|
+
"allowNo": false,
|
|
237
|
+
"type": "boolean"
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
"hasDynamicHelp": false,
|
|
241
|
+
"hiddenAliases": [],
|
|
242
|
+
"id": "config:which",
|
|
243
|
+
"pluginAlias": "@vibemastery/zurf",
|
|
244
|
+
"pluginName": "@vibemastery/zurf",
|
|
245
|
+
"pluginType": "core",
|
|
246
|
+
"strict": true,
|
|
247
|
+
"summary": "Show where API keys are loaded from",
|
|
248
|
+
"enableJsonFlag": false,
|
|
249
|
+
"isESM": true,
|
|
250
|
+
"relativePath": [
|
|
251
|
+
"dist",
|
|
252
|
+
"commands",
|
|
253
|
+
"config",
|
|
254
|
+
"which.js"
|
|
255
|
+
]
|
|
256
|
+
},
|
|
249
257
|
"search": {
|
|
250
258
|
"aliases": [],
|
|
251
259
|
"args": {
|
|
@@ -255,7 +263,7 @@
|
|
|
255
263
|
"required": true
|
|
256
264
|
}
|
|
257
265
|
},
|
|
258
|
-
"description": "Search the web via Browserbase (Exa-powered).\nRequires authentication. Run `zurf
|
|
266
|
+
"description": "Search the web via Browserbase (Exa-powered).\nRequires authentication. Run `zurf setup` or use a project key before first use.",
|
|
259
267
|
"examples": [
|
|
260
268
|
"<%= config.bin %> <%= command.id %> \"browserbase documentation\"",
|
|
261
269
|
"<%= config.bin %> <%= command.id %> \"laravel inertia\" --num-results 5 --json"
|
|
@@ -300,7 +308,54 @@
|
|
|
300
308
|
"search",
|
|
301
309
|
"index.js"
|
|
302
310
|
]
|
|
311
|
+
},
|
|
312
|
+
"setup": {
|
|
313
|
+
"aliases": [],
|
|
314
|
+
"args": {},
|
|
315
|
+
"description": "Interactive setup wizard for configuring API keys for all providers (Browserbase, Perplexity).\nStores keys in global or local config. Re-run to update or add providers.",
|
|
316
|
+
"examples": [
|
|
317
|
+
"<%= config.bin %> <%= command.id %>",
|
|
318
|
+
"<%= config.bin %> <%= command.id %> --global",
|
|
319
|
+
"<%= config.bin %> <%= command.id %> --local"
|
|
320
|
+
],
|
|
321
|
+
"flags": {
|
|
322
|
+
"global": {
|
|
323
|
+
"description": "Store config in user config directory (skip scope prompt)",
|
|
324
|
+
"name": "global",
|
|
325
|
+
"allowNo": false,
|
|
326
|
+
"type": "boolean"
|
|
327
|
+
},
|
|
328
|
+
"json": {
|
|
329
|
+
"description": "Print machine-readable JSON to stdout",
|
|
330
|
+
"env": "ZURF_JSON",
|
|
331
|
+
"name": "json",
|
|
332
|
+
"allowNo": false,
|
|
333
|
+
"type": "boolean"
|
|
334
|
+
},
|
|
335
|
+
"local": {
|
|
336
|
+
"description": "Store config in .zurf/config.json in the current directory (skip scope prompt)",
|
|
337
|
+
"name": "local",
|
|
338
|
+
"allowNo": false,
|
|
339
|
+
"type": "boolean"
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
"hasDynamicHelp": false,
|
|
343
|
+
"hiddenAliases": [],
|
|
344
|
+
"id": "setup",
|
|
345
|
+
"pluginAlias": "@vibemastery/zurf",
|
|
346
|
+
"pluginName": "@vibemastery/zurf",
|
|
347
|
+
"pluginType": "core",
|
|
348
|
+
"strict": true,
|
|
349
|
+
"summary": "Configure API keys for Browserbase and Perplexity",
|
|
350
|
+
"enableJsonFlag": false,
|
|
351
|
+
"isESM": true,
|
|
352
|
+
"relativePath": [
|
|
353
|
+
"dist",
|
|
354
|
+
"commands",
|
|
355
|
+
"setup",
|
|
356
|
+
"index.js"
|
|
357
|
+
]
|
|
303
358
|
}
|
|
304
359
|
},
|
|
305
|
-
"version": "0.
|
|
360
|
+
"version": "0.3.0"
|
|
306
361
|
}
|