@bsbofmusic/agent-browser-mcp-opencode 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/doctor.js ADDED
@@ -0,0 +1,387 @@
1
+ import { execSync } from 'child_process';
2
+ import os from 'os';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+ import { runFullDetection } from './detect.js';
7
+ import ensure from './ensure.js';
8
+ const { getAgentBrowserVersion, checkForUpdates } = ensure;
9
+
10
+ const __filename = fileURLToPath(import.meta.url);
11
+ const __dirname = path.dirname(__filename);
12
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
13
+
14
+ const LOG_LEVEL = process.env.LOG_LEVEL || 'info';
15
+
16
+ function log(level, message, data = null) {
17
+ const levels = { error: 0, warn: 1, info: 2, debug: 3 };
18
+ if (levels[level] <= levels[LOG_LEVEL]) {
19
+ const timestamp = new Date().toISOString();
20
+ console.error(`[${timestamp}] [${level.toUpperCase()}] ${message}`, data ? JSON.stringify(data) : '');
21
+ }
22
+ }
23
+
24
+ export async function diagnoseNetwork() {
25
+ const issues = [];
26
+ const checks = {
27
+ npmRegistry: false,
28
+ github: false,
29
+ google: false,
30
+ };
31
+
32
+ const checkUrl = (url) => {
33
+ try {
34
+ const cmd = process.platform === 'win32'
35
+ ? `ping -n 1 -w 2000 ${url} > nul 2>&1`
36
+ : `ping -c 1 -W 2 ${url} > /dev/null 2>&1`;
37
+ execSync(cmd, { timeout: 5000 });
38
+ return true;
39
+ } catch {
40
+ return false;
41
+ }
42
+ };
43
+
44
+ checks.npmRegistry = checkUrl('registry.npmjs.org');
45
+ checks.github = checkUrl('github.com');
46
+ checks.google = checkUrl('google.com');
47
+
48
+ if (!checks.npmRegistry) {
49
+ issues.push({
50
+ category: 'network',
51
+ severity: 'high',
52
+ message: 'Cannot reach npm registry (registry.npmjs.org)',
53
+ nextSteps: [
54
+ 'Check internet connection',
55
+ 'Configure npm mirror: npm config set registry https://registry.npmmirror.com',
56
+ 'Check proxy settings: npm config get proxy',
57
+ ],
58
+ });
59
+ }
60
+
61
+ if (!checks.github) {
62
+ issues.push({
63
+ category: 'network',
64
+ severity: 'medium',
65
+ message: 'Cannot reach github.com',
66
+ nextSteps: ['Check firewall/proxy settings'],
67
+ });
68
+ }
69
+
70
+ return { checks, issues };
71
+ }
72
+
73
+ export async function diagnosePermissions() {
74
+ const issues = [];
75
+ const checks = {
76
+ npmGlobalWritable: false,
77
+ tempWritable: false,
78
+ homeWritable: false,
79
+ };
80
+
81
+ try {
82
+ const npmPrefix = execSync('npm config get prefix', { encoding: 'utf8' }).trim();
83
+ const globalPath = path.join(npmPrefix, 'lib', 'node_modules');
84
+ try {
85
+ fs.accessSync(globalPath, fs.constants.W_OK);
86
+ checks.npmGlobalWritable = true;
87
+ } catch {
88
+ checks.npmGlobalWritable = false;
89
+ issues.push({
90
+ category: 'permissions',
91
+ severity: 'high',
92
+ message: `No write permission to npm global directory: ${globalPath}`,
93
+ nextSteps: [
94
+ 'Run: sudo chown -R $(whoami) $(npm config get prefix)/lib/node_modules',
95
+ 'Or use npx instead of global install',
96
+ ],
97
+ });
98
+ }
99
+ } catch (e) {
100
+ issues.push({
101
+ category: 'permissions',
102
+ severity: 'medium',
103
+ message: 'Cannot determine npm permissions',
104
+ nextSteps: ['Check npm installation'],
105
+ });
106
+ }
107
+
108
+ try {
109
+ const tempDir = os.tmpdir();
110
+ const testFile = path.join(tempDir, `test-${Date.now()}`);
111
+ fs.writeFileSync(testFile, 'test');
112
+ fs.unlinkSync(testFile);
113
+ checks.tempWritable = true;
114
+ } catch (e) {
115
+ checks.tempWritable = false;
116
+ issues.push({
117
+ category: 'permissions',
118
+ severity: 'high',
119
+ message: 'Cannot write to temp directory',
120
+ nextSteps: ['Check temp directory permissions', 'Set TMPDIR environment variable'],
121
+ });
122
+ }
123
+
124
+ try {
125
+ const homeDir = os.homedir();
126
+ const testFile = path.join(homeDir, `.test-${Date.now()}`);
127
+ fs.writeFileSync(testFile, 'test');
128
+ fs.unlinkSync(testFile);
129
+ checks.homeWritable = true;
130
+ } catch (e) {
131
+ checks.homeWritable = false;
132
+ issues.push({
133
+ category: 'permissions',
134
+ severity: 'high',
135
+ message: 'Cannot write to home directory',
136
+ nextSteps: ['Check home directory permissions'],
137
+ });
138
+ }
139
+
140
+ return { checks, issues };
141
+ }
142
+
143
+ export async function diagnoseDependencies() {
144
+ const issues = [];
145
+ const checks = {
146
+ nodeInstalled: false,
147
+ npmInstalled: false,
148
+ nodeVersion: null,
149
+ npmVersion: null,
150
+ };
151
+
152
+ try {
153
+ checks.nodeVersion = process.version;
154
+ checks.nodeInstalled = true;
155
+ } catch (e) {
156
+ issues.push({
157
+ category: 'dependencies',
158
+ severity: 'critical',
159
+ message: 'Node.js is not installed',
160
+ nextSteps: ['Install Node.js from https://nodejs.org'],
161
+ });
162
+ }
163
+
164
+ try {
165
+ checks.npmVersion = execSync('npm --version', { encoding: 'utf8' }).trim();
166
+ checks.npmInstalled = true;
167
+ } catch (e) {
168
+ issues.push({
169
+ category: 'dependencies',
170
+ severity: 'critical',
171
+ message: 'npm is not installed',
172
+ nextSteps: ['Reinstall Node.js which includes npm'],
173
+ });
174
+ }
175
+
176
+ if (checks.nodeInstalled) {
177
+ const [major] = process.version.slice(1).split('.');
178
+ if (parseInt(major) < 18) {
179
+ issues.push({
180
+ category: 'dependencies',
181
+ severity: 'high',
182
+ message: `Node.js version ${checks.nodeVersion} is too old (minimum 18.0.0)`,
183
+ nextSteps: ['Upgrade Node.js to version 18 or higher'],
184
+ });
185
+ }
186
+ }
187
+
188
+ return { checks, issues };
189
+ }
190
+
191
+ export async function diagnoseSystemLibraries() {
192
+ const issues = [];
193
+ const checks = {};
194
+ const platform = os.platform();
195
+
196
+ if (platform === 'linux') {
197
+ checks.linuxDeps = false;
198
+
199
+ try {
200
+ const result = execSync('ldconfig -p | grep -E "(libx11|libxcomposite|libxdamage|libxrandr|libatk|libatk-bridge|libxkbcommon|libglib)"', { encoding: 'utf8' });
201
+ checks.linuxDeps = result.trim().length > 0;
202
+ } catch {
203
+ issues.push({
204
+ category: 'system_libraries',
205
+ severity: 'high',
206
+ message: 'Missing required Linux system libraries for Chromium',
207
+ nextSteps: [
208
+ 'Run: npx playwright install-deps chromium',
209
+ 'Or: agent-browser install --with-deps',
210
+ ],
211
+ });
212
+ }
213
+ }
214
+
215
+ return { checks, issues };
216
+ }
217
+
218
+ export async function diagnoseExecutable() {
219
+ const issues = [];
220
+ const checks = {
221
+ agentBrowserInstalled: false,
222
+ agentBrowserVersion: null,
223
+ inPath: false,
224
+ };
225
+
226
+ try {
227
+ checks.agentBrowserVersion = execSync('agent-browser --version', { encoding: 'utf8' }).trim();
228
+ checks.agentBrowserInstalled = true;
229
+ checks.inPath = true;
230
+ } catch {
231
+ try {
232
+ checks.agentBrowserVersion = execSync('npx agent-browser --version', { encoding: 'utf8' }).trim();
233
+ checks.agentBrowserInstalled = true;
234
+ checks.inPath = false;
235
+ issues.push({
236
+ category: 'executable',
237
+ severity: 'medium',
238
+ message: 'agent-browser installed but not in PATH',
239
+ nextSteps: [
240
+ 'Add npm global bin to PATH',
241
+ 'Or use npx agent-browser instead of agent-browser',
242
+ ],
243
+ });
244
+ } catch {
245
+ checks.agentBrowserInstalled = false;
246
+ issues.push({
247
+ category: 'executable',
248
+ severity: 'critical',
249
+ message: 'agent-browser is not installed',
250
+ nextSteps: [
251
+ 'Run: npm install -g agent-browser',
252
+ 'Then: npx agent-browser install',
253
+ ],
254
+ });
255
+ }
256
+ }
257
+
258
+ return { checks, issues };
259
+ }
260
+
261
+ export async function diagnoseBrowser() {
262
+ const issues = [];
263
+ const checks = {
264
+ chromiumInstalled: false,
265
+ chromiumPath: null,
266
+ };
267
+
268
+ const homeDir = os.homedir();
269
+ const browserCachePath = path.join(homeDir, '.cache', 'ms-playwright');
270
+
271
+ if (fs.existsSync(browserCachePath)) {
272
+ try {
273
+ const files = fs.readdirSync(browserCachePath);
274
+ checks.chromiumInstalled = files.some(f => f.includes('chromium'));
275
+ checks.chromiumPath = browserCachePath;
276
+ } catch {
277
+ checks.chromiumInstalled = false;
278
+ }
279
+ }
280
+
281
+ if (!checks.chromiumInstalled) {
282
+ const agentBrowserPath = path.join(homeDir, '.agent-browser');
283
+ if (fs.existsSync(agentBrowserPath)) {
284
+ try {
285
+ const files = fs.readdirSync(agentBrowserPath);
286
+ checks.chromiumInstalled = files.some(f => f.includes('chromium') || f.includes('chrome'));
287
+ checks.chromiumPath = agentBrowserPath;
288
+ } catch {
289
+ checks.chromiumInstalled = false;
290
+ }
291
+ }
292
+ }
293
+
294
+ if (!checks.chromiumInstalled) {
295
+ issues.push({
296
+ category: 'browser',
297
+ severity: 'critical',
298
+ message: 'Chromium browser is not installed',
299
+ nextSteps: [
300
+ 'Run: npx agent-browser install',
301
+ 'Or: agent-browser install',
302
+ ],
303
+ });
304
+ }
305
+
306
+ return { checks, issues };
307
+ }
308
+
309
+ export async function diagnoseAuth() {
310
+ const issues = [];
311
+ const checks = {
312
+ hasEncryptedKey: false,
313
+ hasAuthCommands: false,
314
+ };
315
+
316
+ try {
317
+ execSync('agent-browser auth --help', { encoding: 'utf8', stdio: 'ignore' });
318
+ checks.hasAuthCommands = true;
319
+ } catch {
320
+ checks.hasAuthCommands = false;
321
+ }
322
+
323
+ const homeDir = os.homedir();
324
+ const keyPath = path.join(homeDir, '.agent-browser', '.encryption-key');
325
+ if (fs.existsSync(keyPath)) {
326
+ checks.hasEncryptedKey = true;
327
+ }
328
+
329
+ return { checks, issues };
330
+ }
331
+
332
+ export async function runDoctor() {
333
+ log('info', 'Starting doctor diagnosis...');
334
+
335
+ const diagnosis = {
336
+ timestamp: new Date().toISOString(),
337
+ network: await diagnoseNetwork(),
338
+ permissions: await diagnosePermissions(),
339
+ dependencies: await diagnoseDependencies(),
340
+ systemLibraries: await diagnoseSystemLibraries(),
341
+ executable: await diagnoseExecutable(),
342
+ browser: await diagnoseBrowser(),
343
+ auth: await diagnoseAuth(),
344
+ };
345
+
346
+ const allIssues = [
347
+ ...diagnosis.network.issues,
348
+ ...diagnosis.permissions.issues,
349
+ ...diagnosis.dependencies.issues,
350
+ ...diagnosis.systemLibraries.issues,
351
+ ...diagnosis.executable.issues,
352
+ ...diagnosis.browser.issues,
353
+ ...diagnosis.auth.issues,
354
+ ];
355
+
356
+ const summary = {
357
+ totalIssues: allIssues.length,
358
+ critical: allIssues.filter(i => i.severity === 'critical').length,
359
+ high: allIssues.filter(i => i.severity === 'high').length,
360
+ medium: allIssues.filter(i => i.severity === 'medium').length,
361
+ categories: [...new Set(allIssues.map(i => i.category))],
362
+ };
363
+
364
+ const updateInfo = await checkForUpdates();
365
+
366
+ const versionInfo = await getAgentBrowserVersion();
367
+
368
+ return {
369
+ ok: summary.critical === 0 && summary.high === 0,
370
+ summary,
371
+ issues: allIssues,
372
+ diagnosis,
373
+ versionInfo,
374
+ updateInfo,
375
+ };
376
+ }
377
+
378
+ export default {
379
+ runDoctor,
380
+ diagnoseNetwork,
381
+ diagnosePermissions,
382
+ diagnoseDependencies,
383
+ diagnoseSystemLibraries,
384
+ diagnoseExecutable,
385
+ diagnoseBrowser,
386
+ diagnoseAuth,
387
+ };