@thinkbrowse/cli 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/README.md +246 -0
- package/dist/bin/thinkbrowse.d.ts +6 -0
- package/dist/bin/thinkbrowse.d.ts.map +1 -0
- package/dist/bin/thinkbrowse.js +58 -0
- package/dist/bin/thinkbrowse.js.map +1 -0
- package/dist/src/adapters/cloud.d.ts +46 -0
- package/dist/src/adapters/cloud.d.ts.map +1 -0
- package/dist/src/adapters/cloud.js +336 -0
- package/dist/src/adapters/cloud.js.map +1 -0
- package/dist/src/adapters/types.d.ts +39 -0
- package/dist/src/adapters/types.d.ts.map +1 -0
- package/dist/src/adapters/types.js +6 -0
- package/dist/src/adapters/types.js.map +1 -0
- package/dist/src/commands/actions.d.ts +26 -0
- package/dist/src/commands/actions.d.ts.map +1 -0
- package/dist/src/commands/actions.js +540 -0
- package/dist/src/commands/actions.js.map +1 -0
- package/dist/src/commands/cloud.d.ts +6 -0
- package/dist/src/commands/cloud.d.ts.map +1 -0
- package/dist/src/commands/cloud.js +212 -0
- package/dist/src/commands/cloud.js.map +1 -0
- package/dist/src/commands/config.d.ts +6 -0
- package/dist/src/commands/config.d.ts.map +1 -0
- package/dist/src/commands/config.js +123 -0
- package/dist/src/commands/config.js.map +1 -0
- package/dist/src/config/store.d.ts +22 -0
- package/dist/src/config/store.d.ts.map +1 -0
- package/dist/src/config/store.js +80 -0
- package/dist/src/config/store.js.map +1 -0
- package/dist/src/errors.d.ts +22 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +40 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/output/formatter.d.ts +18 -0
- package/dist/src/output/formatter.d.ts.map +1 -0
- package/dist/src/output/formatter.js +28 -0
- package/dist/src/output/formatter.js.map +1 -0
- package/dist/src/types.d.ts +108 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +5 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils.d.ts +5 -0
- package/dist/src/utils.d.ts.map +1 -0
- package/dist/src/utils.js +18 -0
- package/dist/src/utils.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud browser session management commands
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import ora from 'ora';
|
|
7
|
+
import { CloudAdapter } from '../adapters/cloud.js';
|
|
8
|
+
import { config } from '../config/store.js';
|
|
9
|
+
import { ApiError, SessionError } from '../errors.js';
|
|
10
|
+
export function createCloudCommand() {
|
|
11
|
+
const cloudCmd = new Command('cloud')
|
|
12
|
+
.description('Manage cloud browser sessions');
|
|
13
|
+
// cloud start
|
|
14
|
+
cloudCmd
|
|
15
|
+
.command('start')
|
|
16
|
+
.description('Start a new cloud browser session')
|
|
17
|
+
.option('-b, --browser <type>', 'Browser type (chromium|firefox|webkit)', 'chromium')
|
|
18
|
+
.option('--proxy', 'Enable proxy rotation')
|
|
19
|
+
.option('--stealth', 'Enable stealth mode (anti-detection)')
|
|
20
|
+
.option('--headless', 'Run in headless mode', true)
|
|
21
|
+
.option('--no-wait', 'Return immediately without waiting for session to be ready')
|
|
22
|
+
.action(async (options) => {
|
|
23
|
+
const spinner = ora('Starting cloud browser session...').start();
|
|
24
|
+
try {
|
|
25
|
+
const adapter = new CloudAdapter();
|
|
26
|
+
const sessionOptions = {
|
|
27
|
+
browser: options.browser,
|
|
28
|
+
proxy: options.proxy,
|
|
29
|
+
stealth: options.stealth,
|
|
30
|
+
headless: options.headless,
|
|
31
|
+
};
|
|
32
|
+
const session = await adapter.startSession(sessionOptions);
|
|
33
|
+
// Wait for session to be ready unless --no-wait is passed
|
|
34
|
+
if (options.wait !== false) {
|
|
35
|
+
spinner.text = `Provisioning session ${session.sessionId.slice(0, 8)}...`;
|
|
36
|
+
const readySession = await adapter.waitForSessionReady(session.sessionId);
|
|
37
|
+
spinner.succeed('Cloud browser session ready');
|
|
38
|
+
console.log('');
|
|
39
|
+
console.log(' Session ID:', chalk.cyan(readySession.sessionId));
|
|
40
|
+
console.log(' Browser: ', chalk.cyan(options.browser));
|
|
41
|
+
console.log(' Status: ', chalk.green(readySession.status));
|
|
42
|
+
if (readySession.currentUrl) {
|
|
43
|
+
console.log(' URL: ', chalk.cyan(readySession.currentUrl));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
spinner.succeed('Cloud browser session created');
|
|
48
|
+
console.log('');
|
|
49
|
+
console.log(' Session ID:', chalk.cyan(session.sessionId));
|
|
50
|
+
console.log(' Browser: ', chalk.cyan(options.browser));
|
|
51
|
+
console.log(' Status: ', chalk.yellow(session.status));
|
|
52
|
+
}
|
|
53
|
+
if (options.proxy)
|
|
54
|
+
console.log(' Proxy: ', chalk.yellow('enabled'));
|
|
55
|
+
if (options.stealth)
|
|
56
|
+
console.log(' Stealth: ', chalk.yellow('enabled'));
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log(chalk.gray('This session is now active. Run browser commands without --session flag.'));
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
spinner.fail('Failed to start session');
|
|
62
|
+
handleError(error);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
// cloud stop
|
|
66
|
+
cloudCmd
|
|
67
|
+
.command('stop')
|
|
68
|
+
.description('Stop the active cloud browser session')
|
|
69
|
+
.option('-s, --session <id>', 'Session ID (defaults to active session)')
|
|
70
|
+
.option('--all', 'Stop all active sessions')
|
|
71
|
+
.action(async (options) => {
|
|
72
|
+
try {
|
|
73
|
+
const adapter = new CloudAdapter();
|
|
74
|
+
if (options.all) {
|
|
75
|
+
const spinner = ora('Stopping all sessions...').start();
|
|
76
|
+
const sessions = await adapter.listSessions();
|
|
77
|
+
if (sessions.length === 0) {
|
|
78
|
+
spinner.info('No active sessions to stop');
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
for (const session of sessions) {
|
|
82
|
+
await adapter.stopSession(session.sessionId);
|
|
83
|
+
}
|
|
84
|
+
spinner.succeed(`Stopped ${sessions.length} session(s)`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
const sessionId = options.session || config.get('activeSessionId');
|
|
88
|
+
if (!sessionId) {
|
|
89
|
+
console.error(chalk.red('Error:'), 'No active session');
|
|
90
|
+
console.error(chalk.yellow('Tip:'), 'Start one with: thinkbrowse cloud start');
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
const spinner = ora(`Stopping session ${sessionId.slice(0, 8)}...`).start();
|
|
94
|
+
await adapter.stopSession(sessionId);
|
|
95
|
+
spinner.succeed('Session stopped');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
handleError(error);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
// cloud list
|
|
103
|
+
cloudCmd
|
|
104
|
+
.command('list')
|
|
105
|
+
.description('List all active cloud browser sessions')
|
|
106
|
+
.action(async () => {
|
|
107
|
+
const spinner = ora('Fetching sessions...').start();
|
|
108
|
+
try {
|
|
109
|
+
const adapter = new CloudAdapter();
|
|
110
|
+
const sessions = await adapter.listSessions();
|
|
111
|
+
spinner.stop();
|
|
112
|
+
if (sessions.length === 0) {
|
|
113
|
+
console.log(chalk.gray('No active sessions'));
|
|
114
|
+
console.log('');
|
|
115
|
+
console.log('Start one with:', chalk.cyan('thinkbrowse cloud start'));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
console.log('');
|
|
119
|
+
console.log(chalk.bold(`Active Sessions (${sessions.length}):`));
|
|
120
|
+
console.log('');
|
|
121
|
+
const activeSessionId = config.get('activeSessionId');
|
|
122
|
+
for (const session of sessions) {
|
|
123
|
+
const isActive = session.sessionId === activeSessionId;
|
|
124
|
+
const prefix = isActive ? chalk.green('●') : chalk.gray('○');
|
|
125
|
+
const id = session.sessionId.slice(0, 8) + '...';
|
|
126
|
+
console.log(`${prefix} ${chalk.cyan(id)} ${session.status.padEnd(10)} ${session.currentUrl || '(no URL)'}`);
|
|
127
|
+
}
|
|
128
|
+
console.log('');
|
|
129
|
+
if (activeSessionId) {
|
|
130
|
+
console.log(chalk.gray('● = active session'));
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
spinner.fail('Failed to list sessions');
|
|
135
|
+
handleError(error);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
// cloud status
|
|
139
|
+
cloudCmd
|
|
140
|
+
.command('status')
|
|
141
|
+
.description('Show status of the active cloud browser session')
|
|
142
|
+
.option('-s, --session <id>', 'Session ID (defaults to active session)')
|
|
143
|
+
.action(async (options) => {
|
|
144
|
+
try {
|
|
145
|
+
const adapter = new CloudAdapter();
|
|
146
|
+
const sessionId = options.session || config.get('activeSessionId');
|
|
147
|
+
if (!sessionId) {
|
|
148
|
+
console.error(chalk.red('Error:'), 'No active session');
|
|
149
|
+
console.error(chalk.yellow('Tip:'), 'Start one with: thinkbrowse cloud start');
|
|
150
|
+
process.exit(1);
|
|
151
|
+
}
|
|
152
|
+
const spinner = ora('Fetching session status...').start();
|
|
153
|
+
const session = await adapter.getSession(sessionId);
|
|
154
|
+
spinner.stop();
|
|
155
|
+
console.log('');
|
|
156
|
+
console.log(chalk.bold('Session Status:'));
|
|
157
|
+
console.log('');
|
|
158
|
+
console.log(' Session ID: ', chalk.cyan(session.sessionId));
|
|
159
|
+
console.log(' Status: ', getStatusColor(session.status)(session.status));
|
|
160
|
+
console.log(' URL: ', chalk.cyan(session.currentUrl || '(none)'));
|
|
161
|
+
console.log(' Title: ', session.title || '(none)');
|
|
162
|
+
console.log(' Created: ', session.createdAt);
|
|
163
|
+
if (session.isFlyMachine) {
|
|
164
|
+
console.log(' Location: ', chalk.gray('Fly.io'));
|
|
165
|
+
}
|
|
166
|
+
console.log('');
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
handleError(error);
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
// cloud use
|
|
173
|
+
cloudCmd
|
|
174
|
+
.command('use <sessionId>')
|
|
175
|
+
.description('Switch active session')
|
|
176
|
+
.action((sessionId) => {
|
|
177
|
+
config.set('activeSessionId', sessionId);
|
|
178
|
+
console.log(chalk.green('✓'), 'Switched to session', chalk.cyan(sessionId.slice(0, 8) + '...'));
|
|
179
|
+
});
|
|
180
|
+
return cloudCmd;
|
|
181
|
+
}
|
|
182
|
+
function getStatusColor(status) {
|
|
183
|
+
switch (status) {
|
|
184
|
+
case 'active':
|
|
185
|
+
case 'ready':
|
|
186
|
+
case 'running':
|
|
187
|
+
return chalk.green;
|
|
188
|
+
case 'busy':
|
|
189
|
+
case 'provisioning':
|
|
190
|
+
case 'creating':
|
|
191
|
+
case 'pending':
|
|
192
|
+
return chalk.yellow;
|
|
193
|
+
case 'error':
|
|
194
|
+
case 'failed':
|
|
195
|
+
return chalk.red;
|
|
196
|
+
default:
|
|
197
|
+
return chalk.gray;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function handleError(error) {
|
|
201
|
+
if (error instanceof ApiError || error instanceof SessionError) {
|
|
202
|
+
console.error(chalk.red('Error:'), error.message);
|
|
203
|
+
if (error.suggestion) {
|
|
204
|
+
console.error(chalk.yellow('Tip:'), error.suggestion);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
console.error(chalk.red('Error:'), error.message || error);
|
|
209
|
+
}
|
|
210
|
+
process.exit(1);
|
|
211
|
+
}
|
|
212
|
+
//# sourceMappingURL=cloud.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloud.js","sourceRoot":"","sources":["../../../src/commands/cloud.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC,wBAAgB,mBAAmB,IAAI,OAAO,CAqI7C"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration management commands
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { config } from '../config/store.js';
|
|
7
|
+
import { ConfigError } from '../errors.js';
|
|
8
|
+
import { createInterface } from 'readline/promises';
|
|
9
|
+
export function createConfigCommand() {
|
|
10
|
+
const configCmd = new Command('config')
|
|
11
|
+
.description('Manage CLI configuration');
|
|
12
|
+
// config set-key <key>
|
|
13
|
+
configCmd
|
|
14
|
+
.command('set-key [key]')
|
|
15
|
+
.description('Set ThinkBrowse API key')
|
|
16
|
+
.action(async (key) => {
|
|
17
|
+
try {
|
|
18
|
+
let apiKey = key;
|
|
19
|
+
// Interactive prompt if no key provided
|
|
20
|
+
if (!apiKey) {
|
|
21
|
+
const rl = createInterface({
|
|
22
|
+
input: process.stdin,
|
|
23
|
+
output: process.stdout,
|
|
24
|
+
});
|
|
25
|
+
apiKey = await rl.question('Enter your ThinkBrowse API key: ');
|
|
26
|
+
rl.close();
|
|
27
|
+
}
|
|
28
|
+
// Validate key format
|
|
29
|
+
if (!config.validateApiKey(apiKey)) {
|
|
30
|
+
throw new ConfigError('Invalid API key format. Must start with "mech_browse_"', 'Get your API key from: https://thinkbrowse.io/settings');
|
|
31
|
+
}
|
|
32
|
+
// Store key
|
|
33
|
+
config.set('apiKey', apiKey);
|
|
34
|
+
console.log(chalk.green('✓') + ' API key saved');
|
|
35
|
+
console.log(chalk.gray(`Config file: ${config.getPath()}`));
|
|
36
|
+
}
|
|
37
|
+
catch (error) {
|
|
38
|
+
if (error instanceof ConfigError) {
|
|
39
|
+
console.error(chalk.red('Error:'), error.message);
|
|
40
|
+
if (error.suggestion) {
|
|
41
|
+
console.error(chalk.yellow('Tip:'), error.suggestion);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
console.error(chalk.red('Error:'), error);
|
|
46
|
+
}
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
// config show
|
|
51
|
+
configCmd
|
|
52
|
+
.command('show')
|
|
53
|
+
.description('Show current configuration')
|
|
54
|
+
.action(() => {
|
|
55
|
+
const allConfig = config.getAll();
|
|
56
|
+
console.log(chalk.bold('ThinkBrowse Configuration:'));
|
|
57
|
+
console.log('');
|
|
58
|
+
console.log(' API Key: ', chalk.cyan(config.maskApiKey(allConfig.apiKey)));
|
|
59
|
+
console.log(' API URL: ', chalk.cyan(allConfig.apiUrl || '(default)'));
|
|
60
|
+
console.log(' Default Browser:', chalk.cyan(allConfig.defaultBrowser || 'chromium'));
|
|
61
|
+
console.log(' Active Session: ', chalk.cyan(allConfig.activeSessionId || '(none)'));
|
|
62
|
+
console.log('');
|
|
63
|
+
console.log(chalk.gray('Config file:'), config.getPath());
|
|
64
|
+
});
|
|
65
|
+
// config set <key> <value>
|
|
66
|
+
configCmd
|
|
67
|
+
.command('set <key> <value>')
|
|
68
|
+
.description('Set a configuration value')
|
|
69
|
+
.action((key, value) => {
|
|
70
|
+
try {
|
|
71
|
+
if (key === 'apiKey') {
|
|
72
|
+
throw new ConfigError('Use "thinkbrowse config set-key" to set API key');
|
|
73
|
+
}
|
|
74
|
+
const validKeys = ['apiUrl', 'defaultBrowser'];
|
|
75
|
+
if (!validKeys.includes(key)) {
|
|
76
|
+
throw new ConfigError(`Unknown config key: ${key}`, `Valid keys: ${validKeys.join(', ')}`);
|
|
77
|
+
}
|
|
78
|
+
config.set(key, value);
|
|
79
|
+
console.log(chalk.green('✓'), `Set ${key} =`, chalk.cyan(value));
|
|
80
|
+
}
|
|
81
|
+
catch (error) {
|
|
82
|
+
if (error instanceof ConfigError) {
|
|
83
|
+
console.error(chalk.red('Error:'), error.message);
|
|
84
|
+
if (error.suggestion) {
|
|
85
|
+
console.error(chalk.yellow('Tip:'), error.suggestion);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
console.error(chalk.red('Error:'), error);
|
|
90
|
+
}
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
// config reset
|
|
95
|
+
configCmd
|
|
96
|
+
.command('reset')
|
|
97
|
+
.description('Clear all configuration')
|
|
98
|
+
.option('-y, --yes', 'Skip confirmation prompt')
|
|
99
|
+
.action(async (options) => {
|
|
100
|
+
try {
|
|
101
|
+
if (!options.yes) {
|
|
102
|
+
const rl = createInterface({
|
|
103
|
+
input: process.stdin,
|
|
104
|
+
output: process.stdout,
|
|
105
|
+
});
|
|
106
|
+
const answer = await rl.question('Are you sure you want to reset all config? (yes/no): ');
|
|
107
|
+
rl.close();
|
|
108
|
+
if (answer.toLowerCase() !== 'yes') {
|
|
109
|
+
console.log('Cancelled');
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
config.clear();
|
|
114
|
+
console.log(chalk.green('✓'), 'Configuration reset');
|
|
115
|
+
}
|
|
116
|
+
catch (error) {
|
|
117
|
+
console.error(chalk.red('Error:'), error);
|
|
118
|
+
process.exit(1);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
return configCmd;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration store using conf package
|
|
3
|
+
* Stores API key, preferences, and active session
|
|
4
|
+
*/
|
|
5
|
+
import type { CLIConfig } from '../types.js';
|
|
6
|
+
export declare class ConfigStore {
|
|
7
|
+
private conf;
|
|
8
|
+
constructor();
|
|
9
|
+
get<K extends keyof CLIConfig>(key: K): CLIConfig[K];
|
|
10
|
+
set<K extends keyof CLIConfig>(key: K, value: CLIConfig[K]): void;
|
|
11
|
+
has(key: keyof CLIConfig): boolean;
|
|
12
|
+
delete(key: keyof CLIConfig): void;
|
|
13
|
+
clear(): void;
|
|
14
|
+
getAll(): CLIConfig;
|
|
15
|
+
getPath(): string;
|
|
16
|
+
validateApiKey(key: string): boolean;
|
|
17
|
+
maskApiKey(key?: string): string;
|
|
18
|
+
isConfigured(): boolean;
|
|
19
|
+
ensureConfigured(): void;
|
|
20
|
+
}
|
|
21
|
+
export declare const config: ConfigStore;
|
|
22
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/config/store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAqB7C,qBAAa,WAAW;IACtB,OAAO,CAAC,IAAI,CAAkB;;IAa9B,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC;IAIpD,GAAG,CAAC,CAAC,SAAS,MAAM,SAAS,EAAE,GAAG,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,IAAI;IAIjE,GAAG,CAAC,GAAG,EAAE,MAAM,SAAS,GAAG,OAAO;IAIlC,MAAM,CAAC,GAAG,EAAE,MAAM,SAAS,GAAG,IAAI;IAIlC,KAAK,IAAI,IAAI;IAIb,MAAM,IAAI,SAAS;IAInB,OAAO,IAAI,MAAM;IAKjB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIpC,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM;IAOhC,YAAY,IAAI,OAAO;IAIvB,gBAAgB,IAAI,IAAI;CAOzB;AAGD,eAAO,MAAM,MAAM,aAAoB,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration store using conf package
|
|
3
|
+
* Stores API key, preferences, and active session
|
|
4
|
+
*/
|
|
5
|
+
import Conf from 'conf';
|
|
6
|
+
const schema = {
|
|
7
|
+
apiKey: {
|
|
8
|
+
type: 'string',
|
|
9
|
+
pattern: '^mech_browse_[A-Za-z0-9_-]+$',
|
|
10
|
+
},
|
|
11
|
+
apiUrl: {
|
|
12
|
+
type: 'string',
|
|
13
|
+
default: 'https://api.thinkbrowse.io',
|
|
14
|
+
},
|
|
15
|
+
defaultBrowser: {
|
|
16
|
+
type: 'string',
|
|
17
|
+
enum: ['chromium', 'firefox', 'webkit'],
|
|
18
|
+
default: 'chromium',
|
|
19
|
+
},
|
|
20
|
+
activeSessionId: {
|
|
21
|
+
type: 'string',
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
export class ConfigStore {
|
|
25
|
+
conf;
|
|
26
|
+
constructor() {
|
|
27
|
+
this.conf = new Conf({
|
|
28
|
+
projectName: 'thinkbrowse',
|
|
29
|
+
schema: schema,
|
|
30
|
+
defaults: {
|
|
31
|
+
apiUrl: 'https://api.thinkbrowse.io',
|
|
32
|
+
defaultBrowser: 'chromium',
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
get(key) {
|
|
37
|
+
return this.conf.get(key);
|
|
38
|
+
}
|
|
39
|
+
set(key, value) {
|
|
40
|
+
this.conf.set(key, value);
|
|
41
|
+
}
|
|
42
|
+
has(key) {
|
|
43
|
+
return this.conf.has(key);
|
|
44
|
+
}
|
|
45
|
+
delete(key) {
|
|
46
|
+
this.conf.delete(key);
|
|
47
|
+
}
|
|
48
|
+
clear() {
|
|
49
|
+
this.conf.clear();
|
|
50
|
+
}
|
|
51
|
+
getAll() {
|
|
52
|
+
return this.conf.store;
|
|
53
|
+
}
|
|
54
|
+
getPath() {
|
|
55
|
+
return this.conf.path;
|
|
56
|
+
}
|
|
57
|
+
// Validation helpers
|
|
58
|
+
validateApiKey(key) {
|
|
59
|
+
return /^mech_browse_[A-Za-z0-9_-]+$/.test(key);
|
|
60
|
+
}
|
|
61
|
+
maskApiKey(key) {
|
|
62
|
+
if (!key)
|
|
63
|
+
return '(not set)';
|
|
64
|
+
if (key.length < 8)
|
|
65
|
+
return '***';
|
|
66
|
+
return `${key.slice(0, 12)}...${key.slice(-4)}`;
|
|
67
|
+
}
|
|
68
|
+
// Check if config is ready to use
|
|
69
|
+
isConfigured() {
|
|
70
|
+
return this.has('apiKey') && !!this.get('apiKey');
|
|
71
|
+
}
|
|
72
|
+
ensureConfigured() {
|
|
73
|
+
if (!this.isConfigured()) {
|
|
74
|
+
throw new Error('API key not configured. Run: thinkbrowse config set-key <your-api-key>');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
// Singleton instance
|
|
79
|
+
export const config = new ConfigStore();
|
|
80
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/config/store.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAGxB,MAAM,MAAM,GAAG;IACb,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,8BAA8B;KACxC;IACD,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,4BAA4B;KACtC;IACD,cAAc,EAAE;QACd,IAAI,EAAE,QAAQ;QACd,IAAI,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,QAAQ,CAAC;QACvC,OAAO,EAAE,UAAU;KACpB;IACD,eAAe,EAAE;QACf,IAAI,EAAE,QAAQ;KACf;CACO,CAAC;AAEX,MAAM,OAAO,WAAW;IACd,IAAI,CAAkB;IAE9B;QACE,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,CAAY;YAC9B,WAAW,EAAE,aAAa;YAC1B,MAAM,EAAE,MAAa;YACrB,QAAQ,EAAE;gBACR,MAAM,EAAE,4BAA4B;gBACpC,cAAc,EAAE,UAAU;aACpB;SACT,CAAC,CAAC;IACL,CAAC;IAED,GAAG,CAA4B,GAAM;QACnC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,GAAG,CAA4B,GAAM,EAAE,KAAmB;QACxD,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC5B,CAAC;IAED,GAAG,CAAC,GAAoB;QACtB,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,CAAC,GAAoB;QACzB,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,MAAM;QACJ,OAAO,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC;IACzB,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;IACxB,CAAC;IAED,qBAAqB;IACrB,cAAc,CAAC,GAAW;QACxB,OAAO,8BAA8B,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClD,CAAC;IAED,UAAU,CAAC,GAAY;QACrB,IAAI,CAAC,GAAG;YAAE,OAAO,WAAW,CAAC;QAC7B,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACjC,OAAO,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,CAAC;IAED,kCAAkC;IAClC,YAAY;QACV,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACpD,CAAC;IAED,gBAAgB;QACd,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,wEAAwE,CACzE,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AAED,qBAAqB;AACrB,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for ThinkBrowse CLI
|
|
3
|
+
*/
|
|
4
|
+
export declare class ThinkBrowseError extends Error {
|
|
5
|
+
code: string;
|
|
6
|
+
suggestion?: string | undefined;
|
|
7
|
+
constructor(message: string, code: string, suggestion?: string | undefined);
|
|
8
|
+
}
|
|
9
|
+
export declare class ConfigError extends ThinkBrowseError {
|
|
10
|
+
constructor(message: string, suggestion?: string);
|
|
11
|
+
}
|
|
12
|
+
export declare class ApiError extends ThinkBrowseError {
|
|
13
|
+
statusCode?: number | undefined;
|
|
14
|
+
constructor(message: string, statusCode?: number | undefined, suggestion?: string);
|
|
15
|
+
}
|
|
16
|
+
export declare class SessionError extends ThinkBrowseError {
|
|
17
|
+
constructor(message: string, suggestion?: string);
|
|
18
|
+
}
|
|
19
|
+
export declare class ActionError extends ThinkBrowseError {
|
|
20
|
+
constructor(message: string, suggestion?: string);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,qBAAa,gBAAiB,SAAQ,KAAK;IAGhC,IAAI,EAAE,MAAM;IACZ,UAAU,CAAC,EAAE,MAAM;gBAF1B,OAAO,EAAE,MAAM,EACR,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,YAAA;CAK7B;AAED,qBAAa,WAAY,SAAQ,gBAAgB;gBACnC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAIjD;AAED,qBAAa,QAAS,SAAQ,gBAAgB;IAGnC,UAAU,CAAC,EAAE,MAAM;gBAD1B,OAAO,EAAE,MAAM,EACR,UAAU,CAAC,EAAE,MAAM,YAAA,EAC1B,UAAU,CAAC,EAAE,MAAM;CAKtB;AAED,qBAAa,YAAa,SAAQ,gBAAgB;gBACpC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAIjD;AAED,qBAAa,WAAY,SAAQ,gBAAgB;gBACnC,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM;CAIjD"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for ThinkBrowse CLI
|
|
3
|
+
*/
|
|
4
|
+
export class ThinkBrowseError extends Error {
|
|
5
|
+
code;
|
|
6
|
+
suggestion;
|
|
7
|
+
constructor(message, code, suggestion) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.suggestion = suggestion;
|
|
11
|
+
this.name = 'ThinkBrowseError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
export class ConfigError extends ThinkBrowseError {
|
|
15
|
+
constructor(message, suggestion) {
|
|
16
|
+
super(message, 'CONFIG_ERROR', suggestion);
|
|
17
|
+
this.name = 'ConfigError';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export class ApiError extends ThinkBrowseError {
|
|
21
|
+
statusCode;
|
|
22
|
+
constructor(message, statusCode, suggestion) {
|
|
23
|
+
super(message, 'API_ERROR', suggestion);
|
|
24
|
+
this.statusCode = statusCode;
|
|
25
|
+
this.name = 'ApiError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class SessionError extends ThinkBrowseError {
|
|
29
|
+
constructor(message, suggestion) {
|
|
30
|
+
super(message, 'SESSION_ERROR', suggestion);
|
|
31
|
+
this.name = 'SessionError';
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export class ActionError extends ThinkBrowseError {
|
|
35
|
+
constructor(message, suggestion) {
|
|
36
|
+
super(message, 'ACTION_ERROR', suggestion);
|
|
37
|
+
this.name = 'ActionError';
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAGhC;IACA;IAHT,YACE,OAAe,EACR,IAAY,EACZ,UAAmB;QAE1B,KAAK,CAAC,OAAO,CAAC,CAAC;QAHR,SAAI,GAAJ,IAAI,CAAQ;QACZ,eAAU,GAAV,UAAU,CAAS;QAG1B,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;IACjC,CAAC;CACF;AAED,MAAM,OAAO,WAAY,SAAQ,gBAAgB;IAC/C,YAAY,OAAe,EAAE,UAAmB;QAC9C,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF;AAED,MAAM,OAAO,QAAS,SAAQ,gBAAgB;IAGnC;IAFT,YACE,OAAe,EACR,UAAmB,EAC1B,UAAmB;QAEnB,KAAK,CAAC,OAAO,EAAE,WAAW,EAAE,UAAU,CAAC,CAAC;QAHjC,eAAU,GAAV,UAAU,CAAS;QAI1B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,gBAAgB;IAChD,YAAY,OAAe,EAAE,UAAmB;QAC9C,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,UAAU,CAAC,CAAC;QAC5C,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,OAAO,WAAY,SAAQ,gBAAgB;IAC/C,YAAY,OAAe,EAAE,UAAmB;QAC9C,KAAK,CAAC,OAAO,EAAE,cAAc,EAAE,UAAU,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;IAC5B,CAAC;CACF"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities
|
|
3
|
+
* Handles JSON vs pretty output modes
|
|
4
|
+
*/
|
|
5
|
+
export interface FormattedOutput {
|
|
6
|
+
success: boolean;
|
|
7
|
+
data?: any;
|
|
8
|
+
error?: string;
|
|
9
|
+
code?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function formatOutput(result: FormattedOutput, options?: {
|
|
12
|
+
json?: boolean;
|
|
13
|
+
quiet?: boolean;
|
|
14
|
+
}): void;
|
|
15
|
+
export declare function shouldUseJSON(globalOptions?: {
|
|
16
|
+
json?: boolean;
|
|
17
|
+
}): boolean;
|
|
18
|
+
//# sourceMappingURL=formatter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.d.ts","sourceRoot":"","sources":["../../../src/output/formatter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,IAAI,CAkBzG;AAED,wBAAgB,aAAa,CAAC,aAAa,CAAC,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAEzE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatting utilities
|
|
3
|
+
* Handles JSON vs pretty output modes
|
|
4
|
+
*/
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
export function formatOutput(result, options) {
|
|
7
|
+
if (options?.quiet && result.success) {
|
|
8
|
+
return; // Suppress output in quiet mode
|
|
9
|
+
}
|
|
10
|
+
if (options?.json || !process.stdout.isTTY) {
|
|
11
|
+
// JSON output for agents/scripts
|
|
12
|
+
console.log(JSON.stringify(result, null, 2));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
// Pretty output for humans (already handled by individual commands)
|
|
16
|
+
// This is just for consistency with JSON mode
|
|
17
|
+
if (!result.success && result.error) {
|
|
18
|
+
console.error(chalk.red('Error:'), result.error);
|
|
19
|
+
if (result.code) {
|
|
20
|
+
console.error(chalk.gray(`Code: ${result.code}`));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function shouldUseJSON(globalOptions) {
|
|
26
|
+
return globalOptions?.json === true || !process.stdout.isTTY;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=formatter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatter.js","sourceRoot":"","sources":["../../../src/output/formatter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAS1B,MAAM,UAAU,YAAY,CAAC,MAAuB,EAAE,OAA6C;IACjG,IAAI,OAAO,EAAE,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACrC,OAAO,CAAC,gCAAgC;IAC1C,CAAC;IAED,IAAI,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC3C,iCAAiC;QACjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC;SAAM,CAAC;QACN,oEAAoE;QACpE,8CAA8C;QAC9C,IAAI,CAAC,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;YACjD,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;gBAChB,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,aAAkC;IAC9D,OAAO,aAAa,EAAE,IAAI,KAAK,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC;AAC/D,CAAC"}
|