@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.
- package/README.md +3 -1
- package/docs/api-reference.md +33 -33
- package/docs/mcp-vs-cli.md +104 -104
- package/docs/publishing.md +1 -3
- package/docs/quickstart.md +6 -6
- package/docs/unpacked-extension.md +72 -0
- package/manifest.json +3 -17
- package/package.json +44 -42
- package/packages/agent-client/src/cli-helpers.js +10 -5
- package/packages/agent-client/src/cli.js +65 -135
- package/packages/agent-client/src/client.js +37 -17
- package/packages/agent-client/src/command-registry.js +101 -69
- package/packages/agent-client/src/detect.js +3 -6
- package/packages/agent-client/src/install.js +10 -27
- package/packages/agent-client/src/mcp-config.js +11 -30
- package/packages/agent-client/src/runtime.js +41 -20
- package/packages/agent-client/src/setup-status.js +13 -28
- package/packages/extension/src/background-helpers.js +51 -36
- package/packages/extension/src/background-routing.js +11 -13
- package/packages/extension/src/background.js +562 -299
- package/packages/extension/src/content-script-helpers.js +17 -16
- package/packages/extension/src/content-script.js +175 -109
- package/packages/extension/src/sidepanel-helpers.js +3 -1
- package/packages/extension/ui/popup.js +39 -20
- package/packages/extension/ui/sidepanel.js +108 -191
- package/packages/extension/ui/ui.css +2 -1
- package/packages/mcp-server/src/handlers.js +546 -250
- package/packages/mcp-server/src/server.js +558 -257
- package/packages/native-host/bin/bridge-daemon.js +6 -2
- package/packages/native-host/bin/install-manifest.js +2 -2
- package/packages/native-host/bin/postinstall.js +4 -2
- package/packages/native-host/src/config.js +11 -7
- package/packages/native-host/src/daemon.js +143 -92
- package/packages/native-host/src/install-manifest.js +73 -22
- package/packages/native-host/src/native-host.js +55 -40
- package/packages/protocol/src/budget.js +3 -7
- package/packages/protocol/src/capabilities.js +3 -3
- package/packages/protocol/src/errors.js +11 -11
- package/packages/protocol/src/protocol.js +104 -71
- package/packages/protocol/src/registry.js +300 -45
- package/packages/protocol/src/summary.js +249 -106
- package/packages/protocol/src/types.js +1 -1
- package/skills/browser-bridge/SKILL.md +1 -1
- package/skills/browser-bridge/agents/openai.yaml +3 -3
- package/skills/browser-bridge/references/interaction.md +33 -11
- package/skills/browser-bridge/references/patch-workflow.md +3 -0
- package/skills/browser-bridge/references/protocol.md +125 -70
- package/skills/browser-bridge/references/tailwind.md +12 -11
- package/skills/browser-bridge/references/token-efficiency.md +23 -22
- package/skills/browser-bridge/references/ui-workflows.md +8 -0
- package/packages/extension/ui/offscreen.html +0 -6
- 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(
|
|
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(
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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 {
|
|
9
|
-
|
|
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({
|
|
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 =
|
|
144
|
-
|
|
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, {
|
|
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(
|
|
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?.(
|
|
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: {
|
|
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(
|
|
361
|
-
|
|
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 =
|
|
378
|
-
|
|
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(
|
|
422
|
-
|
|
423
|
-
|
|
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 =
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
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 =
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
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(
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
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 =
|
|
738
|
-
|
|
739
|
-
|
|
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 =
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
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
|
}
|