@jobshimo/browser-link 0.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.
- package/LICENSE +21 -0
- package/README.md +83 -0
- package/dist/auth/allowlist.d.ts +2 -0
- package/dist/auth/allowlist.js +53 -0
- package/dist/auth/allowlist.js.map +1 -0
- package/dist/auth/process-identity.d.ts +19 -0
- package/dist/auth/process-identity.js +106 -0
- package/dist/auth/process-identity.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +116 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/about.d.ts +23 -0
- package/dist/commands/about.js +248 -0
- package/dist/commands/about.js.map +1 -0
- package/dist/commands/doctor.d.ts +29 -0
- package/dist/commands/doctor.js +110 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/extension.d.ts +12 -0
- package/dist/commands/extension.js +76 -0
- package/dist/commands/extension.js.map +1 -0
- package/dist/commands/install.d.ts +19 -0
- package/dist/commands/install.js +52 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/menu.d.ts +26 -0
- package/dist/commands/menu.js +187 -0
- package/dist/commands/menu.js.map +1 -0
- package/dist/commands/tty.d.ts +51 -0
- package/dist/commands/tty.js +148 -0
- package/dist/commands/tty.js.map +1 -0
- package/dist/commands/uninstall.d.ts +8 -0
- package/dist/commands/uninstall.js +10 -0
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/commands/welcome.d.ts +33 -0
- package/dist/commands/welcome.js +177 -0
- package/dist/commands/welcome.js.map +1 -0
- package/dist/config.d.ts +11 -0
- package/dist/config.js +35 -0
- package/dist/config.js.map +1 -0
- package/dist/entry-info.d.ts +12 -0
- package/dist/entry-info.js +15 -0
- package/dist/entry-info.js.map +1 -0
- package/dist/extension/background.d.ts +1 -0
- package/dist/extension/background.js +490 -0
- package/dist/extension/background.js.map +1 -0
- package/dist/extension/icons/icon-128.png +0 -0
- package/dist/extension/icons/icon-16.png +0 -0
- package/dist/extension/icons/icon-32.png +0 -0
- package/dist/extension/icons/icon-48.png +0 -0
- package/dist/extension/icons/icon.svg +14 -0
- package/dist/extension/manifest.json +28 -0
- package/dist/extension/popup.d.ts +13 -0
- package/dist/extension/popup.html +88 -0
- package/dist/extension/popup.js +78 -0
- package/dist/extension/popup.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/installers/claude.d.ts +2 -0
- package/dist/installers/claude.js +77 -0
- package/dist/installers/claude.js.map +1 -0
- package/dist/installers/index.d.ts +9 -0
- package/dist/installers/index.js +14 -0
- package/dist/installers/index.js.map +1 -0
- package/dist/installers/opencode.d.ts +2 -0
- package/dist/installers/opencode.js +39 -0
- package/dist/installers/opencode.js.map +1 -0
- package/dist/installers/types.d.ts +30 -0
- package/dist/installers/types.js +2 -0
- package/dist/installers/types.js.map +1 -0
- package/dist/map/db.d.ts +3 -0
- package/dist/map/db.js +81 -0
- package/dist/map/db.js.map +1 -0
- package/dist/map/paths.d.ts +12 -0
- package/dist/map/paths.js +22 -0
- package/dist/map/paths.js.map +1 -0
- package/dist/map/queries.d.ts +72 -0
- package/dist/map/queries.js +162 -0
- package/dist/map/queries.js.map +1 -0
- package/dist/map/tools.d.ts +8 -0
- package/dist/map/tools.js +143 -0
- package/dist/map/tools.js.map +1 -0
- package/dist/messages.d.ts +42 -0
- package/dist/messages.js +9 -0
- package/dist/messages.js.map +1 -0
- package/dist/server.d.ts +6 -0
- package/dist/server.js +217 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/browser-definitions.d.ts +7 -0
- package/dist/tools/browser-definitions.js +127 -0
- package/dist/tools/browser-definitions.js.map +1 -0
- package/dist/tools/browser-dispatch.d.ts +20 -0
- package/dist/tools/browser-dispatch.js +75 -0
- package/dist/tools/browser-dispatch.js.map +1 -0
- package/dist/tools/responses.d.ts +19 -0
- package/dist/tools/responses.js +27 -0
- package/dist/tools/responses.js.map +1 -0
- package/dist/tools/server-instructions.d.ts +3 -0
- package/dist/tools/server-instructions.js +50 -0
- package/dist/tools/server-instructions.js.map +1 -0
- package/dist/tools/types.d.ts +6 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/open-url.d.ts +4 -0
- package/dist/utils/open-url.js +37 -0
- package/dist/utils/open-url.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
interface StatusResult {
|
|
2
|
+
connected: boolean;
|
|
3
|
+
serverTabId?: string;
|
|
4
|
+
}
|
|
5
|
+
interface ConnectResult {
|
|
6
|
+
ok: boolean;
|
|
7
|
+
error?: string;
|
|
8
|
+
serverTabId?: string;
|
|
9
|
+
}
|
|
10
|
+
declare function getCurrentTab(): Promise<chrome.tabs.Tab | null>;
|
|
11
|
+
declare function $(id: string): HTMLElement;
|
|
12
|
+
declare function refresh(): Promise<void>;
|
|
13
|
+
declare function onAction(): Promise<void>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="es">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<title>browser-link</title>
|
|
6
|
+
<style>
|
|
7
|
+
:root {
|
|
8
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
9
|
+
}
|
|
10
|
+
body {
|
|
11
|
+
margin: 0;
|
|
12
|
+
padding: 14px;
|
|
13
|
+
width: 280px;
|
|
14
|
+
color: #1f2937;
|
|
15
|
+
}
|
|
16
|
+
h1 {
|
|
17
|
+
font-size: 14px;
|
|
18
|
+
font-weight: 600;
|
|
19
|
+
margin: 0 0 10px;
|
|
20
|
+
letter-spacing: 0.3px;
|
|
21
|
+
}
|
|
22
|
+
.status {
|
|
23
|
+
padding: 8px 10px;
|
|
24
|
+
border-radius: 6px;
|
|
25
|
+
margin-bottom: 8px;
|
|
26
|
+
font-size: 12px;
|
|
27
|
+
line-height: 1.4;
|
|
28
|
+
}
|
|
29
|
+
.status.connected {
|
|
30
|
+
background: #d1fae5;
|
|
31
|
+
color: #065f46;
|
|
32
|
+
}
|
|
33
|
+
.status.disconnected {
|
|
34
|
+
background: #fef3c7;
|
|
35
|
+
color: #92400e;
|
|
36
|
+
}
|
|
37
|
+
.status.error {
|
|
38
|
+
background: #fee2e2;
|
|
39
|
+
color: #991b1b;
|
|
40
|
+
}
|
|
41
|
+
.url {
|
|
42
|
+
font-size: 11px;
|
|
43
|
+
color: #6b7280;
|
|
44
|
+
word-break: break-all;
|
|
45
|
+
margin-bottom: 10px;
|
|
46
|
+
max-height: 36px;
|
|
47
|
+
overflow: hidden;
|
|
48
|
+
}
|
|
49
|
+
.tab-id {
|
|
50
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
}
|
|
53
|
+
button {
|
|
54
|
+
width: 100%;
|
|
55
|
+
padding: 9px 12px;
|
|
56
|
+
border: none;
|
|
57
|
+
border-radius: 6px;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
font-size: 13px;
|
|
60
|
+
font-weight: 500;
|
|
61
|
+
transition: opacity 0.15s ease;
|
|
62
|
+
}
|
|
63
|
+
button.primary {
|
|
64
|
+
background: #2563eb;
|
|
65
|
+
color: white;
|
|
66
|
+
}
|
|
67
|
+
button.danger {
|
|
68
|
+
background: #dc2626;
|
|
69
|
+
color: white;
|
|
70
|
+
}
|
|
71
|
+
button:hover {
|
|
72
|
+
opacity: 0.9;
|
|
73
|
+
}
|
|
74
|
+
button:disabled {
|
|
75
|
+
background: #9ca3af;
|
|
76
|
+
cursor: not-allowed;
|
|
77
|
+
opacity: 0.6;
|
|
78
|
+
}
|
|
79
|
+
</style>
|
|
80
|
+
</head>
|
|
81
|
+
<body>
|
|
82
|
+
<h1>browser-link</h1>
|
|
83
|
+
<div id="status" class="status disconnected">Cargando…</div>
|
|
84
|
+
<div id="url" class="url"></div>
|
|
85
|
+
<button id="action" class="primary" disabled>…</button>
|
|
86
|
+
<script type="module" src="popup.js"></script>
|
|
87
|
+
</body>
|
|
88
|
+
</html>
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
async function getCurrentTab() {
|
|
3
|
+
const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
|
|
4
|
+
return tab ?? null;
|
|
5
|
+
}
|
|
6
|
+
function $(id) {
|
|
7
|
+
const el = document.getElementById(id);
|
|
8
|
+
if (!el)
|
|
9
|
+
throw new Error(`Element not found: ${id}`);
|
|
10
|
+
return el;
|
|
11
|
+
}
|
|
12
|
+
async function refresh() {
|
|
13
|
+
const tab = await getCurrentTab();
|
|
14
|
+
const statusEl = $('status');
|
|
15
|
+
const urlEl = $('url');
|
|
16
|
+
const actionBtn = $('action');
|
|
17
|
+
if (!tab?.id) {
|
|
18
|
+
statusEl.className = 'status error';
|
|
19
|
+
statusEl.textContent = 'No hay pestaña activa';
|
|
20
|
+
actionBtn.disabled = true;
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
urlEl.textContent = tab.url ?? '';
|
|
24
|
+
const status = (await chrome.runtime.sendMessage({
|
|
25
|
+
action: 'status',
|
|
26
|
+
tabId: tab.id,
|
|
27
|
+
}));
|
|
28
|
+
actionBtn.disabled = false;
|
|
29
|
+
if (status.connected) {
|
|
30
|
+
statusEl.className = 'status connected';
|
|
31
|
+
statusEl.innerHTML = `Conectada · <span class="tab-id">${status.serverTabId ?? '…'}</span>`;
|
|
32
|
+
actionBtn.textContent = 'Desconectar';
|
|
33
|
+
actionBtn.className = 'danger';
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
statusEl.className = 'status disconnected';
|
|
37
|
+
statusEl.textContent = 'No conectada';
|
|
38
|
+
actionBtn.textContent = 'Conectar';
|
|
39
|
+
actionBtn.className = 'primary';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function onAction() {
|
|
43
|
+
const tab = await getCurrentTab();
|
|
44
|
+
if (!tab?.id)
|
|
45
|
+
return;
|
|
46
|
+
const actionBtn = $('action');
|
|
47
|
+
const statusEl = $('status');
|
|
48
|
+
actionBtn.disabled = true;
|
|
49
|
+
const status = (await chrome.runtime.sendMessage({
|
|
50
|
+
action: 'status',
|
|
51
|
+
tabId: tab.id,
|
|
52
|
+
}));
|
|
53
|
+
if (status.connected) {
|
|
54
|
+
await chrome.runtime.sendMessage({ action: 'disconnect', tabId: tab.id });
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
const result = (await chrome.runtime.sendMessage({
|
|
58
|
+
action: 'connect',
|
|
59
|
+
tabId: tab.id,
|
|
60
|
+
}));
|
|
61
|
+
if (!result.ok) {
|
|
62
|
+
statusEl.className = 'status error';
|
|
63
|
+
statusEl.textContent = result.error ?? 'Error desconocido';
|
|
64
|
+
actionBtn.disabled = false;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
await refresh();
|
|
69
|
+
}
|
|
70
|
+
$('action').addEventListener('click', () => {
|
|
71
|
+
onAction().catch((err) => {
|
|
72
|
+
const statusEl = $('status');
|
|
73
|
+
statusEl.className = 'status error';
|
|
74
|
+
statusEl.textContent = err instanceof Error ? err.message : String(err);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
refresh().catch(() => { });
|
|
78
|
+
//# sourceMappingURL=popup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"popup.js","sourceRoot":"","sources":["../src/popup.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
// Backwards-compatible entry: MCP clients that registered
|
|
2
|
+
// `node /path/to/dist/index.js` will keep working.
|
|
3
|
+
// New installs should use the `browser-link` bin (dist/cli.js).
|
|
4
|
+
import { runServer } from './server.js';
|
|
5
|
+
await runServer();
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAC1D,mDAAmD;AACnD,gEAAgE;AAChE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,SAAS,EAAE,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
const SERVER_NAME = 'browser-link';
|
|
5
|
+
function configFile() {
|
|
6
|
+
// Claude Code stores its config at the user's home root on every OS.
|
|
7
|
+
// os.homedir() resolves correctly on Windows (%USERPROFILE%) and *nix.
|
|
8
|
+
return join(homedir(), '.claude.json');
|
|
9
|
+
}
|
|
10
|
+
function readConfig(path) {
|
|
11
|
+
if (!existsSync(path))
|
|
12
|
+
return {};
|
|
13
|
+
try {
|
|
14
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
throw new Error(`Could not parse Claude config at ${path}. Fix the file or delete it.`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function writeConfig(path, cfg) {
|
|
21
|
+
writeFileSync(path, JSON.stringify(cfg, null, 2) + '\n', 'utf8');
|
|
22
|
+
}
|
|
23
|
+
function isRegistered(cfg) {
|
|
24
|
+
if (cfg.mcpServers?.[SERVER_NAME])
|
|
25
|
+
return true;
|
|
26
|
+
const projects = cfg.projects ?? {};
|
|
27
|
+
return Object.values(projects).some((p) => !!p.mcpServers?.[SERVER_NAME]);
|
|
28
|
+
}
|
|
29
|
+
export const claudeInstaller = {
|
|
30
|
+
id: 'claude',
|
|
31
|
+
displayName: 'Claude Code',
|
|
32
|
+
configPath() {
|
|
33
|
+
return configFile();
|
|
34
|
+
},
|
|
35
|
+
detect() {
|
|
36
|
+
const path = configFile();
|
|
37
|
+
if (!existsSync(path)) {
|
|
38
|
+
return { installed: false, registered: false, configPath: path };
|
|
39
|
+
}
|
|
40
|
+
const cfg = readConfig(path);
|
|
41
|
+
return { installed: true, registered: isRegistered(cfg), configPath: path };
|
|
42
|
+
},
|
|
43
|
+
install(command, args) {
|
|
44
|
+
const path = configFile();
|
|
45
|
+
const cfg = readConfig(path);
|
|
46
|
+
cfg.mcpServers = cfg.mcpServers ?? {};
|
|
47
|
+
const existing = cfg.mcpServers[SERVER_NAME];
|
|
48
|
+
cfg.mcpServers[SERVER_NAME] = { type: 'stdio', command, args };
|
|
49
|
+
writeConfig(path, cfg);
|
|
50
|
+
return existing
|
|
51
|
+
? `Updated ${SERVER_NAME} entry (user scope) in ${path}.`
|
|
52
|
+
: `Added ${SERVER_NAME} entry (user scope) to ${path}.`;
|
|
53
|
+
},
|
|
54
|
+
uninstall() {
|
|
55
|
+
const path = configFile();
|
|
56
|
+
if (!existsSync(path))
|
|
57
|
+
return `No Claude config at ${path}; nothing to remove.`;
|
|
58
|
+
const cfg = readConfig(path);
|
|
59
|
+
let removed = false;
|
|
60
|
+
if (cfg.mcpServers?.[SERVER_NAME]) {
|
|
61
|
+
delete cfg.mcpServers[SERVER_NAME];
|
|
62
|
+
removed = true;
|
|
63
|
+
}
|
|
64
|
+
const projects = cfg.projects ?? {};
|
|
65
|
+
for (const proj of Object.values(projects)) {
|
|
66
|
+
if (proj.mcpServers?.[SERVER_NAME]) {
|
|
67
|
+
delete proj.mcpServers[SERVER_NAME];
|
|
68
|
+
removed = true;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (!removed)
|
|
72
|
+
return `${SERVER_NAME} was not registered in ${path}.`;
|
|
73
|
+
writeConfig(path, cfg);
|
|
74
|
+
return `Removed ${SERVER_NAME} entry from ${path} (user + project scopes).`;
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=claude.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/installers/claude.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ClientId, Installer } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Installers that are currently shippable. OpenCode lives in opencode.ts as
|
|
4
|
+
* a scaffold but is not part of this array yet — installFor / installAll
|
|
5
|
+
* will never invoke its (throwing) install/uninstall stubs.
|
|
6
|
+
*/
|
|
7
|
+
export declare const INSTALLERS: Installer[];
|
|
8
|
+
export declare function getInstaller(id: ClientId): Installer;
|
|
9
|
+
export type { ClientId, Installer } from './types.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { claudeInstaller } from './claude.js';
|
|
2
|
+
/**
|
|
3
|
+
* Installers that are currently shippable. OpenCode lives in opencode.ts as
|
|
4
|
+
* a scaffold but is not part of this array yet — installFor / installAll
|
|
5
|
+
* will never invoke its (throwing) install/uninstall stubs.
|
|
6
|
+
*/
|
|
7
|
+
export const INSTALLERS = [claudeInstaller];
|
|
8
|
+
export function getInstaller(id) {
|
|
9
|
+
const found = INSTALLERS.find((i) => i.id === id);
|
|
10
|
+
if (!found)
|
|
11
|
+
throw new Error(`Unknown or unsupported client: ${id}`);
|
|
12
|
+
return found;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/installers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C;;;;GAIG;AACH,MAAM,CAAC,MAAM,UAAU,GAAgB,CAAC,eAAe,CAAC,CAAC;AAEzD,MAAM,UAAU,YAAY,CAAC,EAAY;IACvC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,EAAE,EAAE,CAAC,CAAC;IACpE,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { homedir, platform } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
/**
|
|
5
|
+
* OpenCode integration is a placeholder until we wire up its config format.
|
|
6
|
+
* detect() looks for the conventional config path per OS; install/uninstall
|
|
7
|
+
* throw with a clear message so the CLI surface is consistent.
|
|
8
|
+
*/
|
|
9
|
+
function configFile() {
|
|
10
|
+
if (platform() === 'win32') {
|
|
11
|
+
const appData = process.env.APPDATA ?? join(homedir(), 'AppData', 'Roaming');
|
|
12
|
+
return join(appData, 'opencode', 'opencode.json');
|
|
13
|
+
}
|
|
14
|
+
const xdg = process.env.XDG_CONFIG_HOME;
|
|
15
|
+
if (xdg && xdg.trim().length > 0)
|
|
16
|
+
return join(xdg, 'opencode', 'opencode.json');
|
|
17
|
+
if (platform() === 'darwin') {
|
|
18
|
+
return join(homedir(), 'Library', 'Application Support', 'opencode', 'opencode.json');
|
|
19
|
+
}
|
|
20
|
+
return join(homedir(), '.config', 'opencode', 'opencode.json');
|
|
21
|
+
}
|
|
22
|
+
export const opencodeInstaller = {
|
|
23
|
+
id: 'opencode',
|
|
24
|
+
displayName: 'OpenCode',
|
|
25
|
+
configPath() {
|
|
26
|
+
return configFile();
|
|
27
|
+
},
|
|
28
|
+
detect() {
|
|
29
|
+
const path = configFile();
|
|
30
|
+
return { installed: existsSync(path), registered: false, configPath: path };
|
|
31
|
+
},
|
|
32
|
+
install() {
|
|
33
|
+
throw new Error(`OpenCode installer is not implemented yet. Edit ${configFile()} manually or open an issue.`);
|
|
34
|
+
},
|
|
35
|
+
uninstall() {
|
|
36
|
+
throw new Error(`OpenCode installer is not implemented yet. Edit ${configFile()} manually or open an issue.`);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/installers/opencode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;GAIG;AACH,SAAS,UAAU;IACjB,IAAI,QAAQ,EAAE,KAAK,OAAO,EAAE,CAAC;QAC3B,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;QAC7E,OAAO,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC;IACxC,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,GAAG,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IAChF,IAAI,QAAQ,EAAE,KAAK,QAAQ,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,qBAAqB,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAc;IAC1C,EAAE,EAAE,UAAU;IACd,WAAW,EAAE,UAAU;IAEvB,UAAU;QACR,OAAO,UAAU,EAAE,CAAC;IACtB,CAAC;IAED,MAAM;QACJ,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAC1B,OAAO,EAAE,SAAS,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;IAC9E,CAAC;IAED,OAAO;QACL,MAAM,IAAI,KAAK,CACb,mDAAmD,UAAU,EAAE,6BAA6B,CAC7F,CAAC;IACJ,CAAC;IAED,SAAS;QACP,MAAM,IAAI,KAAK,CACb,mDAAmD,UAAU,EAAE,6BAA6B,CAC7F,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export type ClientId = 'claude' | 'opencode';
|
|
2
|
+
export interface ClientInfo {
|
|
3
|
+
id: ClientId;
|
|
4
|
+
displayName: string;
|
|
5
|
+
}
|
|
6
|
+
export interface DetectResult {
|
|
7
|
+
installed: boolean;
|
|
8
|
+
registered: boolean;
|
|
9
|
+
configPath: string;
|
|
10
|
+
}
|
|
11
|
+
export interface Installer extends ClientInfo {
|
|
12
|
+
/**
|
|
13
|
+
* Where the client's config lives on this OS, if any conventional location
|
|
14
|
+
* is known. Returns the resolved absolute path even when the file does not exist yet.
|
|
15
|
+
*/
|
|
16
|
+
configPath(): string;
|
|
17
|
+
/**
|
|
18
|
+
* Whether the client appears installed on the system (config file or directory exists).
|
|
19
|
+
*/
|
|
20
|
+
detect(): DetectResult;
|
|
21
|
+
/**
|
|
22
|
+
* Register browser-link in the client's MCP config. Idempotent.
|
|
23
|
+
* Returns a brief description of what was changed.
|
|
24
|
+
*/
|
|
25
|
+
install(command: string, args: string[]): string;
|
|
26
|
+
/**
|
|
27
|
+
* Remove the browser-link entry from the client's MCP config. Idempotent.
|
|
28
|
+
*/
|
|
29
|
+
uninstall(): string;
|
|
30
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/installers/types.ts"],"names":[],"mappings":""}
|
package/dist/map/db.d.ts
ADDED
package/dist/map/db.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import Database from 'better-sqlite3';
|
|
2
|
+
import { copyFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { getDbPath } from './paths.js';
|
|
6
|
+
let dbInstance = null;
|
|
7
|
+
export function getDb() {
|
|
8
|
+
if (dbInstance)
|
|
9
|
+
return dbInstance;
|
|
10
|
+
const path = getDbPath();
|
|
11
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
12
|
+
migrateLegacyDb(path);
|
|
13
|
+
const db = new Database(path);
|
|
14
|
+
db.pragma('journal_mode = WAL');
|
|
15
|
+
db.pragma('foreign_keys = ON');
|
|
16
|
+
runMigrations(db);
|
|
17
|
+
dbInstance = db;
|
|
18
|
+
return db;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Older versions of browser-link stored the map at ~/.browser-link/map.db.
|
|
22
|
+
* On first boot with the new XDG/per-OS path, copy the legacy file over so
|
|
23
|
+
* a user upgrading does not lose what they had learned.
|
|
24
|
+
*
|
|
25
|
+
* Only runs when the data dir was NOT overridden via BROWSER_LINK_DATA_DIR.
|
|
26
|
+
* Portable installs and tests that point to a custom dir should start empty.
|
|
27
|
+
*/
|
|
28
|
+
function migrateLegacyDb(targetPath) {
|
|
29
|
+
if (process.env.BROWSER_LINK_DATA_DIR && process.env.BROWSER_LINK_DATA_DIR.trim().length > 0) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
if (existsSync(targetPath))
|
|
33
|
+
return;
|
|
34
|
+
const legacy = join(homedir(), '.browser-link', 'map.db');
|
|
35
|
+
if (!existsSync(legacy))
|
|
36
|
+
return;
|
|
37
|
+
try {
|
|
38
|
+
copyFileSync(legacy, targetPath);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
// If the copy fails we silently fall back to a fresh DB.
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
function runMigrations(db) {
|
|
45
|
+
db.exec(`
|
|
46
|
+
CREATE TABLE IF NOT EXISTS apps (
|
|
47
|
+
id INTEGER PRIMARY KEY,
|
|
48
|
+
origin TEXT NOT NULL,
|
|
49
|
+
app_key TEXT NOT NULL,
|
|
50
|
+
title TEXT,
|
|
51
|
+
notes TEXT,
|
|
52
|
+
created_at TEXT NOT NULL,
|
|
53
|
+
last_seen_at TEXT NOT NULL,
|
|
54
|
+
UNIQUE(origin, app_key)
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
58
|
+
id INTEGER PRIMARY KEY,
|
|
59
|
+
app_id INTEGER NOT NULL REFERENCES apps(id) ON DELETE CASCADE,
|
|
60
|
+
url_pattern TEXT NOT NULL,
|
|
61
|
+
kind TEXT NOT NULL CHECK (kind IN ('selector', 'flow', 'gotcha')),
|
|
62
|
+
purpose TEXT NOT NULL,
|
|
63
|
+
payload TEXT NOT NULL,
|
|
64
|
+
verified_at TEXT,
|
|
65
|
+
failed_at TEXT,
|
|
66
|
+
notes TEXT,
|
|
67
|
+
created_at TEXT NOT NULL,
|
|
68
|
+
updated_at TEXT NOT NULL,
|
|
69
|
+
UNIQUE(app_id, url_pattern, kind, purpose)
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
CREATE INDEX IF NOT EXISTS idx_entries_lookup ON entries(app_id, url_pattern);
|
|
73
|
+
`);
|
|
74
|
+
}
|
|
75
|
+
export function closeDb() {
|
|
76
|
+
if (dbInstance) {
|
|
77
|
+
dbInstance.close();
|
|
78
|
+
dbInstance = null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=db.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/map/db.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,IAAI,UAAU,GAA6B,IAAI,CAAC;AAEhD,MAAM,UAAU,KAAK;IACnB,IAAI,UAAU;QAAE,OAAO,UAAU,CAAC;IAClC,MAAM,IAAI,GAAG,SAAS,EAAE,CAAC;IACzB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,eAAe,CAAC,IAAI,CAAC,CAAC;IACtB,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAChC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAC/B,aAAa,CAAC,EAAE,CAAC,CAAC;IAClB,UAAU,GAAG,EAAE,CAAC;IAChB,OAAO,EAAE,CAAC;AACZ,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,eAAe,CAAC,UAAkB;IACzC,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7F,OAAO;IACT,CAAC;IACD,IAAI,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO;IACnC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;IAC1D,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO;IAChC,IAAI,CAAC;QACH,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC;AAED,SAAS,aAAa,CAAC,EAAqB;IAC1C,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,IAAI,UAAU,EAAE,CAAC;QACf,UAAU,CAAC,KAAK,EAAE,CAAC;QACnB,UAAU,GAAG,IAAI,CAAC;IACpB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the directory where browser-link stores user data (the map DB).
|
|
3
|
+
*
|
|
4
|
+
* Defaults follow per-OS convention via env-paths:
|
|
5
|
+
* - Linux: $XDG_DATA_HOME/browser-link, fallback ~/.local/share/browser-link
|
|
6
|
+
* - macOS: ~/Library/Application Support/browser-link
|
|
7
|
+
* - Windows: %APPDATA%/browser-link
|
|
8
|
+
*
|
|
9
|
+
* Override with $BROWSER_LINK_DATA_DIR for tests or portable installs.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getDataDir(): string;
|
|
12
|
+
export declare function getDbPath(): string;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import envPaths from 'env-paths';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Resolve the directory where browser-link stores user data (the map DB).
|
|
5
|
+
*
|
|
6
|
+
* Defaults follow per-OS convention via env-paths:
|
|
7
|
+
* - Linux: $XDG_DATA_HOME/browser-link, fallback ~/.local/share/browser-link
|
|
8
|
+
* - macOS: ~/Library/Application Support/browser-link
|
|
9
|
+
* - Windows: %APPDATA%/browser-link
|
|
10
|
+
*
|
|
11
|
+
* Override with $BROWSER_LINK_DATA_DIR for tests or portable installs.
|
|
12
|
+
*/
|
|
13
|
+
export function getDataDir() {
|
|
14
|
+
const override = process.env.BROWSER_LINK_DATA_DIR;
|
|
15
|
+
if (override && override.trim().length > 0)
|
|
16
|
+
return override;
|
|
17
|
+
return envPaths('browser-link', { suffix: '' }).data;
|
|
18
|
+
}
|
|
19
|
+
export function getDbPath() {
|
|
20
|
+
return join(getDataDir(), 'map.db');
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/map/paths.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;GASG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IACnD,IAAI,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IAC5D,OAAO,QAAQ,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC;AACvD,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,QAAQ,CAAC,CAAC;AACtC,CAAC"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export type EntryKind = 'selector' | 'flow' | 'gotcha';
|
|
2
|
+
export interface AppRow {
|
|
3
|
+
id: number;
|
|
4
|
+
origin: string;
|
|
5
|
+
app_key: string;
|
|
6
|
+
title: string | null;
|
|
7
|
+
notes: string | null;
|
|
8
|
+
created_at: string;
|
|
9
|
+
last_seen_at: string;
|
|
10
|
+
}
|
|
11
|
+
export interface EntryRow {
|
|
12
|
+
id: number;
|
|
13
|
+
app_id: number;
|
|
14
|
+
url_pattern: string;
|
|
15
|
+
kind: EntryKind;
|
|
16
|
+
purpose: string;
|
|
17
|
+
payload: unknown;
|
|
18
|
+
verified_at: string | null;
|
|
19
|
+
failed_at: string | null;
|
|
20
|
+
notes: string | null;
|
|
21
|
+
created_at: string;
|
|
22
|
+
updated_at: string;
|
|
23
|
+
}
|
|
24
|
+
export interface UpsertAppInput {
|
|
25
|
+
origin: string;
|
|
26
|
+
app_key?: string | null;
|
|
27
|
+
title?: string | null;
|
|
28
|
+
notes?: string | null;
|
|
29
|
+
}
|
|
30
|
+
export declare function upsertApp(input: UpsertAppInput): AppRow;
|
|
31
|
+
export interface SaveEntryInput {
|
|
32
|
+
origin: string;
|
|
33
|
+
app_key?: string | null;
|
|
34
|
+
title?: string | null;
|
|
35
|
+
url_pattern: string;
|
|
36
|
+
kind: EntryKind;
|
|
37
|
+
purpose: string;
|
|
38
|
+
payload: unknown;
|
|
39
|
+
notes?: string | null;
|
|
40
|
+
}
|
|
41
|
+
export declare function saveEntry(input: SaveEntryInput): {
|
|
42
|
+
app: AppRow;
|
|
43
|
+
entry: EntryRow;
|
|
44
|
+
};
|
|
45
|
+
export interface RecallInput {
|
|
46
|
+
origin: string;
|
|
47
|
+
app_key?: string | null;
|
|
48
|
+
url?: string | null;
|
|
49
|
+
}
|
|
50
|
+
export interface RecallResult {
|
|
51
|
+
app: AppRow | null;
|
|
52
|
+
entries: EntryRow[];
|
|
53
|
+
}
|
|
54
|
+
export declare function recall(input: RecallInput): RecallResult;
|
|
55
|
+
export interface RecordUseInput {
|
|
56
|
+
entry_id: number;
|
|
57
|
+
ok: boolean;
|
|
58
|
+
notes?: string | null;
|
|
59
|
+
}
|
|
60
|
+
export declare function recordUse(input: RecordUseInput): EntryRow | null;
|
|
61
|
+
export interface ForgetInput {
|
|
62
|
+
entry_id?: number;
|
|
63
|
+
app_id?: number;
|
|
64
|
+
reason?: string;
|
|
65
|
+
}
|
|
66
|
+
export interface ForgetResult {
|
|
67
|
+
deleted_entries: number;
|
|
68
|
+
deleted_apps: number;
|
|
69
|
+
}
|
|
70
|
+
export declare function forget(input: ForgetInput): ForgetResult;
|
|
71
|
+
export declare function renameApp(app_id: number, new_app_key: string): AppRow | null;
|
|
72
|
+
export declare function listApps(): AppRow[];
|