@opencode/browse 0.0.6-dev.19 → 0.0.6-dev.21
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/dist/{cli-22fe7etn.mjs → cli-qcdv8aqh.mjs} +85 -84
- package/dist/cli.mjs +14 -9
- package/dist/{helpers-rta4d2as.mjs → helpers-d74qp3s1.mjs} +10 -9
- package/dist/{main-yd50d95g.mjs → main-0m569gdn.mjs} +165 -127
- package/dist/{main-2wrztakb.mjs → main-33kf3cfr.mjs} +12 -4
- package/dist/main-3gthmkzw.mjs +112 -0
- package/dist/{main-xatp12cr.mjs → main-6bjnpchg.mjs} +4 -4
- package/dist/{main-75rdz6bc.mjs → main-7qs0mwvc.mjs} +1 -1
- package/dist/main-ek76h9k1.mjs +4 -0
- package/dist/{main-8a245rm1.mjs → main-qm2keaeb.mjs} +199 -186
- package/dist/{main-knahxbey.mjs → main-ybvatjk0.mjs} +5 -5
- package/dist/{main-90enpn5q.mjs → main-yq58hnwq.mjs} +10 -10
- package/dist/{mcp-p0mcjvq9.mjs → mcp-qmq1yerr.mjs} +38 -39
- package/dist/{relay-tfvn856e.mjs → relay-446cn6cs.mjs} +4073 -3894
- package/dist/{runtime-update-pxbj49tf.mjs → runtime-update-fj4s270v.mjs} +6 -5
- package/dist/{setup-y8pd11b8.mjs → setup-atsf76r6.mjs} +3844 -3132
- package/dist/skill-text-v35020jn.mjs +1007 -0
- package/dist/supervisor-bvnx7xgg.mjs +154 -0
- package/dist/{update-5fx8t344.mjs → update-38wp6pt4.mjs} +4 -2
- package/dist/{version-cjhq7cm9.mjs → version-x7djen82.mjs} +1 -1
- package/package.json +3 -2
- package/skills/browse/SKILL.md +29 -29
- package/dist/main-ts9jjqs8.mjs +0 -4
|
@@ -1,22 +1,28 @@
|
|
|
1
1
|
import {
|
|
2
|
-
cliCommand,
|
|
3
|
-
installCommand,
|
|
4
|
-
npmRuntime,
|
|
5
2
|
unpackedExtensionId,
|
|
6
3
|
extensionReconnectAlarmPeriodMs,
|
|
7
4
|
extensionProtocolAdvice,
|
|
8
5
|
parseJsonObject
|
|
9
|
-
} from "./main-
|
|
6
|
+
} from "./main-3gthmkzw.mjs";
|
|
10
7
|
import {
|
|
11
8
|
relayAuthorization
|
|
12
|
-
} from "./main-
|
|
9
|
+
} from "./main-7qs0mwvc.mjs";
|
|
13
10
|
import {
|
|
14
11
|
opencodeBrowserBuildId2
|
|
15
|
-
} from "./main-
|
|
12
|
+
} from "./main-ek76h9k1.mjs";
|
|
13
|
+
import {
|
|
14
|
+
compiledBinary,
|
|
15
|
+
scriptEntry,
|
|
16
|
+
cliCommand,
|
|
17
|
+
installCommand,
|
|
18
|
+
npmRuntime
|
|
19
|
+
} from "./main-0m569gdn.mjs";
|
|
16
20
|
|
|
17
21
|
// src/relay/helpers.ts
|
|
18
|
-
import
|
|
19
|
-
|
|
22
|
+
import { Option, Predicate, Schema as Schema3 } from "effect";
|
|
23
|
+
|
|
24
|
+
// src/relay/http.ts
|
|
25
|
+
import { Effect, Schema as Schema2 } from "effect";
|
|
20
26
|
|
|
21
27
|
// src/relay/schema.ts
|
|
22
28
|
import { Schema } from "effect";
|
|
@@ -524,37 +530,7 @@ var ErrorEnvelope = Schema.Struct({
|
|
|
524
530
|
code: Schema.optionalKey(RelayErrorCode)
|
|
525
531
|
});
|
|
526
532
|
|
|
527
|
-
// src/relay/
|
|
528
|
-
var defaultHost2 = "127.0.0.1";
|
|
529
|
-
var defaultPort2 = 19988;
|
|
530
|
-
var stableUnpackedExtensionOrigin2 = `chrome-extension://${unpackedExtensionId}`;
|
|
531
|
-
function chromeExtensionOriginForPath2(extensionPath, platform = process.platform) {
|
|
532
|
-
const normalizedPath = platform === "win32" && /^[a-z]:/.test(extensionPath) ? extensionPath.charAt(0).toUpperCase() + extensionPath.slice(1) : extensionPath;
|
|
533
|
-
const pathBytes = platform === "win32" ? Buffer.from(normalizedPath, "utf16le") : normalizedPath;
|
|
534
|
-
const digest = crypto.createHash("sha256").update(pathBytes).digest();
|
|
535
|
-
let extensionId = "";
|
|
536
|
-
for (const byte of digest.subarray(0, 16)) {
|
|
537
|
-
extensionId += String.fromCharCode(97 + (byte >> 4), 97 + (byte & 15));
|
|
538
|
-
}
|
|
539
|
-
return `chrome-extension://${extensionId}`;
|
|
540
|
-
}
|
|
541
|
-
var chromeExtensionOriginPattern = /^chrome-extension:\/\/[a-p]+$/;
|
|
542
|
-
function parseAdditionalExtensionOrigins2(raw) {
|
|
543
|
-
if (!raw) {
|
|
544
|
-
return [];
|
|
545
|
-
}
|
|
546
|
-
const seen = new Set;
|
|
547
|
-
const origins = [];
|
|
548
|
-
for (const token of raw.split(/[\s,]+/)) {
|
|
549
|
-
const value = token.trim();
|
|
550
|
-
if (!value || !chromeExtensionOriginPattern.test(value) || seen.has(value)) {
|
|
551
|
-
continue;
|
|
552
|
-
}
|
|
553
|
-
seen.add(value);
|
|
554
|
-
origins.push(value);
|
|
555
|
-
}
|
|
556
|
-
return origins;
|
|
557
|
-
}
|
|
533
|
+
// src/relay/http.ts
|
|
558
534
|
var maxCliBodyBytes = 1e6;
|
|
559
535
|
|
|
560
536
|
class HttpRouteError2 extends Schema2.TaggedError()("HttpApi.HttpRouteError", { message: Schema2.String, status: Schema2.Number, code: RelayErrorCode }) {
|
|
@@ -565,98 +541,6 @@ function formatHostForUrl2(host) {
|
|
|
565
541
|
}
|
|
566
542
|
return host;
|
|
567
543
|
}
|
|
568
|
-
function validateHostHeader2(options) {
|
|
569
|
-
const parsed = parseHostHeader(options.hostHeader);
|
|
570
|
-
if (!parsed) {
|
|
571
|
-
return "Invalid Host header";
|
|
572
|
-
}
|
|
573
|
-
if (parsed.port !== undefined && parsed.port !== options.port) {
|
|
574
|
-
return "Invalid Host header port";
|
|
575
|
-
}
|
|
576
|
-
const allowedHosts = new Set(["localhost", "127.0.0.1", "::1", normalizeHostname(options.host)]);
|
|
577
|
-
if (!allowedHosts.has(parsed.hostname)) {
|
|
578
|
-
return "Invalid Host header";
|
|
579
|
-
}
|
|
580
|
-
return;
|
|
581
|
-
}
|
|
582
|
-
function validateBrowserFetchSite2(request) {
|
|
583
|
-
const secFetchSite = request.headers["sec-fetch-site"];
|
|
584
|
-
const value = Array.isArray(secFetchSite) ? secFetchSite[0] : secFetchSite;
|
|
585
|
-
if (!value || value === "same-origin" || value === "none") {
|
|
586
|
-
return;
|
|
587
|
-
}
|
|
588
|
-
return "Cross-origin browser requests are not allowed";
|
|
589
|
-
}
|
|
590
|
-
function validateWebSocketOrigin2(options) {
|
|
591
|
-
if (!options.origin) {
|
|
592
|
-
return options.requireChromeExtension ? "Extension WebSocket origin is required" : undefined;
|
|
593
|
-
}
|
|
594
|
-
if (options.origin === stableUnpackedExtensionOrigin2 || options.additionalChromeExtensionOrigins?.has(options.origin)) {
|
|
595
|
-
return;
|
|
596
|
-
}
|
|
597
|
-
if (options.requireChromeExtension) {
|
|
598
|
-
return "Extension WebSocket origin is not allowed";
|
|
599
|
-
}
|
|
600
|
-
return "WebSocket origin is not allowed";
|
|
601
|
-
}
|
|
602
|
-
function normalizeHostname(host) {
|
|
603
|
-
const value = host.trim().toLowerCase();
|
|
604
|
-
if (value.startsWith("[") && value.endsWith("]")) {
|
|
605
|
-
return value.slice(1, -1);
|
|
606
|
-
}
|
|
607
|
-
return value;
|
|
608
|
-
}
|
|
609
|
-
function parseHostHeader(hostHeader) {
|
|
610
|
-
const value = hostHeader?.trim().toLowerCase();
|
|
611
|
-
if (!value) {
|
|
612
|
-
return;
|
|
613
|
-
}
|
|
614
|
-
if (value.startsWith("[")) {
|
|
615
|
-
const closingBracket = value.indexOf("]");
|
|
616
|
-
if (closingBracket === -1) {
|
|
617
|
-
return;
|
|
618
|
-
}
|
|
619
|
-
const hostname = value.slice(1, closingBracket);
|
|
620
|
-
const rest = value.slice(closingBracket + 1);
|
|
621
|
-
if (!hostname) {
|
|
622
|
-
return;
|
|
623
|
-
}
|
|
624
|
-
if (!rest) {
|
|
625
|
-
return { hostname };
|
|
626
|
-
}
|
|
627
|
-
if (!rest.startsWith(":")) {
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
const port = parsePort(rest.slice(1));
|
|
631
|
-
return port === undefined ? undefined : { hostname, port };
|
|
632
|
-
}
|
|
633
|
-
if (value === "::1") {
|
|
634
|
-
return { hostname: "::1" };
|
|
635
|
-
}
|
|
636
|
-
const colonCount = value.split(":").length - 1;
|
|
637
|
-
if (colonCount > 1) {
|
|
638
|
-
return;
|
|
639
|
-
}
|
|
640
|
-
if (colonCount === 0) {
|
|
641
|
-
return { hostname: value };
|
|
642
|
-
}
|
|
643
|
-
const [hostname, portText] = value.split(":");
|
|
644
|
-
if (!hostname || portText === undefined) {
|
|
645
|
-
return;
|
|
646
|
-
}
|
|
647
|
-
const port = parsePort(portText);
|
|
648
|
-
return port === undefined ? undefined : { hostname, port };
|
|
649
|
-
}
|
|
650
|
-
function parsePort(value) {
|
|
651
|
-
if (!/^\d+$/.test(value)) {
|
|
652
|
-
return;
|
|
653
|
-
}
|
|
654
|
-
const port = Number(value);
|
|
655
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
656
|
-
return;
|
|
657
|
-
}
|
|
658
|
-
return port;
|
|
659
|
-
}
|
|
660
544
|
function listenHttpServer2(options) {
|
|
661
545
|
return Effect.callback((resume) => {
|
|
662
546
|
const onError = (error) => {
|
|
@@ -791,22 +675,149 @@ function readJsonBody2(request) {
|
|
|
791
675
|
});
|
|
792
676
|
});
|
|
793
677
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
678
|
+
|
|
679
|
+
// src/relay/origins.ts
|
|
680
|
+
import crypto from "node:crypto";
|
|
681
|
+
var stableUnpackedExtensionOrigin2 = `chrome-extension://${unpackedExtensionId}`;
|
|
682
|
+
function chromeExtensionOriginForPath2(extensionPath, platform = process.platform) {
|
|
683
|
+
const normalizedPath = platform === "win32" && /^[a-z]:/.test(extensionPath) ? extensionPath.charAt(0).toUpperCase() + extensionPath.slice(1) : extensionPath;
|
|
684
|
+
const pathBytes = platform === "win32" ? Buffer.from(normalizedPath, "utf16le") : normalizedPath;
|
|
685
|
+
const digest = crypto.createHash("sha256").update(pathBytes).digest();
|
|
686
|
+
let extensionId = "";
|
|
687
|
+
for (const byte of digest.subarray(0, 16)) {
|
|
688
|
+
extensionId += String.fromCharCode(97 + (byte >> 4), 97 + (byte & 15));
|
|
689
|
+
}
|
|
690
|
+
return `chrome-extension://${extensionId}`;
|
|
691
|
+
}
|
|
692
|
+
var chromeExtensionOriginPattern = /^chrome-extension:\/\/[a-p]+$/;
|
|
693
|
+
function parseAdditionalExtensionOrigins2(raw) {
|
|
694
|
+
if (!raw) {
|
|
695
|
+
return [];
|
|
696
|
+
}
|
|
697
|
+
const seen = new Set;
|
|
698
|
+
const origins = [];
|
|
699
|
+
for (const token of raw.split(/[\s,]+/)) {
|
|
700
|
+
const value = token.trim();
|
|
701
|
+
if (!value || !chromeExtensionOriginPattern.test(value) || seen.has(value)) {
|
|
702
|
+
continue;
|
|
703
|
+
}
|
|
704
|
+
seen.add(value);
|
|
705
|
+
origins.push(value);
|
|
706
|
+
}
|
|
707
|
+
return origins;
|
|
708
|
+
}
|
|
709
|
+
function validateHostHeader2(options) {
|
|
710
|
+
const parsed = parseHostHeader(options.hostHeader);
|
|
711
|
+
if (!parsed) {
|
|
712
|
+
return "Invalid Host header";
|
|
713
|
+
}
|
|
714
|
+
if (parsed.port !== undefined && parsed.port !== options.port) {
|
|
715
|
+
return "Invalid Host header port";
|
|
716
|
+
}
|
|
717
|
+
const allowedHosts = new Set(["localhost", "127.0.0.1", "::1", normalizeHostname(options.host)]);
|
|
718
|
+
if (!allowedHosts.has(parsed.hostname)) {
|
|
719
|
+
return "Invalid Host header";
|
|
720
|
+
}
|
|
721
|
+
return;
|
|
722
|
+
}
|
|
723
|
+
function validateBrowserFetchSite2(request) {
|
|
724
|
+
const secFetchSite = request.headers["sec-fetch-site"];
|
|
725
|
+
const value = Array.isArray(secFetchSite) ? secFetchSite[0] : secFetchSite;
|
|
726
|
+
if (!value || value === "same-origin" || value === "none") {
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
return "Cross-origin browser requests are not allowed";
|
|
730
|
+
}
|
|
731
|
+
function validateWebSocketOrigin2(options) {
|
|
732
|
+
if (!options.origin) {
|
|
733
|
+
return options.requireChromeExtension ? "Extension WebSocket origin is required" : undefined;
|
|
734
|
+
}
|
|
735
|
+
if (options.origin === stableUnpackedExtensionOrigin2 || options.additionalChromeExtensionOrigins?.has(options.origin)) {
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
if (options.requireChromeExtension) {
|
|
739
|
+
return "Extension WebSocket origin is not allowed";
|
|
740
|
+
}
|
|
741
|
+
return "WebSocket origin is not allowed";
|
|
742
|
+
}
|
|
743
|
+
function normalizeHostname(host) {
|
|
744
|
+
const value = host.trim().toLowerCase();
|
|
745
|
+
if (value.startsWith("[") && value.endsWith("]")) {
|
|
746
|
+
return value.slice(1, -1);
|
|
747
|
+
}
|
|
748
|
+
return value;
|
|
749
|
+
}
|
|
750
|
+
function parseHostHeader(hostHeader) {
|
|
751
|
+
const value = hostHeader?.trim().toLowerCase();
|
|
752
|
+
if (!value) {
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
755
|
+
if (value.startsWith("[")) {
|
|
756
|
+
const closingBracket = value.indexOf("]");
|
|
757
|
+
if (closingBracket === -1) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
const hostname = value.slice(1, closingBracket);
|
|
761
|
+
const rest = value.slice(closingBracket + 1);
|
|
762
|
+
if (!hostname) {
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (!rest) {
|
|
766
|
+
return { hostname };
|
|
767
|
+
}
|
|
768
|
+
if (!rest.startsWith(":")) {
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
const port = parsePort(rest.slice(1));
|
|
772
|
+
return port === undefined ? undefined : { hostname, port };
|
|
773
|
+
}
|
|
774
|
+
if (value === "::1") {
|
|
775
|
+
return { hostname: "::1" };
|
|
776
|
+
}
|
|
777
|
+
const colonCount = value.split(":").length - 1;
|
|
778
|
+
if (colonCount > 1) {
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (colonCount === 0) {
|
|
782
|
+
return { hostname: value };
|
|
783
|
+
}
|
|
784
|
+
const [hostname, portText] = value.split(":");
|
|
785
|
+
if (!hostname || portText === undefined) {
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
788
|
+
const port = parsePort(portText);
|
|
789
|
+
return port === undefined ? undefined : { hostname, port };
|
|
790
|
+
}
|
|
791
|
+
function parsePort(value) {
|
|
792
|
+
if (!/^\d+$/.test(value)) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
const port = Number(value);
|
|
796
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
797
|
+
return;
|
|
798
|
+
}
|
|
799
|
+
return port;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/relay/helpers.ts
|
|
803
|
+
var defaultHost2 = "127.0.0.1";
|
|
804
|
+
var defaultPort2 = 19988;
|
|
805
|
+
var RawTargetSelection = Schema3.Struct({
|
|
806
|
+
urlIncludes: Schema3.optionalKey(Schema3.String),
|
|
807
|
+
index: Schema3.optionalKey(Schema3.Int.check(Schema3.isGreaterThanOrEqualTo(0)))
|
|
797
808
|
});
|
|
798
|
-
var decodeRawTargetSelection =
|
|
799
|
-
var RawTargetInfo =
|
|
800
|
-
targetId:
|
|
801
|
-
type:
|
|
802
|
-
title:
|
|
803
|
-
url:
|
|
804
|
-
canAccessOpener:
|
|
805
|
-
browserContextId:
|
|
806
|
-
openerId:
|
|
807
|
-
parentFrameId:
|
|
809
|
+
var decodeRawTargetSelection = Schema3.decodeUnknownOption(RawTargetSelection);
|
|
810
|
+
var RawTargetInfo = Schema3.Struct({
|
|
811
|
+
targetId: Schema3.String,
|
|
812
|
+
type: Schema3.Literals(["page", "iframe", "worker"]),
|
|
813
|
+
title: Schema3.optionalKey(Schema3.String),
|
|
814
|
+
url: Schema3.String,
|
|
815
|
+
canAccessOpener: Schema3.optionalKey(Schema3.Boolean),
|
|
816
|
+
browserContextId: Schema3.optionalKey(Schema3.String),
|
|
817
|
+
openerId: Schema3.optionalKey(Schema3.String),
|
|
818
|
+
parentFrameId: Schema3.optionalKey(Schema3.String)
|
|
808
819
|
});
|
|
809
|
-
var decodeRawTargetInfo =
|
|
820
|
+
var decodeRawTargetInfo = Schema3.decodeUnknownOption(RawTargetInfo);
|
|
810
821
|
function optionalSessionId2(value) {
|
|
811
822
|
if (!Predicate.isString(value) || !value.trim()) {
|
|
812
823
|
return;
|
|
@@ -947,7 +958,7 @@ async function dataUrlDocument2(url) {
|
|
|
947
958
|
}
|
|
948
959
|
|
|
949
960
|
// src/relay/lifecycle.ts
|
|
950
|
-
import { Config as Config2, Effect as Effect3, Result, Schedule, Schema as
|
|
961
|
+
import { Config as Config2, Effect as Effect3, Result, Schedule, Schema as Schema5 } from "effect";
|
|
951
962
|
import { spawn } from "node:child_process";
|
|
952
963
|
import crypto2 from "node:crypto";
|
|
953
964
|
import path from "node:path";
|
|
@@ -956,52 +967,52 @@ import { fileURLToPath } from "node:url";
|
|
|
956
967
|
|
|
957
968
|
// src/relay/client.ts
|
|
958
969
|
import { NodeHttpClient } from "@effect/platform-node";
|
|
959
|
-
import { Config, Context, Effect as Effect2, Layer, Option as Option2, Schema as
|
|
970
|
+
import { Config, Context, Effect as Effect2, Layer, Option as Option2, Schema as Schema4 } from "effect";
|
|
960
971
|
import { HttpClient, HttpClientRequest } from "effect/http";
|
|
961
972
|
var portConfig = Config.Int("OPENCODE_BROWSER_PORT").pipe(Config.withDefault(defaultPort2));
|
|
962
973
|
var extensionOriginsConfig = Config.String("OPENCODE_BROWSER_EXTENSION_ORIGINS").pipe(Config.withDefault(""));
|
|
963
974
|
var endpointForPort = (port) => `http://127.0.0.1:${port}`;
|
|
964
975
|
|
|
965
|
-
class RelayUnreachable extends
|
|
966
|
-
message:
|
|
967
|
-
endpoint:
|
|
968
|
-
path:
|
|
969
|
-
cause:
|
|
976
|
+
class RelayUnreachable extends Schema4.TaggedError()("RelayClient.RelayUnreachable", {
|
|
977
|
+
message: Schema4.String,
|
|
978
|
+
endpoint: Schema4.String,
|
|
979
|
+
path: Schema4.String,
|
|
980
|
+
cause: Schema4.Defect()
|
|
970
981
|
}) {
|
|
971
982
|
}
|
|
972
983
|
|
|
973
|
-
class RelayRejected extends
|
|
974
|
-
message:
|
|
975
|
-
status:
|
|
976
|
-
path:
|
|
977
|
-
code:
|
|
984
|
+
class RelayRejected extends Schema4.TaggedError()("RelayClient.RelayRejected", {
|
|
985
|
+
message: Schema4.String,
|
|
986
|
+
status: Schema4.Number,
|
|
987
|
+
path: Schema4.String,
|
|
988
|
+
code: Schema4.optionalKey(RelayErrorCode)
|
|
978
989
|
}) {
|
|
979
990
|
}
|
|
980
991
|
|
|
981
|
-
class RelayDecodeFailed extends
|
|
982
|
-
message:
|
|
983
|
-
path:
|
|
984
|
-
cause:
|
|
992
|
+
class RelayDecodeFailed extends Schema4.TaggedError()("RelayClient.RelayDecodeFailed", {
|
|
993
|
+
message: Schema4.String,
|
|
994
|
+
path: Schema4.String,
|
|
995
|
+
cause: Schema4.Defect()
|
|
985
996
|
}) {
|
|
986
997
|
}
|
|
987
998
|
|
|
988
|
-
class RelayEncodeFailed extends
|
|
989
|
-
message:
|
|
990
|
-
path:
|
|
991
|
-
cause:
|
|
999
|
+
class RelayEncodeFailed extends Schema4.TaggedError()("RelayClient.RelayEncodeFailed", {
|
|
1000
|
+
message: Schema4.String,
|
|
1001
|
+
path: Schema4.String,
|
|
1002
|
+
cause: Schema4.Defect()
|
|
992
1003
|
}) {
|
|
993
1004
|
}
|
|
994
1005
|
|
|
995
|
-
class RelayConfigInvalid extends
|
|
996
|
-
message:
|
|
997
|
-
cause:
|
|
1006
|
+
class RelayConfigInvalid extends Schema4.TaggedError()("RelayClient.RelayConfigInvalid", {
|
|
1007
|
+
message: Schema4.String,
|
|
1008
|
+
cause: Schema4.Defect()
|
|
998
1009
|
}) {
|
|
999
1010
|
}
|
|
1000
1011
|
|
|
1001
1012
|
class Service extends Context.Service()("opencode-browser-cli/RelayClient") {
|
|
1002
1013
|
}
|
|
1003
|
-
var decodeErrorEnvelope =
|
|
1004
|
-
var decodeErrorMessage =
|
|
1014
|
+
var decodeErrorEnvelope = Schema4.decodeUnknownOption(ErrorEnvelope);
|
|
1015
|
+
var decodeErrorMessage = Schema4.decodeUnknownOption(Schema4.Struct({ error: Schema4.String }));
|
|
1005
1016
|
var make = Effect2.fn("RelayClient.make")(function* (options) {
|
|
1006
1017
|
const port = yield* portConfig.pipe(Effect2.mapError((cause) => new RelayConfigInvalid({
|
|
1007
1018
|
message: `Invalid OPENCODE_BROWSER_PORT configuration: ${cause.message}`,
|
|
@@ -1025,14 +1036,14 @@ var make = Effect2.fn("RelayClient.make")(function* (options) {
|
|
|
1025
1036
|
...Option2.isSome(envelope) && envelope.value.code ? { code: envelope.value.code } : {}
|
|
1026
1037
|
}));
|
|
1027
1038
|
}
|
|
1028
|
-
return
|
|
1039
|
+
return Schema4.decodeUnknownEffect(schema)(body).pipe(Effect2.mapError((cause) => new RelayDecodeFailed({
|
|
1029
1040
|
message: `Relay response for ${path} did not match the expected shape: ${cause.message}`,
|
|
1030
1041
|
path,
|
|
1031
1042
|
cause
|
|
1032
1043
|
})));
|
|
1033
1044
|
}));
|
|
1034
1045
|
const transportError = (path) => (cause) => new RelayUnreachable({
|
|
1035
|
-
message: `
|
|
1046
|
+
message: `browse relay is not reachable at ${endpoint}. Relay-backed CLI commands start it automatically; use \`${cliCommand("serve")}\` only for foreground debugging.`,
|
|
1036
1047
|
endpoint,
|
|
1037
1048
|
path,
|
|
1038
1049
|
cause
|
|
@@ -1127,7 +1138,7 @@ function mcpClientPid() {
|
|
|
1127
1138
|
var layerFetchMcp = Layer.effect(Service, make({ clientPid: mcpClientPid() })).pipe(Layer.provide(NodeHttpClient.layerNodeHttp));
|
|
1128
1139
|
|
|
1129
1140
|
// src/relay/lifecycle.ts
|
|
1130
|
-
var loadedCliEntrypoint = fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? "../main.ts" : "./cli.mjs", import.meta.url));
|
|
1141
|
+
var loadedCliEntrypoint = compiledBinary() ? process2.execPath : fileURLToPath(new URL(import.meta.url.endsWith(".ts") ? "../main.ts" : "./cli.mjs", import.meta.url));
|
|
1131
1142
|
var clientInstanceId = crypto2.randomUUID();
|
|
1132
1143
|
function shouldWaitForExtensionReconnect(readiness) {
|
|
1133
1144
|
return readiness.started || readiness.waitForReconnect === true;
|
|
@@ -1136,19 +1147,19 @@ function shouldWaitForExtensionReconnect(readiness) {
|
|
|
1136
1147
|
class RelayStillRunning extends Error {
|
|
1137
1148
|
}
|
|
1138
1149
|
|
|
1139
|
-
class RelayStartFailed extends
|
|
1140
|
-
message:
|
|
1141
|
-
endpoint:
|
|
1142
|
-
cause:
|
|
1150
|
+
class RelayStartFailed extends Schema5.TaggedError()("RelayLifecycle.RelayStartFailed", {
|
|
1151
|
+
message: Schema5.String,
|
|
1152
|
+
endpoint: Schema5.String,
|
|
1153
|
+
cause: Schema5.Defect()
|
|
1143
1154
|
}) {
|
|
1144
1155
|
}
|
|
1145
1156
|
|
|
1146
|
-
class ExtensionDisconnected extends
|
|
1157
|
+
class ExtensionDisconnected extends Schema5.TaggedError()("RelayLifecycle.ExtensionDisconnected", { message: Schema5.String, needsPairing: Schema5.optionalKey(Schema5.Boolean) }) {
|
|
1147
1158
|
}
|
|
1148
1159
|
|
|
1149
|
-
class ExtensionProtocolIncompatible extends
|
|
1150
|
-
message:
|
|
1151
|
-
protocolVersion:
|
|
1160
|
+
class ExtensionProtocolIncompatible extends Schema5.TaggedError()("RelayLifecycle.ExtensionProtocolIncompatible", {
|
|
1161
|
+
message: Schema5.String,
|
|
1162
|
+
protocolVersion: Schema5.NullOr(Schema5.Number)
|
|
1152
1163
|
}) {
|
|
1153
1164
|
}
|
|
1154
1165
|
function supersededRuntime() {
|
|
@@ -1205,7 +1216,7 @@ function waitForRelayReady(options) {
|
|
|
1205
1216
|
schedule: Schedule.spaced(options.retryDelayMs ?? 50),
|
|
1206
1217
|
while: isRelayStartingOrUnreachable
|
|
1207
1218
|
}), Effect3.mapError((error) => isRelayStartingOrUnreachable(error) ? new RelayStartFailed({
|
|
1208
|
-
message: `
|
|
1219
|
+
message: `browse relay did not start at ${options.relay.endpoint}`,
|
|
1209
1220
|
endpoint: options.relay.endpoint,
|
|
1210
1221
|
cause: error
|
|
1211
1222
|
}) : error));
|
|
@@ -1278,7 +1289,7 @@ var restartRelay = Effect3.fn("RelayLifecycle.restartRelay")(function* (options)
|
|
|
1278
1289
|
return { version: replacement, started, waitForReconnect: true };
|
|
1279
1290
|
});
|
|
1280
1291
|
function waitForRelayExitOrReplacement(options) {
|
|
1281
|
-
return options.relay.version.pipe(Effect3.flatMap((version) => isSameRelayInstance(options.version, version) ? Effect3.fail(new RelayStillRunning("
|
|
1292
|
+
return options.relay.version.pipe(Effect3.flatMap((version) => isSameRelayInstance(options.version, version) ? Effect3.fail(new RelayStillRunning("browse relay is still draining; no replacement was started")) : Effect3.succeed(version)), Effect3.catch((error) => isRelayUnreachable(error) ? Effect3.succeed(undefined) : Effect3.fail(error)), Effect3.retry({
|
|
1282
1293
|
times: options.retryTimes ?? 200,
|
|
1283
1294
|
schedule: Schedule.spaced(options.retryDelayMs ?? 50),
|
|
1284
1295
|
while: (error) => error instanceof RelayStillRunning || isRelayStarting(error)
|
|
@@ -1311,7 +1322,7 @@ var ensureExtensionConnected = Effect3.fn("RelayLifecycle.ensureExtensionConnect
|
|
|
1311
1322
|
}));
|
|
1312
1323
|
}
|
|
1313
1324
|
return status.connected ? Effect3.succeed(status) : Effect3.fail(new ExtensionDisconnected({
|
|
1314
|
-
message: status.nextStep ?? `
|
|
1325
|
+
message: status.nextStep ?? `browse extension is not connected. Open the browser with browse installed (\`${installCommand()}\`); it reconnects automatically after relay or browser startup.`,
|
|
1315
1326
|
needsPairing: status.pairingState === "refused" || status.pairingState === "unpaired"
|
|
1316
1327
|
}));
|
|
1317
1328
|
}));
|
|
@@ -1351,7 +1362,7 @@ function startManagedRelay(entrypoint = loadedCliEntrypoint, executable = proces
|
|
|
1351
1362
|
});
|
|
1352
1363
|
child.unref();
|
|
1353
1364
|
},
|
|
1354
|
-
catch: (cause) => cause instanceof Error ? cause : new Error("Failed to start
|
|
1365
|
+
catch: (cause) => cause instanceof Error ? cause : new Error("Failed to start browse relay", { cause })
|
|
1355
1366
|
});
|
|
1356
1367
|
}
|
|
1357
1368
|
var relayEnvironmentNames = new Set([
|
|
@@ -1403,6 +1414,8 @@ function relayEnvironment(env) {
|
|
|
1403
1414
|
}));
|
|
1404
1415
|
}
|
|
1405
1416
|
function managedRelayLaunch(entrypoint = loadedCliEntrypoint, executable = process2.execPath, execArgv = process2.execArgv) {
|
|
1417
|
+
if (!scriptEntry(entrypoint))
|
|
1418
|
+
return { executable: entrypoint, args: ["serve"] };
|
|
1406
1419
|
return {
|
|
1407
1420
|
executable,
|
|
1408
1421
|
args: [...execArgv, managedRelayEntrypoint(entrypoint), "serve"]
|
|
@@ -1424,4 +1437,4 @@ function isRelayStartingOrUnreachable(error) {
|
|
|
1424
1437
|
return isRelayStarting(error) || isRelayUnreachable(error);
|
|
1425
1438
|
}
|
|
1426
1439
|
|
|
1427
|
-
export { ExecuteRequest, SessionAdoptRequest, SessionNewRequest, SessionEnsureRequest, SessionIdRequest, SessionAllowlistRequest, AuthenticatedJsonRequest, AuthenticatedJsonOutcome, RelayShutdownRequest, NetworkStartRequest, NetworkSessionRequest, NetworkStopRequest, DeadboltLoginsRequest, AuthProfileRequest, AuthRefreshRequest, AuthRunRequest, RecordingTargetRequest, RecordingStartRequest, FlightRecorderStartRequest, FlightRecorderSaveRequest,
|
|
1440
|
+
export { ExecuteRequest, SessionAdoptRequest, SessionNewRequest, SessionEnsureRequest, SessionIdRequest, SessionAllowlistRequest, AuthenticatedJsonRequest, AuthenticatedJsonOutcome, RelayShutdownRequest, NetworkStartRequest, NetworkSessionRequest, NetworkStopRequest, DeadboltLoginsRequest, AuthProfileRequest, AuthRefreshRequest, AuthRunRequest, RecordingTargetRequest, RecordingStartRequest, FlightRecorderStartRequest, FlightRecorderSaveRequest, HttpRouteError2, formatHostForUrl2, listenHttpServer2, closeHttpServer2, closeWebSocketServer2, logCloseError2, sendJson2, readJsonBody2, stableUnpackedExtensionOrigin2, chromeExtensionOriginForPath2, parseAdditionalExtensionOrigins2, validateHostHeader2, validateBrowserFetchSite2, validateWebSocketOrigin2, defaultHost2, defaultPort2, optionalSessionId2, isValidSessionId2, requiredSessionId2, parseTargetSelection2, generateSessionId2, sendCdpResponse2, sendCdpEvent2, getObject2, getString2, getNumber2, getIdText2, headerValue2, getTargetInfo2, isRestrictedTarget2, isRestrictedUrl2, dataUrlDocument2, portConfig, extensionOriginsConfig, endpointForPort, RelayUnreachable, RelayRejected, Service, layerFetch, layerFetchMcp, shouldWaitForExtensionReconnect, relayBuildProblem, ensureRelay, restartRelay, extensionReconnectWaitMs, ensureExtensionConnected, stoppedRelayStatus, statusCollections, startManagedRelay };
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {
|
|
2
2
|
isNodeError
|
|
3
|
-
} from "./main-
|
|
4
|
-
import {
|
|
5
|
-
dataRoot
|
|
6
|
-
} from "./main-yd50d95g.mjs";
|
|
3
|
+
} from "./main-7qs0mwvc.mjs";
|
|
7
4
|
import {
|
|
8
5
|
isValidSessionId2
|
|
9
|
-
} from "./main-
|
|
6
|
+
} from "./main-qm2keaeb.mjs";
|
|
7
|
+
import {
|
|
8
|
+
dataRoot
|
|
9
|
+
} from "./main-0m569gdn.mjs";
|
|
10
10
|
|
|
11
11
|
// src/session-manager/journal.ts
|
|
12
12
|
import fs from "node:fs";
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
dataRoot,
|
|
3
|
-
cliCommand
|
|
4
|
-
} from "./main-yd50d95g.mjs";
|
|
5
1
|
import {
|
|
6
2
|
parseTargetSelection2,
|
|
7
3
|
getObject2,
|
|
8
4
|
getString2
|
|
9
|
-
} from "./main-
|
|
5
|
+
} from "./main-qm2keaeb.mjs";
|
|
10
6
|
import {
|
|
11
7
|
isNodeError,
|
|
12
8
|
writeJsonFileAtomically
|
|
13
|
-
} from "./main-
|
|
9
|
+
} from "./main-7qs0mwvc.mjs";
|
|
10
|
+
import {
|
|
11
|
+
dataRoot,
|
|
12
|
+
cliCommand
|
|
13
|
+
} from "./main-0m569gdn.mjs";
|
|
14
14
|
|
|
15
15
|
// src/relay/user-settings.ts
|
|
16
16
|
var settingKeys = ["window", "grouping", "idleMinutes", "cursor", "humanInput", "handoffNotifications", "autoUpdate"];
|
|
@@ -145,7 +145,7 @@ function browsersNote2(browsers) {
|
|
|
145
145
|
return ` Connected browsers: ${list}. Pass browser to use one other than the default.`;
|
|
146
146
|
}
|
|
147
147
|
function mcpUpdateNote2(notice) {
|
|
148
|
-
return `Note:
|
|
148
|
+
return `Note: browse has an update: ${notice.summary}. Tell the user they can run \`${notice.command}\` and then restart opencode, or ask you to run it for them.`;
|
|
149
149
|
}
|
|
150
150
|
function objectSchema(properties, required = []) {
|
|
151
151
|
return {
|
|
@@ -410,7 +410,7 @@ function errorCode(code) {
|
|
|
410
410
|
}
|
|
411
411
|
var errorHints = {
|
|
412
412
|
locked: "Deadbolt is locked, so agent sign-ins are paused until the user unlocks it.",
|
|
413
|
-
forbidden: "Deadbolt doesn't know this
|
|
413
|
+
forbidden: "Deadbolt doesn't know this browse install (its client was removed or revoked). Ask the user to run `opencode-browser deadbolt connect`.",
|
|
414
414
|
rate_limited: "Deadbolt is rate-limiting this client; wait before trying again."
|
|
415
415
|
};
|
|
416
416
|
function rawRequest(socket, request, timeoutMs = requestTimeoutMs) {
|
|
@@ -502,7 +502,7 @@ function toLogin(raw) {
|
|
|
502
502
|
function connect(options = {}) {
|
|
503
503
|
const client = options.client ?? readClient(options.root);
|
|
504
504
|
if (!client) {
|
|
505
|
-
throw new DeadboltError("not_connected", "
|
|
505
|
+
throw new DeadboltError("not_connected", "browse isn't connected to Deadbolt. Ask the user to run `opencode-browser deadbolt connect` and to allow the logins agents may use with `deadbolt agents allow <site>`.");
|
|
506
506
|
}
|
|
507
507
|
const socket = options.socket ?? socketPath();
|
|
508
508
|
let protocol;
|
|
@@ -604,7 +604,7 @@ function pickLogin(logins, site, username, field) {
|
|
|
604
604
|
if (candidates.length === 1)
|
|
605
605
|
return candidates[0];
|
|
606
606
|
if (candidates.length === 0) {
|
|
607
|
-
throw new DeadboltError("not_granted", username === undefined ? `No Deadbolt login is granted to
|
|
607
|
+
throw new DeadboltError("not_granted", username === undefined ? `No Deadbolt login is granted to browse for ${site}${field ? ` (${field})` : ""}. Ask the user to allow one with \`deadbolt agents allow ${site}\`.` : `No Deadbolt login for ${username} is granted to browse for ${site}${field ? ` (${field})` : ""}. Ask the user to allow it with \`deadbolt agents allow ${site} --login ${username}\`.`, { site, ...username ? { login: username } : {} });
|
|
608
608
|
}
|
|
609
609
|
throw new DeadboltError("failed", `Several Deadbolt logins are granted for ${site}; name one: deadbolt:${site}/<username> (${candidates.map((login) => login.username ?? login.title).join(", ")})`);
|
|
610
610
|
}
|