@btraut/browser-bridge 0.12.0 → 0.12.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/CHANGELOG.md +10 -0
- package/README.md +6 -8
- package/extension/assets/ui.css +13 -89
- package/extension/dist/background.js +46 -0
- package/extension/dist/background.js.map +2 -2
- package/extension/dist/popup-ui.js +12 -78
- package/extension/dist/popup-ui.js.map +2 -2
- package/extension/manifest.json +1 -1
- package/package.json +1 -1
- package/skills/browser-bridge/skill.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,16 @@ The format is based on "Keep a Changelog", and this project adheres to Semantic
|
|
|
8
8
|
|
|
9
9
|
_TBD_
|
|
10
10
|
|
|
11
|
+
## [0.12.1] - 2026-02-17
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Extension popup now shows a compact `Connected` indicator (green/red) instead of the verbose connection diagnostics panel.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Extension background now preflights Core `/health` before dialing websocket, avoiding noisy `ERR_CONNECTION_REFUSED` extension errors while Core is offline.
|
|
20
|
+
|
|
11
21
|
## [0.12.0] - 2026-02-17
|
|
12
22
|
|
|
13
23
|
### Changed
|
package/README.md
CHANGED
|
@@ -318,7 +318,7 @@ tail -n 80 .context/logs/browser-bridge/mcp-adapter.jsonl
|
|
|
318
318
|
- CLI: `browser-bridge diagnostics doctor --session-id <id>`
|
|
319
319
|
- Reports extension and debugger status alongside session state.
|
|
320
320
|
- Includes runtime context for caller, Core, and extension endpoints so mismatch causes are visible in one run.
|
|
321
|
-
- Popup
|
|
321
|
+
- Popup shows a simple `Connected` indicator (`green` when connected, `red` otherwise).
|
|
322
322
|
|
|
323
323
|
### End-to-End Connection Troubleshooting Flow
|
|
324
324
|
|
|
@@ -336,17 +336,15 @@ browser-bridge dev info --json
|
|
|
336
336
|
browser-bridge diagnostics doctor --json
|
|
337
337
|
```
|
|
338
338
|
|
|
339
|
-
3. Open extension popup and
|
|
340
|
-
-
|
|
341
|
-
-
|
|
342
|
-
- `Source`
|
|
343
|
-
- `Last failure`
|
|
339
|
+
3. Open the extension popup and check `Connected`:
|
|
340
|
+
- Green dot: extension is currently connected to Core.
|
|
341
|
+
- Red dot: extension is disconnected or reconnecting.
|
|
344
342
|
|
|
345
|
-
4. If caller/core/extension endpoints differ:
|
|
343
|
+
4. If caller/core/extension endpoints differ in the diagnostics report:
|
|
346
344
|
- Default mode: remove custom host/port env overrides and retry (`BROWSER_BRIDGE_CORE_HOST`, `BROWSER_BRIDGE_CORE_PORT`).
|
|
347
345
|
- Isolated mode: re-run `browser-bridge dev activate --extension-id <id>` for the intended worktree.
|
|
348
346
|
|
|
349
|
-
5. If
|
|
347
|
+
5. If the popup stays red and failures continue:
|
|
350
348
|
- Inspect logs:
|
|
351
349
|
|
|
352
350
|
```bash
|
package/extension/assets/ui.css
CHANGED
|
@@ -68,111 +68,35 @@ body.bb-page.bb-page--popup {
|
|
|
68
68
|
padding: 2px;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
.bb-
|
|
71
|
+
.bb-connection {
|
|
72
72
|
border: 1px solid var(--bb-border-2);
|
|
73
73
|
border-radius: var(--bb-radius-sm);
|
|
74
74
|
background: var(--bb-bg);
|
|
75
75
|
box-shadow: 0 3px 8px rgba(0, 0, 0, 0.06);
|
|
76
76
|
padding: 10px 12px;
|
|
77
77
|
margin: 0 0 10px;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
.bb-health-head {
|
|
81
78
|
display: flex;
|
|
82
79
|
align-items: center;
|
|
83
80
|
justify-content: space-between;
|
|
84
|
-
margin-bottom: 8px;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
.bb-health-label {
|
|
88
|
-
font-size: 12px;
|
|
89
|
-
font-weight: 700;
|
|
90
|
-
letter-spacing: 0.04em;
|
|
91
|
-
color: var(--bb-ink-2);
|
|
92
|
-
text-transform: uppercase;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
.bb-health-state {
|
|
96
|
-
border: 1px solid var(--bb-border);
|
|
97
|
-
border-radius: 999px;
|
|
98
|
-
padding: 2px 8px;
|
|
99
|
-
font-size: 11px;
|
|
100
|
-
font-weight: 700;
|
|
101
|
-
text-transform: capitalize;
|
|
102
|
-
color: var(--bb-ink);
|
|
103
|
-
background: rgba(0, 0, 0, 0.04);
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
.bb-health-state[data-state='connected'] {
|
|
107
|
-
color: #1f6f3f;
|
|
108
|
-
border-color: rgba(31, 111, 63, 0.35);
|
|
109
|
-
background: rgba(31, 111, 63, 0.12);
|
|
110
81
|
}
|
|
111
82
|
|
|
112
|
-
.bb-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
border-color: rgba(138, 82, 0, 0.35);
|
|
116
|
-
background: rgba(138, 82, 0, 0.12);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
.bb-health-state[data-state='disconnected'] {
|
|
120
|
-
color: #a22b2b;
|
|
121
|
-
border-color: rgba(162, 43, 43, 0.35);
|
|
122
|
-
background: rgba(162, 43, 43, 0.12);
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
.bb-health-grid {
|
|
126
|
-
display: grid;
|
|
127
|
-
grid-template-columns: auto 1fr;
|
|
128
|
-
gap: 6px 8px;
|
|
129
|
-
margin: 0;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
.bb-health-grid dt {
|
|
133
|
-
margin: 0;
|
|
134
|
-
font-size: 11px;
|
|
135
|
-
color: var(--bb-ink-2);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
.bb-health-grid dd {
|
|
139
|
-
margin: 0;
|
|
140
|
-
font-size: 12px;
|
|
141
|
-
color: var(--bb-ink);
|
|
142
|
-
overflow-wrap: anywhere;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.bb-health-error {
|
|
146
|
-
min-height: 14px;
|
|
147
|
-
margin: 8px 0 0;
|
|
148
|
-
font-size: 11px;
|
|
149
|
-
color: #a22b2b;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
.bb-health-actions {
|
|
153
|
-
margin-top: 6px;
|
|
154
|
-
display: flex;
|
|
155
|
-
align-items: center;
|
|
156
|
-
gap: 8px;
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
.bb-health-copy {
|
|
160
|
-
border: 1px solid var(--bb-border);
|
|
161
|
-
border-radius: 8px;
|
|
162
|
-
background: var(--bb-bg);
|
|
83
|
+
.bb-connection-label {
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
font-weight: 600;
|
|
163
86
|
color: var(--bb-ink);
|
|
164
|
-
padding: 5px 8px;
|
|
165
|
-
font-size: 12px;
|
|
166
|
-
cursor: pointer;
|
|
167
87
|
}
|
|
168
88
|
|
|
169
|
-
.bb-
|
|
170
|
-
|
|
89
|
+
.bb-connection-dot {
|
|
90
|
+
width: 11px;
|
|
91
|
+
height: 11px;
|
|
92
|
+
border-radius: 999px;
|
|
93
|
+
border: 1px solid rgba(162, 43, 43, 0.35);
|
|
94
|
+
background: #c93939;
|
|
171
95
|
}
|
|
172
96
|
|
|
173
|
-
.bb-
|
|
174
|
-
|
|
175
|
-
|
|
97
|
+
.bb-connection-dot[data-connected='true'] {
|
|
98
|
+
border-color: rgba(31, 111, 63, 0.4);
|
|
99
|
+
background: #2b9a52;
|
|
176
100
|
}
|
|
177
101
|
|
|
178
102
|
.bb-popup-head {
|
|
@@ -488,6 +488,8 @@ var ConnectionStateTracker = class {
|
|
|
488
488
|
var DEFAULT_CORE_PORT = 3210;
|
|
489
489
|
var CORE_PORT_KEY = "corePort";
|
|
490
490
|
var CORE_WS_PATH = "/drive";
|
|
491
|
+
var CORE_HEALTH_PATH = "/health";
|
|
492
|
+
var CORE_HEALTH_TIMEOUT_MS = 1200;
|
|
491
493
|
var DEBUGGER_PROTOCOL_VERSION = "1.3";
|
|
492
494
|
var DEBUGGER_IDLE_TIMEOUT_KEY = "debuggerIdleTimeoutMs";
|
|
493
495
|
var DEFAULT_DEBUGGER_IDLE_TIMEOUT_MS = 15e3;
|
|
@@ -1153,6 +1155,7 @@ var getWsEndpoint = async () => {
|
|
|
1153
1155
|
url: `ws://${endpoint.host}:${endpoint.port}${CORE_WS_PATH}`
|
|
1154
1156
|
};
|
|
1155
1157
|
};
|
|
1158
|
+
var getHealthEndpoint = (endpoint) => `http://${endpoint.host}:${endpoint.port}${CORE_HEALTH_PATH}`;
|
|
1156
1159
|
var DriveSocket = class {
|
|
1157
1160
|
constructor() {
|
|
1158
1161
|
this.socket = null;
|
|
@@ -1209,6 +1212,16 @@ var DriveSocket = class {
|
|
|
1209
1212
|
async connect() {
|
|
1210
1213
|
const { endpoint, url } = await getWsEndpoint();
|
|
1211
1214
|
this.connection.setEndpoint(endpoint);
|
|
1215
|
+
const health = await this.checkCoreHealth(endpoint);
|
|
1216
|
+
if (!health.ok) {
|
|
1217
|
+
this.connection.markDisconnected();
|
|
1218
|
+
this.recordConnectionFailure(
|
|
1219
|
+
"core unavailable",
|
|
1220
|
+
new Error(health.detail)
|
|
1221
|
+
);
|
|
1222
|
+
this.scheduleReconnect();
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1212
1225
|
try {
|
|
1213
1226
|
const socket2 = new WebSocket(url);
|
|
1214
1227
|
this.socket = socket2;
|
|
@@ -1241,6 +1254,39 @@ var DriveSocket = class {
|
|
|
1241
1254
|
this.scheduleReconnect();
|
|
1242
1255
|
}
|
|
1243
1256
|
}
|
|
1257
|
+
async checkCoreHealth(endpoint) {
|
|
1258
|
+
const controller = new AbortController();
|
|
1259
|
+
const timeoutId = self.setTimeout(() => {
|
|
1260
|
+
controller.abort();
|
|
1261
|
+
}, CORE_HEALTH_TIMEOUT_MS);
|
|
1262
|
+
try {
|
|
1263
|
+
const response = await fetch(getHealthEndpoint(endpoint), {
|
|
1264
|
+
method: "GET",
|
|
1265
|
+
cache: "no-store",
|
|
1266
|
+
signal: controller.signal
|
|
1267
|
+
});
|
|
1268
|
+
if (!response.ok) {
|
|
1269
|
+
return {
|
|
1270
|
+
ok: false,
|
|
1271
|
+
detail: `health returned HTTP ${response.status}`
|
|
1272
|
+
};
|
|
1273
|
+
}
|
|
1274
|
+
return { ok: true, detail: "ok" };
|
|
1275
|
+
} catch (error) {
|
|
1276
|
+
if (error instanceof DOMException && error.name === "AbortError") {
|
|
1277
|
+
return {
|
|
1278
|
+
ok: false,
|
|
1279
|
+
detail: `health timed out after ${CORE_HEALTH_TIMEOUT_MS}ms`
|
|
1280
|
+
};
|
|
1281
|
+
}
|
|
1282
|
+
return {
|
|
1283
|
+
ok: false,
|
|
1284
|
+
detail: error instanceof Error && error.message.length > 0 ? error.message : "health check failed"
|
|
1285
|
+
};
|
|
1286
|
+
} finally {
|
|
1287
|
+
clearTimeout(timeoutId);
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1244
1290
|
getConnectionStatus() {
|
|
1245
1291
|
return this.connection.getStatus();
|
|
1246
1292
|
}
|