@browserbridge/bbx 1.6.3 → 1.6.4

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@browserbridge/bbx",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "agent-tools",
@@ -132,6 +132,67 @@ export function summarizeToolError(error) {
132
132
  );
133
133
  }
134
134
 
135
+ /**
136
+ * @param {ToolResult} result
137
+ * @returns {boolean}
138
+ */
139
+ function shouldTryRemoteFallback(result) {
140
+ if (!result.isError && result.structuredContent.ok !== false) {
141
+ return false;
142
+ }
143
+ const text = result.content[0]?.text ?? '';
144
+ return /\b(ACCESS_DENIED|DAEMON_OFFLINE|EXTENSION_DISCONNECTED|NATIVE_HOST_UNAVAILABLE|CONNECTION_LOST)\b|\b(ENOENT|ECONNREFUSED|ETIMEDOUT)\b|ERROR: connect\b/u.test(
145
+ text
146
+ );
147
+ }
148
+
149
+ /**
150
+ * @param {ToolResult} result
151
+ * @param {string} destinationId
152
+ * @returns {ToolResult}
153
+ */
154
+ function annotateAutoDestination(result, destinationId) {
155
+ return {
156
+ ...result,
157
+ structuredContent: {
158
+ ...result.structuredContent,
159
+ destinationId,
160
+ autoSelectedDestinationId: destinationId,
161
+ },
162
+ };
163
+ }
164
+
165
+ /**
166
+ * @param {(client: import('../../agent-client/src/client.js').BridgeClient) => Promise<ToolResult>} callback
167
+ * @param {ToolResult} localResult
168
+ * @returns {Promise<ToolResult>}
169
+ */
170
+ async function tryRemoteFallback(callback, localResult) {
171
+ const remotes = (await listBridgeDestinations()).filter((destination) => !destination.local);
172
+ if (remotes.length === 0) {
173
+ return localResult;
174
+ }
175
+
176
+ let lastFallbackResult = localResult;
177
+ for (const remote of remotes) {
178
+ const client = await createBridgeClientForDestination(remote.id);
179
+ try {
180
+ await client.connect();
181
+ const result = annotateAutoDestination(await callback(client), remote.id);
182
+ lastFallbackResult = result;
183
+ if (!shouldTryRemoteFallback(result)) {
184
+ return result;
185
+ }
186
+ } catch (error) {
187
+ lastFallbackResult = annotateAutoDestination(summarizeToolError(error), remote.id);
188
+ } finally {
189
+ await client.close();
190
+ }
191
+ }
192
+
193
+ return lastFallbackResult;
194
+ }
195
+
135
196
  /**
136
197
  * @param {(client: import('../../agent-client/src/client.js').BridgeClient) => Promise<ToolResult>} callback
137
198
  * @param {{ destinationId?: string | null }} [options]
@@ -140,7 +201,8 @@ export function summarizeToolError(error) {
140
201
  export async function withToolClient(callback, options = {}) {
141
202
  try {
142
203
  if (!options.destinationId) {
143
- return await withBridgeClient(callback);
204
+ const result = await withBridgeClient(callback);
205
+ return shouldTryRemoteFallback(result) ? await tryRemoteFallback(callback, result) : result;
144
206
  }
145
207
  const client = await createBridgeClientForDestination(options.destinationId);
146
208
  await client.connect();
@@ -67,10 +67,31 @@ export {
67
67
  const HOME_DIR = os.homedir();
68
68
 
69
69
  /**
70
+ * @param {{ destinationId?: string }} [args]
70
71
  * @returns {Promise<ToolResult>}
71
72
  */
72
- export async function handleStatusTool() {
73
+ export async function handleStatusTool(args = {}) {
73
74
  try {
75
+ const requestedDestinationId =
76
+ typeof args.destinationId === 'string' ? args.destinationId : null;
77
+ if (requestedDestinationId && requestedDestinationId !== 'local') {
78
+ const destination = (await getBridgeDestinations()).find(
79
+ (entry) => entry.id === requestedDestinationId
80
+ );
81
+ const result = await callRemoteHealth(requestedDestinationId);
82
+ return createToolResult(
83
+ result.reachable
84
+ ? `Browser Bridge destination "${requestedDestinationId}" is reachable.`
85
+ : `Browser Bridge destination "${requestedDestinationId}" is not reachable.`,
86
+ {
87
+ ok: result.reachable === true,
88
+ destination: destination ?? { id: requestedDestinationId, local: false },
89
+ ...result,
90
+ },
91
+ result.reachable !== true
92
+ );
93
+ }
94
+
74
95
  const report = await getDoctorReport();
75
96
  const destinations = await Promise.all(
76
97
  (await getBridgeDestinations()).map(async (destination) => {