@ai-sdk/harness-claude-code 1.0.68 → 1.0.70
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 +16 -0
- package/dist/bridge/index.mjs +3 -0
- package/dist/bridge/index.mjs.map +1 -1
- package/dist/index.js +79 -65
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/bridge/create-emit-stream-event.ts +8 -0
- package/src/claude-code-harness.ts +89 -74
package/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
writeSkills as writeHarnessSkills
|
|
23
23
|
} from "@ai-sdk/harness/utils";
|
|
24
24
|
import {
|
|
25
|
+
safeParseJSON,
|
|
25
26
|
tool
|
|
26
27
|
} from "@ai-sdk/provider-utils";
|
|
27
28
|
import { WebSocket } from "ws";
|
|
@@ -151,7 +152,7 @@ var inboundMessageSchema = z.discriminatedUnion("type", [
|
|
|
151
152
|
]);
|
|
152
153
|
|
|
153
154
|
// src/version.ts
|
|
154
|
-
var VERSION = true ? "1.0.
|
|
155
|
+
var VERSION = true ? "1.0.70" : "0.0.0-test";
|
|
155
156
|
|
|
156
157
|
// src/claude-code-harness.ts
|
|
157
158
|
var CLAUDE_CODE_CLIENT_APP = `ai-sdk/harness-claude-code/${VERSION}`;
|
|
@@ -1045,32 +1046,77 @@ async function readBridgeAsset(name) {
|
|
|
1045
1046
|
}
|
|
1046
1047
|
throw lastErr ?? new Error(`bridge asset not found: ${name}`);
|
|
1047
1048
|
}
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1049
|
+
function openWebSocketAndWaitForBridgeHello({
|
|
1050
|
+
url,
|
|
1051
|
+
openTimeoutMs,
|
|
1052
|
+
getHelloTimeoutMs
|
|
1051
1053
|
}) {
|
|
1052
|
-
|
|
1054
|
+
return new Promise((resolve, reject) => {
|
|
1055
|
+
const ws = new WebSocket(url);
|
|
1056
|
+
let opened = false;
|
|
1057
|
+
let sawBridgeHello = false;
|
|
1053
1058
|
let settled = false;
|
|
1059
|
+
let openTimer;
|
|
1060
|
+
let helloTimer;
|
|
1054
1061
|
const cleanup = () => {
|
|
1062
|
+
if (openTimer) clearTimeout(openTimer);
|
|
1063
|
+
if (helloTimer) clearTimeout(helloTimer);
|
|
1064
|
+
ws.off("open", onOpen);
|
|
1055
1065
|
ws.off("message", onMessage);
|
|
1056
1066
|
ws.off("close", onClose);
|
|
1057
1067
|
ws.off("error", onError);
|
|
1058
|
-
if (timer) clearTimeout(timer);
|
|
1059
1068
|
};
|
|
1060
1069
|
const settle = (err) => {
|
|
1061
1070
|
if (settled) return;
|
|
1062
1071
|
settled = true;
|
|
1063
1072
|
cleanup();
|
|
1064
|
-
if (err)
|
|
1065
|
-
|
|
1073
|
+
if (err) {
|
|
1074
|
+
try {
|
|
1075
|
+
ws.terminate();
|
|
1076
|
+
} catch {
|
|
1077
|
+
}
|
|
1078
|
+
reject(err);
|
|
1079
|
+
} else {
|
|
1080
|
+
resolve(ws);
|
|
1081
|
+
}
|
|
1066
1082
|
};
|
|
1067
|
-
const
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1083
|
+
const tryResolve = () => {
|
|
1084
|
+
if (opened && sawBridgeHello) settle();
|
|
1085
|
+
};
|
|
1086
|
+
const startHelloTimer = () => {
|
|
1087
|
+
if (helloTimer) return;
|
|
1088
|
+
const helloTimeoutMs = getHelloTimeoutMs();
|
|
1089
|
+
helloTimer = setTimeout(
|
|
1090
|
+
() => settle(
|
|
1091
|
+
new Error(
|
|
1092
|
+
`claude-code bridge did not send bridge-hello within ${helloTimeoutMs}ms`
|
|
1093
|
+
)
|
|
1094
|
+
),
|
|
1095
|
+
helloTimeoutMs
|
|
1096
|
+
);
|
|
1097
|
+
helloTimer.unref?.();
|
|
1098
|
+
};
|
|
1099
|
+
const onOpen = () => {
|
|
1100
|
+
opened = true;
|
|
1101
|
+
if (openTimer) {
|
|
1102
|
+
clearTimeout(openTimer);
|
|
1103
|
+
openTimer = void 0;
|
|
1073
1104
|
}
|
|
1105
|
+
startHelloTimer();
|
|
1106
|
+
tryResolve();
|
|
1107
|
+
};
|
|
1108
|
+
const onMessage = (raw) => {
|
|
1109
|
+
void (async () => {
|
|
1110
|
+
const parsed = await safeParseJSON({
|
|
1111
|
+
text: webSocketMessageToString(raw)
|
|
1112
|
+
});
|
|
1113
|
+
if (!parsed.success || settled) return;
|
|
1114
|
+
const value = parsed.value;
|
|
1115
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value) && value.type === "bridge-hello") {
|
|
1116
|
+
sawBridgeHello = true;
|
|
1117
|
+
tryResolve();
|
|
1118
|
+
}
|
|
1119
|
+
})();
|
|
1074
1120
|
};
|
|
1075
1121
|
const onClose = () => {
|
|
1076
1122
|
settle(
|
|
@@ -1078,15 +1124,12 @@ async function waitForBridgeHello({
|
|
|
1078
1124
|
);
|
|
1079
1125
|
};
|
|
1080
1126
|
const onError = (err) => settle(err);
|
|
1081
|
-
|
|
1082
|
-
() => settle(
|
|
1083
|
-
|
|
1084
|
-
`claude-code bridge did not send bridge-hello within ${timeoutMs}ms`
|
|
1085
|
-
)
|
|
1086
|
-
),
|
|
1087
|
-
timeoutMs
|
|
1127
|
+
openTimer = setTimeout(
|
|
1128
|
+
() => settle(new Error(`WebSocket open timed out after ${openTimeoutMs}ms`)),
|
|
1129
|
+
openTimeoutMs
|
|
1088
1130
|
);
|
|
1089
|
-
|
|
1131
|
+
openTimer.unref?.();
|
|
1132
|
+
ws.on("open", onOpen);
|
|
1090
1133
|
ws.on("message", onMessage);
|
|
1091
1134
|
ws.on("close", onClose);
|
|
1092
1135
|
ws.on("error", onError);
|
|
@@ -1101,24 +1144,15 @@ async function openBridgeWebSocket({
|
|
|
1101
1144
|
let lastError;
|
|
1102
1145
|
while (Date.now() < deadline) {
|
|
1103
1146
|
attempt++;
|
|
1104
|
-
let ws;
|
|
1105
1147
|
try {
|
|
1106
1148
|
const remaining = Math.max(1, deadline - Date.now());
|
|
1107
|
-
|
|
1149
|
+
return await openWebSocketAndWaitForBridgeHello({
|
|
1108
1150
|
url: wsUrl,
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
await waitForBridgeHello({
|
|
1112
|
-
ws,
|
|
1113
|
-
timeoutMs: Math.min(5e3, Math.max(1, deadline - Date.now()))
|
|
1151
|
+
openTimeoutMs: Math.min(1e4, remaining),
|
|
1152
|
+
getHelloTimeoutMs: () => Math.min(5e3, Math.max(1, deadline - Date.now()))
|
|
1114
1153
|
});
|
|
1115
|
-
return ws;
|
|
1116
1154
|
} catch (err) {
|
|
1117
1155
|
lastError = err;
|
|
1118
|
-
try {
|
|
1119
|
-
ws?.close();
|
|
1120
|
-
} catch {
|
|
1121
|
-
}
|
|
1122
1156
|
const remaining = deadline - Date.now();
|
|
1123
1157
|
if (remaining <= 0) break;
|
|
1124
1158
|
await sleep(Math.min(250 * attempt, 1e3, remaining));
|
|
@@ -1128,37 +1162,17 @@ async function openBridgeWebSocket({
|
|
|
1128
1162
|
`claude-code bridge did not complete WebSocket handshake within ${timeoutMs}ms after ${attempt} attempt(s). Last error: ${formatUnknownError(lastError)}`
|
|
1129
1163
|
);
|
|
1130
1164
|
}
|
|
1131
|
-
function
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
}
|
|
1143
|
-
reject(new Error(`WebSocket open timed out after ${timeoutMs}ms`));
|
|
1144
|
-
}, timeoutMs);
|
|
1145
|
-
timer.unref?.();
|
|
1146
|
-
const cleanup = () => {
|
|
1147
|
-
clearTimeout(timer);
|
|
1148
|
-
ws.off("open", onOpen);
|
|
1149
|
-
ws.off("error", onError);
|
|
1150
|
-
};
|
|
1151
|
-
const onOpen = () => {
|
|
1152
|
-
cleanup();
|
|
1153
|
-
resolve(ws);
|
|
1154
|
-
};
|
|
1155
|
-
const onError = (err) => {
|
|
1156
|
-
cleanup();
|
|
1157
|
-
reject(err);
|
|
1158
|
-
};
|
|
1159
|
-
ws.once("open", onOpen);
|
|
1160
|
-
ws.once("error", onError);
|
|
1161
|
-
});
|
|
1165
|
+
function webSocketMessageToString(raw) {
|
|
1166
|
+
if (typeof raw === "string") return raw;
|
|
1167
|
+
if (Buffer.isBuffer(raw)) return raw.toString("utf8");
|
|
1168
|
+
if (Array.isArray(raw)) return Buffer.concat(raw).toString("utf8");
|
|
1169
|
+
if (raw instanceof ArrayBuffer) return Buffer.from(raw).toString("utf8");
|
|
1170
|
+
if (ArrayBuffer.isView(raw)) {
|
|
1171
|
+
return Buffer.from(raw.buffer, raw.byteOffset, raw.byteLength).toString(
|
|
1172
|
+
"utf8"
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
return String(raw);
|
|
1162
1176
|
}
|
|
1163
1177
|
function sleep(ms) {
|
|
1164
1178
|
return new Promise((resolve) => {
|