@browserbridge/bbx 1.0.0 → 1.0.1

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.
Files changed (52) hide show
  1. package/README.md +3 -1
  2. package/docs/api-reference.md +33 -33
  3. package/docs/mcp-vs-cli.md +104 -104
  4. package/docs/publishing.md +1 -3
  5. package/docs/quickstart.md +6 -6
  6. package/docs/unpacked-extension.md +72 -0
  7. package/manifest.json +3 -17
  8. package/package.json +44 -42
  9. package/packages/agent-client/src/cli-helpers.js +10 -5
  10. package/packages/agent-client/src/cli.js +65 -135
  11. package/packages/agent-client/src/client.js +37 -17
  12. package/packages/agent-client/src/command-registry.js +101 -69
  13. package/packages/agent-client/src/detect.js +3 -6
  14. package/packages/agent-client/src/install.js +10 -27
  15. package/packages/agent-client/src/mcp-config.js +11 -30
  16. package/packages/agent-client/src/runtime.js +41 -20
  17. package/packages/agent-client/src/setup-status.js +13 -28
  18. package/packages/extension/src/background-helpers.js +51 -36
  19. package/packages/extension/src/background-routing.js +11 -13
  20. package/packages/extension/src/background.js +562 -299
  21. package/packages/extension/src/content-script-helpers.js +17 -16
  22. package/packages/extension/src/content-script.js +175 -109
  23. package/packages/extension/src/sidepanel-helpers.js +3 -1
  24. package/packages/extension/ui/popup.js +39 -20
  25. package/packages/extension/ui/sidepanel.js +108 -191
  26. package/packages/extension/ui/ui.css +2 -1
  27. package/packages/mcp-server/src/handlers.js +546 -250
  28. package/packages/mcp-server/src/server.js +558 -257
  29. package/packages/native-host/bin/bridge-daemon.js +6 -2
  30. package/packages/native-host/bin/install-manifest.js +2 -2
  31. package/packages/native-host/bin/postinstall.js +4 -2
  32. package/packages/native-host/src/config.js +11 -7
  33. package/packages/native-host/src/daemon.js +143 -92
  34. package/packages/native-host/src/install-manifest.js +73 -22
  35. package/packages/native-host/src/native-host.js +55 -40
  36. package/packages/protocol/src/budget.js +3 -7
  37. package/packages/protocol/src/capabilities.js +3 -3
  38. package/packages/protocol/src/errors.js +11 -11
  39. package/packages/protocol/src/protocol.js +104 -71
  40. package/packages/protocol/src/registry.js +300 -45
  41. package/packages/protocol/src/summary.js +249 -106
  42. package/packages/protocol/src/types.js +1 -1
  43. package/skills/browser-bridge/SKILL.md +1 -1
  44. package/skills/browser-bridge/agents/openai.yaml +3 -3
  45. package/skills/browser-bridge/references/interaction.md +33 -11
  46. package/skills/browser-bridge/references/patch-workflow.md +3 -0
  47. package/skills/browser-bridge/references/protocol.md +125 -70
  48. package/skills/browser-bridge/references/tailwind.md +12 -11
  49. package/skills/browser-bridge/references/token-efficiency.md +23 -22
  50. package/skills/browser-bridge/references/ui-workflows.md +8 -0
  51. package/packages/extension/ui/offscreen.html +0 -6
  52. package/packages/extension/ui/offscreen.js +0 -61
@@ -35,10 +35,14 @@ for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP']) {
35
35
  }
36
36
 
37
37
  process.on('unhandledRejection', (reason) => {
38
- process.stderr.write(`Unhandled rejection: ${reason instanceof Error ? reason.stack : String(reason)}\n`);
38
+ process.stderr.write(
39
+ `Unhandled rejection: ${reason instanceof Error ? reason.stack : String(reason)}\n`
40
+ );
39
41
  });
40
42
 
41
43
  process.on('uncaughtException', (error) => {
42
- process.stderr.write(`Uncaught exception: ${error instanceof Error ? error.stack : String(error)}\n`);
44
+ process.stderr.write(
45
+ `Uncaught exception: ${error instanceof Error ? error.stack : String(error)}\n`
46
+ );
43
47
  void shutdown();
44
48
  });
@@ -37,7 +37,7 @@ for (let i = 0; i < args.length; i++) {
37
37
  if (extensionIdArg && !parseExtensionId(extensionIdArg)) {
38
38
  process.stderr.write(
39
39
  `Invalid extension ID: ${extensionIdArg}\n` +
40
- 'Expected 32 lowercase letters (e.g. abcdefghijklmnopabcdefghijklmnop)\n'
40
+ 'Expected 32 lowercase letters (e.g. abcdefghijklmnopabcdefghijklmnop)\n'
41
41
  );
42
42
  process.exit(1);
43
43
  }
@@ -52,6 +52,6 @@ for (const target of targets) {
52
52
  await installNativeManifest({
53
53
  repoRoot,
54
54
  extensionIdArg,
55
- browser: target
55
+ browser: target,
56
56
  });
57
57
  }
@@ -16,10 +16,12 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
16
  const repoRoot = path.resolve(__dirname, '../../..');
17
17
 
18
18
  try {
19
- await installNativeManifest({ repoRoot });
19
+ await installNativeManifest({ repoRoot, preserveCustomExtensionId: true });
20
20
  process.stdout.write('Browser Bridge: native host installed. Run `bbx doctor` to verify.\n');
21
21
  } catch (err) {
22
22
  // Non-fatal - user can run `bbx install` manually.
23
23
  const message = err instanceof Error ? err.message : String(err);
24
- process.stderr.write(`Browser Bridge: native host auto-install skipped (${message}).\nRun \`bbx install\` manually if needed.\n`);
24
+ process.stderr.write(
25
+ `Browser Bridge: native host auto-install skipped (${message}).\nRun \`bbx install\` manually if needed.\n`
26
+ );
25
27
  }
@@ -50,9 +50,7 @@ export function getSocketPath() {
50
50
  * @returns {string}
51
51
  */
52
52
  export function getLauncherFilename() {
53
- return os.platform() === 'win32'
54
- ? 'native-host-launcher.cmd'
55
- : 'native-host-launcher.sh';
53
+ return os.platform() === 'win32' ? 'native-host-launcher.cmd' : 'native-host-launcher.sh';
56
54
  }
57
55
 
58
56
  /**
@@ -84,7 +82,7 @@ export function getManifestInstallDir(browser = 'chrome') {
84
82
  edge: path.join(macBase, 'Microsoft Edge', 'NativeMessagingHosts'),
85
83
  brave: path.join(macBase, 'BraveSoftware', 'Brave-Browser', 'NativeMessagingHosts'),
86
84
  chromium: path.join(macBase, 'Chromium', 'NativeMessagingHosts'),
87
- arc: path.join(macBase, 'Arc', 'User Data', 'NativeMessagingHosts')
85
+ arc: path.join(macBase, 'Arc', 'User Data', 'NativeMessagingHosts'),
88
86
  };
89
87
  return macPaths[browser] ?? macPaths.chrome;
90
88
  }
@@ -94,9 +92,15 @@ export function getManifestInstallDir(browser = 'chrome') {
94
92
  const winPaths = {
95
93
  chrome: path.join(winBase, 'Google', 'Chrome', 'User Data', 'NativeMessagingHosts'),
96
94
  edge: path.join(winBase, 'Microsoft', 'Edge', 'User Data', 'NativeMessagingHosts'),
97
- brave: path.join(winBase, 'BraveSoftware', 'Brave-Browser', 'User Data', 'NativeMessagingHosts'),
95
+ brave: path.join(
96
+ winBase,
97
+ 'BraveSoftware',
98
+ 'Brave-Browser',
99
+ 'User Data',
100
+ 'NativeMessagingHosts'
101
+ ),
98
102
  chromium: path.join(winBase, 'Chromium', 'User Data', 'NativeMessagingHosts'),
99
- arc: path.join(winBase, 'Arc', 'User Data', 'NativeMessagingHosts')
103
+ arc: path.join(winBase, 'Arc', 'User Data', 'NativeMessagingHosts'),
100
104
  };
101
105
  return winPaths[browser] ?? winPaths.chrome;
102
106
  }
@@ -107,7 +111,7 @@ export function getManifestInstallDir(browser = 'chrome') {
107
111
  edge: path.join(home, '.config', 'microsoft-edge', 'NativeMessagingHosts'),
108
112
  brave: path.join(home, '.config', 'BraveSoftware', 'Brave-Browser', 'NativeMessagingHosts'),
109
113
  chromium: path.join(home, '.config', 'chromium', 'NativeMessagingHosts'),
110
- arc: path.join(home, '.config', 'Arc', 'User Data', 'NativeMessagingHosts')
114
+ arc: path.join(home, '.config', 'Arc', 'User Data', 'NativeMessagingHosts'),
111
115
  };
112
116
  return linuxPaths[browser] ?? linuxPaths.chrome;
113
117
  }
@@ -5,8 +5,16 @@ import net from 'node:net';
5
5
  import path from 'node:path';
6
6
  import { randomUUID } from 'node:crypto';
7
7
 
8
- import { installAgentFiles, isSupportedTarget, removeAgentFiles } from '../../agent-client/src/install.js';
9
- import { installMcpConfig, isMcpClientName, removeMcpConfig } from '../../agent-client/src/mcp-config.js';
8
+ import {
9
+ installAgentFiles,
10
+ isSupportedTarget,
11
+ removeAgentFiles,
12
+ } from '../../agent-client/src/install.js';
13
+ import {
14
+ installMcpConfig,
15
+ isMcpClientName,
16
+ removeMcpConfig,
17
+ } from '../../agent-client/src/mcp-config.js';
10
18
  import { collectSetupStatus } from '../../agent-client/src/setup-status.js';
11
19
  import {
12
20
  createFailure,
@@ -19,7 +27,7 @@ import {
19
27
  parseJsonLines,
20
28
  PROTOCOL_VERSION,
21
29
  SUPPORTED_VERSIONS,
22
- validateBridgeRequest
30
+ validateBridgeRequest,
23
31
  } from '../../protocol/src/index.js';
24
32
  import { getSocketPath } from './config.js';
25
33
  import { writeJsonLine } from './framing.js';
@@ -76,7 +84,7 @@ function getVersionNegotiationPayload(requestedVersion) {
76
84
  ...(localIsNewer ? { deprecated_since: latestSupported } : {}),
77
85
  migration_hint: localIsNewer
78
86
  ? `Browser Bridge daemon is newer than the client protocol ${requestedVersion}. Restart or update the Browser Bridge CLI/npm package to ${latestSupported} or later.`
79
- : `Browser Bridge daemon is older than the client protocol ${requestedVersion}. Restart or update the Browser Bridge CLI so the daemon supports ${requestedVersion}.`
87
+ : `Browser Bridge daemon is older than the client protocol ${requestedVersion}. Restart or update the Browser Bridge CLI so the daemon supports ${requestedVersion}.`,
80
88
  };
81
89
  }
82
90
 
@@ -108,7 +116,13 @@ export class BridgeDaemon {
108
116
  * logger?: Pick<Console, 'log' | 'error'>
109
117
  * }} [options={}]
110
118
  */
111
- constructor({ socketPath = getSocketPath(), listenOptions = null, setupStatusLoader = collectSetupStatus, setupInstaller = installSetupTarget, logger = console } = {}) {
119
+ constructor({
120
+ socketPath = getSocketPath(),
121
+ listenOptions = null,
122
+ setupStatusLoader = collectSetupStatus,
123
+ setupInstaller = installSetupTarget,
124
+ logger = console,
125
+ } = {}) {
112
126
  this.socketPath = socketPath;
113
127
  this.listenOptions = listenOptions;
114
128
  this.setupStatusLoader = setupStatusLoader;
@@ -140,8 +154,10 @@ export class BridgeDaemon {
140
154
  if (message.role === 'extension') {
141
155
  const extensionId = randomUUID();
142
156
  socket.__extensionId = extensionId;
143
- socket.__browserName = typeof message.browserName === 'string' ? message.browserName : undefined;
144
- socket.__profileLabel = typeof message.profileLabel === 'string' ? message.profileLabel : undefined;
157
+ socket.__browserName =
158
+ typeof message.browserName === 'string' ? message.browserName : undefined;
159
+ socket.__profileLabel =
160
+ typeof message.profileLabel === 'string' ? message.profileLabel : undefined;
145
161
  socket.__lastActiveAt = Date.now();
146
162
  this.extensionSockets.set(extensionId, socket);
147
163
  void writeJsonLine(socket, { type: 'registered', role: 'extension' });
@@ -152,7 +168,11 @@ export class BridgeDaemon {
152
168
  const clientId = message.clientId || randomUUID();
153
169
  this.agentSockets.set(clientId, socket);
154
170
  socket.__clientId = clientId;
155
- void writeJsonLine(socket, { type: 'registered', role: 'agent', clientId });
171
+ void writeJsonLine(socket, {
172
+ type: 'registered',
173
+ role: 'agent',
174
+ clientId,
175
+ });
156
176
  return;
157
177
  }
158
178
  }
@@ -169,7 +189,9 @@ export class BridgeDaemon {
169
189
  try {
170
190
  await fs.promises.access(this.socketPath);
171
191
  if (await pingExistingDaemon(this.socketPath)) {
172
- throw new Error(`Another daemon is already running on ${this.socketPath}. Stop it before starting a new one.`);
192
+ throw new Error(
193
+ `Another daemon is already running on ${this.socketPath}. Stop it before starting a new one.`
194
+ );
173
195
  }
174
196
  this.logger.log('[daemon] Removing stale socket from previous run:', this.socketPath);
175
197
  } catch (error) {
@@ -189,7 +211,10 @@ export class BridgeDaemon {
189
211
  parseJsonLines(typedSocket, (raw) => {
190
212
  const message = /** @type {DaemonMessage} */ (raw);
191
213
  void this.handleClientMessage(typedSocket, message).catch((err) => {
192
- this.logger.error?.('[daemon] handler error:', err instanceof Error ? err.message : String(err));
214
+ this.logger.error?.(
215
+ '[daemon] handler error:',
216
+ err instanceof Error ? err.message : String(err)
217
+ );
193
218
  });
194
219
  });
195
220
  typedSocket.on('close', () => this.handleSocketClose(typedSocket));
@@ -314,7 +339,10 @@ export class BridgeDaemon {
314
339
 
315
340
  await writeJsonLine(socket, {
316
341
  type: 'error',
317
- error: { code: ERROR_CODES.INVALID_REQUEST, message: 'Unknown message type.' }
342
+ error: {
343
+ code: ERROR_CODES.INVALID_REQUEST,
344
+ message: 'Unknown message type.',
345
+ },
318
346
  });
319
347
  }
320
348
 
@@ -332,7 +360,7 @@ export class BridgeDaemon {
332
360
  extensionConnected: false,
333
361
  socketPath: this.socketPath,
334
362
  connectedExtensions: [],
335
- ...getVersionNegotiationPayload(request.meta?.protocol_version)
363
+ ...getVersionNegotiationPayload(request.meta?.protocol_version),
336
364
  });
337
365
  await writeJsonLine(socket, { type: 'agent.response', response });
338
366
  return;
@@ -341,7 +369,7 @@ export class BridgeDaemon {
341
369
 
342
370
  if (request.method === 'log.tail') {
343
371
  const response = createSuccess(request.id, {
344
- entries: this.recentLog.slice(-DEFAULT_LOG_TAIL_LIMIT)
372
+ entries: this.recentLog.slice(-DEFAULT_LOG_TAIL_LIMIT),
345
373
  });
346
374
  await writeJsonLine(socket, { type: 'agent.response', response });
347
375
  return;
@@ -349,7 +377,7 @@ export class BridgeDaemon {
349
377
 
350
378
  if (request.method === 'setup.get_status') {
351
379
  const response = createSuccess(request.id, await this.setupStatusLoader(), {
352
- method: request.method
380
+ method: request.method,
353
381
  });
354
382
  await writeJsonLine(socket, { type: 'agent.response', response });
355
383
  return;
@@ -357,9 +385,13 @@ export class BridgeDaemon {
357
385
 
358
386
  if (request.method === 'setup.install') {
359
387
  try {
360
- const response = createSuccess(request.id, await this.setupInstaller(request.params ?? {}), {
361
- method: request.method
362
- });
388
+ const response = createSuccess(
389
+ request.id,
390
+ await this.setupInstaller(request.params ?? {}),
391
+ {
392
+ method: request.method,
393
+ }
394
+ );
363
395
  await writeJsonLine(socket, { type: 'agent.response', response });
364
396
  } catch (error) {
365
397
  const response = createFailure(
@@ -374,8 +406,10 @@ export class BridgeDaemon {
374
406
  return;
375
407
  }
376
408
 
377
- const targetBrowser = typeof request.meta?.target_browser === 'string' ? request.meta.target_browser : null;
378
- const targetProfile = typeof request.meta?.target_profile === 'string' ? request.meta.target_profile : null;
409
+ const targetBrowser =
410
+ typeof request.meta?.target_browser === 'string' ? request.meta.target_browser : null;
411
+ const targetProfile =
412
+ typeof request.meta?.target_profile === 'string' ? request.meta.target_profile : null;
379
413
  const hasExplicitTarget = Boolean(targetBrowser || targetProfile);
380
414
 
381
415
  let targets = Array.from(this.extensionSockets.values());
@@ -418,16 +452,19 @@ export class BridgeDaemon {
418
452
  const pending = this.pendingRequests.get(request.id);
419
453
  if (!pending) return;
420
454
  this.pendingRequests.delete(request.id);
421
- const response = createFailure(request.id, ERROR_CODES.TIMEOUT, 'Extension did not respond in time.');
422
- void writeJsonLine(pending.socket, { type: 'agent.response', response });
423
- }, this.pendingTimeoutMs)
455
+ const response = createFailure(
456
+ request.id,
457
+ ERROR_CODES.TIMEOUT,
458
+ 'Extension did not respond in time.'
459
+ );
460
+ void writeJsonLine(pending.socket, {
461
+ type: 'agent.response',
462
+ response,
463
+ });
464
+ }, this.pendingTimeoutMs),
424
465
  });
425
466
  const broadcastPayload = { type: 'extension.request', request };
426
- await Promise.all(
427
- targets.map(
428
- (extSocket) => writeJsonLine(extSocket, broadcastPayload)
429
- )
430
- );
467
+ await Promise.all(targets.map((extSocket) => writeJsonLine(extSocket, broadcastPayload)));
431
468
  }
432
469
 
433
470
  /**
@@ -440,15 +477,15 @@ export class BridgeDaemon {
440
477
  await writeJsonLine(socket, {
441
478
  type: 'extension.setup_status.response',
442
479
  requestId: message.requestId,
443
- status: await this.setupStatusLoader()
480
+ status: await this.setupStatusLoader(),
444
481
  });
445
482
  } catch (error) {
446
483
  await writeJsonLine(socket, {
447
484
  type: 'extension.setup_status.error',
448
485
  requestId: message.requestId,
449
486
  error: {
450
- message: error instanceof Error ? error.message : String(error)
451
- }
487
+ message: error instanceof Error ? error.message : String(error),
488
+ },
452
489
  });
453
490
  }
454
491
  }
@@ -483,9 +520,7 @@ export class BridgeDaemon {
483
520
  */
484
521
  handleExtensionActivity(socket, message) {
485
522
  socket.__lastActiveAt =
486
- typeof message.at === 'number' && Number.isFinite(message.at)
487
- ? message.at
488
- : Date.now();
523
+ typeof message.at === 'number' && Number.isFinite(message.at) ? message.at : Date.now();
489
524
  }
490
525
 
491
526
  /**
@@ -514,31 +549,36 @@ export class BridgeDaemon {
514
549
  method: responseMessage.meta?.method ?? null,
515
550
  ok: true,
516
551
  id: responseMessage.id,
517
- source: pending.source || null
552
+ source: pending.source || null,
518
553
  });
519
- const response = pending.method === 'health.ping'
520
- ? createSuccess(responseMessage.id, {
521
- daemon: 'ok',
522
- extensionConnected: true,
523
- socketPath: this.socketPath,
524
- connectedExtensions: Array.from(this.extensionSockets.entries()).map(
525
- ([_id, extSocket]) => ({
526
- extensionId: _id,
527
- browserName: extSocket.__browserName ?? null,
528
- profileLabel: extSocket.__profileLabel ?? null,
529
- accessEnabled: extSocket.__accessEnabled ?? false
530
- })
531
- ),
532
- .../** @type {Record<string, unknown>} */ (responseMessage.result)
533
- }, {
534
- ...responseMessage.meta,
535
- method: responseMessage.meta?.method ?? pending.method
536
- })
537
- : responseMessage;
554
+ const response =
555
+ pending.method === 'health.ping'
556
+ ? createSuccess(
557
+ responseMessage.id,
558
+ {
559
+ daemon: 'ok',
560
+ extensionConnected: true,
561
+ socketPath: this.socketPath,
562
+ connectedExtensions: Array.from(this.extensionSockets.entries()).map(
563
+ ([_id, extSocket]) => ({
564
+ extensionId: _id,
565
+ browserName: extSocket.__browserName ?? null,
566
+ profileLabel: extSocket.__profileLabel ?? null,
567
+ accessEnabled: extSocket.__accessEnabled ?? false,
568
+ })
569
+ ),
570
+ .../** @type {Record<string, unknown>} */ (responseMessage.result),
571
+ },
572
+ {
573
+ ...responseMessage.meta,
574
+ method: responseMessage.meta?.method ?? pending.method,
575
+ }
576
+ )
577
+ : responseMessage;
538
578
 
539
579
  await writeJsonLine(pending.socket, {
540
580
  type: 'agent.response',
541
- response
581
+ response,
542
582
  });
543
583
  return;
544
584
  }
@@ -591,25 +631,27 @@ export class BridgeDaemon {
591
631
  clearTimeout(pending.timeoutId);
592
632
  this.pendingRequests.delete(requestId);
593
633
 
594
- const response = pending.lastErrorResponse ?? createFailure(
595
- requestId,
596
- ERROR_CODES.EXTENSION_DISCONNECTED,
597
- 'Target extension disconnected before responding.',
598
- null,
599
- { method: pending.method }
600
- );
634
+ const response =
635
+ pending.lastErrorResponse ??
636
+ createFailure(
637
+ requestId,
638
+ ERROR_CODES.EXTENSION_DISCONNECTED,
639
+ 'Target extension disconnected before responding.',
640
+ null,
641
+ { method: pending.method }
642
+ );
601
643
 
602
644
  this.pushLog({
603
645
  at: new Date().toISOString(),
604
646
  method: response.meta?.method ?? pending.method ?? null,
605
647
  ok: false,
606
648
  id: requestId,
607
- source: pending.source || null
649
+ source: pending.source || null,
608
650
  });
609
651
 
610
652
  await writeJsonLine(pending.socket, {
611
653
  type: 'agent.response',
612
- response
654
+ response,
613
655
  });
614
656
  }
615
657
 
@@ -636,8 +678,7 @@ function selectMostRecentlyActiveExtension(sockets) {
636
678
 
637
679
  return sockets.reduce((best, current) => {
638
680
  const bestAt = typeof best.__lastActiveAt === 'number' ? best.__lastActiveAt : 0;
639
- const currentAt =
640
- typeof current.__lastActiveAt === 'number' ? current.__lastActiveAt : 0;
681
+ const currentAt = typeof current.__lastActiveAt === 'number' ? current.__lastActiveAt : 0;
641
682
  return currentAt > bestAt ? current : best;
642
683
  });
643
684
  }
@@ -679,16 +720,18 @@ async function pingExistingDaemon(socketPath) {
679
720
  });
680
721
 
681
722
  socket.once('connect', () => {
682
- socket.write(`${JSON.stringify({
683
- type: 'agent.request',
684
- request: {
685
- id: 'ping_probe',
686
- method: 'health.ping',
687
- tab_id: null,
688
- params: {},
689
- meta: { protocol_version: PROTOCOL_VERSION, token_budget: null }
690
- }
691
- })}\n`);
723
+ socket.write(
724
+ `${JSON.stringify({
725
+ type: 'agent.request',
726
+ request: {
727
+ id: 'ping_probe',
728
+ method: 'health.ping',
729
+ tab_id: null,
730
+ params: {},
731
+ meta: { protocol_version: PROTOCOL_VERSION, token_budget: null },
732
+ },
733
+ })}\n`
734
+ );
692
735
  });
693
736
  });
694
737
  }
@@ -724,7 +767,7 @@ export async function installSetupTarget(
724
767
  installMcpConfig,
725
768
  isMcpClientName,
726
769
  removeMcpConfig,
727
- cwd: process.cwd()
770
+ cwd: process.cwd(),
728
771
  }
729
772
  ) {
730
773
  /** @type {SetupInstallDeps} */
@@ -734,14 +777,21 @@ export async function installSetupTarget(
734
777
  if (!resolvedDeps.isMcpClientName(normalized.target)) {
735
778
  throw new Error(`Unsupported MCP client "${normalized.target}".`);
736
779
  }
737
- const paths = normalized.action === 'uninstall'
738
- ? await resolvedDeps.removeMcpConfig(normalized.target, { global: true })
739
- : [await resolvedDeps.installMcpConfig(normalized.target, { global: true })];
780
+ const paths =
781
+ normalized.action === 'uninstall'
782
+ ? await resolvedDeps.removeMcpConfig(normalized.target, {
783
+ global: true,
784
+ })
785
+ : [
786
+ await resolvedDeps.installMcpConfig(normalized.target, {
787
+ global: true,
788
+ }),
789
+ ];
740
790
  return {
741
791
  action: normalized.action,
742
792
  kind: 'mcp',
743
793
  target: normalized.target,
744
- paths
794
+ paths,
745
795
  };
746
796
  }
747
797
 
@@ -749,21 +799,22 @@ export async function installSetupTarget(
749
799
  throw new Error(`Unsupported skill target "${normalized.target}".`);
750
800
  }
751
801
 
752
- const paths = normalized.action === 'uninstall'
753
- ? await resolvedDeps.removeAgentFiles({
754
- targets: [normalized.target],
755
- projectPath: resolvedDeps.cwd,
756
- global: true
757
- })
758
- : await resolvedDeps.installAgentFiles({
759
- targets: [normalized.target],
760
- projectPath: resolvedDeps.cwd,
761
- global: true
762
- });
802
+ const paths =
803
+ normalized.action === 'uninstall'
804
+ ? await resolvedDeps.removeAgentFiles({
805
+ targets: [normalized.target],
806
+ projectPath: resolvedDeps.cwd,
807
+ global: true,
808
+ })
809
+ : await resolvedDeps.installAgentFiles({
810
+ targets: [normalized.target],
811
+ projectPath: resolvedDeps.cwd,
812
+ global: true,
813
+ });
763
814
  return {
764
815
  action: normalized.action,
765
816
  kind: 'skill',
766
817
  target: normalized.target,
767
- paths
818
+ paths,
768
819
  };
769
820
  }