@btraut/browser-bridge 0.11.1 → 0.12.0
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 +23 -0
- package/README.md +41 -0
- package/dist/api.js +878 -128
- package/dist/api.js.map +4 -4
- package/dist/index.js +861 -378
- package/dist/index.js.map +4 -4
- package/extension/assets/ui.css +108 -1
- package/extension/dist/background.js +161 -17
- package/extension/dist/background.js.map +4 -4
- package/extension/dist/popup-ui.js +110 -3
- 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/dist/index.js
CHANGED
|
@@ -26,55 +26,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// packages/cli/src/index.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
|
|
29
|
-
// packages/shared/src/
|
|
30
|
-
var
|
|
31
|
-
var ErrorCodeSchema = import_zod.z.enum([
|
|
32
|
-
"UNKNOWN",
|
|
33
|
-
"INVALID_ARGUMENT",
|
|
34
|
-
"NOT_FOUND",
|
|
35
|
-
"ALREADY_EXISTS",
|
|
36
|
-
"FAILED_PRECONDITION",
|
|
37
|
-
"UNAUTHORIZED",
|
|
38
|
-
"FORBIDDEN",
|
|
39
|
-
"PERMISSION_REQUIRED",
|
|
40
|
-
"PERMISSION_DENIED",
|
|
41
|
-
"PERMISSION_PROMPT_TIMEOUT",
|
|
42
|
-
"CONFLICT",
|
|
43
|
-
"TIMEOUT",
|
|
44
|
-
"CANCELLED",
|
|
45
|
-
"UNAVAILABLE",
|
|
46
|
-
"RATE_LIMITED",
|
|
47
|
-
"NOT_IMPLEMENTED",
|
|
48
|
-
"INTERNAL",
|
|
49
|
-
"SESSION_NOT_FOUND",
|
|
50
|
-
"SESSION_CLOSED",
|
|
51
|
-
"SESSION_BROKEN",
|
|
52
|
-
"DRIVE_UNAVAILABLE",
|
|
53
|
-
"INSPECT_UNAVAILABLE",
|
|
54
|
-
"EXTENSION_DISCONNECTED",
|
|
55
|
-
"DEBUGGER_IN_USE",
|
|
56
|
-
"ATTACH_DENIED",
|
|
57
|
-
"TAB_NOT_FOUND",
|
|
58
|
-
"NOT_SUPPORTED",
|
|
59
|
-
"LOCATOR_NOT_FOUND",
|
|
60
|
-
"NAVIGATION_FAILED",
|
|
61
|
-
"EVALUATION_FAILED",
|
|
62
|
-
"ARTIFACT_IO_ERROR"
|
|
63
|
-
]);
|
|
64
|
-
var ErrorInfoSchema = import_zod.z.object({
|
|
65
|
-
code: ErrorCodeSchema,
|
|
66
|
-
message: import_zod.z.string(),
|
|
67
|
-
retryable: import_zod.z.boolean(),
|
|
68
|
-
details: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
69
|
-
});
|
|
70
|
-
var ErrorEnvelopeSchema = import_zod.z.object({
|
|
71
|
-
ok: import_zod.z.literal(false),
|
|
72
|
-
error: ErrorInfoSchema
|
|
73
|
-
});
|
|
74
|
-
var successEnvelopeSchema = (result) => import_zod.z.object({
|
|
75
|
-
ok: import_zod.z.literal(true),
|
|
76
|
-
result
|
|
77
|
-
});
|
|
29
|
+
// packages/shared/src/core-readiness.ts
|
|
30
|
+
var import_promises = require("node:timers/promises");
|
|
78
31
|
|
|
79
32
|
// packages/shared/src/logging.ts
|
|
80
33
|
var import_node_fs2 = require("node:fs");
|
|
@@ -605,6 +558,248 @@ var createJsonlLogger = (options) => {
|
|
|
605
558
|
return buildLogger(state, options.bindings ?? {});
|
|
606
559
|
};
|
|
607
560
|
|
|
561
|
+
// packages/shared/src/core-readiness.ts
|
|
562
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
563
|
+
var DEFAULT_HEALTH_RETRY_MS = 250;
|
|
564
|
+
var DEFAULT_HEALTH_ATTEMPTS = 20;
|
|
565
|
+
var DEFAULT_HEALTH_TIMEOUT_MS = 2e3;
|
|
566
|
+
var DEFAULT_HEALTH_BUDGET_MS = 15e3;
|
|
567
|
+
var resolveTimeoutMs = (timeoutMs) => {
|
|
568
|
+
const candidate = timeoutMs ?? (process.env.BROWSER_BRIDGE_CORE_TIMEOUT_MS ? Number.parseInt(process.env.BROWSER_BRIDGE_CORE_TIMEOUT_MS, 10) : process.env.BROWSER_VISION_CORE_TIMEOUT_MS ? Number.parseInt(process.env.BROWSER_VISION_CORE_TIMEOUT_MS, 10) : void 0);
|
|
569
|
+
if (candidate === void 0 || candidate === null) {
|
|
570
|
+
return DEFAULT_TIMEOUT_MS;
|
|
571
|
+
}
|
|
572
|
+
const parsed = typeof candidate === "number" ? candidate : Number(candidate);
|
|
573
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
574
|
+
throw new Error(`Invalid timeoutMs: ${String(candidate)}`);
|
|
575
|
+
}
|
|
576
|
+
return Math.floor(parsed);
|
|
577
|
+
};
|
|
578
|
+
var resolvePositiveInteger = (value, fallback) => {
|
|
579
|
+
if (value === void 0) {
|
|
580
|
+
return fallback;
|
|
581
|
+
}
|
|
582
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
583
|
+
throw new Error(`Invalid positive integer value: ${String(value)}`);
|
|
584
|
+
}
|
|
585
|
+
return Math.floor(value);
|
|
586
|
+
};
|
|
587
|
+
var hasExplicitRuntimeInput = (options) => options.host !== void 0 || options.port !== void 0 || process.env.BROWSER_BRIDGE_CORE_HOST !== void 0 || process.env.BROWSER_VISION_CORE_HOST !== void 0 || process.env.BROWSER_BRIDGE_CORE_PORT !== void 0 || process.env.BROWSER_VISION_CORE_PORT !== void 0;
|
|
588
|
+
var createCoreReadinessController = (options = {}) => {
|
|
589
|
+
const logger = options.logger ?? createJsonlLogger({
|
|
590
|
+
stream: "cli",
|
|
591
|
+
cwd: options.cwd
|
|
592
|
+
}).child({ scope: "core-readiness" });
|
|
593
|
+
const logPrefix = options.logPrefix ?? "core";
|
|
594
|
+
const timeoutMs = resolveTimeoutMs(options.timeoutMs);
|
|
595
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
596
|
+
const ensureDaemon = options.ensureDaemon ?? true;
|
|
597
|
+
const healthRetryMs = resolvePositiveInteger(
|
|
598
|
+
options.healthRetryMs,
|
|
599
|
+
DEFAULT_HEALTH_RETRY_MS
|
|
600
|
+
);
|
|
601
|
+
const healthAttempts = resolvePositiveInteger(
|
|
602
|
+
options.healthAttempts,
|
|
603
|
+
DEFAULT_HEALTH_ATTEMPTS
|
|
604
|
+
);
|
|
605
|
+
const healthTimeoutMs = resolvePositiveInteger(
|
|
606
|
+
options.healthTimeoutMs,
|
|
607
|
+
Math.min(timeoutMs, DEFAULT_HEALTH_TIMEOUT_MS)
|
|
608
|
+
);
|
|
609
|
+
const healthBudgetMs = resolvePositiveInteger(
|
|
610
|
+
options.healthBudgetMs,
|
|
611
|
+
DEFAULT_HEALTH_BUDGET_MS
|
|
612
|
+
);
|
|
613
|
+
let runtime = resolveCoreRuntime({
|
|
614
|
+
host: options.host,
|
|
615
|
+
port: options.port,
|
|
616
|
+
cwd: options.cwd,
|
|
617
|
+
strictEnvPort: options.strictEnvPort ?? true
|
|
618
|
+
});
|
|
619
|
+
let baseUrl = `http://${runtime.host}:${runtime.port}`;
|
|
620
|
+
const allowRuntimeRefresh = !hasExplicitRuntimeInput(options);
|
|
621
|
+
const refreshRuntime = () => {
|
|
622
|
+
if (!allowRuntimeRefresh) {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
runtime = resolveCoreRuntime({
|
|
626
|
+
cwd: options.cwd,
|
|
627
|
+
strictEnvPort: options.strictEnvPort ?? true
|
|
628
|
+
});
|
|
629
|
+
baseUrl = `http://${runtime.host}:${runtime.port}`;
|
|
630
|
+
};
|
|
631
|
+
const checkHealth = async () => {
|
|
632
|
+
try {
|
|
633
|
+
const controller = new AbortController();
|
|
634
|
+
const timeout = setTimeout(() => controller.abort(), healthTimeoutMs);
|
|
635
|
+
try {
|
|
636
|
+
let response;
|
|
637
|
+
try {
|
|
638
|
+
response = await fetchImpl(`${baseUrl}/health`, {
|
|
639
|
+
method: "GET",
|
|
640
|
+
signal: controller.signal
|
|
641
|
+
});
|
|
642
|
+
} catch (error) {
|
|
643
|
+
if (controller.signal.aborted || error instanceof Error && error.name === "AbortError") {
|
|
644
|
+
logger.warn(`${logPrefix}.health.timeout`, {
|
|
645
|
+
base_url: baseUrl,
|
|
646
|
+
timeout_ms: healthTimeoutMs
|
|
647
|
+
});
|
|
648
|
+
return false;
|
|
649
|
+
}
|
|
650
|
+
logger.warn(`${logPrefix}.health.fetch_failed`, {
|
|
651
|
+
base_url: baseUrl,
|
|
652
|
+
error
|
|
653
|
+
});
|
|
654
|
+
throw error;
|
|
655
|
+
}
|
|
656
|
+
if (!response.ok) {
|
|
657
|
+
logger.warn(`${logPrefix}.health.non_ok`, {
|
|
658
|
+
base_url: baseUrl,
|
|
659
|
+
status: response.status
|
|
660
|
+
});
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
const data = await response.json().catch(() => null);
|
|
664
|
+
const ok = Boolean(data?.ok);
|
|
665
|
+
if (!ok) {
|
|
666
|
+
logger.warn(`${logPrefix}.health.not_ready`, {
|
|
667
|
+
base_url: baseUrl
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
return ok;
|
|
671
|
+
} finally {
|
|
672
|
+
clearTimeout(timeout);
|
|
673
|
+
}
|
|
674
|
+
} catch (error) {
|
|
675
|
+
logger.warn(`${logPrefix}.health.error`, {
|
|
676
|
+
base_url: baseUrl,
|
|
677
|
+
error
|
|
678
|
+
});
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
};
|
|
682
|
+
const ensureCoreRunning = async () => {
|
|
683
|
+
refreshRuntime();
|
|
684
|
+
if (await checkHealth()) {
|
|
685
|
+
logger.debug(`${logPrefix}.ensure_ready.already_running`, {
|
|
686
|
+
base_url: baseUrl
|
|
687
|
+
});
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
if (!options.spawnDaemon) {
|
|
691
|
+
logger.error(`${logPrefix}.ensure_ready.missing_spawn`, {
|
|
692
|
+
host: runtime.host,
|
|
693
|
+
port: runtime.port
|
|
694
|
+
});
|
|
695
|
+
throw new Error(
|
|
696
|
+
`Core daemon is not running on ${runtime.host}:${runtime.port} and spawnDaemon is not configured.`
|
|
697
|
+
);
|
|
698
|
+
}
|
|
699
|
+
options.spawnDaemon(runtime);
|
|
700
|
+
const deadlineAt = Date.now() + healthBudgetMs;
|
|
701
|
+
for (let attempt = 0; attempt < healthAttempts; attempt += 1) {
|
|
702
|
+
const remainingBudgetMs = deadlineAt - Date.now();
|
|
703
|
+
if (remainingBudgetMs <= 0) {
|
|
704
|
+
break;
|
|
705
|
+
}
|
|
706
|
+
await (0, import_promises.setTimeout)(Math.min(healthRetryMs, remainingBudgetMs));
|
|
707
|
+
refreshRuntime();
|
|
708
|
+
if (await checkHealth()) {
|
|
709
|
+
logger.info(`${logPrefix}.ensure_ready.ready`, {
|
|
710
|
+
base_url: baseUrl,
|
|
711
|
+
attempts: attempt + 1
|
|
712
|
+
});
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
logger.error(`${logPrefix}.ensure_ready.failed`, {
|
|
717
|
+
host: runtime.host,
|
|
718
|
+
port: runtime.port,
|
|
719
|
+
attempts: healthAttempts,
|
|
720
|
+
health_budget_ms: healthBudgetMs,
|
|
721
|
+
health_timeout_ms: healthTimeoutMs
|
|
722
|
+
});
|
|
723
|
+
throw new Error(
|
|
724
|
+
`Core daemon failed to start on ${runtime.host}:${runtime.port}.`
|
|
725
|
+
);
|
|
726
|
+
};
|
|
727
|
+
let ensurePromise = null;
|
|
728
|
+
const ensureReady = async () => {
|
|
729
|
+
if (!ensureDaemon) {
|
|
730
|
+
return;
|
|
731
|
+
}
|
|
732
|
+
if (!ensurePromise) {
|
|
733
|
+
ensurePromise = ensureCoreRunning().catch((error) => {
|
|
734
|
+
ensurePromise = null;
|
|
735
|
+
throw error;
|
|
736
|
+
});
|
|
737
|
+
}
|
|
738
|
+
await ensurePromise;
|
|
739
|
+
};
|
|
740
|
+
return {
|
|
741
|
+
get baseUrl() {
|
|
742
|
+
return baseUrl;
|
|
743
|
+
},
|
|
744
|
+
get runtime() {
|
|
745
|
+
return runtime;
|
|
746
|
+
},
|
|
747
|
+
refreshRuntime,
|
|
748
|
+
ensureReady,
|
|
749
|
+
checkHealth
|
|
750
|
+
};
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
// packages/shared/src/errors.ts
|
|
754
|
+
var import_zod = require("zod");
|
|
755
|
+
var ErrorCodeSchema = import_zod.z.enum([
|
|
756
|
+
"UNKNOWN",
|
|
757
|
+
"INVALID_ARGUMENT",
|
|
758
|
+
"NOT_FOUND",
|
|
759
|
+
"ALREADY_EXISTS",
|
|
760
|
+
"FAILED_PRECONDITION",
|
|
761
|
+
"UNAUTHORIZED",
|
|
762
|
+
"FORBIDDEN",
|
|
763
|
+
"PERMISSION_REQUIRED",
|
|
764
|
+
"PERMISSION_DENIED",
|
|
765
|
+
"PERMISSION_PROMPT_TIMEOUT",
|
|
766
|
+
"CONFLICT",
|
|
767
|
+
"TIMEOUT",
|
|
768
|
+
"CANCELLED",
|
|
769
|
+
"UNAVAILABLE",
|
|
770
|
+
"RATE_LIMITED",
|
|
771
|
+
"NOT_IMPLEMENTED",
|
|
772
|
+
"INTERNAL",
|
|
773
|
+
"SESSION_NOT_FOUND",
|
|
774
|
+
"SESSION_CLOSED",
|
|
775
|
+
"SESSION_BROKEN",
|
|
776
|
+
"DRIVE_UNAVAILABLE",
|
|
777
|
+
"INSPECT_UNAVAILABLE",
|
|
778
|
+
"EXTENSION_DISCONNECTED",
|
|
779
|
+
"DEBUGGER_IN_USE",
|
|
780
|
+
"ATTACH_DENIED",
|
|
781
|
+
"TAB_NOT_FOUND",
|
|
782
|
+
"NOT_SUPPORTED",
|
|
783
|
+
"LOCATOR_NOT_FOUND",
|
|
784
|
+
"NAVIGATION_FAILED",
|
|
785
|
+
"EVALUATION_FAILED",
|
|
786
|
+
"ARTIFACT_IO_ERROR"
|
|
787
|
+
]);
|
|
788
|
+
var ErrorInfoSchema = import_zod.z.object({
|
|
789
|
+
code: ErrorCodeSchema,
|
|
790
|
+
message: import_zod.z.string(),
|
|
791
|
+
retryable: import_zod.z.boolean(),
|
|
792
|
+
details: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional()
|
|
793
|
+
});
|
|
794
|
+
var ErrorEnvelopeSchema = import_zod.z.object({
|
|
795
|
+
ok: import_zod.z.literal(false),
|
|
796
|
+
error: ErrorInfoSchema
|
|
797
|
+
});
|
|
798
|
+
var successEnvelopeSchema = (result) => import_zod.z.object({
|
|
799
|
+
ok: import_zod.z.literal(true),
|
|
800
|
+
result
|
|
801
|
+
});
|
|
802
|
+
|
|
608
803
|
// packages/shared/src/schemas.ts
|
|
609
804
|
var import_zod2 = require("zod");
|
|
610
805
|
var LocatorRoleSchema = import_zod2.z.object({
|
|
@@ -669,6 +864,39 @@ var DiagnosticCheckSchema = import_zod2.z.object({
|
|
|
669
864
|
message: import_zod2.z.string().optional(),
|
|
670
865
|
details: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional()
|
|
671
866
|
});
|
|
867
|
+
var DiagnosticsRuntimeEndpointSchema = import_zod2.z.object({
|
|
868
|
+
host: import_zod2.z.string().optional(),
|
|
869
|
+
port: import_zod2.z.number().finite().optional(),
|
|
870
|
+
base_url: import_zod2.z.string().optional(),
|
|
871
|
+
host_source: import_zod2.z.string().optional(),
|
|
872
|
+
port_source: import_zod2.z.string().optional(),
|
|
873
|
+
metadata_path: import_zod2.z.string().optional(),
|
|
874
|
+
isolated_mode: import_zod2.z.boolean().optional()
|
|
875
|
+
});
|
|
876
|
+
var DiagnosticsRuntimeProcessSchema = import_zod2.z.object({
|
|
877
|
+
component: import_zod2.z.enum(["cli", "mcp", "core"]).optional(),
|
|
878
|
+
version: import_zod2.z.string().optional(),
|
|
879
|
+
pid: import_zod2.z.number().int().positive().optional(),
|
|
880
|
+
node_version: import_zod2.z.string().optional(),
|
|
881
|
+
binary_path: import_zod2.z.string().optional(),
|
|
882
|
+
argv_entry: import_zod2.z.string().optional()
|
|
883
|
+
});
|
|
884
|
+
var DiagnosticsRuntimeCallerSchema = import_zod2.z.object({
|
|
885
|
+
endpoint: DiagnosticsRuntimeEndpointSchema.optional(),
|
|
886
|
+
process: DiagnosticsRuntimeProcessSchema.optional()
|
|
887
|
+
});
|
|
888
|
+
var DiagnosticsRuntimeContextSchema = import_zod2.z.object({
|
|
889
|
+
caller: DiagnosticsRuntimeCallerSchema.optional(),
|
|
890
|
+
core: import_zod2.z.object({
|
|
891
|
+
endpoint: DiagnosticsRuntimeEndpointSchema.optional(),
|
|
892
|
+
process: DiagnosticsRuntimeProcessSchema.optional()
|
|
893
|
+
}).optional(),
|
|
894
|
+
extension: import_zod2.z.object({
|
|
895
|
+
version: import_zod2.z.string().optional(),
|
|
896
|
+
endpoint: DiagnosticsRuntimeEndpointSchema.optional(),
|
|
897
|
+
port_source: import_zod2.z.enum(["default", "storage"]).optional()
|
|
898
|
+
}).optional()
|
|
899
|
+
});
|
|
672
900
|
var DiagnosticReportSchema = import_zod2.z.object({
|
|
673
901
|
ok: import_zod2.z.boolean(),
|
|
674
902
|
session_id: import_zod2.z.string().optional(),
|
|
@@ -717,7 +945,8 @@ var DiagnosticReportSchema = import_zod2.z.object({
|
|
|
717
945
|
loop_detected: import_zod2.z.boolean().optional()
|
|
718
946
|
}).optional(),
|
|
719
947
|
warnings: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
720
|
-
notes: import_zod2.z.array(import_zod2.z.string()).optional()
|
|
948
|
+
notes: import_zod2.z.array(import_zod2.z.string()).optional(),
|
|
949
|
+
runtime: DiagnosticsRuntimeContextSchema.optional()
|
|
721
950
|
});
|
|
722
951
|
var SessionIdSchema = import_zod2.z.object({
|
|
723
952
|
session_id: import_zod2.z.string().min(1)
|
|
@@ -1109,7 +1338,8 @@ var HealthCheckOutputSchema = import_zod2.z.object({
|
|
|
1109
1338
|
}).passthrough()
|
|
1110
1339
|
}).passthrough();
|
|
1111
1340
|
var DiagnosticsDoctorInputSchema = import_zod2.z.object({
|
|
1112
|
-
session_id: import_zod2.z.string().min(1).optional()
|
|
1341
|
+
session_id: import_zod2.z.string().min(1).optional(),
|
|
1342
|
+
caller: DiagnosticsRuntimeCallerSchema.optional()
|
|
1113
1343
|
});
|
|
1114
1344
|
var DiagnosticsDoctorOutputSchema = DiagnosticReportSchema;
|
|
1115
1345
|
|
|
@@ -1119,7 +1349,6 @@ var import_zod3 = require("zod");
|
|
|
1119
1349
|
// packages/cli/src/core-client.ts
|
|
1120
1350
|
var import_node_child_process = require("node:child_process");
|
|
1121
1351
|
var import_node_path3 = require("node:path");
|
|
1122
|
-
var import_promises = require("node:timers/promises");
|
|
1123
1352
|
var CoreClientError = class extends Error {
|
|
1124
1353
|
constructor(info) {
|
|
1125
1354
|
super(info.message);
|
|
@@ -1127,13 +1356,11 @@ var CoreClientError = class extends Error {
|
|
|
1127
1356
|
this.info = info;
|
|
1128
1357
|
}
|
|
1129
1358
|
};
|
|
1130
|
-
var
|
|
1131
|
-
var
|
|
1132
|
-
var HEALTH_ATTEMPTS = 20;
|
|
1133
|
-
var resolveTimeoutMs = (timeoutMs) => {
|
|
1359
|
+
var DEFAULT_TIMEOUT_MS2 = 3e4;
|
|
1360
|
+
var resolveTimeoutMs2 = (timeoutMs) => {
|
|
1134
1361
|
const candidate = timeoutMs ?? (process.env.BROWSER_BRIDGE_CORE_TIMEOUT_MS ? Number.parseInt(process.env.BROWSER_BRIDGE_CORE_TIMEOUT_MS, 10) : process.env.BROWSER_VISION_CORE_TIMEOUT_MS ? Number.parseInt(process.env.BROWSER_VISION_CORE_TIMEOUT_MS, 10) : void 0);
|
|
1135
1362
|
if (candidate === void 0 || candidate === null) {
|
|
1136
|
-
return
|
|
1363
|
+
return DEFAULT_TIMEOUT_MS2;
|
|
1137
1364
|
}
|
|
1138
1365
|
const parsed = typeof candidate === "number" ? candidate : Number(candidate);
|
|
1139
1366
|
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
@@ -1148,42 +1375,70 @@ var createCoreClient = (options = {}) => {
|
|
|
1148
1375
|
stream: "cli",
|
|
1149
1376
|
cwd: options.cwd
|
|
1150
1377
|
}).child({ scope: "core-client" });
|
|
1151
|
-
|
|
1378
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
1379
|
+
const spawnImpl = options.spawnImpl ?? import_node_child_process.spawn;
|
|
1380
|
+
const timeoutMs = resolveTimeoutMs2(options.timeoutMs);
|
|
1381
|
+
const readiness = createCoreReadinessController({
|
|
1152
1382
|
host: options.host,
|
|
1153
1383
|
port: options.port,
|
|
1154
1384
|
cwd: options.cwd,
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1385
|
+
timeoutMs,
|
|
1386
|
+
ensureDaemon: options.ensureDaemon ?? true,
|
|
1387
|
+
strictEnvPort: true,
|
|
1388
|
+
fetchImpl,
|
|
1389
|
+
logger,
|
|
1390
|
+
logPrefix: "cli.core",
|
|
1391
|
+
spawnDaemon: (runtime) => {
|
|
1392
|
+
const coreEntry = (0, import_node_path3.resolve)(__dirname, "api.js");
|
|
1393
|
+
const startOptions = [];
|
|
1394
|
+
if (runtime.hostSource === "option" || runtime.hostSource === "env") {
|
|
1395
|
+
startOptions.push(`host: ${JSON.stringify(runtime.host)}`);
|
|
1396
|
+
}
|
|
1397
|
+
if (runtime.portSource === "option" || runtime.portSource === "env") {
|
|
1398
|
+
startOptions.push(`port: ${runtime.port}`);
|
|
1399
|
+
}
|
|
1400
|
+
const script = `const { startCoreServer } = require(${JSON.stringify(
|
|
1401
|
+
coreEntry
|
|
1402
|
+
)});
|
|
1403
|
+
startCoreServer({ ${startOptions.join(
|
|
1404
|
+
", "
|
|
1405
|
+
)} })
|
|
1406
|
+
.catch((err) => { console.error(err); process.exit(1); });`;
|
|
1407
|
+
logger.info("cli.core.spawn.start", {
|
|
1408
|
+
host: runtime.host,
|
|
1409
|
+
port: runtime.port,
|
|
1410
|
+
host_source: runtime.hostSource,
|
|
1411
|
+
port_source: runtime.portSource
|
|
1412
|
+
});
|
|
1413
|
+
const child = spawnImpl(process.execPath, ["-e", script], {
|
|
1414
|
+
detached: true,
|
|
1415
|
+
stdio: "ignore",
|
|
1416
|
+
env: { ...process.env }
|
|
1417
|
+
});
|
|
1418
|
+
child.on("error", (error) => {
|
|
1419
|
+
logger.error("cli.core.spawn.error", {
|
|
1420
|
+
host: runtime.host,
|
|
1421
|
+
port: runtime.port,
|
|
1422
|
+
error
|
|
1423
|
+
});
|
|
1424
|
+
});
|
|
1425
|
+
child.unref();
|
|
1166
1426
|
}
|
|
1167
|
-
|
|
1168
|
-
cwd: options.cwd,
|
|
1169
|
-
strictEnvPort: true
|
|
1170
|
-
});
|
|
1171
|
-
baseUrl = `http://${runtime.host}:${runtime.port}`;
|
|
1172
|
-
};
|
|
1427
|
+
});
|
|
1173
1428
|
const requestJson = async (method, path9, body) => {
|
|
1174
1429
|
const requestPath = normalizePath(path9);
|
|
1175
1430
|
const startedAt = process.hrtime.bigint();
|
|
1176
1431
|
logger.debug("cli.core.request.start", {
|
|
1177
1432
|
method,
|
|
1178
1433
|
path: requestPath,
|
|
1179
|
-
base_url: baseUrl
|
|
1434
|
+
base_url: readiness.baseUrl
|
|
1180
1435
|
});
|
|
1181
1436
|
const controller = new AbortController();
|
|
1182
1437
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
1183
1438
|
try {
|
|
1184
1439
|
let response;
|
|
1185
1440
|
try {
|
|
1186
|
-
response = await fetchImpl(`${baseUrl}${requestPath}`, {
|
|
1441
|
+
response = await fetchImpl(`${readiness.baseUrl}${requestPath}`, {
|
|
1187
1442
|
method,
|
|
1188
1443
|
headers: {
|
|
1189
1444
|
"content-type": "application/json"
|
|
@@ -1196,203 +1451,77 @@ var createCoreClient = (options = {}) => {
|
|
|
1196
1451
|
logger.warn("cli.core.request.timeout", {
|
|
1197
1452
|
method,
|
|
1198
1453
|
path: requestPath,
|
|
1199
|
-
base_url: baseUrl,
|
|
1454
|
+
base_url: readiness.baseUrl,
|
|
1200
1455
|
timeout_ms: timeoutMs,
|
|
1201
|
-
duration_ms: durationMs(startedAt)
|
|
1202
|
-
});
|
|
1203
|
-
throw new CoreClientError({
|
|
1204
|
-
code: "TIMEOUT",
|
|
1205
|
-
message: `Core request timed out after ${timeoutMs}ms.`,
|
|
1206
|
-
retryable: true,
|
|
1207
|
-
details: {
|
|
1208
|
-
timeout_ms: timeoutMs,
|
|
1209
|
-
base_url: baseUrl,
|
|
1210
|
-
path: requestPath
|
|
1211
|
-
}
|
|
1212
|
-
});
|
|
1213
|
-
}
|
|
1214
|
-
logger.error("cli.core.request.failed", {
|
|
1215
|
-
method,
|
|
1216
|
-
path: requestPath,
|
|
1217
|
-
base_url: baseUrl,
|
|
1218
|
-
duration_ms: durationMs(startedAt),
|
|
1219
|
-
error
|
|
1220
|
-
});
|
|
1221
|
-
throw error;
|
|
1222
|
-
}
|
|
1223
|
-
const raw = await response.text();
|
|
1224
|
-
if (!raw) {
|
|
1225
|
-
logger.warn("cli.core.request.empty_response", {
|
|
1226
|
-
method,
|
|
1227
|
-
path: requestPath,
|
|
1228
|
-
base_url: baseUrl,
|
|
1229
|
-
status: response.status,
|
|
1230
|
-
duration_ms: durationMs(startedAt)
|
|
1231
|
-
});
|
|
1232
|
-
throw new Error(`Empty response from Core (${response.status}).`);
|
|
1233
|
-
}
|
|
1234
|
-
try {
|
|
1235
|
-
const parsed = JSON.parse(raw);
|
|
1236
|
-
logger.debug("cli.core.request.end", {
|
|
1237
|
-
method,
|
|
1238
|
-
path: requestPath,
|
|
1239
|
-
base_url: baseUrl,
|
|
1240
|
-
status: response.status,
|
|
1241
|
-
duration_ms: durationMs(startedAt)
|
|
1242
|
-
});
|
|
1243
|
-
return parsed;
|
|
1244
|
-
} catch (error) {
|
|
1245
|
-
const message = error instanceof Error ? error.message : "Unknown JSON parse error";
|
|
1246
|
-
logger.error("cli.core.request.invalid_json", {
|
|
1247
|
-
method,
|
|
1248
|
-
path: requestPath,
|
|
1249
|
-
base_url: baseUrl,
|
|
1250
|
-
status: response.status,
|
|
1251
|
-
duration_ms: durationMs(startedAt),
|
|
1252
|
-
error
|
|
1253
|
-
});
|
|
1254
|
-
throw new Error(`Failed to parse Core response: ${message}`);
|
|
1255
|
-
}
|
|
1256
|
-
} finally {
|
|
1257
|
-
clearTimeout(timeout);
|
|
1258
|
-
}
|
|
1259
|
-
};
|
|
1260
|
-
const checkHealth = async () => {
|
|
1261
|
-
try {
|
|
1262
|
-
const controller = new AbortController();
|
|
1263
|
-
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
1264
|
-
try {
|
|
1265
|
-
let response;
|
|
1266
|
-
try {
|
|
1267
|
-
response = await fetchImpl(`${baseUrl}/health`, {
|
|
1268
|
-
method: "GET",
|
|
1269
|
-
signal: controller.signal
|
|
1270
|
-
});
|
|
1271
|
-
} catch (error) {
|
|
1272
|
-
if (controller.signal.aborted || error instanceof Error && error.name === "AbortError") {
|
|
1273
|
-
logger.warn("cli.core.health.timeout", {
|
|
1274
|
-
base_url: baseUrl,
|
|
1275
|
-
timeout_ms: timeoutMs
|
|
1276
|
-
});
|
|
1277
|
-
return false;
|
|
1278
|
-
}
|
|
1279
|
-
logger.warn("cli.core.health.fetch_failed", {
|
|
1280
|
-
base_url: baseUrl,
|
|
1281
|
-
error
|
|
1282
|
-
});
|
|
1283
|
-
throw error;
|
|
1284
|
-
}
|
|
1285
|
-
if (!response.ok) {
|
|
1286
|
-
logger.warn("cli.core.health.non_ok", {
|
|
1287
|
-
base_url: baseUrl,
|
|
1288
|
-
status: response.status
|
|
1289
|
-
});
|
|
1290
|
-
return false;
|
|
1291
|
-
}
|
|
1292
|
-
const data = await response.json().catch(() => null);
|
|
1293
|
-
const ok = Boolean(data?.ok);
|
|
1294
|
-
if (!ok) {
|
|
1295
|
-
logger.warn("cli.core.health.not_ready", {
|
|
1296
|
-
base_url: baseUrl
|
|
1297
|
-
});
|
|
1298
|
-
}
|
|
1299
|
-
return ok;
|
|
1300
|
-
} finally {
|
|
1301
|
-
clearTimeout(timeout);
|
|
1302
|
-
}
|
|
1303
|
-
} catch (error) {
|
|
1304
|
-
logger.warn("cli.core.health.error", {
|
|
1305
|
-
base_url: baseUrl,
|
|
1306
|
-
error
|
|
1307
|
-
});
|
|
1308
|
-
return false;
|
|
1309
|
-
}
|
|
1310
|
-
};
|
|
1311
|
-
const spawnDaemon = () => {
|
|
1312
|
-
const coreEntry = (0, import_node_path3.resolve)(__dirname, "api.js");
|
|
1313
|
-
const startOptions = [];
|
|
1314
|
-
if (runtime.hostSource === "option" || runtime.hostSource === "env") {
|
|
1315
|
-
startOptions.push(`host: ${JSON.stringify(runtime.host)}`);
|
|
1316
|
-
}
|
|
1317
|
-
if (runtime.portSource === "option" || runtime.portSource === "env") {
|
|
1318
|
-
startOptions.push(`port: ${runtime.port}`);
|
|
1319
|
-
}
|
|
1320
|
-
const script = `const { startCoreServer } = require(${JSON.stringify(
|
|
1321
|
-
coreEntry
|
|
1322
|
-
)});
|
|
1323
|
-
startCoreServer({ ${startOptions.join(
|
|
1324
|
-
", "
|
|
1325
|
-
)} })
|
|
1326
|
-
.catch((err) => { console.error(err); process.exit(1); });`;
|
|
1327
|
-
logger.info("cli.core.spawn.start", {
|
|
1328
|
-
host: runtime.host,
|
|
1329
|
-
port: runtime.port,
|
|
1330
|
-
host_source: runtime.hostSource,
|
|
1331
|
-
port_source: runtime.portSource
|
|
1332
|
-
});
|
|
1333
|
-
const child = spawnImpl(process.execPath, ["-e", script], {
|
|
1334
|
-
detached: true,
|
|
1335
|
-
stdio: "ignore",
|
|
1336
|
-
env: { ...process.env }
|
|
1337
|
-
});
|
|
1338
|
-
child.on("error", (error) => {
|
|
1339
|
-
logger.error("cli.core.spawn.error", {
|
|
1340
|
-
host: runtime.host,
|
|
1341
|
-
port: runtime.port,
|
|
1342
|
-
error
|
|
1343
|
-
});
|
|
1344
|
-
});
|
|
1345
|
-
child.unref();
|
|
1346
|
-
};
|
|
1347
|
-
const ensureCoreRunning = async () => {
|
|
1348
|
-
refreshRuntime();
|
|
1349
|
-
if (await checkHealth()) {
|
|
1350
|
-
logger.debug("cli.core.ensure_ready.already_running", {
|
|
1351
|
-
base_url: baseUrl
|
|
1352
|
-
});
|
|
1353
|
-
return;
|
|
1354
|
-
}
|
|
1355
|
-
spawnDaemon();
|
|
1356
|
-
for (let attempt = 0; attempt < HEALTH_ATTEMPTS; attempt += 1) {
|
|
1357
|
-
await (0, import_promises.setTimeout)(HEALTH_RETRY_MS);
|
|
1358
|
-
refreshRuntime();
|
|
1359
|
-
if (await checkHealth()) {
|
|
1360
|
-
logger.info("cli.core.ensure_ready.ready", {
|
|
1361
|
-
base_url: baseUrl,
|
|
1362
|
-
attempts: attempt + 1
|
|
1456
|
+
duration_ms: durationMs(startedAt)
|
|
1457
|
+
});
|
|
1458
|
+
throw new CoreClientError({
|
|
1459
|
+
code: "TIMEOUT",
|
|
1460
|
+
message: `Core request timed out after ${timeoutMs}ms.`,
|
|
1461
|
+
retryable: true,
|
|
1462
|
+
details: {
|
|
1463
|
+
timeout_ms: timeoutMs,
|
|
1464
|
+
base_url: readiness.baseUrl,
|
|
1465
|
+
path: requestPath
|
|
1466
|
+
}
|
|
1467
|
+
});
|
|
1468
|
+
}
|
|
1469
|
+
logger.error("cli.core.request.failed", {
|
|
1470
|
+
method,
|
|
1471
|
+
path: requestPath,
|
|
1472
|
+
base_url: readiness.baseUrl,
|
|
1473
|
+
duration_ms: durationMs(startedAt),
|
|
1474
|
+
error
|
|
1363
1475
|
});
|
|
1364
|
-
|
|
1476
|
+
throw error;
|
|
1365
1477
|
}
|
|
1478
|
+
const raw = await response.text();
|
|
1479
|
+
if (!raw) {
|
|
1480
|
+
logger.warn("cli.core.request.empty_response", {
|
|
1481
|
+
method,
|
|
1482
|
+
path: requestPath,
|
|
1483
|
+
base_url: readiness.baseUrl,
|
|
1484
|
+
status: response.status,
|
|
1485
|
+
duration_ms: durationMs(startedAt)
|
|
1486
|
+
});
|
|
1487
|
+
throw new Error(`Empty response from Core (${response.status}).`);
|
|
1488
|
+
}
|
|
1489
|
+
try {
|
|
1490
|
+
const parsed = JSON.parse(raw);
|
|
1491
|
+
logger.debug("cli.core.request.end", {
|
|
1492
|
+
method,
|
|
1493
|
+
path: requestPath,
|
|
1494
|
+
base_url: readiness.baseUrl,
|
|
1495
|
+
status: response.status,
|
|
1496
|
+
duration_ms: durationMs(startedAt)
|
|
1497
|
+
});
|
|
1498
|
+
return parsed;
|
|
1499
|
+
} catch (error) {
|
|
1500
|
+
const message = error instanceof Error ? error.message : "Unknown JSON parse error";
|
|
1501
|
+
logger.error("cli.core.request.invalid_json", {
|
|
1502
|
+
method,
|
|
1503
|
+
path: requestPath,
|
|
1504
|
+
base_url: readiness.baseUrl,
|
|
1505
|
+
status: response.status,
|
|
1506
|
+
duration_ms: durationMs(startedAt),
|
|
1507
|
+
error
|
|
1508
|
+
});
|
|
1509
|
+
throw new Error(`Failed to parse Core response: ${message}`);
|
|
1510
|
+
}
|
|
1511
|
+
} finally {
|
|
1512
|
+
clearTimeout(timeout);
|
|
1366
1513
|
}
|
|
1367
|
-
logger.error("cli.core.ensure_ready.failed", {
|
|
1368
|
-
host: runtime.host,
|
|
1369
|
-
port: runtime.port,
|
|
1370
|
-
attempts: HEALTH_ATTEMPTS
|
|
1371
|
-
});
|
|
1372
|
-
throw new Error(
|
|
1373
|
-
`Core daemon failed to start on ${runtime.host}:${runtime.port}.`
|
|
1374
|
-
);
|
|
1375
|
-
};
|
|
1376
|
-
let ensurePromise = null;
|
|
1377
|
-
const ensureReady = async () => {
|
|
1378
|
-
if (!ensureDaemon) {
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
if (!ensurePromise) {
|
|
1382
|
-
ensurePromise = ensureCoreRunning();
|
|
1383
|
-
}
|
|
1384
|
-
await ensurePromise;
|
|
1385
1514
|
};
|
|
1386
1515
|
const post = async (path9, body) => {
|
|
1387
|
-
await ensureReady();
|
|
1388
|
-
refreshRuntime();
|
|
1516
|
+
await readiness.ensureReady();
|
|
1517
|
+
readiness.refreshRuntime();
|
|
1389
1518
|
return requestJson("POST", path9, body);
|
|
1390
1519
|
};
|
|
1391
1520
|
return {
|
|
1392
1521
|
get baseUrl() {
|
|
1393
|
-
return baseUrl;
|
|
1522
|
+
return readiness.baseUrl;
|
|
1394
1523
|
},
|
|
1395
|
-
ensureReady,
|
|
1524
|
+
ensureReady: readiness.ensureReady,
|
|
1396
1525
|
post
|
|
1397
1526
|
};
|
|
1398
1527
|
};
|
|
@@ -1627,9 +1756,26 @@ var registerDialogCommands = (program2) => {
|
|
|
1627
1756
|
var registerDiagnosticsCommands = (program2) => {
|
|
1628
1757
|
const diagnostics = program2.command("diagnostics").description("Diagnostics commands");
|
|
1629
1758
|
diagnostics.command("doctor").description("Run diagnostics").option("--session-id <id>", "Session identifier").action(async (options, command) => {
|
|
1630
|
-
await runCommand(command, (client) => {
|
|
1759
|
+
await runCommand(command, (client, globalOptions) => {
|
|
1760
|
+
const runtime = resolveCoreRuntime({
|
|
1761
|
+
host: globalOptions.host,
|
|
1762
|
+
port: globalOptions.port,
|
|
1763
|
+
strictEnvPort: true
|
|
1764
|
+
});
|
|
1631
1765
|
const payload = parseInput(DiagnosticsDoctorInputSchema, {
|
|
1632
|
-
session_id: options.sessionId
|
|
1766
|
+
session_id: options.sessionId,
|
|
1767
|
+
caller: {
|
|
1768
|
+
endpoint: {
|
|
1769
|
+
host: runtime.host,
|
|
1770
|
+
port: runtime.port,
|
|
1771
|
+
base_url: `http://${runtime.host}:${runtime.port}`,
|
|
1772
|
+
host_source: runtime.hostSource,
|
|
1773
|
+
port_source: runtime.portSource
|
|
1774
|
+
},
|
|
1775
|
+
process: {
|
|
1776
|
+
component: "cli"
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1633
1779
|
});
|
|
1634
1780
|
return client.post("/diagnostics/doctor", payload);
|
|
1635
1781
|
});
|
|
@@ -2243,36 +2389,92 @@ var registerInspectCommands = (program2) => {
|
|
|
2243
2389
|
};
|
|
2244
2390
|
|
|
2245
2391
|
// packages/mcp-adapter/src/core-client.ts
|
|
2246
|
-
var
|
|
2392
|
+
var import_node_child_process3 = require("node:child_process");
|
|
2393
|
+
var import_node_path4 = require("node:path");
|
|
2394
|
+
var DEFAULT_TIMEOUT_MS3 = 3e4;
|
|
2247
2395
|
var normalizePath2 = (path9) => path9.startsWith("/") ? path9 : `/${path9}`;
|
|
2248
2396
|
var durationMs3 = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
|
|
2397
|
+
var toReadinessErrorEnvelope = (error, baseUrl) => ({
|
|
2398
|
+
ok: false,
|
|
2399
|
+
error: {
|
|
2400
|
+
code: "UNAVAILABLE",
|
|
2401
|
+
message: error instanceof Error ? `Core not ready at ${baseUrl}: ${error.message}` : `Core not ready at ${baseUrl}.`,
|
|
2402
|
+
retryable: true,
|
|
2403
|
+
details: {
|
|
2404
|
+
base_url: baseUrl
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
});
|
|
2249
2408
|
var createCoreClient2 = (options = {}) => {
|
|
2250
2409
|
const logger = options.logger ?? createJsonlLogger({
|
|
2251
2410
|
stream: "mcp-adapter",
|
|
2252
2411
|
cwd: options.cwd
|
|
2253
2412
|
}).child({ scope: "core-client" });
|
|
2254
|
-
const
|
|
2413
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS3;
|
|
2414
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
2415
|
+
const spawnImpl = options.spawnImpl ?? import_node_child_process3.spawn;
|
|
2416
|
+
const ensureDaemon = options.ensureDaemon ?? false;
|
|
2417
|
+
const componentVersion = options.componentVersion ?? process.env.BROWSER_BRIDGE_VERSION ?? process.env.npm_package_version;
|
|
2418
|
+
const readiness = createCoreReadinessController({
|
|
2255
2419
|
host: options.host,
|
|
2256
2420
|
port: options.port,
|
|
2257
2421
|
cwd: options.cwd,
|
|
2258
|
-
|
|
2422
|
+
timeoutMs,
|
|
2423
|
+
ensureDaemon,
|
|
2424
|
+
strictEnvPort: true,
|
|
2425
|
+
fetchImpl,
|
|
2426
|
+
logger,
|
|
2427
|
+
logPrefix: "mcp.core",
|
|
2428
|
+
healthRetryMs: options.healthRetryMs,
|
|
2429
|
+
healthAttempts: options.healthAttempts,
|
|
2430
|
+
spawnDaemon: ensureDaemon ? (runtime) => {
|
|
2431
|
+
const coreEntry = (0, import_node_path4.resolve)(__dirname, "api.js");
|
|
2432
|
+
const startOptions = [];
|
|
2433
|
+
if (runtime.hostSource === "option" || runtime.hostSource === "env") {
|
|
2434
|
+
startOptions.push(`host: ${JSON.stringify(runtime.host)}`);
|
|
2435
|
+
}
|
|
2436
|
+
if (runtime.portSource === "option" || runtime.portSource === "env") {
|
|
2437
|
+
startOptions.push(`port: ${runtime.port}`);
|
|
2438
|
+
}
|
|
2439
|
+
const script = `const { startCoreServer } = require(${JSON.stringify(
|
|
2440
|
+
coreEntry
|
|
2441
|
+
)});
|
|
2442
|
+
startCoreServer({ ${startOptions.join(
|
|
2443
|
+
", "
|
|
2444
|
+
)} })
|
|
2445
|
+
.catch((err) => { console.error(err); process.exit(1); });`;
|
|
2446
|
+
logger.info("mcp.core.spawn.start", {
|
|
2447
|
+
host: runtime.host,
|
|
2448
|
+
port: runtime.port,
|
|
2449
|
+
host_source: runtime.hostSource,
|
|
2450
|
+
port_source: runtime.portSource
|
|
2451
|
+
});
|
|
2452
|
+
const child = spawnImpl(process.execPath, ["-e", script], {
|
|
2453
|
+
detached: true,
|
|
2454
|
+
stdio: "ignore",
|
|
2455
|
+
env: { ...process.env }
|
|
2456
|
+
});
|
|
2457
|
+
child.on("error", (error) => {
|
|
2458
|
+
logger.error("mcp.core.spawn.error", {
|
|
2459
|
+
host: runtime.host,
|
|
2460
|
+
port: runtime.port,
|
|
2461
|
+
error
|
|
2462
|
+
});
|
|
2463
|
+
});
|
|
2464
|
+
child.unref();
|
|
2465
|
+
} : void 0
|
|
2259
2466
|
});
|
|
2260
|
-
const host = runtime.host;
|
|
2261
|
-
const port = runtime.port;
|
|
2262
|
-
const baseUrl = `http://${host}:${port}`;
|
|
2263
|
-
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
|
|
2264
|
-
const fetchImpl = options.fetchImpl ?? fetch;
|
|
2265
2467
|
const requestJson = async (path9, body) => {
|
|
2266
2468
|
const requestPath = normalizePath2(path9);
|
|
2267
2469
|
const startedAt = process.hrtime.bigint();
|
|
2268
2470
|
logger.debug("mcp.core.request.start", {
|
|
2269
2471
|
path: requestPath,
|
|
2270
|
-
base_url: baseUrl
|
|
2472
|
+
base_url: readiness.baseUrl
|
|
2271
2473
|
});
|
|
2272
2474
|
const controller = new AbortController();
|
|
2273
2475
|
const timeout = setTimeout(() => controller.abort(), timeoutMs);
|
|
2274
2476
|
try {
|
|
2275
|
-
const response = await fetchImpl(`${baseUrl}${requestPath}`, {
|
|
2477
|
+
const response = await fetchImpl(`${readiness.baseUrl}${requestPath}`, {
|
|
2276
2478
|
method: "POST",
|
|
2277
2479
|
headers: {
|
|
2278
2480
|
"content-type": "application/json"
|
|
@@ -2284,7 +2486,7 @@ var createCoreClient2 = (options = {}) => {
|
|
|
2284
2486
|
if (!raw) {
|
|
2285
2487
|
logger.warn("mcp.core.request.empty_response", {
|
|
2286
2488
|
path: requestPath,
|
|
2287
|
-
base_url: baseUrl,
|
|
2489
|
+
base_url: readiness.baseUrl,
|
|
2288
2490
|
status: response.status,
|
|
2289
2491
|
duration_ms: durationMs3(startedAt)
|
|
2290
2492
|
});
|
|
@@ -2294,7 +2496,7 @@ var createCoreClient2 = (options = {}) => {
|
|
|
2294
2496
|
const parsed = JSON.parse(raw);
|
|
2295
2497
|
logger.debug("mcp.core.request.end", {
|
|
2296
2498
|
path: requestPath,
|
|
2297
|
-
base_url: baseUrl,
|
|
2499
|
+
base_url: readiness.baseUrl,
|
|
2298
2500
|
status: response.status,
|
|
2299
2501
|
duration_ms: durationMs3(startedAt)
|
|
2300
2502
|
});
|
|
@@ -2303,7 +2505,7 @@ var createCoreClient2 = (options = {}) => {
|
|
|
2303
2505
|
const message = error instanceof Error ? error.message : "Unknown JSON parse error";
|
|
2304
2506
|
logger.error("mcp.core.request.invalid_json", {
|
|
2305
2507
|
path: requestPath,
|
|
2306
|
-
base_url: baseUrl,
|
|
2508
|
+
base_url: readiness.baseUrl,
|
|
2307
2509
|
status: response.status,
|
|
2308
2510
|
duration_ms: durationMs3(startedAt),
|
|
2309
2511
|
error
|
|
@@ -2313,7 +2515,7 @@ var createCoreClient2 = (options = {}) => {
|
|
|
2313
2515
|
} catch (error) {
|
|
2314
2516
|
logger.error("mcp.core.request.failed", {
|
|
2315
2517
|
path: requestPath,
|
|
2316
|
-
base_url: baseUrl,
|
|
2518
|
+
base_url: readiness.baseUrl,
|
|
2317
2519
|
duration_ms: durationMs3(startedAt),
|
|
2318
2520
|
error
|
|
2319
2521
|
});
|
|
@@ -2323,9 +2525,47 @@ var createCoreClient2 = (options = {}) => {
|
|
|
2323
2525
|
}
|
|
2324
2526
|
};
|
|
2325
2527
|
const post = async (path9, body) => {
|
|
2326
|
-
|
|
2528
|
+
try {
|
|
2529
|
+
await readiness.ensureReady();
|
|
2530
|
+
} catch (error) {
|
|
2531
|
+
logger.warn("mcp.core.ensure_ready.unavailable", {
|
|
2532
|
+
base_url: readiness.baseUrl,
|
|
2533
|
+
error
|
|
2534
|
+
});
|
|
2535
|
+
throw toReadinessErrorEnvelope(error, readiness.baseUrl);
|
|
2536
|
+
}
|
|
2537
|
+
readiness.refreshRuntime();
|
|
2538
|
+
const payload = path9 === "/diagnostics/doctor" && (!body || typeof body === "object" && !Array.isArray(body)) ? {
|
|
2539
|
+
...body && typeof body === "object" ? body : {},
|
|
2540
|
+
caller: {
|
|
2541
|
+
endpoint: {
|
|
2542
|
+
host: readiness.runtime.host,
|
|
2543
|
+
port: readiness.runtime.port,
|
|
2544
|
+
base_url: readiness.baseUrl,
|
|
2545
|
+
host_source: readiness.runtime.hostSource,
|
|
2546
|
+
port_source: readiness.runtime.portSource,
|
|
2547
|
+
metadata_path: readiness.runtime.metadataPath,
|
|
2548
|
+
isolated_mode: readiness.runtime.isolatedMode
|
|
2549
|
+
},
|
|
2550
|
+
process: {
|
|
2551
|
+
component: "mcp",
|
|
2552
|
+
version: componentVersion,
|
|
2553
|
+
pid: process.pid,
|
|
2554
|
+
node_version: process.version,
|
|
2555
|
+
binary_path: process.execPath,
|
|
2556
|
+
argv_entry: process.argv[1]
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
} : body;
|
|
2560
|
+
return requestJson(path9, payload);
|
|
2561
|
+
};
|
|
2562
|
+
return {
|
|
2563
|
+
get baseUrl() {
|
|
2564
|
+
return readiness.baseUrl;
|
|
2565
|
+
},
|
|
2566
|
+
ensureReady: readiness.ensureReady,
|
|
2567
|
+
post
|
|
2327
2568
|
};
|
|
2328
|
-
return { baseUrl, post };
|
|
2329
2569
|
};
|
|
2330
2570
|
|
|
2331
2571
|
// packages/mcp-adapter/src/tools.ts
|
|
@@ -2722,10 +2962,11 @@ var TOOL_DEFINITIONS = [
|
|
|
2722
2962
|
}
|
|
2723
2963
|
}
|
|
2724
2964
|
];
|
|
2725
|
-
var createToolHandler = (
|
|
2965
|
+
var createToolHandler = (clientProvider, corePath) => {
|
|
2726
2966
|
return (async (args, _extra) => {
|
|
2727
2967
|
void _extra;
|
|
2728
2968
|
try {
|
|
2969
|
+
const client = typeof clientProvider === "function" ? await clientProvider() : clientProvider;
|
|
2729
2970
|
const envelopeResult = await client.post(corePath, args);
|
|
2730
2971
|
return toToolResult(envelopeResult);
|
|
2731
2972
|
} catch (error) {
|
|
@@ -2737,7 +2978,7 @@ var createToolHandler = (client, corePath) => {
|
|
|
2737
2978
|
}
|
|
2738
2979
|
});
|
|
2739
2980
|
};
|
|
2740
|
-
var registerBrowserBridgeTools = (server,
|
|
2981
|
+
var registerBrowserBridgeTools = (server, clientProvider) => {
|
|
2741
2982
|
for (const tool of TOOL_DEFINITIONS) {
|
|
2742
2983
|
server.registerTool(
|
|
2743
2984
|
tool.name,
|
|
@@ -2747,73 +2988,310 @@ var registerBrowserBridgeTools = (server, client) => {
|
|
|
2747
2988
|
inputSchema: tool.config.inputSchema,
|
|
2748
2989
|
outputSchema: tool.config.outputSchema
|
|
2749
2990
|
},
|
|
2750
|
-
createToolHandler(
|
|
2991
|
+
createToolHandler(clientProvider, tool.config.corePath)
|
|
2751
2992
|
);
|
|
2752
2993
|
}
|
|
2753
2994
|
};
|
|
2754
2995
|
|
|
2755
2996
|
// packages/mcp-adapter/src/server.ts
|
|
2756
|
-
var import_node_http = require("node:http");
|
|
2757
2997
|
var import_node_crypto = require("node:crypto");
|
|
2998
|
+
var import_node_http = require("node:http");
|
|
2758
2999
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
2759
3000
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
2760
3001
|
var import_streamableHttp = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
2761
3002
|
var import_types = require("@modelcontextprotocol/sdk/types.js");
|
|
3003
|
+
|
|
3004
|
+
// packages/mcp-adapter/src/deferred-logger.ts
|
|
3005
|
+
var LOG_LEVEL_PRIORITY2 = {
|
|
3006
|
+
debug: 10,
|
|
3007
|
+
info: 20,
|
|
3008
|
+
warn: 30,
|
|
3009
|
+
error: 40
|
|
3010
|
+
};
|
|
3011
|
+
var isEnabled = (state, level) => LOG_LEVEL_PRIORITY2[level] >= LOG_LEVEL_PRIORITY2[state.level];
|
|
3012
|
+
var enqueue = (state, entry) => {
|
|
3013
|
+
if (state.buffered.length >= state.maxBufferEntries) {
|
|
3014
|
+
state.buffered.shift();
|
|
3015
|
+
state.droppedEntries += 1;
|
|
3016
|
+
}
|
|
3017
|
+
state.buffered.push(entry);
|
|
3018
|
+
};
|
|
3019
|
+
var flushBuffered = (state) => {
|
|
3020
|
+
const destination = state.destination;
|
|
3021
|
+
if (!destination) {
|
|
3022
|
+
return;
|
|
3023
|
+
}
|
|
3024
|
+
if (state.droppedEntries > 0) {
|
|
3025
|
+
destination.warn("mcp.log.buffer.dropped", {
|
|
3026
|
+
dropped_entries: state.droppedEntries
|
|
3027
|
+
});
|
|
3028
|
+
state.droppedEntries = 0;
|
|
3029
|
+
}
|
|
3030
|
+
for (const entry of state.buffered) {
|
|
3031
|
+
destination.log(entry.level, entry.event, {
|
|
3032
|
+
...entry.bindings,
|
|
3033
|
+
...entry.fields
|
|
3034
|
+
});
|
|
3035
|
+
}
|
|
3036
|
+
state.buffered.length = 0;
|
|
3037
|
+
};
|
|
3038
|
+
var buildLogger2 = (state, bindings) => {
|
|
3039
|
+
const log = (level, event, fields = {}) => {
|
|
3040
|
+
if (!isEnabled(state, level)) {
|
|
3041
|
+
return;
|
|
3042
|
+
}
|
|
3043
|
+
if (state.destination) {
|
|
3044
|
+
state.destination.log(level, event, {
|
|
3045
|
+
...bindings,
|
|
3046
|
+
...fields
|
|
3047
|
+
});
|
|
3048
|
+
return;
|
|
3049
|
+
}
|
|
3050
|
+
enqueue(state, {
|
|
3051
|
+
level,
|
|
3052
|
+
event,
|
|
3053
|
+
fields: { ...fields },
|
|
3054
|
+
bindings: { ...bindings }
|
|
3055
|
+
});
|
|
3056
|
+
};
|
|
3057
|
+
return {
|
|
3058
|
+
stream: state.stream,
|
|
3059
|
+
get level() {
|
|
3060
|
+
return state.destination?.level ?? state.level;
|
|
3061
|
+
},
|
|
3062
|
+
get logDir() {
|
|
3063
|
+
return state.destination?.logDir ?? "";
|
|
3064
|
+
},
|
|
3065
|
+
get filePath() {
|
|
3066
|
+
return state.destination?.filePath ?? "";
|
|
3067
|
+
},
|
|
3068
|
+
child: (childBindings) => buildLogger2(state, {
|
|
3069
|
+
...bindings,
|
|
3070
|
+
...childBindings
|
|
3071
|
+
}),
|
|
3072
|
+
log,
|
|
3073
|
+
debug: (event, fields) => log("debug", event, fields),
|
|
3074
|
+
info: (event, fields) => log("info", event, fields),
|
|
3075
|
+
warn: (event, fields) => log("warn", event, fields),
|
|
3076
|
+
error: (event, fields) => log("error", event, fields)
|
|
3077
|
+
};
|
|
3078
|
+
};
|
|
3079
|
+
var createDeferredJsonlLogger = (options) => {
|
|
3080
|
+
const state = {
|
|
3081
|
+
stream: options.stream,
|
|
3082
|
+
level: options.level ?? "debug",
|
|
3083
|
+
destination: null,
|
|
3084
|
+
buffered: [],
|
|
3085
|
+
droppedEntries: 0,
|
|
3086
|
+
maxBufferEntries: Math.max(1, options.maxBufferEntries ?? 2e3)
|
|
3087
|
+
};
|
|
3088
|
+
return {
|
|
3089
|
+
logger: buildLogger2(state, options.bindings ?? {}),
|
|
3090
|
+
activate: () => {
|
|
3091
|
+
if (!state.destination) {
|
|
3092
|
+
state.destination = createJsonlLogger(options);
|
|
3093
|
+
}
|
|
3094
|
+
flushBuffered(state);
|
|
3095
|
+
return state.destination;
|
|
3096
|
+
},
|
|
3097
|
+
isActivated: () => state.destination !== null
|
|
3098
|
+
};
|
|
3099
|
+
};
|
|
3100
|
+
|
|
3101
|
+
// packages/mcp-adapter/src/server.ts
|
|
2762
3102
|
var DEFAULT_SERVER_NAME = "browser-bridge";
|
|
2763
3103
|
var DEFAULT_SERVER_VERSION = "0.0.0";
|
|
2764
3104
|
var DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
2765
3105
|
var DEFAULT_HTTP_PATH = "/mcp";
|
|
3106
|
+
var ENV_MCP_EAGER = "BROWSER_BRIDGE_MCP_EAGER";
|
|
3107
|
+
var ENV_LEGACY_MCP_EAGER = "BROWSER_VISION_MCP_EAGER";
|
|
2766
3108
|
var durationMs4 = (startedAt) => Number((Number(process.hrtime.bigint() - startedAt) / 1e6).toFixed(3));
|
|
2767
|
-
var
|
|
2768
|
-
|
|
2769
|
-
|
|
3109
|
+
var parseBoolean2 = (value) => {
|
|
3110
|
+
if (value === void 0) {
|
|
3111
|
+
return void 0;
|
|
3112
|
+
}
|
|
3113
|
+
const normalized = value.trim().toLowerCase();
|
|
3114
|
+
if (normalized === "1" || normalized === "true" || normalized === "yes" || normalized === "on") {
|
|
3115
|
+
return true;
|
|
3116
|
+
}
|
|
3117
|
+
if (normalized === "0" || normalized === "false" || normalized === "no" || normalized === "off") {
|
|
3118
|
+
return false;
|
|
3119
|
+
}
|
|
3120
|
+
return void 0;
|
|
3121
|
+
};
|
|
3122
|
+
var resolveEagerMode = (explicit) => {
|
|
3123
|
+
if (typeof explicit === "boolean") {
|
|
3124
|
+
return explicit;
|
|
3125
|
+
}
|
|
3126
|
+
const envValue = parseBoolean2(process.env[ENV_MCP_EAGER]) ?? parseBoolean2(process.env[ENV_LEGACY_MCP_EAGER]);
|
|
3127
|
+
return envValue ?? false;
|
|
3128
|
+
};
|
|
3129
|
+
var toCoreClientOptions = (options, logger) => ({
|
|
3130
|
+
host: options.host,
|
|
3131
|
+
port: options.port,
|
|
3132
|
+
cwd: options.cwd,
|
|
3133
|
+
timeoutMs: options.timeoutMs,
|
|
3134
|
+
ensureDaemon: options.ensureDaemon ?? true,
|
|
3135
|
+
componentVersion: options.version ?? DEFAULT_SERVER_VERSION,
|
|
3136
|
+
healthRetryMs: options.healthRetryMs,
|
|
3137
|
+
healthAttempts: options.healthAttempts,
|
|
3138
|
+
fetchImpl: options.fetchImpl,
|
|
3139
|
+
spawnImpl: options.spawnImpl,
|
|
3140
|
+
logger
|
|
2770
3141
|
});
|
|
2771
|
-
var
|
|
2772
|
-
const
|
|
3142
|
+
var buildInitializationError = (error) => {
|
|
3143
|
+
const message = error instanceof Error ? error.message : typeof error === "string" ? error : "Unknown initialization failure.";
|
|
3144
|
+
return {
|
|
3145
|
+
ok: false,
|
|
3146
|
+
error: {
|
|
3147
|
+
code: "UNAVAILABLE",
|
|
3148
|
+
message: `MCP runtime initialization failed: ${message}`,
|
|
3149
|
+
retryable: true,
|
|
3150
|
+
details: {
|
|
3151
|
+
phase: "mcp_runtime_init"
|
|
3152
|
+
}
|
|
3153
|
+
}
|
|
3154
|
+
};
|
|
3155
|
+
};
|
|
3156
|
+
var resolveDeferredLoggerController = (options) => {
|
|
3157
|
+
if (options.logger) {
|
|
3158
|
+
return {
|
|
3159
|
+
logger: options.logger,
|
|
3160
|
+
activate: () => void 0
|
|
3161
|
+
};
|
|
3162
|
+
}
|
|
3163
|
+
const deferred = createDeferredJsonlLogger({
|
|
3164
|
+
stream: "mcp-adapter",
|
|
3165
|
+
cwd: options.cwd
|
|
3166
|
+
});
|
|
3167
|
+
return {
|
|
3168
|
+
logger: deferred.logger,
|
|
3169
|
+
activate: () => {
|
|
3170
|
+
deferred.activate();
|
|
3171
|
+
}
|
|
3172
|
+
};
|
|
3173
|
+
};
|
|
3174
|
+
var createRuntimeController = (options) => {
|
|
3175
|
+
const deferredLogger = resolveDeferredLoggerController(options);
|
|
3176
|
+
const logger = deferredLogger.logger;
|
|
3177
|
+
const coreLogger = logger.child({ scope: "core-client" });
|
|
3178
|
+
let initializedClient = null;
|
|
3179
|
+
let initializationPromise = null;
|
|
3180
|
+
const createClient = async () => {
|
|
3181
|
+
if (options.coreClient) {
|
|
3182
|
+
return options.coreClient;
|
|
3183
|
+
}
|
|
3184
|
+
if (options.coreClientFactory) {
|
|
3185
|
+
return await options.coreClientFactory(coreLogger);
|
|
3186
|
+
}
|
|
3187
|
+
return createCoreClient2(toCoreClientOptions(options, coreLogger));
|
|
3188
|
+
};
|
|
3189
|
+
const proxyClient = {
|
|
3190
|
+
get baseUrl() {
|
|
3191
|
+
return initializedClient?.baseUrl ?? "";
|
|
3192
|
+
},
|
|
3193
|
+
ensureReady: async () => {
|
|
3194
|
+
await ensureInitialized();
|
|
3195
|
+
},
|
|
3196
|
+
post: async (path9, body) => {
|
|
3197
|
+
const client = await ensureInitialized();
|
|
3198
|
+
return client.post(path9, body);
|
|
3199
|
+
}
|
|
3200
|
+
};
|
|
3201
|
+
const ensureInitialized = async () => {
|
|
3202
|
+
if (initializedClient) {
|
|
3203
|
+
return initializedClient;
|
|
3204
|
+
}
|
|
3205
|
+
if (!initializationPromise) {
|
|
3206
|
+
initializationPromise = (async () => {
|
|
3207
|
+
logger.info("mcp.runtime.init.begin");
|
|
3208
|
+
try {
|
|
3209
|
+
const candidate = await createClient();
|
|
3210
|
+
const maybeEnsureReady = candidate.ensureReady;
|
|
3211
|
+
if (typeof maybeEnsureReady === "function") {
|
|
3212
|
+
await maybeEnsureReady.call(candidate);
|
|
3213
|
+
}
|
|
3214
|
+
deferredLogger.activate();
|
|
3215
|
+
initializedClient = candidate;
|
|
3216
|
+
logger.info("mcp.runtime.init.ready", {
|
|
3217
|
+
core_base_url: candidate.baseUrl
|
|
3218
|
+
});
|
|
3219
|
+
return candidate;
|
|
3220
|
+
} catch (error) {
|
|
3221
|
+
logger.error("mcp.runtime.init.failed", {
|
|
3222
|
+
error
|
|
3223
|
+
});
|
|
3224
|
+
throw buildInitializationError(error);
|
|
3225
|
+
}
|
|
3226
|
+
})();
|
|
3227
|
+
initializationPromise = initializationPromise.catch((error) => {
|
|
3228
|
+
initializationPromise = null;
|
|
3229
|
+
throw error;
|
|
3230
|
+
});
|
|
3231
|
+
}
|
|
3232
|
+
return initializationPromise;
|
|
3233
|
+
};
|
|
3234
|
+
return {
|
|
3235
|
+
logger,
|
|
3236
|
+
client: options.coreClient ?? proxyClient,
|
|
3237
|
+
ensureInitialized,
|
|
3238
|
+
isInitialized: () => initializedClient !== null
|
|
3239
|
+
};
|
|
3240
|
+
};
|
|
3241
|
+
var createMcpServerBootstrap = (options = {}) => {
|
|
3242
|
+
const runtime = createRuntimeController(options);
|
|
2773
3243
|
const server = new import_mcp.McpServer({
|
|
2774
3244
|
name: options.name ?? DEFAULT_SERVER_NAME,
|
|
2775
3245
|
version: options.version ?? DEFAULT_SERVER_VERSION
|
|
2776
3246
|
});
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
logger: logger.child({ scope: "core-client" })
|
|
2780
|
-
});
|
|
2781
|
-
registerBrowserBridgeTools(server, client);
|
|
2782
|
-
logger.info("mcp.server.created", {
|
|
3247
|
+
registerBrowserBridgeTools(server, runtime.ensureInitialized);
|
|
3248
|
+
runtime.logger.info("mcp.server.created", {
|
|
2783
3249
|
name: options.name ?? DEFAULT_SERVER_NAME,
|
|
2784
3250
|
version: options.version ?? DEFAULT_SERVER_VERSION,
|
|
2785
|
-
|
|
3251
|
+
lazy_init: true
|
|
2786
3252
|
});
|
|
2787
|
-
return {
|
|
3253
|
+
return {
|
|
3254
|
+
server,
|
|
3255
|
+
client: runtime.client,
|
|
3256
|
+
logger: runtime.logger,
|
|
3257
|
+
ensureInitialized: runtime.ensureInitialized,
|
|
3258
|
+
isInitialized: runtime.isInitialized
|
|
3259
|
+
};
|
|
2788
3260
|
};
|
|
2789
3261
|
var startMcpServer = async (options = {}) => {
|
|
2790
|
-
const
|
|
2791
|
-
|
|
3262
|
+
const eager = resolveEagerMode(options.eager);
|
|
3263
|
+
const handle = createMcpServerBootstrap(options);
|
|
3264
|
+
handle.logger.info("mcp.stdio.start.begin", {
|
|
2792
3265
|
name: options.name ?? DEFAULT_SERVER_NAME,
|
|
2793
|
-
version: options.version ?? DEFAULT_SERVER_VERSION
|
|
2794
|
-
|
|
2795
|
-
const handle = createMcpServer({
|
|
2796
|
-
...options,
|
|
2797
|
-
logger
|
|
3266
|
+
version: options.version ?? DEFAULT_SERVER_VERSION,
|
|
3267
|
+
eager
|
|
2798
3268
|
});
|
|
2799
3269
|
const transport = new import_stdio.StdioServerTransport();
|
|
2800
3270
|
try {
|
|
3271
|
+
if (eager) {
|
|
3272
|
+
await handle.ensureInitialized();
|
|
3273
|
+
}
|
|
2801
3274
|
await handle.server.connect(transport);
|
|
2802
|
-
logger.info("mcp.stdio.start.ready", {
|
|
2803
|
-
core_base_url: handle.client.baseUrl
|
|
3275
|
+
handle.logger.info("mcp.stdio.start.ready", {
|
|
3276
|
+
core_base_url: handle.isInitialized() ? handle.client.baseUrl : null,
|
|
3277
|
+
eager
|
|
2804
3278
|
});
|
|
2805
3279
|
} catch (error) {
|
|
2806
|
-
logger.error("mcp.stdio.start.failed", {
|
|
3280
|
+
handle.logger.error("mcp.stdio.start.failed", {
|
|
2807
3281
|
error
|
|
2808
3282
|
});
|
|
2809
3283
|
throw error;
|
|
2810
3284
|
}
|
|
2811
|
-
return {
|
|
3285
|
+
return {
|
|
3286
|
+
server: handle.server,
|
|
3287
|
+
client: handle.client,
|
|
3288
|
+
transport
|
|
3289
|
+
};
|
|
2812
3290
|
};
|
|
2813
3291
|
var readJsonBody = async (req, maxBytes = 5 * 1024 * 1024) => {
|
|
2814
3292
|
const chunks = [];
|
|
2815
3293
|
let total = 0;
|
|
2816
|
-
await new Promise((
|
|
3294
|
+
await new Promise((resolve4, reject) => {
|
|
2817
3295
|
req.on("data", (chunk) => {
|
|
2818
3296
|
total += chunk.length;
|
|
2819
3297
|
if (total > maxBytes) {
|
|
@@ -2823,7 +3301,7 @@ var readJsonBody = async (req, maxBytes = 5 * 1024 * 1024) => {
|
|
|
2823
3301
|
}
|
|
2824
3302
|
chunks.push(chunk);
|
|
2825
3303
|
});
|
|
2826
|
-
req.on("end", () =>
|
|
3304
|
+
req.on("end", () => resolve4());
|
|
2827
3305
|
req.on("error", (err) => reject(err));
|
|
2828
3306
|
});
|
|
2829
3307
|
const raw = Buffer.concat(chunks).toString("utf8");
|
|
@@ -2842,19 +3320,21 @@ var getHeaderValue = (value) => {
|
|
|
2842
3320
|
return void 0;
|
|
2843
3321
|
};
|
|
2844
3322
|
var startMcpHttpServer = async (options = {}) => {
|
|
2845
|
-
const
|
|
3323
|
+
const eager = resolveEagerMode(options.eager);
|
|
3324
|
+
const runtime = createRuntimeController(options);
|
|
3325
|
+
const logger = runtime.logger.child({ scope: "http-server" });
|
|
2846
3326
|
const host = options.host ?? DEFAULT_HTTP_HOST;
|
|
2847
3327
|
const port = typeof options.port === "number" ? options.port : 0;
|
|
2848
3328
|
const path9 = options.path ?? DEFAULT_HTTP_PATH;
|
|
2849
3329
|
logger.info("mcp.http.start.begin", {
|
|
2850
3330
|
host,
|
|
2851
3331
|
port,
|
|
2852
|
-
path: path9
|
|
2853
|
-
|
|
2854
|
-
const client = options.coreClient ?? createCoreClient2({
|
|
2855
|
-
...options,
|
|
2856
|
-
logger: logger.child({ scope: "core-client" })
|
|
3332
|
+
path: path9,
|
|
3333
|
+
eager
|
|
2857
3334
|
});
|
|
3335
|
+
if (eager) {
|
|
3336
|
+
await runtime.ensureInitialized();
|
|
3337
|
+
}
|
|
2858
3338
|
const sessions = /* @__PURE__ */ new Map();
|
|
2859
3339
|
const closeAllSessions = async () => {
|
|
2860
3340
|
const entries = Array.from(sessions.values());
|
|
@@ -2965,7 +3445,7 @@ var startMcpHttpServer = async (options = {}) => {
|
|
|
2965
3445
|
name: options.name ?? DEFAULT_SERVER_NAME,
|
|
2966
3446
|
version: options.version ?? DEFAULT_SERVER_VERSION
|
|
2967
3447
|
});
|
|
2968
|
-
registerBrowserBridgeTools(sessionServer,
|
|
3448
|
+
registerBrowserBridgeTools(sessionServer, runtime.ensureInitialized);
|
|
2969
3449
|
await sessionServer.connect(transport);
|
|
2970
3450
|
sessionEntry = { transport, server: sessionServer };
|
|
2971
3451
|
await transport.handleRequest(req, res, parsedBody);
|
|
@@ -2989,10 +3469,10 @@ var startMcpHttpServer = async (options = {}) => {
|
|
|
2989
3469
|
);
|
|
2990
3470
|
}
|
|
2991
3471
|
});
|
|
2992
|
-
const resolvedPort = await new Promise((
|
|
3472
|
+
const resolvedPort = await new Promise((resolve4, reject) => {
|
|
2993
3473
|
httpServer.listen(port, host, () => {
|
|
2994
3474
|
const address = httpServer.address();
|
|
2995
|
-
|
|
3475
|
+
resolve4(typeof address === "object" && address ? address.port : port);
|
|
2996
3476
|
});
|
|
2997
3477
|
httpServer.on("error", reject);
|
|
2998
3478
|
});
|
|
@@ -3000,10 +3480,11 @@ var startMcpHttpServer = async (options = {}) => {
|
|
|
3000
3480
|
host,
|
|
3001
3481
|
port: resolvedPort,
|
|
3002
3482
|
path: path9,
|
|
3003
|
-
core_base_url: client.baseUrl
|
|
3483
|
+
core_base_url: runtime.isInitialized() ? runtime.client.baseUrl : null,
|
|
3484
|
+
eager
|
|
3004
3485
|
});
|
|
3005
3486
|
return {
|
|
3006
|
-
client,
|
|
3487
|
+
client: runtime.client,
|
|
3007
3488
|
host,
|
|
3008
3489
|
port: resolvedPort,
|
|
3009
3490
|
path: path9,
|
|
@@ -3012,12 +3493,12 @@ var startMcpHttpServer = async (options = {}) => {
|
|
|
3012
3493
|
host,
|
|
3013
3494
|
port: resolvedPort
|
|
3014
3495
|
});
|
|
3015
|
-
await new Promise((
|
|
3496
|
+
await new Promise((resolve4, reject) => {
|
|
3016
3497
|
httpServer.close((err) => {
|
|
3017
3498
|
if (err) {
|
|
3018
3499
|
reject(err);
|
|
3019
3500
|
} else {
|
|
3020
|
-
|
|
3501
|
+
resolve4();
|
|
3021
3502
|
}
|
|
3022
3503
|
});
|
|
3023
3504
|
});
|
|
@@ -3054,19 +3535,19 @@ var checkboxPrompt = async (options) => {
|
|
|
3054
3535
|
};
|
|
3055
3536
|
|
|
3056
3537
|
// packages/cli/src/installer/mcp-install.ts
|
|
3057
|
-
var
|
|
3538
|
+
var import_node_child_process4 = require("node:child_process");
|
|
3058
3539
|
|
|
3059
3540
|
// packages/cli/src/installer/cursor-mcp.ts
|
|
3060
3541
|
var import_promises2 = __toESM(require("node:fs/promises"));
|
|
3061
3542
|
var import_node_os = __toESM(require("node:os"));
|
|
3062
|
-
var
|
|
3543
|
+
var import_node_path5 = __toESM(require("node:path"));
|
|
3063
3544
|
var isObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3064
3545
|
var resolveCursorUserSettingsPath = (options) => {
|
|
3065
3546
|
const platform = options?.platform ?? process.platform;
|
|
3066
3547
|
const homeDir = options?.homeDir ?? import_node_os.default.homedir();
|
|
3067
3548
|
const env = options?.env ?? process.env;
|
|
3068
3549
|
if (platform === "darwin") {
|
|
3069
|
-
return
|
|
3550
|
+
return import_node_path5.default.join(
|
|
3070
3551
|
homeDir,
|
|
3071
3552
|
"Library",
|
|
3072
3553
|
"Application Support",
|
|
@@ -3082,13 +3563,13 @@ var resolveCursorUserSettingsPath = (options) => {
|
|
|
3082
3563
|
"APPDATA is not set; cannot resolve Cursor settings path."
|
|
3083
3564
|
);
|
|
3084
3565
|
}
|
|
3085
|
-
return
|
|
3566
|
+
return import_node_path5.default.join(appData, "Cursor", "User", "settings.json");
|
|
3086
3567
|
}
|
|
3087
|
-
return
|
|
3568
|
+
return import_node_path5.default.join(homeDir, ".config", "Cursor", "User", "settings.json");
|
|
3088
3569
|
};
|
|
3089
3570
|
var installCursorMcp = async (settingsPath) => {
|
|
3090
3571
|
const filePath = settingsPath ?? resolveCursorUserSettingsPath();
|
|
3091
|
-
const dir =
|
|
3572
|
+
const dir = import_node_path5.default.dirname(filePath);
|
|
3092
3573
|
await import_promises2.default.mkdir(dir, { recursive: true });
|
|
3093
3574
|
let settings = {};
|
|
3094
3575
|
try {
|
|
@@ -3124,15 +3605,15 @@ var installCursorMcp = async (settingsPath) => {
|
|
|
3124
3605
|
|
|
3125
3606
|
// packages/cli/src/installer/mcp-install.ts
|
|
3126
3607
|
var runQuiet = async (cmd, args) => {
|
|
3127
|
-
await new Promise((
|
|
3128
|
-
const child = (0,
|
|
3608
|
+
await new Promise((resolve4, reject) => {
|
|
3609
|
+
const child = (0, import_node_child_process4.spawn)(cmd, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
3129
3610
|
let stderr = "";
|
|
3130
3611
|
child.stderr?.on("data", (chunk) => {
|
|
3131
3612
|
stderr += String(chunk);
|
|
3132
3613
|
});
|
|
3133
3614
|
child.on("error", reject);
|
|
3134
3615
|
child.on("exit", (code) => {
|
|
3135
|
-
if (code === 0)
|
|
3616
|
+
if (code === 0) resolve4();
|
|
3136
3617
|
else {
|
|
3137
3618
|
const suffix = stderr.trim() ? `: ${stderr.trim()}` : "";
|
|
3138
3619
|
reject(new Error(`${cmd} exited with ${code ?? "unknown"}${suffix}`));
|
|
@@ -3211,16 +3692,17 @@ var installMcp = async (harness) => {
|
|
|
3211
3692
|
var registerMcpCommand = (program2) => {
|
|
3212
3693
|
const startServer = async (options, command) => {
|
|
3213
3694
|
const globals = getGlobalOptions(command);
|
|
3214
|
-
const coreClient = createCoreClient({
|
|
3215
|
-
host: globals.host,
|
|
3216
|
-
port: globals.port,
|
|
3217
|
-
ensureDaemon: globals.daemon !== false
|
|
3218
|
-
});
|
|
3219
3695
|
try {
|
|
3220
3696
|
await startMcpServer({
|
|
3221
3697
|
name: options.name,
|
|
3222
3698
|
version: options.version,
|
|
3223
|
-
|
|
3699
|
+
eager: options.eager,
|
|
3700
|
+
coreClientFactory: (logger) => createCoreClient({
|
|
3701
|
+
host: globals.host,
|
|
3702
|
+
port: globals.port,
|
|
3703
|
+
ensureDaemon: globals.daemon !== false,
|
|
3704
|
+
logger
|
|
3705
|
+
})
|
|
3224
3706
|
});
|
|
3225
3707
|
} catch (error) {
|
|
3226
3708
|
console.error(error);
|
|
@@ -3257,15 +3739,10 @@ var registerMcpCommand = (program2) => {
|
|
|
3257
3739
|
return { ok: true, result: { installed: results } };
|
|
3258
3740
|
});
|
|
3259
3741
|
});
|
|
3260
|
-
mcp.option("--name <name>", "MCP server name").option("--version <version>", "MCP server version").action(startServer);
|
|
3261
|
-
mcp.command("serve").description("Run the MCP server over stdio").option("--name <name>", "MCP server name").option("--version <version>", "MCP server version").action(startServer);
|
|
3262
|
-
mcp.command("serve-http").description("Run the MCP server over Streamable HTTP").option("--name <name>", "MCP server name").option("--version <version>", "MCP server version").option("--host <host>", "HTTP host (default 127.0.0.1)").option("--port <port>", "HTTP port (default random available port)").option("--path <path>", "HTTP path (default /mcp)").action(async (options, command) => {
|
|
3742
|
+
mcp.option("--name <name>", "MCP server name").option("--version <version>", "MCP server version").option("--eager", "Initialize runtime on startup (debug only)").action(startServer);
|
|
3743
|
+
mcp.command("serve").description("Run the MCP server over stdio").option("--name <name>", "MCP server name").option("--version <version>", "MCP server version").option("--eager", "Initialize runtime on startup (debug only)").action(startServer);
|
|
3744
|
+
mcp.command("serve-http").description("Run the MCP server over Streamable HTTP").option("--name <name>", "MCP server name").option("--version <version>", "MCP server version").option("--host <host>", "HTTP host (default 127.0.0.1)").option("--port <port>", "HTTP port (default random available port)").option("--path <path>", "HTTP path (default /mcp)").option("--eager", "Initialize runtime on startup (debug only)").action(async (options, command) => {
|
|
3263
3745
|
const globals = getGlobalOptions(command);
|
|
3264
|
-
const coreClient = createCoreClient({
|
|
3265
|
-
host: globals.host,
|
|
3266
|
-
port: globals.port,
|
|
3267
|
-
ensureDaemon: globals.daemon !== false
|
|
3268
|
-
});
|
|
3269
3746
|
const parsedPort = typeof options.port === "string" && options.port.length > 0 ? Number(options.port) : void 0;
|
|
3270
3747
|
try {
|
|
3271
3748
|
const handle = await startMcpHttpServer({
|
|
@@ -3274,7 +3751,13 @@ var registerMcpCommand = (program2) => {
|
|
|
3274
3751
|
host: options.host,
|
|
3275
3752
|
port: typeof parsedPort === "number" && Number.isFinite(parsedPort) ? parsedPort : void 0,
|
|
3276
3753
|
path: options.path,
|
|
3277
|
-
|
|
3754
|
+
eager: options.eager,
|
|
3755
|
+
coreClientFactory: (logger) => createCoreClient({
|
|
3756
|
+
host: globals.host,
|
|
3757
|
+
port: globals.port,
|
|
3758
|
+
ensureDaemon: globals.daemon !== false,
|
|
3759
|
+
logger
|
|
3760
|
+
})
|
|
3278
3761
|
});
|
|
3279
3762
|
console.error(
|
|
3280
3763
|
`MCP HTTP server listening on http://${handle.host}:${handle.port}${handle.path}`
|
|
@@ -3300,10 +3783,10 @@ var import_turndown = __toESM(require("turndown"));
|
|
|
3300
3783
|
// packages/core/src/artifacts.ts
|
|
3301
3784
|
var import_promises3 = require("node:fs/promises");
|
|
3302
3785
|
var import_node_os2 = __toESM(require("node:os"));
|
|
3303
|
-
var
|
|
3786
|
+
var import_node_path6 = __toESM(require("node:path"));
|
|
3304
3787
|
var ARTIFACTS_DIR_NAME = "browser-agent";
|
|
3305
3788
|
var resolveTempRoot = () => process.env.TMPDIR || process.env.TEMP || process.env.TMP || import_node_os2.default.tmpdir();
|
|
3306
|
-
var getArtifactRootDir = (sessionId) =>
|
|
3789
|
+
var getArtifactRootDir = (sessionId) => import_node_path6.default.join(resolveTempRoot(), ARTIFACTS_DIR_NAME, sessionId);
|
|
3307
3790
|
var ensureArtifactRootDir = async (sessionId) => {
|
|
3308
3791
|
const rootDir = getArtifactRootDir(sessionId);
|
|
3309
3792
|
await (0, import_promises3.mkdir)(rootDir, { recursive: true });
|
|
@@ -3490,60 +3973,60 @@ var registerSessionCommands = (program2) => {
|
|
|
3490
3973
|
// packages/cli/src/commands/skill.ts
|
|
3491
3974
|
var import_promises7 = __toESM(require("node:fs/promises"));
|
|
3492
3975
|
var import_node_os4 = __toESM(require("node:os"));
|
|
3493
|
-
var
|
|
3976
|
+
var import_node_path11 = __toESM(require("node:path"));
|
|
3494
3977
|
|
|
3495
3978
|
// packages/cli/src/installer/harness-targets.ts
|
|
3496
3979
|
var import_node_os3 = __toESM(require("node:os"));
|
|
3497
|
-
var
|
|
3980
|
+
var import_node_path7 = __toESM(require("node:path"));
|
|
3498
3981
|
var getDefaultHarnessTargets = (homeDir) => {
|
|
3499
3982
|
const home = homeDir ?? import_node_os3.default.homedir();
|
|
3500
3983
|
return [
|
|
3501
3984
|
{
|
|
3502
3985
|
id: "codex",
|
|
3503
3986
|
label: "Codex",
|
|
3504
|
-
skillsDir:
|
|
3987
|
+
skillsDir: import_node_path7.default.join(home, ".agents", "skills"),
|
|
3505
3988
|
supportsMcpInstall: true
|
|
3506
3989
|
},
|
|
3507
3990
|
{
|
|
3508
3991
|
id: "claude",
|
|
3509
3992
|
label: "Claude",
|
|
3510
|
-
skillsDir:
|
|
3993
|
+
skillsDir: import_node_path7.default.join(home, ".claude", "skills"),
|
|
3511
3994
|
supportsMcpInstall: true
|
|
3512
3995
|
},
|
|
3513
3996
|
{
|
|
3514
3997
|
id: "cursor",
|
|
3515
3998
|
label: "Cursor",
|
|
3516
|
-
skillsDir:
|
|
3999
|
+
skillsDir: import_node_path7.default.join(home, ".cursor", "skills"),
|
|
3517
4000
|
supportsMcpInstall: true
|
|
3518
4001
|
},
|
|
3519
4002
|
{
|
|
3520
4003
|
id: "factory",
|
|
3521
4004
|
label: "Factory",
|
|
3522
|
-
skillsDir:
|
|
4005
|
+
skillsDir: import_node_path7.default.join(home, ".factory", "skills"),
|
|
3523
4006
|
supportsMcpInstall: false
|
|
3524
4007
|
},
|
|
3525
4008
|
{
|
|
3526
4009
|
id: "opencode",
|
|
3527
4010
|
label: "OpenCode",
|
|
3528
|
-
skillsDir:
|
|
4011
|
+
skillsDir: import_node_path7.default.join(home, ".opencode", "skills"),
|
|
3529
4012
|
supportsMcpInstall: false
|
|
3530
4013
|
},
|
|
3531
4014
|
{
|
|
3532
4015
|
id: "gemini",
|
|
3533
4016
|
label: "Gemini",
|
|
3534
|
-
skillsDir:
|
|
4017
|
+
skillsDir: import_node_path7.default.join(home, ".gemini", "skills"),
|
|
3535
4018
|
supportsMcpInstall: false
|
|
3536
4019
|
},
|
|
3537
4020
|
{
|
|
3538
4021
|
id: "github",
|
|
3539
4022
|
label: "GitHub",
|
|
3540
|
-
skillsDir:
|
|
4023
|
+
skillsDir: import_node_path7.default.join(home, ".github", "skills"),
|
|
3541
4024
|
supportsMcpInstall: false
|
|
3542
4025
|
},
|
|
3543
4026
|
{
|
|
3544
4027
|
id: "ampcode",
|
|
3545
4028
|
label: "Ampcode",
|
|
3546
|
-
skillsDir:
|
|
4029
|
+
skillsDir: import_node_path7.default.join(home, ".ampcode", "skills"),
|
|
3547
4030
|
supportsMcpInstall: false
|
|
3548
4031
|
}
|
|
3549
4032
|
];
|
|
@@ -3551,7 +4034,7 @@ var getDefaultHarnessTargets = (homeDir) => {
|
|
|
3551
4034
|
|
|
3552
4035
|
// packages/cli/src/installer/package-info.ts
|
|
3553
4036
|
var import_promises4 = __toESM(require("node:fs/promises"));
|
|
3554
|
-
var
|
|
4037
|
+
var import_node_path8 = __toESM(require("node:path"));
|
|
3555
4038
|
var PACKAGE_NAME = "@btraut/browser-bridge";
|
|
3556
4039
|
var tryReadJson = async (filePath) => {
|
|
3557
4040
|
try {
|
|
@@ -3564,12 +4047,12 @@ var tryReadJson = async (filePath) => {
|
|
|
3564
4047
|
var resolveCliPackageRootDir = async () => {
|
|
3565
4048
|
let dir = __dirname;
|
|
3566
4049
|
for (let i = 0; i < 12; i++) {
|
|
3567
|
-
const candidate =
|
|
4050
|
+
const candidate = import_node_path8.default.join(dir, "package.json");
|
|
3568
4051
|
const parsed = await tryReadJson(candidate);
|
|
3569
4052
|
if (parsed && parsed.name === PACKAGE_NAME) {
|
|
3570
4053
|
return dir;
|
|
3571
4054
|
}
|
|
3572
|
-
const parent =
|
|
4055
|
+
const parent = import_node_path8.default.dirname(dir);
|
|
3573
4056
|
if (parent === dir) {
|
|
3574
4057
|
break;
|
|
3575
4058
|
}
|
|
@@ -3581,7 +4064,7 @@ var resolveCliPackageRootDir = async () => {
|
|
|
3581
4064
|
};
|
|
3582
4065
|
var readCliPackageVersion = async () => {
|
|
3583
4066
|
const rootDir = await resolveCliPackageRootDir();
|
|
3584
|
-
const pkgPath =
|
|
4067
|
+
const pkgPath = import_node_path8.default.join(rootDir, "package.json");
|
|
3585
4068
|
const parsed = await tryReadJson(pkgPath);
|
|
3586
4069
|
if (!parsed || typeof parsed.version !== "string" || !parsed.version) {
|
|
3587
4070
|
throw new Error(`Unable to read version from ${pkgPath}`);
|
|
@@ -3590,14 +4073,14 @@ var readCliPackageVersion = async () => {
|
|
|
3590
4073
|
};
|
|
3591
4074
|
var resolveSkillSourceDir = async () => {
|
|
3592
4075
|
const rootDir = await resolveCliPackageRootDir();
|
|
3593
|
-
const packaged =
|
|
4076
|
+
const packaged = import_node_path8.default.join(rootDir, "skills", "browser-bridge");
|
|
3594
4077
|
try {
|
|
3595
4078
|
await import_promises4.default.stat(packaged);
|
|
3596
4079
|
return packaged;
|
|
3597
4080
|
} catch {
|
|
3598
4081
|
}
|
|
3599
|
-
const repoRoot =
|
|
3600
|
-
const docsSkill =
|
|
4082
|
+
const repoRoot = import_node_path8.default.resolve(rootDir, "..", "..");
|
|
4083
|
+
const docsSkill = import_node_path8.default.join(repoRoot, "docs", "skills", "browser-bridge");
|
|
3601
4084
|
try {
|
|
3602
4085
|
await import_promises4.default.stat(docsSkill);
|
|
3603
4086
|
return docsSkill;
|
|
@@ -3610,16 +4093,16 @@ var resolveSkillSourceDir = async () => {
|
|
|
3610
4093
|
|
|
3611
4094
|
// packages/cli/src/installer/skill-install.ts
|
|
3612
4095
|
var import_promises6 = __toESM(require("node:fs/promises"));
|
|
3613
|
-
var
|
|
4096
|
+
var import_node_path10 = __toESM(require("node:path"));
|
|
3614
4097
|
|
|
3615
4098
|
// packages/cli/src/installer/skill-manifest.ts
|
|
3616
4099
|
var import_promises5 = __toESM(require("node:fs/promises"));
|
|
3617
|
-
var
|
|
4100
|
+
var import_node_path9 = __toESM(require("node:path"));
|
|
3618
4101
|
var SKILL_MANIFEST_FILENAME = "skill.json";
|
|
3619
4102
|
var readSkillManifest = async (skillDir) => {
|
|
3620
4103
|
try {
|
|
3621
4104
|
const raw = await import_promises5.default.readFile(
|
|
3622
|
-
|
|
4105
|
+
import_node_path9.default.join(skillDir, SKILL_MANIFEST_FILENAME),
|
|
3623
4106
|
"utf8"
|
|
3624
4107
|
);
|
|
3625
4108
|
const parsed = JSON.parse(raw);
|
|
@@ -3634,7 +4117,7 @@ var readSkillManifest = async (skillDir) => {
|
|
|
3634
4117
|
var writeSkillManifest = async (skillDir, version) => {
|
|
3635
4118
|
const payload = { name: "browser-bridge", version };
|
|
3636
4119
|
await import_promises5.default.writeFile(
|
|
3637
|
-
|
|
4120
|
+
import_node_path9.default.join(skillDir, SKILL_MANIFEST_FILENAME),
|
|
3638
4121
|
JSON.stringify(payload, null, 2) + "\n",
|
|
3639
4122
|
"utf8"
|
|
3640
4123
|
);
|
|
@@ -3642,7 +4125,7 @@ var writeSkillManifest = async (skillDir, version) => {
|
|
|
3642
4125
|
|
|
3643
4126
|
// packages/cli/src/installer/skill-install.ts
|
|
3644
4127
|
var installBrowserBridgeSkill = async (options) => {
|
|
3645
|
-
const destDir =
|
|
4128
|
+
const destDir = import_node_path10.default.join(options.destSkillsDir, "browser-bridge");
|
|
3646
4129
|
await import_promises6.default.mkdir(options.destSkillsDir, { recursive: true });
|
|
3647
4130
|
await import_promises6.default.rm(destDir, { recursive: true, force: true });
|
|
3648
4131
|
await import_promises6.default.cp(options.srcSkillDir, destDir, { recursive: true });
|
|
@@ -3654,9 +4137,9 @@ var installBrowserBridgeSkill = async (options) => {
|
|
|
3654
4137
|
var getHarnessMarkerDir = (homeDir, harness) => {
|
|
3655
4138
|
switch (harness) {
|
|
3656
4139
|
case "codex":
|
|
3657
|
-
return
|
|
4140
|
+
return import_node_path11.default.join(homeDir, ".agents");
|
|
3658
4141
|
default:
|
|
3659
|
-
return
|
|
4142
|
+
return import_node_path11.default.join(homeDir, `.${harness}`);
|
|
3660
4143
|
}
|
|
3661
4144
|
};
|
|
3662
4145
|
var registerSkillCommands = (program2) => {
|
|
@@ -3734,7 +4217,7 @@ var registerSkillCommands = (program2) => {
|
|
|
3734
4217
|
const targets = getDefaultHarnessTargets();
|
|
3735
4218
|
const rows = [];
|
|
3736
4219
|
for (const t of targets) {
|
|
3737
|
-
const skillDir =
|
|
4220
|
+
const skillDir = import_node_path11.default.join(t.skillsDir, "browser-bridge");
|
|
3738
4221
|
let installed = false;
|
|
3739
4222
|
try {
|
|
3740
4223
|
await import_promises7.default.stat(skillDir);
|
|
@@ -3762,7 +4245,7 @@ var registerSkillCommands = (program2) => {
|
|
|
3762
4245
|
// packages/cli/src/commands/install.ts
|
|
3763
4246
|
var import_promises8 = __toESM(require("node:fs/promises"));
|
|
3764
4247
|
var import_node_os5 = __toESM(require("node:os"));
|
|
3765
|
-
var
|
|
4248
|
+
var import_node_path12 = __toESM(require("node:path"));
|
|
3766
4249
|
var formatInstallSummary = (options) => {
|
|
3767
4250
|
const wantsSkill = options.setup.includes("skill");
|
|
3768
4251
|
const wantsMcp = options.setup.includes("mcp");
|
|
@@ -3797,9 +4280,9 @@ var getHarnessMarkerDir2 = (harness) => {
|
|
|
3797
4280
|
const homeDir = import_node_os5.default.homedir();
|
|
3798
4281
|
switch (harness) {
|
|
3799
4282
|
case "codex":
|
|
3800
|
-
return
|
|
4283
|
+
return import_node_path12.default.join(homeDir, ".agents");
|
|
3801
4284
|
default:
|
|
3802
|
-
return
|
|
4285
|
+
return import_node_path12.default.join(homeDir, `.${harness}`);
|
|
3803
4286
|
}
|
|
3804
4287
|
};
|
|
3805
4288
|
var registerInstallCommand = (program2) => {
|