@jobshimo/browser-link 0.2.0 → 0.4.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 (63) hide show
  1. package/README.md +37 -0
  2. package/dist/bridge/client.d.ts +101 -0
  3. package/dist/bridge/client.js +435 -0
  4. package/dist/bridge/client.js.map +1 -0
  5. package/dist/bridge/dispatch.d.ts +29 -0
  6. package/dist/bridge/dispatch.js +39 -0
  7. package/dist/bridge/dispatch.js.map +1 -0
  8. package/dist/bridge/events.d.ts +39 -0
  9. package/dist/bridge/events.js +47 -0
  10. package/dist/bridge/events.js.map +1 -0
  11. package/dist/bridge/protocol.d.ts +80 -0
  12. package/dist/bridge/protocol.js +79 -0
  13. package/dist/bridge/protocol.js.map +1 -0
  14. package/dist/bridge/server.d.ts +42 -0
  15. package/dist/bridge/server.js +336 -0
  16. package/dist/bridge/server.js.map +1 -0
  17. package/dist/bridge/token.d.ts +17 -0
  18. package/dist/bridge/token.js +79 -0
  19. package/dist/bridge/token.js.map +1 -0
  20. package/dist/cli.js +106 -15
  21. package/dist/cli.js.map +1 -1
  22. package/dist/commands/doctor.d.ts +12 -1
  23. package/dist/commands/doctor.js +90 -20
  24. package/dist/commands/doctor.js.map +1 -1
  25. package/dist/commands/extension.d.ts +3 -2
  26. package/dist/commands/extension.js +53 -28
  27. package/dist/commands/extension.js.map +1 -1
  28. package/dist/commands/free-port.d.ts +21 -0
  29. package/dist/commands/free-port.js +146 -0
  30. package/dist/commands/free-port.js.map +1 -0
  31. package/dist/commands/multi-agent.d.ts +7 -0
  32. package/dist/commands/multi-agent.js +109 -0
  33. package/dist/commands/multi-agent.js.map +1 -0
  34. package/dist/commands/tools.d.ts +11 -0
  35. package/dist/commands/tools.js +168 -0
  36. package/dist/commands/tools.js.map +1 -0
  37. package/dist/commands/updates.d.ts +2 -1
  38. package/dist/commands/updates.js +24 -7
  39. package/dist/commands/updates.js.map +1 -1
  40. package/dist/config.d.ts +25 -3
  41. package/dist/config.js +35 -2
  42. package/dist/config.js.map +1 -1
  43. package/dist/messages.d.ts +7 -0
  44. package/dist/permissions.d.ts +37 -0
  45. package/dist/permissions.js +156 -0
  46. package/dist/permissions.js.map +1 -0
  47. package/dist/server.d.ts +7 -3
  48. package/dist/server.js +196 -32
  49. package/dist/server.js.map +1 -1
  50. package/dist/tools/browser-definitions.js +18 -0
  51. package/dist/tools/browser-definitions.js.map +1 -1
  52. package/dist/tools/browser-dispatch.d.ts +7 -0
  53. package/dist/tools/browser-dispatch.js +11 -0
  54. package/dist/tools/browser-dispatch.js.map +1 -1
  55. package/dist/tools/server-instructions.d.ts +1 -1
  56. package/dist/tools/server-instructions.js +4 -0
  57. package/dist/tools/server-instructions.js.map +1 -1
  58. package/dist/ui/app.js +20 -1
  59. package/dist/ui/app.js.map +1 -1
  60. package/dist/ui/screens.d.ts +18 -1
  61. package/dist/ui/screens.js +395 -2
  62. package/dist/ui/screens.js.map +1 -1
  63. package/package.json +4 -3
@@ -23,54 +23,79 @@ export function resolveExtensionPath() {
23
23
  }
24
24
  return null;
25
25
  }
26
- function osHints(extPath) {
26
+ const EXT_I18N = {
27
+ en: {
28
+ openChrome: 'Open Chrome and go to: chrome://extensions',
29
+ toggleDev: 'Toggle "Developer mode" (top-right).',
30
+ loadUnpacked: 'Click "Load unpacked".',
31
+ pickFolder: (p) => `Browse to: ${p}`,
32
+ selectButton: 'Click "Select Folder".',
33
+ pathLabel: 'Chrome extension assets are at:',
34
+ stepsLabel: 'Install steps:',
35
+ afterLoading: 'After loading, open the extension popup on any tab and click "Conectar" to bridge it.',
36
+ notFound: 'Extension assets not found. Run `npm run build:extension` (dev) or reinstall the package.',
37
+ },
38
+ es: {
39
+ openChrome: 'Abrí Chrome y entrá a: chrome://extensions',
40
+ toggleDev: 'Activá "Modo desarrollador" (arriba a la derecha).',
41
+ loadUnpacked: 'Hacé click en "Cargar descomprimida".',
42
+ pickFolder: (p) => `Buscá la carpeta: ${p}`,
43
+ selectButton: 'Hacé click en "Seleccionar carpeta".',
44
+ pathLabel: 'Los assets de la extensión están en:',
45
+ stepsLabel: 'Pasos de instalación:',
46
+ afterLoading: 'Después de cargarla, abrí el popup de la extensión en cualquier pestaña y hacé click en "Conectar" para puentearla.',
47
+ notFound: 'No se encontraron los assets. Corré `npm run build:extension` (dev) o reinstalá el paquete.',
48
+ },
49
+ };
50
+ function macFolderHint(p, language) {
51
+ return language === 'es'
52
+ ? `En el selector de archivos, apretá ⌘⇧G y pegá: ${p}`
53
+ : `In the file picker, press ⌘⇧G and paste: ${p}`;
54
+ }
55
+ function macReturnHint(language) {
56
+ return language === 'es' ? 'Apretá Return y "Seleccionar".' : 'Press Return, then "Select".';
57
+ }
58
+ function linuxPickHint(p, language) {
59
+ return language === 'es' ? `Elegí la carpeta: ${p}` : `Select the folder: ${p}`;
60
+ }
61
+ function osHints(extPath, language) {
62
+ const t = EXT_I18N[language];
27
63
  const p = platform();
28
64
  if (p === 'win32') {
29
- return [
30
- 'Open Chrome and go to: chrome://extensions',
31
- 'Toggle "Developer mode" (top-right).',
32
- 'Click "Load unpacked".',
33
- `Browse to: ${extPath}`,
34
- 'Click "Select Folder".',
35
- ].join('\n ');
65
+ return [t.openChrome, t.toggleDev, t.loadUnpacked, t.pickFolder(extPath), t.selectButton].join('\n ');
36
66
  }
37
67
  if (p === 'darwin') {
38
68
  return [
39
- 'Open Chrome and go to: chrome://extensions',
40
- 'Toggle "Developer mode" (top-right).',
41
- 'Click "Load unpacked".',
42
- `In the file picker, press ⌘⇧G and paste: ${extPath}`,
43
- 'Press Return, then "Select".',
69
+ t.openChrome,
70
+ t.toggleDev,
71
+ t.loadUnpacked,
72
+ macFolderHint(extPath, language),
73
+ macReturnHint(language),
44
74
  ].join('\n ');
45
75
  }
46
- return [
47
- 'Open Chrome and go to: chrome://extensions',
48
- 'Toggle "Developer mode" (top-right).',
49
- 'Click "Load unpacked".',
50
- `Select the folder: ${extPath}`,
51
- ].join('\n ');
76
+ return [t.openChrome, t.toggleDev, t.loadUnpacked, linuxPickHint(extPath, language)].join('\n ');
52
77
  }
53
- export function getExtensionInfo() {
78
+ export function getExtensionInfo(language = 'en') {
79
+ const t = EXT_I18N[language];
54
80
  const path = resolveExtensionPath();
55
81
  return {
56
82
  path,
57
- hints: path
58
- ? osHints(path)
59
- : 'Extension assets not found. Run `npm run build:extension` (dev) or reinstall the package.',
83
+ hints: path ? osHints(path, language) : t.notFound,
60
84
  };
61
85
  }
62
- export function printExtensionInstructions() {
63
- const info = getExtensionInfo();
86
+ export function printExtensionInstructions(language = 'en') {
87
+ const t = EXT_I18N[language];
88
+ const info = getExtensionInfo(language);
64
89
  if (!info.path) {
65
90
  console.log(info.hints);
66
91
  return;
67
92
  }
68
- console.log('Chrome extension assets are at:');
93
+ console.log(t.pathLabel);
69
94
  console.log(` ${info.path}`);
70
95
  console.log('');
71
- console.log('Install steps:');
96
+ console.log(t.stepsLabel);
72
97
  console.log(` ${info.hints}`);
73
98
  console.log('');
74
- console.log('After loading, open the extension popup on any tab and click "Conectar" to bridge it.');
99
+ console.log(t.afterLoading);
75
100
  }
76
101
  //# sourceMappingURL=extension.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../src/commands/extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;GAIG;AACH,MAAM,UAAU,oBAAoB;IAClC,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG;QACjB,+DAA+D;QAC/D,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,CAAC;QAC7B,gFAAgF;QAChF,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC;QACpD,gGAAgG;QAChG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,CAAC;KAC/C,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IACrD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,OAAO,CAAC,OAAe;IAC9B,MAAM,CAAC,GAAG,QAAQ,EAAE,CAAC;IACrB,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;QAClB,OAAO;YACL,4CAA4C;YAC5C,sCAAsC;YACtC,wBAAwB;YACxB,cAAc,OAAO,EAAE;YACvB,wBAAwB;SACzB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IACD,IAAI,CAAC,KAAK,QAAQ,EAAE,CAAC;QACnB,OAAO;YACL,4CAA4C;YAC5C,sCAAsC;YACtC,wBAAwB;YACxB,4CAA4C,OAAO,EAAE;YACrD,8BAA8B;SAC/B,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACjB,CAAC;IACD,OAAO;QACL,4CAA4C;QAC5C,sCAAsC;QACtC,wBAAwB;QACxB,sBAAsB,OAAO,EAAE;KAChC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACjB,CAAC;AAOD,MAAM,UAAU,gBAAgB;IAC9B,MAAM,IAAI,GAAG,oBAAoB,EAAE,CAAC;IACpC,OAAO;QACL,IAAI;QACJ,KAAK,EAAE,IAAI;YACT,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,2FAA2F;KAChG,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,MAAM,IAAI,GAAG,gBAAgB,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QACf,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACxB,OAAO;IACT,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAC/C,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;IAC/B,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CACT,uFAAuF,CACxF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"extension.js","sourceRoot":"","sources":["../../src/commands/extension.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import type { Language } from './welcome.js';
2
+ export interface FreePortResult {
3
+ /** True when the port was free (nothing to do) OR the owning process was killed. */
4
+ ok: boolean;
5
+ /** PID found bound to WS_PORT, or null when the port was already free. */
6
+ pid: number | null;
7
+ /** Image / executable name reported by the OS, used as a safety check. */
8
+ imageName: string | null;
9
+ /** Human-readable message in the requested language. */
10
+ message: string;
11
+ }
12
+ /**
13
+ * Find the process listening on WS_PORT and try to stop it.
14
+ *
15
+ * Safety rule: only kill processes whose image name starts with "node".
16
+ * Anything else (or unidentified) is left alone with a clear message.
17
+ * This stops a stray browser-link from blocking the next MCP client
18
+ * without ever risking killing some unrelated user process that happens
19
+ * to share the port.
20
+ */
21
+ export declare function runFreePort(language?: Language): FreePortResult;
@@ -0,0 +1,146 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { platform } from 'node:os';
3
+ const WS_HOST = '127.0.0.1';
4
+ const WS_PORT = 17529;
5
+ /**
6
+ * Best-effort lookup of the PID owning the WS port, cross-platform.
7
+ * Returns null when nothing is listening on the port, when the OS tools
8
+ * needed to find the owner are missing, or when parsing fails.
9
+ *
10
+ * We don't shell out via a string command — `execFileSync` with an argv
11
+ * array avoids any quoting / injection surprises.
12
+ */
13
+ function findPidOnPort(port) {
14
+ try {
15
+ if (platform() === 'win32') {
16
+ // netstat -ano -p TCP produces lines like:
17
+ // " TCP 127.0.0.1:17529 0.0.0.0:0 LISTENING 13212"
18
+ const out = execFileSync('netstat', ['-ano', '-p', 'TCP'], {
19
+ encoding: 'utf8',
20
+ stdio: ['ignore', 'pipe', 'ignore'],
21
+ });
22
+ for (const line of out.split(/\r?\n/)) {
23
+ if (!line.includes(`:${port}`))
24
+ continue;
25
+ if (!line.includes('LISTENING'))
26
+ continue;
27
+ const cols = line.trim().split(/\s+/);
28
+ const pid = Number.parseInt(cols[cols.length - 1] ?? '', 10);
29
+ if (Number.isFinite(pid) && pid > 0)
30
+ return pid;
31
+ }
32
+ return null;
33
+ }
34
+ // Unix-likes: lsof gives just the PID with -t.
35
+ const out = execFileSync('lsof', ['-nP', `-iTCP:${port}`, '-sTCP:LISTEN', '-t'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] });
36
+ const pid = Number.parseInt(out.trim().split('\n')[0] ?? '', 10);
37
+ return Number.isFinite(pid) && pid > 0 ? pid : null;
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ }
43
+ /**
44
+ * Return the image / executable name of a PID, or null when the lookup
45
+ * fails. We use this as a safety check before killing: we will only kill
46
+ * processes whose image name starts with "node" — refuse to nuke anything
47
+ * else that happens to share the port (some other dev server, malware,
48
+ * a misconfigured tool, etc.).
49
+ */
50
+ function imageNameOf(pid) {
51
+ try {
52
+ if (platform() === 'win32') {
53
+ // tasklist /FI "PID eq 13212" /FO CSV /NH produces:
54
+ // "node.exe","13212","Console","1","45,000 K"
55
+ const out = execFileSync('tasklist', ['/FI', `PID eq ${pid}`, '/FO', 'CSV', '/NH'], { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
56
+ if (!out || out.startsWith('INFO:'))
57
+ return null;
58
+ // Strip leading quote, then take up to next quote.
59
+ const first = out.indexOf('"');
60
+ const second = out.indexOf('"', first + 1);
61
+ if (first === -1 || second === -1)
62
+ return null;
63
+ return out.slice(first + 1, second);
64
+ }
65
+ const out = execFileSync('ps', ['-p', String(pid), '-o', 'comm='], {
66
+ encoding: 'utf8',
67
+ stdio: ['ignore', 'pipe', 'ignore'],
68
+ }).trim();
69
+ return out || null;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ function isNodeImage(image) {
76
+ if (!image)
77
+ return false;
78
+ const lc = image.toLowerCase();
79
+ return lc.startsWith('node') || lc === 'node.exe';
80
+ }
81
+ function killByPid(pid) {
82
+ try {
83
+ if (platform() === 'win32') {
84
+ execFileSync('taskkill', ['/F', '/PID', String(pid)], {
85
+ stdio: ['ignore', 'ignore', 'ignore'],
86
+ });
87
+ return true;
88
+ }
89
+ process.kill(pid, 'SIGTERM');
90
+ return true;
91
+ }
92
+ catch {
93
+ return false;
94
+ }
95
+ }
96
+ const I18N = {
97
+ en: {
98
+ alreadyFree: `Port ${WS_HOST}:${WS_PORT} is already free — nothing to stop.`,
99
+ killed: (pid) => `✓ Stopped browser-link primary (PID ${pid}). Port ${WS_HOST}:${WS_PORT} is now free.`,
100
+ killFailed: (pid) => `✗ Could not kill PID ${pid}. Try again as administrator, or close the MCP client manually.`,
101
+ notNode: (pid, image) => `✗ Port ${WS_HOST}:${WS_PORT} is held by PID ${pid} (${image}), which is NOT a node process. ` +
102
+ `Refusing to kill it — close that process yourself if you know what it is.`,
103
+ unknownOwner: (pid) => `✗ Port ${WS_HOST}:${WS_PORT} is held by PID ${pid}, but we could not identify the process. ` +
104
+ `Refusing to kill it. Close it manually with: taskkill /F /PID ${pid} (Windows) or kill ${pid} (Unix).`,
105
+ },
106
+ es: {
107
+ alreadyFree: `El puerto ${WS_HOST}:${WS_PORT} ya está libre — no hay nada que parar.`,
108
+ killed: (pid) => `✓ browser-link primary detenido (PID ${pid}). El puerto ${WS_HOST}:${WS_PORT} quedó libre.`,
109
+ killFailed: (pid) => `✗ No se pudo matar el PID ${pid}. Probá de nuevo como administrador o cerrá el cliente MCP a mano.`,
110
+ notNode: (pid, image) => `✗ El puerto ${WS_HOST}:${WS_PORT} lo tiene el PID ${pid} (${image}), que NO es un proceso node. ` +
111
+ `Por seguridad no se mata — cerralo a mano si sabés qué es.`,
112
+ unknownOwner: (pid) => `✗ El puerto ${WS_HOST}:${WS_PORT} lo tiene el PID ${pid}, pero no pudimos identificar el proceso. ` +
113
+ `Por seguridad no se mata. Cerralo a mano con: taskkill /F /PID ${pid} (Windows) o kill ${pid} (Unix).`,
114
+ },
115
+ };
116
+ /**
117
+ * Find the process listening on WS_PORT and try to stop it.
118
+ *
119
+ * Safety rule: only kill processes whose image name starts with "node".
120
+ * Anything else (or unidentified) is left alone with a clear message.
121
+ * This stops a stray browser-link from blocking the next MCP client
122
+ * without ever risking killing some unrelated user process that happens
123
+ * to share the port.
124
+ */
125
+ export function runFreePort(language = 'en') {
126
+ const t = I18N[language];
127
+ const pid = findPidOnPort(WS_PORT);
128
+ if (pid == null) {
129
+ return { ok: true, pid: null, imageName: null, message: t.alreadyFree };
130
+ }
131
+ const image = imageNameOf(pid);
132
+ if (image == null) {
133
+ return { ok: false, pid, imageName: null, message: t.unknownOwner(pid) };
134
+ }
135
+ if (!isNodeImage(image)) {
136
+ return { ok: false, pid, imageName: image, message: t.notNode(pid, image) };
137
+ }
138
+ const killed = killByPid(pid);
139
+ return {
140
+ ok: killed,
141
+ pid,
142
+ imageName: image,
143
+ message: killed ? t.killed(pid) : t.killFailed(pid),
144
+ };
145
+ }
146
+ //# sourceMappingURL=free-port.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"free-port.js","sourceRoot":"","sources":["../../src/commands/free-port.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { Language } from './welcome.js';
2
+ export declare function listMultiAgentStatus(language?: Language): string;
3
+ export declare function enableMultiAgent(language?: Language): string;
4
+ export declare function disableMultiAgent(language?: Language): string;
5
+ export declare function enableAutoReelect(language?: Language): string;
6
+ export declare function disableAutoReelect(language?: Language): string;
7
+ export declare function runMultiAgentCommand(argv: string[], language?: Language): string;
@@ -0,0 +1,109 @@
1
+ import { loadConfig, saveConfig } from '../config.js';
2
+ const MA_I18N = {
3
+ en: {
4
+ header: 'Multi-agent settings',
5
+ multiAgentLabel: 'Multi-agent mode',
6
+ autoReelectLabel: 'Auto-reelect on primary close',
7
+ on: 'on',
8
+ off: 'off',
9
+ restartNote: 'Restart every MCP client for these changes to take effect.',
10
+ enabledMulti: 'Multi-agent mode enabled.',
11
+ disabledMulti: 'Multi-agent mode disabled.',
12
+ enabledReelect: 'Auto-reelect enabled.',
13
+ disabledReelect: 'Auto-reelect disabled.',
14
+ noChange: 'No change.',
15
+ autoReelectRequiresMulti: 'Cannot enable auto-reelect while multi-agent mode is off. Enable multi-agent first.',
16
+ unknownAction: (action) => `Unknown multi-agent action: ${action}. Use enable | disable | auto-reelect | list.`,
17
+ unknownReelectAction: (action) => `Unknown auto-reelect action: ${action}. Use enable | disable.`,
18
+ usage: 'Usage: browser-link multi-agent <enable|disable|auto-reelect|list>',
19
+ },
20
+ es: {
21
+ header: 'Configuración multi-agente',
22
+ multiAgentLabel: 'Modo multi-agente',
23
+ autoReelectLabel: 'Re-elección automática al cerrar el primary',
24
+ on: 'activado',
25
+ off: 'desactivado',
26
+ restartNote: 'Reiniciá cada cliente MCP para que los cambios tengan efecto.',
27
+ enabledMulti: 'Modo multi-agente activado.',
28
+ disabledMulti: 'Modo multi-agente desactivado.',
29
+ enabledReelect: 'Re-elección automática activada.',
30
+ disabledReelect: 'Re-elección automática desactivada.',
31
+ noChange: 'Sin cambios.',
32
+ autoReelectRequiresMulti: 'No se puede activar la re-elección automática con el modo multi-agente apagado. Activá primero multi-agente.',
33
+ unknownAction: (action) => `Acción multi-agente desconocida: ${action}. Usá enable | disable | auto-reelect | list.`,
34
+ unknownReelectAction: (action) => `Acción de auto-reelect desconocida: ${action}. Usá enable | disable.`,
35
+ usage: 'Uso: browser-link multi-agent <enable|disable|auto-reelect|list>',
36
+ },
37
+ };
38
+ export function listMultiAgentStatus(language = 'en') {
39
+ const t = MA_I18N[language];
40
+ const cfg = loadConfig();
41
+ const multi = cfg.multiAgent === true;
42
+ const reelect = cfg.autoReelect === true;
43
+ const lines = [];
44
+ lines.push(t.header);
45
+ lines.push('');
46
+ lines.push(` ${t.multiAgentLabel} ${multi ? t.on : t.off}`);
47
+ lines.push(` ${t.autoReelectLabel} ${reelect ? t.on : t.off}`);
48
+ lines.push('');
49
+ lines.push(t.restartNote);
50
+ return lines.join('\n');
51
+ }
52
+ export function enableMultiAgent(language = 'en') {
53
+ const t = MA_I18N[language];
54
+ const cfg = loadConfig();
55
+ if (cfg.multiAgent === true)
56
+ return t.noChange;
57
+ saveConfig({ multiAgent: true });
58
+ return t.enabledMulti;
59
+ }
60
+ export function disableMultiAgent(language = 'en') {
61
+ const t = MA_I18N[language];
62
+ const cfg = loadConfig();
63
+ if (cfg.multiAgent !== true)
64
+ return t.noChange;
65
+ // Turning multi-agent off also clears autoReelect — the normalise step
66
+ // in config.ts drops it because it only makes sense when multi-agent is on.
67
+ saveConfig({ multiAgent: false, autoReelect: false });
68
+ return t.disabledMulti;
69
+ }
70
+ export function enableAutoReelect(language = 'en') {
71
+ const t = MA_I18N[language];
72
+ const cfg = loadConfig();
73
+ if (cfg.multiAgent !== true)
74
+ throw new Error(t.autoReelectRequiresMulti);
75
+ if (cfg.autoReelect === true)
76
+ return t.noChange;
77
+ saveConfig({ autoReelect: true });
78
+ return t.enabledReelect;
79
+ }
80
+ export function disableAutoReelect(language = 'en') {
81
+ const t = MA_I18N[language];
82
+ const cfg = loadConfig();
83
+ if (cfg.autoReelect !== true)
84
+ return t.noChange;
85
+ saveConfig({ autoReelect: false });
86
+ return t.disabledReelect;
87
+ }
88
+ export function runMultiAgentCommand(argv, language = 'en') {
89
+ const t = MA_I18N[language];
90
+ const [action, ...rest] = argv;
91
+ if (!action || action === 'list')
92
+ return listMultiAgentStatus(language);
93
+ if (action === 'enable')
94
+ return enableMultiAgent(language);
95
+ if (action === 'disable')
96
+ return disableMultiAgent(language);
97
+ if (action === 'auto-reelect') {
98
+ const [sub] = rest;
99
+ if (sub === 'enable')
100
+ return enableAutoReelect(language);
101
+ if (sub === 'disable')
102
+ return disableAutoReelect(language);
103
+ if (!sub)
104
+ return listMultiAgentStatus(language); // bare `auto-reelect` is a no-op listing
105
+ throw new Error(t.unknownReelectAction(sub));
106
+ }
107
+ throw new Error(t.unknownAction(action));
108
+ }
109
+ //# sourceMappingURL=multi-agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multi-agent.js","sourceRoot":"","sources":["../../src/commands/multi-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AA8BtD,MAAM,OAAO,GAAqC;IAChD,EAAE,EAAE;QACF,MAAM,EAAE,sBAAsB;QAC9B,eAAe,EAAE,kBAAkB;QACnC,gBAAgB,EAAE,+BAA+B;QACjD,EAAE,EAAE,IAAI;QACR,GAAG,EAAE,KAAK;QACV,WAAW,EAAE,4DAA4D;QACzE,YAAY,EAAE,2BAA2B;QACzC,aAAa,EAAE,4BAA4B;QAC3C,cAAc,EAAE,uBAAuB;QACvC,eAAe,EAAE,wBAAwB;QACzC,QAAQ,EAAE,YAAY;QACtB,wBAAwB,EACtB,qFAAqF;QACvF,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE,CACxB,+BAA+B,MAAM,+CAA+C;QACtF,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/B,gCAAgC,MAAM,yBAAyB;QACjE,KAAK,EAAE,oEAAoE;KAC5E;IACD,EAAE,EAAE;QACF,MAAM,EAAE,4BAA4B;QACpC,eAAe,EAAE,mBAAmB;QACpC,gBAAgB,EAAE,6CAA6C;QAC/D,EAAE,EAAE,UAAU;QACd,GAAG,EAAE,aAAa;QAClB,WAAW,EAAE,+DAA+D;QAC5E,YAAY,EAAE,6BAA6B;QAC3C,aAAa,EAAE,gCAAgC;QAC/C,cAAc,EAAE,kCAAkC;QAClD,eAAe,EAAE,qCAAqC;QACtD,QAAQ,EAAE,cAAc;QACxB,wBAAwB,EACtB,8GAA8G;QAChH,aAAa,EAAE,CAAC,MAAM,EAAE,EAAE,CACxB,oCAAoC,MAAM,+CAA+C;QAC3F,oBAAoB,EAAE,CAAC,MAAM,EAAE,EAAE,CAC/B,uCAAuC,MAAM,yBAAyB;QACxE,KAAK,EAAE,kEAAkE;KAC1E;CACF,CAAC;AAEF,MAAM,UAAU,oBAAoB,CAAC,WAAqB,IAAI;IAC5D,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,MAAM,KAAK,GAAG,GAAG,CAAC,UAAU,KAAK,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,WAAW,KAAK,IAAI,CAAC;IACzC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IACrB,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,eAAe,gBAAgB,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACzE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,gBAAgB,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;IACjE,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACf,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,WAAqB,IAAI;IACxD,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IAC/C,UAAU,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;IACjC,OAAO,CAAC,CAAC,YAAY,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,WAAqB,IAAI;IACzD,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IAC/C,uEAAuE;IACvE,4EAA4E;IAC5E,UAAU,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,OAAO,CAAC,CAAC,aAAa,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,WAAqB,IAAI;IACzD,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC;IACzE,IAAI,GAAG,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IAChD,UAAU,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;IAClC,OAAO,CAAC,CAAC,cAAc,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,WAAqB,IAAI;IAC1D,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,IAAI,GAAG,CAAC,WAAW,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IAChD,UAAU,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC,eAAe,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,IAAc,EAAE,WAAqB,IAAI;IAC5E,MAAM,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5B,MAAM,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;IAC/B,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM;QAAE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IACxE,IAAI,MAAM,KAAK,QAAQ;QAAE,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAC3D,IAAI,MAAM,KAAK,SAAS;QAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IAC7D,IAAI,MAAM,KAAK,cAAc,EAAE,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QACnB,IAAI,GAAG,KAAK,QAAQ;YAAE,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,GAAG,KAAK,SAAS;YAAE,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;QAC3D,IAAI,CAAC,GAAG;YAAE,OAAO,oBAAoB,CAAC,QAAQ,CAAC,CAAC,CAAC,yCAAyC;QAC1F,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,oBAAoB,CAAC,GAAG,CAAC,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,IAAI,KAAK,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,11 @@
1
+ import type { Language } from './welcome.js';
2
+ export declare function listToolsStatus(language?: Language): string;
3
+ export declare function enableTools(names: string[], language?: Language): string;
4
+ export declare function disableTools(names: string[], language?: Language): string;
5
+ export declare function applyPreset(id: string, language?: Language): string;
6
+ export interface ToolsArgs {
7
+ action: 'list' | 'enable' | 'disable' | 'preset';
8
+ names: string[];
9
+ }
10
+ export declare function parseToolsArgs(argv: string[], language?: Language): ToolsArgs;
11
+ export declare function runToolsCommand(argv: string[], language?: Language): string;
@@ -0,0 +1,168 @@
1
+ import { loadConfig, saveConfig } from '../config.js';
2
+ import { PRESETS, TOOL_CATALOGUE, getPreset, isKnownTool } from '../permissions.js';
3
+ /* The scriptable surface of the tool-permissions feature. Mirrors what the
4
+ * Permissions screen does in the Ink UI:
5
+ * - `browser-link tools` list current state
6
+ * - `browser-link tools enable <name>` add to allow (remove from disabled)
7
+ * - `browser-link tools disable <name>` add to disabled
8
+ * - `browser-link tools preset <id>` replace disabled list with preset */
9
+ const VALID_PRESETS = PRESETS.map((p) => p.id);
10
+ const TOOLS_I18N = {
11
+ en: {
12
+ header: (state) => `Tool permissions — ${state}`,
13
+ allEnabled: 'all enabled',
14
+ someDisabled: (n) => `${n} disabled`,
15
+ bridgeHeader: 'Browser bridge:',
16
+ mapHeader: 'Persistent UI map:',
17
+ presetsHeader: 'Presets:',
18
+ restartNote: 'Changes take effect the next time your MCP client starts the server.',
19
+ usageEnable: 'Usage: browser-link tools enable <name> [<name>…]',
20
+ usageDisable: 'Usage: browser-link tools disable <name> [<name>…]',
21
+ unknownTool: (n) => `Unknown tool: ${n}`,
22
+ noChangeAlreadyEnabled: (names) => `No change — none of [${names}] were disabled.`,
23
+ noChangeAlreadyDisabled: (names) => `No change — [${names}] already disabled.`,
24
+ enabledN: (n, names) => `Enabled ${n}: ${names}`,
25
+ disabledN: (n, names) => `Disabled ${n}: ${names}`,
26
+ allToolsEnabled: 'All tools enabled.',
27
+ unknownPreset: (id, valid) => `Unknown preset: ${id}. Valid: ${valid}`,
28
+ unknownAction: (action) => `Unknown tools action: ${action}. Use list | enable | disable | preset.`,
29
+ appliedPreset: (id, follow) => `Applied preset "${id}" — ${follow}`,
30
+ presetUsage: (ids) => `Usage: browser-link tools preset <${ids}>`,
31
+ },
32
+ es: {
33
+ header: (state) => `Permisos de tools — ${state}`,
34
+ allEnabled: 'todo habilitado',
35
+ someDisabled: (n) => `${n} deshabilitada${n === 1 ? '' : 's'}`,
36
+ bridgeHeader: 'Bridge del browser:',
37
+ mapHeader: 'Mapa persistente:',
38
+ presetsHeader: 'Presets:',
39
+ restartNote: 'Los cambios tienen efecto la próxima vez que el cliente MCP arranque el servidor.',
40
+ usageEnable: 'Uso: browser-link tools enable <nombre> [<nombre>…]',
41
+ usageDisable: 'Uso: browser-link tools disable <nombre> [<nombre>…]',
42
+ unknownTool: (n) => `Tool desconocida: ${n}`,
43
+ noChangeAlreadyEnabled: (names) => `Sin cambios — ninguna de [${names}] estaba deshabilitada.`,
44
+ noChangeAlreadyDisabled: (names) => `Sin cambios — [${names}] ya estaba deshabilitada.`,
45
+ enabledN: (n, names) => `Habilitadas (${n}): ${names}`,
46
+ disabledN: (n, names) => `Deshabilitadas (${n}): ${names}`,
47
+ allToolsEnabled: 'Todas las tools habilitadas.',
48
+ unknownPreset: (id, valid) => `Preset desconocido: ${id}. Válidos: ${valid}`,
49
+ unknownAction: (action) => `Acción desconocida: ${action}. Usá list | enable | disable | preset.`,
50
+ appliedPreset: (id, follow) => `Preset "${id}" aplicado — ${follow}`,
51
+ presetUsage: (ids) => `Uso: browser-link tools preset <${ids}>`,
52
+ },
53
+ };
54
+ export function listToolsStatus(language = 'en') {
55
+ const t = TOOLS_I18N[language];
56
+ const cfg = loadConfig();
57
+ const disabled = new Set(cfg.disabledTools ?? []);
58
+ const lines = [];
59
+ lines.push(t.header(disabled.size === 0 ? t.allEnabled : t.someDisabled(disabled.size)));
60
+ lines.push('');
61
+ let lastFamily = null;
62
+ for (const tool of TOOL_CATALOGUE) {
63
+ if (tool.family !== lastFamily) {
64
+ if (lastFamily !== null)
65
+ lines.push('');
66
+ lines.push(tool.family === 'bridge' ? t.bridgeHeader : t.mapHeader);
67
+ lastFamily = tool.family;
68
+ }
69
+ const mark = disabled.has(tool.name) ? '✗' : '✓';
70
+ lines.push(` ${mark} ${tool.name.padEnd(28)} ${tool.summary}`);
71
+ }
72
+ lines.push('');
73
+ lines.push(t.presetsHeader);
74
+ for (const p of PRESETS) {
75
+ lines.push(` ${p.id.padEnd(10)} ${p.label}`);
76
+ }
77
+ lines.push('');
78
+ lines.push(t.restartNote);
79
+ return lines.join('\n');
80
+ }
81
+ function applyDisabled(disabled, language) {
82
+ const t = TOOLS_I18N[language];
83
+ saveConfig({ disabledTools: disabled });
84
+ if (disabled.length === 0)
85
+ return t.allToolsEnabled;
86
+ return t.disabledN(disabled.length, disabled.join(', '));
87
+ }
88
+ export function enableTools(names, language = 'en') {
89
+ const t = TOOLS_I18N[language];
90
+ if (names.length === 0)
91
+ throw new Error(t.usageEnable);
92
+ for (const n of names) {
93
+ if (!isKnownTool(n))
94
+ throw new Error(t.unknownTool(n));
95
+ }
96
+ const cfg = loadConfig();
97
+ const before = new Set(cfg.disabledTools ?? []);
98
+ const removed = [];
99
+ for (const n of names) {
100
+ if (before.delete(n))
101
+ removed.push(n);
102
+ }
103
+ const next = [...before].sort();
104
+ saveConfig({ disabledTools: next });
105
+ if (removed.length === 0)
106
+ return t.noChangeAlreadyEnabled(names.join(', '));
107
+ return t.enabledN(removed.length, removed.join(', '));
108
+ }
109
+ export function disableTools(names, language = 'en') {
110
+ const t = TOOLS_I18N[language];
111
+ if (names.length === 0)
112
+ throw new Error(t.usageDisable);
113
+ for (const n of names) {
114
+ if (!isKnownTool(n))
115
+ throw new Error(t.unknownTool(n));
116
+ }
117
+ const cfg = loadConfig();
118
+ const before = new Set(cfg.disabledTools ?? []);
119
+ const added = [];
120
+ for (const n of names) {
121
+ if (!before.has(n)) {
122
+ before.add(n);
123
+ added.push(n);
124
+ }
125
+ }
126
+ const next = [...before].sort();
127
+ saveConfig({ disabledTools: next });
128
+ if (added.length === 0)
129
+ return t.noChangeAlreadyDisabled(names.join(', '));
130
+ return t.disabledN(added.length, added.join(', '));
131
+ }
132
+ export function applyPreset(id, language = 'en') {
133
+ const t = TOOLS_I18N[language];
134
+ if (!VALID_PRESETS.includes(id)) {
135
+ throw new Error(t.unknownPreset(id, VALID_PRESETS.join(', ')));
136
+ }
137
+ const preset = getPreset(id);
138
+ return t.appliedPreset(preset.id, applyDisabled([...preset.disabled], language));
139
+ }
140
+ export function parseToolsArgs(argv, language = 'en') {
141
+ const t = TOOLS_I18N[language];
142
+ const [action, ...rest] = argv;
143
+ if (!action || action === 'list')
144
+ return { action: 'list', names: [] };
145
+ if (action === 'enable' || action === 'disable' || action === 'preset') {
146
+ return { action, names: rest };
147
+ }
148
+ throw new Error(t.unknownAction(action));
149
+ }
150
+ export function runToolsCommand(argv, language = 'en') {
151
+ const t = TOOLS_I18N[language];
152
+ const { action, names } = parseToolsArgs(argv, language);
153
+ switch (action) {
154
+ case 'list':
155
+ return listToolsStatus(language);
156
+ case 'enable':
157
+ return enableTools(names, language);
158
+ case 'disable':
159
+ return disableTools(names, language);
160
+ case 'preset': {
161
+ const [presetId] = names;
162
+ if (!presetId)
163
+ throw new Error(t.presetUsage(VALID_PRESETS.join('|')));
164
+ return applyPreset(presetId, language);
165
+ }
166
+ }
167
+ }
168
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/commands/tools.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import type { Language } from './welcome.js';
1
2
  export interface UpdateInfo {
2
3
  current: string;
3
4
  latest: string | null;
@@ -16,4 +17,4 @@ export interface UpdateInfo {
16
17
  */
17
18
  export declare function checkUpdates(timeoutMs?: number): Promise<UpdateInfo>;
18
19
  /** Plain-text formatter for the non-interactive `browser-link updates`. */
19
- export declare function formatUpdate(info: UpdateInfo): string;
20
+ export declare function formatUpdate(info: UpdateInfo, language?: Language): string;