natureco-cli 2.23.29 → 2.23.31
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 +94 -11
- package/bin/natureco.js +495 -94
- package/package.json +1 -1
- package/src/commands/acp.js +39 -0
- package/src/commands/admin-rpc.js +302 -0
- package/src/commands/agent.js +280 -0
- package/src/commands/agents.js +114 -30
- package/src/commands/approvals.js +214 -0
- package/src/commands/backup.js +124 -0
- package/src/commands/bonjour.js +167 -0
- package/src/commands/browser.js +815 -0
- package/src/commands/capability.js +237 -0
- package/src/commands/channels.js +422 -267
- package/src/commands/chat.js +5 -8
- package/src/commands/clawbot.js +19 -0
- package/src/commands/clickclack.js +130 -0
- package/src/commands/code.js +3 -2
- package/src/commands/commitments.js +148 -0
- package/src/commands/completion.js +84 -0
- package/src/commands/config.js +219 -30
- package/src/commands/configure.js +110 -0
- package/src/commands/crestodian.js +92 -0
- package/src/commands/cron.js +239 -19
- package/src/commands/daemon.js +90 -0
- package/src/commands/dashboard.js +47 -374
- package/src/commands/device-pair.js +248 -0
- package/src/commands/devices.js +137 -0
- package/src/commands/directory.js +179 -0
- package/src/commands/dns.js +196 -0
- package/src/commands/docs.js +136 -0
- package/src/commands/doctor.js +143 -492
- package/src/commands/exec-policy.js +80 -0
- package/src/commands/gateway-server.js +1155 -24
- package/src/commands/gateway.js +492 -249
- package/src/commands/health.js +148 -0
- package/src/commands/help.js +24 -25
- package/src/commands/hooks.js +141 -87
- package/src/commands/imessage.js +128 -14
- package/src/commands/infer.js +1474 -0
- package/src/commands/irc.js +64 -15
- package/src/commands/logs.js +122 -99
- package/src/commands/mattermost.js +114 -12
- package/src/commands/mcp.js +121 -309
- package/src/commands/memory-cmd.js +134 -1
- package/src/commands/memory.js +128 -0
- package/src/commands/message.js +720 -134
- package/src/commands/migrate.js +213 -2
- package/src/commands/models.js +39 -1
- package/src/commands/node.js +98 -0
- package/src/commands/nodes.js +362 -0
- package/src/commands/oc-path.js +200 -0
- package/src/commands/onboard.js +129 -0
- package/src/commands/open-prose.js +67 -0
- package/src/commands/pairing.js +108 -107
- package/src/commands/path.js +206 -0
- package/src/commands/plugins.js +35 -1
- package/src/commands/policy.js +176 -0
- package/src/commands/proxy.js +306 -0
- package/src/commands/qr.js +70 -0
- package/src/commands/reset.js +101 -94
- package/src/commands/sandbox.js +125 -0
- package/src/commands/secrets.js +201 -0
- package/src/commands/sessions.js +110 -51
- package/src/commands/setup.js +102 -543
- package/src/commands/signal.js +447 -18
- package/src/commands/skills.js +67 -1
- package/src/commands/sms.js +123 -19
- package/src/commands/status.js +101 -127
- package/src/commands/system.js +53 -0
- package/src/commands/tasks.js +208 -100
- package/src/commands/terminal.js +139 -0
- package/src/commands/thread-ownership.js +157 -0
- package/src/commands/transcripts.js +95 -0
- package/src/commands/tui.js +41 -0
- package/src/commands/uninstall.js +73 -92
- package/src/commands/update.js +146 -91
- package/src/commands/voice.js +82 -0
- package/src/commands/vydra.js +98 -0
- package/src/commands/webhooks.js +58 -66
- package/src/commands/wiki.js +783 -0
- package/src/commands/workboard.js +207 -0
- package/src/tools/audio_understanding.js +154 -0
- package/src/tools/browser.js +112 -0
- package/src/tools/canvas.js +104 -0
- package/src/tools/document_extract.js +84 -0
- package/src/tools/duckduckgo.js +54 -0
- package/src/tools/exa_search.js +66 -0
- package/src/tools/firecrawl.js +104 -0
- package/src/tools/image_generation.js +99 -0
- package/src/tools/llm_task.js +118 -0
- package/src/tools/media_understanding.js +128 -0
- package/src/tools/music_generation.js +113 -0
- package/src/tools/parallel_search.js +77 -0
- package/src/tools/phone_control.js +80 -0
- package/src/tools/phone_control_enhanced.js +184 -0
- package/src/tools/searxng.js +61 -0
- package/src/tools/speech_to_text.js +135 -0
- package/src/tools/text_to_speech.js +105 -0
- package/src/tools/thread_ownership.js +88 -0
- package/src/tools/video_generation.js +72 -0
- package/src/tools/web_readability.js +104 -0
- package/src/utils/agents-md.js +85 -0
- package/src/utils/api.js +39 -40
- package/src/utils/format.js +144 -0
- package/src/utils/headless.js +2 -1
- package/src/utils/memory.js +200 -0
- package/src/utils/parallel-tools.js +106 -0
- package/src/utils/sub-agent.js +148 -0
- package/src/utils/token-budget.js +304 -0
- package/src/utils/tool-runner.js +7 -5
- package/src/utils/web-fetch.js +107 -0
|
@@ -0,0 +1,815 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const os = require('os');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const { getConfig, saveConfig } = require('../utils/config');
|
|
6
|
+
|
|
7
|
+
const BROWSER_STATE_FILE = path.join(os.homedir(), '.natureco', 'browser-state.json');
|
|
8
|
+
|
|
9
|
+
function getState() {
|
|
10
|
+
if (!fs.existsSync(BROWSER_STATE_FILE)) {
|
|
11
|
+
return { running: false, currentUrl: null, tabs: [], focusedTabId: null };
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(fs.readFileSync(BROWSER_STATE_FILE, 'utf8'));
|
|
15
|
+
} catch {
|
|
16
|
+
return { running: false, currentUrl: null, tabs: [], focusedTabId: null };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function saveState(state) {
|
|
21
|
+
const dir = path.dirname(BROWSER_STATE_FILE);
|
|
22
|
+
if (!fs.existsSync(dir)) {
|
|
23
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
24
|
+
}
|
|
25
|
+
fs.writeFileSync(BROWSER_STATE_FILE, JSON.stringify(state, null, 2), 'utf8');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function browser(args) {
|
|
29
|
+
const [action, ...params] = args || [];
|
|
30
|
+
|
|
31
|
+
if (!action || action === 'status') return cmdStatus();
|
|
32
|
+
if (action === 'doctor') return cmdDoctor();
|
|
33
|
+
if (action === 'start') return cmdStart();
|
|
34
|
+
if (action === 'stop') return cmdStop();
|
|
35
|
+
if (action === 'profiles') return cmdProfiles();
|
|
36
|
+
if (action === 'tabs') return cmdTabs();
|
|
37
|
+
if (action === 'open') return cmdOpen(params);
|
|
38
|
+
if (action === 'close') return cmdClose(params[0]);
|
|
39
|
+
if (action === 'focus') return cmdFocus(params[0]);
|
|
40
|
+
if (action === 'navigate') return cmdNavigate(params[0]);
|
|
41
|
+
if (action === 'screenshot') return cmdScreenshot(params);
|
|
42
|
+
if (action === 'snapshot') return cmdSnapshot();
|
|
43
|
+
if (action === 'click') return cmdClick(params[0]);
|
|
44
|
+
if (action === 'type') return cmdType(params[0], params.slice(1).join(' '));
|
|
45
|
+
if (action === 'press') return cmdPress(params[0]);
|
|
46
|
+
if (action === 'resize') return cmdResize(params[0], params[1]);
|
|
47
|
+
if (action === 'hover') return cmdHover(params[0]);
|
|
48
|
+
if (action === 'drag') return cmdDrag(params[0], params[1], params[2]);
|
|
49
|
+
if (action === 'select') return cmdSelect(params[0], params[1]);
|
|
50
|
+
if (action === 'upload') return cmdUpload(params[0], params[1]);
|
|
51
|
+
if (action === 'fill') return cmdFill(params[0], params.slice(1).join(' '));
|
|
52
|
+
if (action === 'dialog') return cmdDialog(params[0]);
|
|
53
|
+
if (action === 'wait') return cmdWait(params[0]);
|
|
54
|
+
if (action === 'evaluate') return cmdEvaluate(params.join(' '));
|
|
55
|
+
if (action === 'console') return cmdConsole();
|
|
56
|
+
if (action === 'pdf') return cmdPdf(params[0]);
|
|
57
|
+
if (action === 'reset-profile') return cmdResetProfile(params[0]);
|
|
58
|
+
if (action === 'create-profile') return cmdCreateProfile(params[0]);
|
|
59
|
+
if (action === 'delete-profile') return cmdDeleteProfile(params[0]);
|
|
60
|
+
|
|
61
|
+
console.log(chalk.red(`\n Unknown browser command: ${action}\n`));
|
|
62
|
+
console.log(chalk.gray(' Usage: natureco browser <command> [options]\n'));
|
|
63
|
+
console.log(chalk.gray(' Commands:'));
|
|
64
|
+
console.log(chalk.gray(' status Show browser status'));
|
|
65
|
+
console.log(chalk.gray(' doctor Check browser readiness'));
|
|
66
|
+
console.log(chalk.gray(' start Start browser session'));
|
|
67
|
+
console.log(chalk.gray(' stop Stop browser session'));
|
|
68
|
+
console.log(chalk.gray(' profiles List browser profiles'));
|
|
69
|
+
console.log(chalk.gray(' tabs List open tabs'));
|
|
70
|
+
console.log(chalk.gray(' open <url> [--label <name>] Open URL in new tab'));
|
|
71
|
+
console.log(chalk.gray(' close <target> Close tab by id or label'));
|
|
72
|
+
console.log(chalk.gray(' focus <target> Focus tab by id or label'));
|
|
73
|
+
console.log(chalk.gray(' navigate <url> Navigate current tab'));
|
|
74
|
+
console.log(chalk.gray(' screenshot [--full-page] Take screenshot'));
|
|
75
|
+
console.log(chalk.gray(' snapshot Get page snapshot'));
|
|
76
|
+
console.log(chalk.gray(' click <ref> Click element by ref'));
|
|
77
|
+
console.log(chalk.gray(' type <ref> <text> Type text into element'));
|
|
78
|
+
console.log(chalk.gray(' press <key> Press keyboard key'));
|
|
79
|
+
console.log(chalk.gray(' resize <width> <height> Resize browser window'));
|
|
80
|
+
console.log(chalk.gray(' hover <selector> Hover over element'));
|
|
81
|
+
console.log(chalk.gray(' drag <selector> <x> <y> Drag element by offset'));
|
|
82
|
+
console.log(chalk.gray(' select <selector> <value> Select dropdown option'));
|
|
83
|
+
console.log(chalk.gray(' upload <selector> <path> Upload file'));
|
|
84
|
+
console.log(chalk.gray(' fill <selector> <text> Fill form field'));
|
|
85
|
+
console.log(chalk.gray(' dialog <action> Handle dialog (accept/dismiss)'));
|
|
86
|
+
console.log(chalk.gray(' wait <ms> Wait for milliseconds'));
|
|
87
|
+
console.log(chalk.gray(' evaluate <code> Evaluate JS in page'));
|
|
88
|
+
console.log(chalk.gray(' console Get console logs'));
|
|
89
|
+
console.log(chalk.gray(' pdf <path> Save page as PDF'));
|
|
90
|
+
console.log(chalk.gray(' reset-profile [name] Reset browser profile'));
|
|
91
|
+
console.log(chalk.gray(' create-profile <name> Create new profile'));
|
|
92
|
+
console.log(chalk.gray(' delete-profile <name> Delete profile\n'));
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function cmdStatus() {
|
|
97
|
+
const state = getState();
|
|
98
|
+
|
|
99
|
+
console.log(chalk.cyan('\n Browser Status\n'));
|
|
100
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
101
|
+
|
|
102
|
+
if (state.running) {
|
|
103
|
+
console.log(chalk.green(' Status: Running'));
|
|
104
|
+
} else {
|
|
105
|
+
console.log(chalk.gray(' Status: Stopped'));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const tabCount = state.tabs ? state.tabs.length : 0;
|
|
109
|
+
console.log(chalk.white(` Tabs: ${tabCount}`));
|
|
110
|
+
|
|
111
|
+
if (state.currentUrl) {
|
|
112
|
+
console.log(chalk.white(' Current URL:'), chalk.gray(state.currentUrl));
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (state.focusedTabId) {
|
|
116
|
+
const focused = (state.tabs || []).find(t => t.id === state.focusedTabId);
|
|
117
|
+
if (focused) {
|
|
118
|
+
console.log(chalk.white(' Focused tab:'), chalk.gray(`${focused.label || focused.id} (${focused.url})`));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
console.log(chalk.gray(' State file:'), chalk.gray(BROWSER_STATE_FILE));
|
|
123
|
+
console.log();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function cmdDoctor() {
|
|
127
|
+
const config = getConfig();
|
|
128
|
+
const profiles = config.browser && config.browser.profiles ? config.browser.profiles : {};
|
|
129
|
+
|
|
130
|
+
console.log(chalk.cyan('\n Browser Doctor\n'));
|
|
131
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
132
|
+
|
|
133
|
+
let allGood = true;
|
|
134
|
+
|
|
135
|
+
const profileCount = Object.keys(profiles).length;
|
|
136
|
+
if (profileCount > 0) {
|
|
137
|
+
console.log(chalk.green(' Profiles:'), chalk.white(`${profileCount} configured`));
|
|
138
|
+
} else {
|
|
139
|
+
console.log(chalk.yellow(' Profiles: None configured'));
|
|
140
|
+
console.log(chalk.gray(' Run `browser start` to create a default profile'));
|
|
141
|
+
allGood = false;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const stateDir = path.dirname(BROWSER_STATE_FILE);
|
|
145
|
+
if (fs.existsSync(stateDir)) {
|
|
146
|
+
console.log(chalk.green(' State directory:'), chalk.white(stateDir));
|
|
147
|
+
} else {
|
|
148
|
+
console.log(chalk.yellow(' State directory: Not created yet'));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
const chromiumPaths = getChromiumPaths();
|
|
152
|
+
let foundBrowser = false;
|
|
153
|
+
for (const cp of chromiumPaths) {
|
|
154
|
+
if (fs.existsSync(cp)) {
|
|
155
|
+
console.log(chalk.green(' Browser binary:'), chalk.white(cp));
|
|
156
|
+
foundBrowser = true;
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (!foundBrowser) {
|
|
161
|
+
console.log(chalk.yellow(' Browser binary: Not detected'));
|
|
162
|
+
console.log(chalk.gray(' Install Chrome/Chromium/Brave for automation support'));
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (allGood) {
|
|
166
|
+
console.log(chalk.green('\n All checks passed.\n'));
|
|
167
|
+
} else {
|
|
168
|
+
console.log(chalk.yellow('\n Some items need attention.\n'));
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function cmdStart() {
|
|
173
|
+
const state = getState();
|
|
174
|
+
if (state.running) {
|
|
175
|
+
console.log(chalk.yellow('\n Browser session is already running.\n'));
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const config = getConfig();
|
|
180
|
+
if (!config.browser) config.browser = {};
|
|
181
|
+
if (!config.browser.profiles) config.browser.profiles = {};
|
|
182
|
+
|
|
183
|
+
const profiles = config.browser.profiles;
|
|
184
|
+
if (Object.keys(profiles).length === 0) {
|
|
185
|
+
const defaultProfile = {
|
|
186
|
+
name: 'default',
|
|
187
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
|
188
|
+
viewport: { width: 1280, height: 720 },
|
|
189
|
+
created: new Date().toISOString()
|
|
190
|
+
};
|
|
191
|
+
config.browser.profiles.default = defaultProfile;
|
|
192
|
+
saveConfig(config);
|
|
193
|
+
console.log(chalk.green(' Created default browser profile.\n'));
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
state.running = true;
|
|
197
|
+
state.currentUrl = null;
|
|
198
|
+
state.tabs = [];
|
|
199
|
+
state.focusedTabId = null;
|
|
200
|
+
saveState(state);
|
|
201
|
+
|
|
202
|
+
console.log(chalk.green('\n Browser session started.\n'));
|
|
203
|
+
console.log(chalk.gray(' Browser automation is ready. Use CDP-compatible browser to connect.\n'));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function cmdStop() {
|
|
207
|
+
const state = getState();
|
|
208
|
+
if (!state.running) {
|
|
209
|
+
console.log(chalk.yellow('\n No browser session is running.\n'));
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
state.running = false;
|
|
214
|
+
state.currentUrl = null;
|
|
215
|
+
state.tabs = [];
|
|
216
|
+
state.focusedTabId = null;
|
|
217
|
+
saveState(state);
|
|
218
|
+
|
|
219
|
+
console.log(chalk.gray('\n Browser session stopped.\n'));
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function cmdProfiles() {
|
|
223
|
+
const config = getConfig();
|
|
224
|
+
const profiles = config.browser && config.browser.profiles ? config.browser.profiles : {};
|
|
225
|
+
|
|
226
|
+
console.log(chalk.cyan('\n Browser Profiles\n'));
|
|
227
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
228
|
+
|
|
229
|
+
const keys = Object.keys(profiles);
|
|
230
|
+
if (keys.length === 0) {
|
|
231
|
+
console.log(chalk.gray(' No profiles configured.\n'));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
for (const key of keys) {
|
|
236
|
+
const p = profiles[key];
|
|
237
|
+
console.log(chalk.white(` ${key}`));
|
|
238
|
+
console.log(chalk.gray(` User Agent: ${p.userAgent || 'default'}`));
|
|
239
|
+
if (p.viewport) {
|
|
240
|
+
console.log(chalk.gray(` Viewport: ${p.viewport.width}x${p.viewport.height}`));
|
|
241
|
+
}
|
|
242
|
+
if (p.created) {
|
|
243
|
+
console.log(chalk.gray(` Created: ${p.created}`));
|
|
244
|
+
}
|
|
245
|
+
console.log();
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function cmdTabs() {
|
|
250
|
+
const state = getState();
|
|
251
|
+
if (!state.running) {
|
|
252
|
+
console.log(chalk.yellow('\n Browser is not running. Start it with `browser start`.\n'));
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
const tabs = state.tabs || [];
|
|
257
|
+
|
|
258
|
+
console.log(chalk.cyan('\n Open Tabs\n'));
|
|
259
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
260
|
+
|
|
261
|
+
if (tabs.length === 0) {
|
|
262
|
+
console.log(chalk.gray(' No open tabs.\n'));
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
for (const tab of tabs) {
|
|
267
|
+
const focusMark = tab.id === state.focusedTabId ? chalk.green(' <-- focused') : '';
|
|
268
|
+
console.log(chalk.white(` [${tab.id}]`), chalk.gray(tab.label || 'untitled'), chalk.gray('-'), chalk.white(tab.url) + focusMark);
|
|
269
|
+
}
|
|
270
|
+
console.log();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function cmdOpen(params) {
|
|
274
|
+
const state = getState();
|
|
275
|
+
if (!state.running) {
|
|
276
|
+
console.log(chalk.yellow('\n Browser is not running. Start it with `browser start`.\n'));
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
const url = params[0];
|
|
281
|
+
if (!url) {
|
|
282
|
+
console.log(chalk.red('\n URL is required.\n'));
|
|
283
|
+
console.log(chalk.gray(' Usage: browser open <url> [--label <name>]\n'));
|
|
284
|
+
process.exit(1);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let label = null;
|
|
288
|
+
const labelIdx = params.indexOf('--label');
|
|
289
|
+
if (labelIdx !== -1 && params[labelIdx + 1]) {
|
|
290
|
+
label = params[labelIdx + 1];
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const tabId = Date.now().toString(36) + Math.random().toString(36).slice(2, 6);
|
|
294
|
+
const tab = { id: tabId, label: label || url, url };
|
|
295
|
+
state.tabs = state.tabs || [];
|
|
296
|
+
state.tabs.push(tab);
|
|
297
|
+
state.focusedTabId = tabId;
|
|
298
|
+
state.currentUrl = url;
|
|
299
|
+
saveState(state);
|
|
300
|
+
|
|
301
|
+
console.log(chalk.green(`\n Opening: ${url}\n`));
|
|
302
|
+
console.log(chalk.gray(` Tab ID: ${tabId}`));
|
|
303
|
+
if (label) {
|
|
304
|
+
console.log(chalk.gray(` Label: ${label}`));
|
|
305
|
+
}
|
|
306
|
+
console.log(chalk.gray(' (CDP: Chrome DevTools Protocol would launch a new tab here)\n'));
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
function cmdClose(target) {
|
|
310
|
+
const state = getState();
|
|
311
|
+
if (!state.running) {
|
|
312
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (!target) {
|
|
317
|
+
console.log(chalk.red('\n Target tab id or label is required.\n'));
|
|
318
|
+
process.exit(1);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
const idx = (state.tabs || []).findIndex(t => t.id === target || t.label === target);
|
|
322
|
+
if (idx === -1) {
|
|
323
|
+
console.log(chalk.yellow(`\n Tab not found: ${target}\n`));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const removed = state.tabs.splice(idx, 1)[0];
|
|
328
|
+
if (state.focusedTabId === removed.id) {
|
|
329
|
+
state.focusedTabId = state.tabs.length > 0 ? state.tabs[state.tabs.length - 1].id : null;
|
|
330
|
+
}
|
|
331
|
+
state.currentUrl = state.focusedTabId
|
|
332
|
+
? (state.tabs.find(t => t.id === state.focusedTabId) || {}).url || null
|
|
333
|
+
: null;
|
|
334
|
+
saveState(state);
|
|
335
|
+
|
|
336
|
+
console.log(chalk.gray(`\n Closed tab: ${removed.label || removed.id}\n`));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function cmdFocus(target) {
|
|
340
|
+
const state = getState();
|
|
341
|
+
if (!state.running) {
|
|
342
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (!target) {
|
|
347
|
+
console.log(chalk.red('\n Target tab id or label is required.\n'));
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const tab = (state.tabs || []).find(t => t.id === target || t.label === target);
|
|
352
|
+
if (!tab) {
|
|
353
|
+
console.log(chalk.yellow(`\n Tab not found: ${target}\n`));
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
state.focusedTabId = tab.id;
|
|
358
|
+
state.currentUrl = tab.url;
|
|
359
|
+
saveState(state);
|
|
360
|
+
|
|
361
|
+
console.log(chalk.green(`\n Focused tab: ${tab.label || tab.id} (${tab.url})\n`));
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function cmdNavigate(url) {
|
|
365
|
+
const state = getState();
|
|
366
|
+
if (!state.running) {
|
|
367
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
if (!url) {
|
|
372
|
+
console.log(chalk.red('\n URL is required.\n'));
|
|
373
|
+
process.exit(1);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
if (state.focusedTabId) {
|
|
377
|
+
const tab = (state.tabs || []).find(t => t.id === state.focusedTabId);
|
|
378
|
+
if (tab) {
|
|
379
|
+
tab.url = url;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
state.currentUrl = url;
|
|
383
|
+
saveState(state);
|
|
384
|
+
|
|
385
|
+
console.log(chalk.green(`\n Navigating to: ${url}\n`));
|
|
386
|
+
console.log(chalk.gray(' (CDP: Page.navigate would be called)\n'));
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function cmdScreenshot(params) {
|
|
390
|
+
const state = getState();
|
|
391
|
+
if (!state.running) {
|
|
392
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
const fullPage = params.includes('--full-page');
|
|
397
|
+
|
|
398
|
+
const filename = `screenshot-${Date.now()}.png`;
|
|
399
|
+
const dir = path.join(os.homedir(), '.natureco', 'screenshots');
|
|
400
|
+
if (!fs.existsSync(dir)) {
|
|
401
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
402
|
+
}
|
|
403
|
+
const filepath = path.join(dir, filename);
|
|
404
|
+
|
|
405
|
+
console.log(chalk.cyan('\n Screenshot\n'));
|
|
406
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
407
|
+
console.log(chalk.white(` File: ${filepath}`));
|
|
408
|
+
console.log(chalk.white(` Full page: ${fullPage ? 'Yes' : 'No'}`));
|
|
409
|
+
console.log(chalk.gray(' (CDP: Page.captureScreenshot would be called)'));
|
|
410
|
+
console.log(chalk.gray(' (Screenshot metadata logged — actual capture requires CDP)\n'));
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function cmdSnapshot() {
|
|
414
|
+
const state = getState();
|
|
415
|
+
if (!state.running) {
|
|
416
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
417
|
+
return;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
const filename = `snapshot-${Date.now()}.html`;
|
|
421
|
+
const dir = path.join(os.homedir(), '.natureco', 'snapshots');
|
|
422
|
+
if (!fs.existsSync(dir)) {
|
|
423
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
424
|
+
}
|
|
425
|
+
const filepath = path.join(dir, filename);
|
|
426
|
+
|
|
427
|
+
let html = '<html><body><p>Snapshot mock — actual content requires CDP.</p></body></html>';
|
|
428
|
+
if (state.currentUrl) {
|
|
429
|
+
html = `<!DOCTYPE html><html><head><title>Snapshot of ${state.currentUrl}</title></head><body><p>Snapshot captured at ${new Date().toISOString()}</p><p>URL: ${state.currentUrl}</p></body></html>`;
|
|
430
|
+
}
|
|
431
|
+
fs.writeFileSync(filepath, html, 'utf8');
|
|
432
|
+
|
|
433
|
+
console.log(chalk.cyan('\n Page Snapshot\n'));
|
|
434
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
435
|
+
console.log(chalk.white(` Saved to: ${filepath}`));
|
|
436
|
+
console.log(chalk.gray(' (CDP: Page.captureSnapshot would be called)\n'));
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function cmdClick(ref) {
|
|
440
|
+
const state = getState();
|
|
441
|
+
if (!state.running) {
|
|
442
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
if (!ref) {
|
|
447
|
+
console.log(chalk.red('\n Element reference is required.\n'));
|
|
448
|
+
console.log(chalk.gray(' Usage: browser click <ref>\n'));
|
|
449
|
+
process.exit(1);
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
console.log(chalk.green(`\n Clicking element: ${ref}\n`));
|
|
453
|
+
console.log(chalk.gray(' (CDP: Input.dispatchMouseEvent would be called)\n'));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function cmdType(ref, text) {
|
|
457
|
+
const state = getState();
|
|
458
|
+
if (!state.running) {
|
|
459
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
if (!ref || !text) {
|
|
464
|
+
console.log(chalk.red('\n Element reference and text are required.\n'));
|
|
465
|
+
console.log(chalk.gray(' Usage: browser type <ref> <text>\n'));
|
|
466
|
+
process.exit(1);
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
console.log(chalk.green(`\n Typing into element: ${ref}\n`));
|
|
470
|
+
console.log(chalk.white(` Text: ${text}`));
|
|
471
|
+
console.log(chalk.gray(' (CDP: Input.dispatchKeyEvent would be called)\n'));
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function cmdPress(key) {
|
|
475
|
+
const state = getState();
|
|
476
|
+
if (!state.running) {
|
|
477
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (!key) {
|
|
482
|
+
console.log(chalk.red('\n Key is required.\n'));
|
|
483
|
+
console.log(chalk.gray(' Usage: browser press <key>\n'));
|
|
484
|
+
process.exit(1);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
console.log(chalk.green(`\n Pressing key: ${key}\n`));
|
|
488
|
+
console.log(chalk.gray(' (CDP: Input.dispatchKeyEvent would be called)\n'));
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function cmdResize(width, height) {
|
|
492
|
+
const state = getState();
|
|
493
|
+
if (!state.running) {
|
|
494
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
if (!width || !height) {
|
|
499
|
+
console.log(chalk.red('\n Width and height are required.\n'));
|
|
500
|
+
console.log(chalk.gray(' Usage: browser resize <width> <height>\n'));
|
|
501
|
+
process.exit(1);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
const w = parseInt(width, 10);
|
|
505
|
+
const h = parseInt(height, 10);
|
|
506
|
+
|
|
507
|
+
state.viewport = { width: w, height: h };
|
|
508
|
+
saveState(state);
|
|
509
|
+
|
|
510
|
+
console.log(chalk.green(`\n Resized browser to ${w}x${h}\n`));
|
|
511
|
+
console.log(chalk.gray(' (CDP: Browser.setWindowBounds would be called)\n'));
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function cmdHover(selector) {
|
|
515
|
+
const state = getState();
|
|
516
|
+
if (!state.running) {
|
|
517
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (!selector) {
|
|
522
|
+
console.log(chalk.red('\n Selector is required.\n'));
|
|
523
|
+
console.log(chalk.gray(' Usage: browser hover <selector>\n'));
|
|
524
|
+
process.exit(1);
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
console.log(chalk.green(`\n Hovering over: ${selector}\n`));
|
|
528
|
+
console.log(chalk.gray(' (CDP: Runtime.evaluate + Input.dispatchMouseEvent would be called)\n'));
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
function cmdDrag(selector, x, y) {
|
|
532
|
+
const state = getState();
|
|
533
|
+
if (!state.running) {
|
|
534
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
if (!selector || x === undefined || y === undefined) {
|
|
539
|
+
console.log(chalk.red('\n Selector, x, and y are required.\n'));
|
|
540
|
+
console.log(chalk.gray(' Usage: browser drag <selector> <x> <y>\n'));
|
|
541
|
+
process.exit(1);
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
console.log(chalk.green(`\n Dragging element: ${selector}\n`));
|
|
545
|
+
console.log(chalk.white(` Offset: (${x}, ${y})`));
|
|
546
|
+
console.log(chalk.gray(' (CDP: Input.dispatchMouseEvent mousedown + mousemove + mouseup would be called)\n'));
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
function cmdSelect(selector, value) {
|
|
550
|
+
const state = getState();
|
|
551
|
+
if (!state.running) {
|
|
552
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
if (!selector || value === undefined) {
|
|
557
|
+
console.log(chalk.red('\n Selector and value are required.\n'));
|
|
558
|
+
console.log(chalk.gray(' Usage: browser select <selector> <value>\n'));
|
|
559
|
+
process.exit(1);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
console.log(chalk.green(`\n Selecting option in: ${selector}\n`));
|
|
563
|
+
console.log(chalk.white(` Value: ${value}`));
|
|
564
|
+
console.log(chalk.gray(' (CDP: Runtime.evaluate to set selectedIndex would be called)\n'));
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
function cmdUpload(selector, filepath) {
|
|
568
|
+
const state = getState();
|
|
569
|
+
if (!state.running) {
|
|
570
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
571
|
+
return;
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (!selector || !filepath) {
|
|
575
|
+
console.log(chalk.red('\n Selector and file path are required.\n'));
|
|
576
|
+
console.log(chalk.gray(' Usage: browser upload <selector> <path>\n'));
|
|
577
|
+
process.exit(1);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
if (!fs.existsSync(filepath)) {
|
|
581
|
+
console.log(chalk.red(`\n File not found: ${filepath}\n`));
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
console.log(chalk.green(`\n Uploading file to: ${selector}\n`));
|
|
586
|
+
console.log(chalk.white(` File: ${filepath}`));
|
|
587
|
+
console.log(chalk.gray(' (CDP: DOM.setFileInputFiles would be called)\n'));
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function cmdFill(selector, text) {
|
|
591
|
+
const state = getState();
|
|
592
|
+
if (!state.running) {
|
|
593
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
if (!selector || text === undefined || text === '') {
|
|
598
|
+
console.log(chalk.red('\n Selector and text are required.\n'));
|
|
599
|
+
console.log(chalk.gray(' Usage: browser fill <selector> <text>\n'));
|
|
600
|
+
process.exit(1);
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
console.log(chalk.green(`\n Filling form field: ${selector}\n`));
|
|
604
|
+
console.log(chalk.white(` Text: ${text}`));
|
|
605
|
+
console.log(chalk.gray(' (CDP: Runtime.evaluate to set value + dispatch input event would be called)\n'));
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function cmdDialog(action) {
|
|
609
|
+
const state = getState();
|
|
610
|
+
if (!state.running) {
|
|
611
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
if (!action || (action !== 'accept' && action !== 'dismiss')) {
|
|
616
|
+
console.log(chalk.red('\n Action must be "accept" or "dismiss".\n'));
|
|
617
|
+
console.log(chalk.gray(' Usage: browser dialog <accept|dismiss>\n'));
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
state.lastDialogAction = action;
|
|
622
|
+
saveState(state);
|
|
623
|
+
|
|
624
|
+
console.log(chalk.green(`\n Dialog action: ${action}\n`));
|
|
625
|
+
console.log(chalk.gray(' (CDP: Page.handleJavaScriptDialog would be called)\n'));
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
function cmdWait(ms) {
|
|
629
|
+
const state = getState();
|
|
630
|
+
if (!state.running) {
|
|
631
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
if (!ms || isNaN(parseInt(ms, 10)) || parseInt(ms, 10) < 0) {
|
|
636
|
+
console.log(chalk.red('\n Valid milliseconds value is required.\n'));
|
|
637
|
+
console.log(chalk.gray(' Usage: browser wait <ms>\n'));
|
|
638
|
+
process.exit(1);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
console.log(chalk.gray(`\n Waiting ${ms}ms... (stub — would wait asynchronously)\n`));
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function cmdEvaluate(code) {
|
|
645
|
+
const state = getState();
|
|
646
|
+
if (!state.running) {
|
|
647
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
648
|
+
return;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (!code) {
|
|
652
|
+
console.log(chalk.red('\n JavaScript code is required.\n'));
|
|
653
|
+
console.log(chalk.gray(' Usage: browser evaluate <code>\n'));
|
|
654
|
+
process.exit(1);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
console.log(chalk.cyan('\n Evaluating JavaScript\n'));
|
|
658
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
659
|
+
console.log(chalk.white(' Code:'));
|
|
660
|
+
console.log(chalk.gray(` ${code}`));
|
|
661
|
+
console.log(chalk.gray(' (CDP: Runtime.evaluate would be called and result returned)\n'));
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
function cmdConsole() {
|
|
665
|
+
const state = getState();
|
|
666
|
+
if (!state.running) {
|
|
667
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
const logs = state.consoleLogs || [];
|
|
672
|
+
|
|
673
|
+
console.log(chalk.cyan('\n Console Logs\n'));
|
|
674
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
675
|
+
|
|
676
|
+
if (logs.length === 0) {
|
|
677
|
+
console.log(chalk.gray(' No console logs captured yet.\n'));
|
|
678
|
+
return;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
for (const log of logs) {
|
|
682
|
+
const level = log.level || 'log';
|
|
683
|
+
const color = level === 'error' ? chalk.red : level === 'warn' ? chalk.yellow : chalk.white;
|
|
684
|
+
console.log(` ${chalk.gray(`[${log.timestamp || ''}]`)} ${color(`[${level}]`)} ${log.text}`);
|
|
685
|
+
}
|
|
686
|
+
console.log();
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
function cmdPdf(filepath) {
|
|
690
|
+
const state = getState();
|
|
691
|
+
if (!state.running) {
|
|
692
|
+
console.log(chalk.yellow('\n Browser is not running.\n'));
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (!filepath) {
|
|
697
|
+
console.log(chalk.red('\n File path is required.\n'));
|
|
698
|
+
console.log(chalk.gray(' Usage: browser pdf <path>\n'));
|
|
699
|
+
process.exit(1);
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
console.log(chalk.cyan('\n Saving PDF\n'));
|
|
703
|
+
console.log(chalk.gray(' ' + '-'.repeat(48)));
|
|
704
|
+
console.log(chalk.white(` File: ${filepath}`));
|
|
705
|
+
console.log(chalk.gray(' (CDP: Page.printToPDF would be called)\n'));
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
function cmdResetProfile(name) {
|
|
709
|
+
const config = getConfig();
|
|
710
|
+
if (!config.browser) config.browser = {};
|
|
711
|
+
if (!config.browser.profiles) config.browser.profiles = {};
|
|
712
|
+
|
|
713
|
+
const profileName = name || 'default';
|
|
714
|
+
|
|
715
|
+
if (!config.browser.profiles[profileName]) {
|
|
716
|
+
console.log(chalk.yellow(`\n Profile not found: ${profileName}\n`));
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
config.browser.profiles[profileName] = {
|
|
721
|
+
name: profileName,
|
|
722
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
|
723
|
+
viewport: { width: 1280, height: 720 },
|
|
724
|
+
created: new Date().toISOString()
|
|
725
|
+
};
|
|
726
|
+
saveConfig(config);
|
|
727
|
+
|
|
728
|
+
console.log(chalk.green(`\n Profile reset: ${profileName}\n`));
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
function cmdCreateProfile(name) {
|
|
732
|
+
if (!name) {
|
|
733
|
+
console.log(chalk.red('\n Profile name is required.\n'));
|
|
734
|
+
console.log(chalk.gray(' Usage: browser create-profile <name>\n'));
|
|
735
|
+
process.exit(1);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
const config = getConfig();
|
|
739
|
+
if (!config.browser) config.browser = {};
|
|
740
|
+
if (!config.browser.profiles) config.browser.profiles = {};
|
|
741
|
+
|
|
742
|
+
if (config.browser.profiles[name]) {
|
|
743
|
+
console.log(chalk.yellow(`\n Profile already exists: ${name}\n`));
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
config.browser.profiles[name] = {
|
|
748
|
+
name,
|
|
749
|
+
userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
|
750
|
+
viewport: { width: 1280, height: 720 },
|
|
751
|
+
created: new Date().toISOString()
|
|
752
|
+
};
|
|
753
|
+
saveConfig(config);
|
|
754
|
+
|
|
755
|
+
console.log(chalk.green(`\n Profile created: ${name}\n`));
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function cmdDeleteProfile(name) {
|
|
759
|
+
if (!name) {
|
|
760
|
+
console.log(chalk.red('\n Profile name is required.\n'));
|
|
761
|
+
console.log(chalk.gray(' Usage: browser delete-profile <name>\n'));
|
|
762
|
+
process.exit(1);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const config = getConfig();
|
|
766
|
+
if (!config.browser) config.browser = {};
|
|
767
|
+
if (!config.browser.profiles) config.browser.profiles = {};
|
|
768
|
+
|
|
769
|
+
if (!config.browser.profiles[name]) {
|
|
770
|
+
console.log(chalk.yellow(`\n Profile not found: ${name}\n`));
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
delete config.browser.profiles[name];
|
|
775
|
+
saveConfig(config);
|
|
776
|
+
|
|
777
|
+
console.log(chalk.green(`\n Profile deleted: ${name}\n`));
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
function getChromiumPaths() {
|
|
781
|
+
const candidates = [];
|
|
782
|
+
const home = os.homedir();
|
|
783
|
+
|
|
784
|
+
const winPaths = [
|
|
785
|
+
path.join(process.env['PROGRAMFILES'] || 'C:\\Program Files', 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
786
|
+
path.join(process.env['PROGRAMFILES(X86)'] || 'C:\\Program Files (x86)', 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
787
|
+
path.join(process.env['LOCALAPPDATA'] || path.join(home, 'AppData', 'Local'), 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
788
|
+
path.join(process.env['PROGRAMFILES'] || 'C:\\Program Files', 'Chromium', 'Application', 'chrome.exe'),
|
|
789
|
+
path.join(process.env['LOCALAPPDATA'] || path.join(home, 'AppData', 'Local'), 'Chromium', 'Application', 'chrome.exe'),
|
|
790
|
+
path.join(process.env['PROGRAMFILES'] || 'C:\\Program Files', 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
|
|
791
|
+
path.join(process.env['LOCALAPPDATA'] || path.join(home, 'AppData', 'Local'), 'BraveSoftware', 'Brave-Browser', 'Application', 'brave.exe'),
|
|
792
|
+
path.join(process.env['PROGRAMFILES'] || 'C:\\Program Files', 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
|
|
793
|
+
path.join(process.env['LOCALAPPDATA'] || path.join(home, 'AppData', 'Local'), 'Microsoft', 'Edge', 'Application', 'msedge.exe'),
|
|
794
|
+
];
|
|
795
|
+
|
|
796
|
+
const unixPaths = [
|
|
797
|
+
'/usr/bin/google-chrome',
|
|
798
|
+
'/usr/bin/google-chrome-stable',
|
|
799
|
+
'/usr/bin/chromium',
|
|
800
|
+
'/usr/bin/chromium-browser',
|
|
801
|
+
'/usr/bin/brave-browser',
|
|
802
|
+
'/usr/bin/microsoft-edge',
|
|
803
|
+
'/snap/bin/chromium',
|
|
804
|
+
];
|
|
805
|
+
|
|
806
|
+
if (process.platform === 'win32') {
|
|
807
|
+
candidates.push(...winPaths);
|
|
808
|
+
} else {
|
|
809
|
+
candidates.push(...unixPaths);
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
return candidates;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
module.exports = browser;
|