@ai-sdk/harness-claude-code 1.0.73 → 1.0.75
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 +20 -0
- package/dist/index.d.ts +8 -2
- package/dist/index.js +174 -69
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/claude-code-auth.ts +99 -8
- package/src/claude-code-bootstrap.ts +65 -0
- package/src/claude-code-harness.ts +84 -87
- package/src/index.ts +4 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @ai-sdk/harness-claude-code
|
|
2
2
|
|
|
3
|
+
## 1.0.75
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 69bb613: feat(harness): support request transformations in network sandbox abstraction and use it to apply credential brokering when available
|
|
8
|
+
- 52bc889: feat(harness): add `getPortEndpoint()` as more comprehensive replacement to `getPortUrl()` (now deprecated) in `HarnessV1NetworkSandboxSession`
|
|
9
|
+
- 4cd4989: chore(harness): decouple bridge based harness bootstrap recipe logic from dynamic params and enforce unique harnesses in `prepareSandboxForHarness()` helper
|
|
10
|
+
- Updated dependencies [69bb613]
|
|
11
|
+
- Updated dependencies [52bc889]
|
|
12
|
+
- Updated dependencies [4cd4989]
|
|
13
|
+
- @ai-sdk/harness@1.0.72
|
|
14
|
+
|
|
15
|
+
## 1.0.74
|
|
16
|
+
|
|
17
|
+
### Patch Changes
|
|
18
|
+
|
|
19
|
+
- 83fe754: chore(harness): simplify the `auth` param to be a simple string to choose the auth method
|
|
20
|
+
- Updated dependencies [8d717b3]
|
|
21
|
+
- @ai-sdk/harness@1.0.71
|
|
22
|
+
|
|
3
23
|
## 1.0.73
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,12 @@ import { Experimental_SandboxSession } from '@ai-sdk/provider-utils';
|
|
|
4
4
|
import * as _ai_sdk_harness from '@ai-sdk/harness';
|
|
5
5
|
import { HarnessV1, HarnessV1BuiltinTool } from '@ai-sdk/harness';
|
|
6
6
|
|
|
7
|
-
type
|
|
7
|
+
type ClaudeCodeResolvedAuthenticationMode = 'direct' | 'ai-gateway';
|
|
8
|
+
type ClaudeCodeAuthenticationMode = ClaudeCodeResolvedAuthenticationMode | 'auto';
|
|
9
|
+
/**
|
|
10
|
+
* @deprecated Passing an object to auth options is deprecated. Use a `ClaudeCodeAuthenticationMode` string value ("auto" | "direct" | "ai-gateway") instead, and pass credentials via environment variables.
|
|
11
|
+
*/
|
|
12
|
+
type LegacyClaudeCodeAuthOptions = {
|
|
8
13
|
readonly anthropic?: {
|
|
9
14
|
readonly apiKey?: string;
|
|
10
15
|
readonly authToken?: string;
|
|
@@ -15,6 +20,7 @@ type ClaudeCodeAuthOptions = {
|
|
|
15
20
|
readonly baseUrl?: string;
|
|
16
21
|
};
|
|
17
22
|
};
|
|
23
|
+
type ClaudeCodeAuthOptions = ClaudeCodeAuthenticationMode | LegacyClaudeCodeAuthOptions;
|
|
18
24
|
|
|
19
25
|
type ClaudeCodeThinkingConfig = {
|
|
20
26
|
readonly type: 'adaptive' | 'enabled';
|
|
@@ -25428,4 +25434,4 @@ declare const claudeCode: _ai_sdk_harness.HarnessV1<{
|
|
|
25428
25434
|
};
|
|
25429
25435
|
}>;
|
|
25430
25436
|
|
|
25431
|
-
export { type ClaudeCodeAuthOptions, type ClaudeCodeHarnessSettings, type ClaudeCodeThinkingConfig, VERSION, claudeCode, createClaudeCode };
|
|
25437
|
+
export { type ClaudeCodeAuthOptions, type ClaudeCodeAuthenticationMode, type ClaudeCodeHarnessSettings, type ClaudeCodeThinkingConfig, VERSION, claudeCode, createClaudeCode };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
// src/claude-code-harness.ts
|
|
2
2
|
import { randomBytes } from "crypto";
|
|
3
|
-
import { readFile } from "fs/promises";
|
|
4
3
|
import { posix } from "path";
|
|
5
|
-
import { fileURLToPath } from "url";
|
|
6
4
|
import {
|
|
7
5
|
commonTool,
|
|
8
6
|
harnessV1DiagnosticFromBridgeFrame,
|
|
@@ -15,9 +13,11 @@ import {
|
|
|
15
13
|
drainBridgeProcessStream,
|
|
16
14
|
forwardBridgeProcessStream,
|
|
17
15
|
markBridgeStarting,
|
|
16
|
+
maskSandboxCredentials,
|
|
18
17
|
resolveSandboxHomeDir,
|
|
19
18
|
SandboxChannel,
|
|
20
19
|
shellQuote,
|
|
20
|
+
warnCredentialBrokeringUnavailable,
|
|
21
21
|
waitForBridgeReady,
|
|
22
22
|
writeSkills as writeHarnessSkills
|
|
23
23
|
} from "@ai-sdk/harness/utils";
|
|
@@ -28,21 +28,98 @@ import {
|
|
|
28
28
|
import { WebSocket } from "ws";
|
|
29
29
|
import { z as z2 } from "zod/v4";
|
|
30
30
|
|
|
31
|
+
// src/claude-code-bootstrap.ts
|
|
32
|
+
import { readFile } from "fs/promises";
|
|
33
|
+
import { fileURLToPath } from "url";
|
|
34
|
+
var CLAUDE_CODE_BOOTSTRAP_DIR = ".harness-bootstrap/claude-code";
|
|
35
|
+
var cachedBootstrap;
|
|
36
|
+
async function getClaudeCodeBootstrap() {
|
|
37
|
+
if (cachedBootstrap != null) return cachedBootstrap;
|
|
38
|
+
const [pkg, lock, bridge] = await Promise.all([
|
|
39
|
+
readBridgeAsset("package.json"),
|
|
40
|
+
readBridgeAsset("pnpm-lock.yaml"),
|
|
41
|
+
readBridgeAsset("index.mjs")
|
|
42
|
+
]);
|
|
43
|
+
cachedBootstrap = {
|
|
44
|
+
harnessId: "claude-code",
|
|
45
|
+
bootstrapDir: CLAUDE_CODE_BOOTSTRAP_DIR,
|
|
46
|
+
files: [
|
|
47
|
+
{ path: `${CLAUDE_CODE_BOOTSTRAP_DIR}/package.json`, content: pkg },
|
|
48
|
+
{ path: `${CLAUDE_CODE_BOOTSTRAP_DIR}/pnpm-lock.yaml`, content: lock },
|
|
49
|
+
{ path: `${CLAUDE_CODE_BOOTSTRAP_DIR}/bridge.mjs`, content: bridge }
|
|
50
|
+
],
|
|
51
|
+
commands: [
|
|
52
|
+
{
|
|
53
|
+
command: "pnpm install --frozen-lockfile --store-dir .pnpm-store"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
command: "if [ -f node_modules/@anthropic-ai/claude-code/install.cjs ]; then node node_modules/@anthropic-ai/claude-code/install.cjs; fi && ./node_modules/.bin/claude --version"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
};
|
|
60
|
+
return cachedBootstrap;
|
|
61
|
+
}
|
|
62
|
+
async function readBridgeAsset(name) {
|
|
63
|
+
const candidates = [
|
|
64
|
+
new URL(`./bridge/${name}`, import.meta.url),
|
|
65
|
+
new URL(`../bridge/${name}`, import.meta.url)
|
|
66
|
+
];
|
|
67
|
+
let lastErr;
|
|
68
|
+
for (const url of candidates) {
|
|
69
|
+
try {
|
|
70
|
+
return await readFile(fileURLToPath(url), "utf8");
|
|
71
|
+
} catch (err) {
|
|
72
|
+
const code = err.code;
|
|
73
|
+
if (code !== "ENOENT") throw err;
|
|
74
|
+
lastErr = err;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
throw lastErr ?? new Error(`bridge asset not found: ${name}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
31
80
|
// src/claude-code-auth.ts
|
|
32
81
|
import { execFileSync } from "child_process";
|
|
33
82
|
import { readFileSync } from "fs";
|
|
34
83
|
import { homedir } from "os";
|
|
35
84
|
import { join } from "path";
|
|
36
|
-
import {
|
|
85
|
+
import {
|
|
86
|
+
createCredentialRequestTransformation,
|
|
87
|
+
getAiGatewayAuthFromEnv
|
|
88
|
+
} from "@ai-sdk/harness/utils";
|
|
89
|
+
var CLAUDE_CODE_CREDENTIAL_ENVIRONMENT_VARIABLES = [
|
|
90
|
+
"AI_GATEWAY_API_KEY",
|
|
91
|
+
"ANTHROPIC_API_KEY",
|
|
92
|
+
"ANTHROPIC_AUTH_TOKEN"
|
|
93
|
+
];
|
|
94
|
+
function createClaudeCodeRequestTransformations(env, auth) {
|
|
95
|
+
const headers = {};
|
|
96
|
+
if (env.ANTHROPIC_API_KEY) {
|
|
97
|
+
headers["x-api-key"] = env.ANTHROPIC_API_KEY;
|
|
98
|
+
}
|
|
99
|
+
if (env.ANTHROPIC_AUTH_TOKEN) {
|
|
100
|
+
headers.Authorization = `Bearer ${env.ANTHROPIC_AUTH_TOKEN}`;
|
|
101
|
+
}
|
|
102
|
+
return Object.keys(headers).length === 0 ? [] : [
|
|
103
|
+
createCredentialRequestTransformation({
|
|
104
|
+
baseUrl: auth === "ai-gateway" ? env.ANTHROPIC_BASE_URL : env.ANTHROPIC_BASE_URL ?? "https://api.anthropic.com",
|
|
105
|
+
headers
|
|
106
|
+
})
|
|
107
|
+
];
|
|
108
|
+
}
|
|
37
109
|
function resolveClaudeCodeEnv(auth, processEnv = process.env, options = {}) {
|
|
110
|
+
const normalizedAuth = normalizeClaudeCodeAuthToLegacyAuth(auth);
|
|
38
111
|
const readApiKey = options.readApiKeyHelper ?? readApiKeyHelper;
|
|
39
|
-
if (
|
|
40
|
-
return pickAnthropic({
|
|
112
|
+
if (normalizedAuth?.anthropic) {
|
|
113
|
+
return pickAnthropic({
|
|
114
|
+
explicit: normalizedAuth.anthropic,
|
|
115
|
+
processEnv,
|
|
116
|
+
readApiKey
|
|
117
|
+
});
|
|
41
118
|
}
|
|
42
119
|
const gatewayAuthFromEnv = getAiGatewayAuthFromEnv({ env: processEnv });
|
|
43
|
-
if (
|
|
120
|
+
if (normalizedAuth?.gateway) {
|
|
44
121
|
return pickGateway({
|
|
45
|
-
explicit:
|
|
122
|
+
explicit: normalizedAuth.gateway,
|
|
46
123
|
gatewayAuthFromEnv
|
|
47
124
|
});
|
|
48
125
|
}
|
|
@@ -54,6 +131,34 @@ function resolveClaudeCodeEnv(auth, processEnv = process.env, options = {}) {
|
|
|
54
131
|
}
|
|
55
132
|
return pickAnthropic({ processEnv, readApiKey });
|
|
56
133
|
}
|
|
134
|
+
function resolveClaudeCodeAuthenticationMode(auth, processEnv = process.env) {
|
|
135
|
+
if (auth === "direct" || typeof auth !== "string" && auth?.anthropic) {
|
|
136
|
+
return "direct";
|
|
137
|
+
}
|
|
138
|
+
if (auth === "ai-gateway" || typeof auth !== "string" && auth?.gateway) {
|
|
139
|
+
return "ai-gateway";
|
|
140
|
+
}
|
|
141
|
+
return getAiGatewayAuthFromEnv({ env: processEnv }).apiKey ? "ai-gateway" : "direct";
|
|
142
|
+
}
|
|
143
|
+
function normalizeClaudeCodeAuthToLegacyAuth(auth) {
|
|
144
|
+
if (auth == null || auth === "auto") {
|
|
145
|
+
return void 0;
|
|
146
|
+
}
|
|
147
|
+
if (typeof auth === "string") {
|
|
148
|
+
switch (auth) {
|
|
149
|
+
case "direct":
|
|
150
|
+
return { anthropic: {} };
|
|
151
|
+
case "ai-gateway":
|
|
152
|
+
return { gateway: {} };
|
|
153
|
+
default:
|
|
154
|
+
return void 0;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
console.warn(
|
|
158
|
+
'[claude-code] Passing an object to auth options is deprecated. Use a string mode ("auto" | "direct" | "ai-gateway") instead, and pass credentials via environment variables.'
|
|
159
|
+
);
|
|
160
|
+
return auth;
|
|
161
|
+
}
|
|
57
162
|
function pickAnthropic({
|
|
58
163
|
explicit,
|
|
59
164
|
processEnv,
|
|
@@ -153,7 +258,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
153
258
|
]);
|
|
154
259
|
|
|
155
260
|
// src/version.ts
|
|
156
|
-
var VERSION = true ? "1.0.
|
|
261
|
+
var VERSION = true ? "1.0.75" : "0.0.0-test";
|
|
157
262
|
|
|
158
263
|
// src/claude-code-harness.ts
|
|
159
264
|
var CLAUDE_CODE_CLIENT_APP = `ai-sdk/harness-claude-code/${VERSION}`;
|
|
@@ -750,7 +855,6 @@ var CLAUDE_CODE_BUILTIN_TOOLS = {
|
|
|
750
855
|
toolUseKind: "edit"
|
|
751
856
|
}
|
|
752
857
|
};
|
|
753
|
-
var BOOTSTRAP_DIR = ".harness-bootstrap/claude-code";
|
|
754
858
|
var claudeCodeBridgeCoordsSchema = z2.object({
|
|
755
859
|
port: z2.number(),
|
|
756
860
|
token: z2.string(),
|
|
@@ -766,7 +870,6 @@ function createClaudeCode(settings = {}) {
|
|
|
766
870
|
'Claude Code MCP server name "harness-tools" is reserved for HarnessAgent tools.'
|
|
767
871
|
);
|
|
768
872
|
}
|
|
769
|
-
let cachedBootstrap;
|
|
770
873
|
const thinking = settings.thinking ?? {
|
|
771
874
|
type: "adaptive",
|
|
772
875
|
display: "summarized"
|
|
@@ -778,39 +881,44 @@ function createClaudeCode(settings = {}) {
|
|
|
778
881
|
supportsBuiltinToolApprovals: true,
|
|
779
882
|
supportsBuiltinToolFiltering: true,
|
|
780
883
|
lifecycleStateSchema: claudeCodeResumeStateSchema,
|
|
781
|
-
getBootstrap:
|
|
782
|
-
if (cachedBootstrap != null) return cachedBootstrap;
|
|
783
|
-
const [pkg, lock, bridge] = await Promise.all([
|
|
784
|
-
readBridgeAsset("package.json"),
|
|
785
|
-
readBridgeAsset("pnpm-lock.yaml"),
|
|
786
|
-
readBridgeAsset("index.mjs")
|
|
787
|
-
]);
|
|
788
|
-
cachedBootstrap = {
|
|
789
|
-
harnessId: "claude-code",
|
|
790
|
-
bootstrapDir: BOOTSTRAP_DIR,
|
|
791
|
-
files: [
|
|
792
|
-
{ path: `${BOOTSTRAP_DIR}/package.json`, content: pkg },
|
|
793
|
-
{ path: `${BOOTSTRAP_DIR}/pnpm-lock.yaml`, content: lock },
|
|
794
|
-
{ path: `${BOOTSTRAP_DIR}/bridge.mjs`, content: bridge }
|
|
795
|
-
],
|
|
796
|
-
commands: [
|
|
797
|
-
{
|
|
798
|
-
command: "pnpm install --frozen-lockfile --store-dir .pnpm-store"
|
|
799
|
-
},
|
|
800
|
-
{
|
|
801
|
-
command: "if [ -f node_modules/@anthropic-ai/claude-code/install.cjs ]; then node node_modules/@anthropic-ai/claude-code/install.cjs; fi && ./node_modules/.bin/claude --version"
|
|
802
|
-
}
|
|
803
|
-
]
|
|
804
|
-
};
|
|
805
|
-
return cachedBootstrap;
|
|
806
|
-
},
|
|
884
|
+
getBootstrap: getClaudeCodeBootstrap,
|
|
807
885
|
doStart: async (startOpts) => {
|
|
808
886
|
const sandboxSession = startOpts.sandboxSession;
|
|
887
|
+
const authenticationMode = resolveClaudeCodeAuthenticationMode(
|
|
888
|
+
settings.auth
|
|
889
|
+
);
|
|
890
|
+
const resolvedAuthEnvironment = resolveClaudeCodeEnv(settings.auth);
|
|
891
|
+
let authEnv = resolvedAuthEnvironment;
|
|
892
|
+
let sandboxTurnEnvironment = settings.env;
|
|
893
|
+
if (sandboxSession.addRequestTransformations != null) {
|
|
894
|
+
const requestTransformations = createClaudeCodeRequestTransformations(
|
|
895
|
+
{
|
|
896
|
+
...resolvedAuthEnvironment,
|
|
897
|
+
...settings.env
|
|
898
|
+
},
|
|
899
|
+
authenticationMode
|
|
900
|
+
);
|
|
901
|
+
if (requestTransformations.length > 0) {
|
|
902
|
+
await sandboxSession.addRequestTransformations(
|
|
903
|
+
requestTransformations
|
|
904
|
+
);
|
|
905
|
+
}
|
|
906
|
+
authEnv = maskSandboxCredentials({
|
|
907
|
+
environment: resolvedAuthEnvironment,
|
|
908
|
+
credentialEnvironmentVariables: CLAUDE_CODE_CREDENTIAL_ENVIRONMENT_VARIABLES
|
|
909
|
+
});
|
|
910
|
+
sandboxTurnEnvironment = maskSandboxCredentials({
|
|
911
|
+
environment: settings.env ?? {},
|
|
912
|
+
credentialEnvironmentVariables: CLAUDE_CODE_CREDENTIAL_ENVIRONMENT_VARIABLES
|
|
913
|
+
});
|
|
914
|
+
} else {
|
|
915
|
+
warnCredentialBrokeringUnavailable();
|
|
916
|
+
}
|
|
809
917
|
const session = sandboxSession.restricted();
|
|
810
918
|
const sandboxId = sandboxSession.id;
|
|
811
919
|
const bootstrapDir = posix.resolve(
|
|
812
920
|
sandboxSession.defaultWorkingDirectory,
|
|
813
|
-
|
|
921
|
+
CLAUDE_CODE_BOOTSTRAP_DIR
|
|
814
922
|
);
|
|
815
923
|
const lifecycleState = startOpts.continueFrom ?? startOpts.resumeFrom;
|
|
816
924
|
const isResume = lifecycleState != null;
|
|
@@ -831,17 +939,21 @@ function createClaudeCode(settings = {}) {
|
|
|
831
939
|
harnessId: "claude-code",
|
|
832
940
|
sessionId: startOpts.sessionId
|
|
833
941
|
});
|
|
834
|
-
const buildConnect = (
|
|
835
|
-
return openBridgeWebSocket({
|
|
942
|
+
const buildConnect = (endpoint2) => async () => {
|
|
943
|
+
return openBridgeWebSocket({ endpoint: endpoint2, timeoutMs });
|
|
836
944
|
};
|
|
837
945
|
if (coords) {
|
|
838
946
|
try {
|
|
839
|
-
const
|
|
947
|
+
const endpoint2 = await sandboxSession.getPortEndpoint({
|
|
840
948
|
port: coords.port,
|
|
841
949
|
protocol: "ws"
|
|
842
|
-
})
|
|
950
|
+
});
|
|
951
|
+
const attachEndpoint = withBridgeToken({
|
|
952
|
+
endpoint: endpoint2,
|
|
953
|
+
token: coords.token
|
|
954
|
+
});
|
|
843
955
|
const attachChannel = new SandboxChannel({
|
|
844
|
-
connect: buildConnect(
|
|
956
|
+
connect: buildConnect(attachEndpoint),
|
|
845
957
|
outboundSchema: outboundMessageSchema,
|
|
846
958
|
initialLastSeenEventId: coords.lastSeenEventId,
|
|
847
959
|
onDiagnostic,
|
|
@@ -857,7 +969,7 @@ function createClaudeCode(settings = {}) {
|
|
|
857
969
|
proc: void 0,
|
|
858
970
|
model: settings.model,
|
|
859
971
|
maxTurns: settings.maxTurns,
|
|
860
|
-
env:
|
|
972
|
+
env: sandboxTurnEnvironment,
|
|
861
973
|
thinking,
|
|
862
974
|
effort: settings.effort,
|
|
863
975
|
isResume: true,
|
|
@@ -893,7 +1005,6 @@ function createClaudeCode(settings = {}) {
|
|
|
893
1005
|
}) : void 0;
|
|
894
1006
|
const port = resolveBridgePort(sandboxSession, settings.port);
|
|
895
1007
|
const token = settings.mintBridgeToken == null ? randomBytes(32).toString("hex") : settings.mintBridgeToken(sandboxId);
|
|
896
|
-
const authEnv = resolveClaudeCodeEnv(settings.auth);
|
|
897
1008
|
const env = {
|
|
898
1009
|
...authEnv,
|
|
899
1010
|
/*
|
|
@@ -967,12 +1078,13 @@ function createClaudeCode(settings = {}) {
|
|
|
967
1078
|
})
|
|
968
1079
|
});
|
|
969
1080
|
void drainBridgeProcessStream(proc.stdout);
|
|
970
|
-
const
|
|
1081
|
+
const endpoint = await sandboxSession.getPortEndpoint({
|
|
971
1082
|
port: boundPort,
|
|
972
1083
|
protocol: "ws"
|
|
973
|
-
})
|
|
1084
|
+
});
|
|
1085
|
+
const bridgeEndpoint = withBridgeToken({ endpoint, token });
|
|
974
1086
|
const channel = new SandboxChannel({
|
|
975
|
-
connect: buildConnect(
|
|
1087
|
+
connect: buildConnect(bridgeEndpoint),
|
|
976
1088
|
outboundSchema: outboundMessageSchema,
|
|
977
1089
|
onDiagnostic,
|
|
978
1090
|
onBridgeError,
|
|
@@ -990,7 +1102,7 @@ function createClaudeCode(settings = {}) {
|
|
|
990
1102
|
proc,
|
|
991
1103
|
model: settings.model,
|
|
992
1104
|
maxTurns: settings.maxTurns,
|
|
993
|
-
env:
|
|
1105
|
+
env: sandboxTurnEnvironment,
|
|
994
1106
|
thinking,
|
|
995
1107
|
effort: settings.effort,
|
|
996
1108
|
isResume: respawnStrategy !== void 0,
|
|
@@ -1032,30 +1144,15 @@ async function writeClaudeCodeSkills({
|
|
|
1032
1144
|
trailingNewline: true
|
|
1033
1145
|
});
|
|
1034
1146
|
}
|
|
1035
|
-
async function readBridgeAsset(name) {
|
|
1036
|
-
const candidates = [
|
|
1037
|
-
new URL(`./bridge/${name}`, import.meta.url),
|
|
1038
|
-
new URL(`../bridge/${name}`, import.meta.url)
|
|
1039
|
-
];
|
|
1040
|
-
let lastErr;
|
|
1041
|
-
for (const url of candidates) {
|
|
1042
|
-
try {
|
|
1043
|
-
return await readFile(fileURLToPath(url), "utf8");
|
|
1044
|
-
} catch (err) {
|
|
1045
|
-
const code = err.code;
|
|
1046
|
-
if (code !== "ENOENT") throw err;
|
|
1047
|
-
lastErr = err;
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
throw lastErr ?? new Error(`bridge asset not found: ${name}`);
|
|
1051
|
-
}
|
|
1052
1147
|
function openWebSocketAndWaitForBridgeHello({
|
|
1053
|
-
|
|
1148
|
+
endpoint,
|
|
1054
1149
|
openTimeoutMs,
|
|
1055
1150
|
getHelloTimeoutMs
|
|
1056
1151
|
}) {
|
|
1057
1152
|
return new Promise((resolve, reject) => {
|
|
1058
|
-
const ws = new WebSocket(url
|
|
1153
|
+
const ws = new WebSocket(endpoint.url, {
|
|
1154
|
+
headers: endpoint.headers == null ? void 0 : { ...endpoint.headers }
|
|
1155
|
+
});
|
|
1059
1156
|
let opened = false;
|
|
1060
1157
|
let sawBridgeHello = false;
|
|
1061
1158
|
let settled = false;
|
|
@@ -1139,7 +1236,7 @@ function openWebSocketAndWaitForBridgeHello({
|
|
|
1139
1236
|
});
|
|
1140
1237
|
}
|
|
1141
1238
|
async function openBridgeWebSocket({
|
|
1142
|
-
|
|
1239
|
+
endpoint,
|
|
1143
1240
|
timeoutMs
|
|
1144
1241
|
}) {
|
|
1145
1242
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -1150,7 +1247,7 @@ async function openBridgeWebSocket({
|
|
|
1150
1247
|
try {
|
|
1151
1248
|
const remaining = Math.max(1, deadline - Date.now());
|
|
1152
1249
|
return await openWebSocketAndWaitForBridgeHello({
|
|
1153
|
-
|
|
1250
|
+
endpoint,
|
|
1154
1251
|
openTimeoutMs: Math.min(1e4, remaining),
|
|
1155
1252
|
getHelloTimeoutMs: () => Math.min(5e3, Math.max(1, deadline - Date.now()))
|
|
1156
1253
|
});
|
|
@@ -1177,6 +1274,14 @@ function webSocketMessageToString(raw) {
|
|
|
1177
1274
|
}
|
|
1178
1275
|
return String(raw);
|
|
1179
1276
|
}
|
|
1277
|
+
function withBridgeToken({
|
|
1278
|
+
endpoint,
|
|
1279
|
+
token
|
|
1280
|
+
}) {
|
|
1281
|
+
const bridgeUrl = new URL(endpoint.url);
|
|
1282
|
+
bridgeUrl.searchParams.set("agent_bridge_token", token);
|
|
1283
|
+
return { ...endpoint, url: bridgeUrl.toString() };
|
|
1284
|
+
}
|
|
1180
1285
|
function sleep(ms) {
|
|
1181
1286
|
return new Promise((resolve) => {
|
|
1182
1287
|
const timer = setTimeout(resolve, ms);
|