@react-grab/opencode 0.1.0-beta.8 → 0.1.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/dist/cli.cjs +34 -9
- package/dist/cli.js +34 -9
- package/dist/client.cjs +14 -7
- package/dist/client.global.js +449 -2
- package/dist/client.js +14 -7
- package/package.json +13 -13
package/dist/cli.cjs
CHANGED
|
@@ -5787,8 +5787,13 @@ ${context.content.join("\n\n")}`;
|
|
|
5787
5787
|
signal
|
|
5788
5788
|
})) {
|
|
5789
5789
|
if (signal.aborted) break;
|
|
5790
|
+
const getBrowserMessageType = (messageType) => {
|
|
5791
|
+
if (messageType === "status") return "agent-status";
|
|
5792
|
+
if (messageType === "error") return "agent-error";
|
|
5793
|
+
return "agent-done";
|
|
5794
|
+
};
|
|
5790
5795
|
sendToBrowser(browserSocket, {
|
|
5791
|
-
type: message.type
|
|
5796
|
+
type: getBrowserMessageType(message.type),
|
|
5792
5797
|
agentId: handler.agentId,
|
|
5793
5798
|
sessionId,
|
|
5794
5799
|
content: message.content
|
|
@@ -5991,9 +5996,13 @@ ${context.content.join("\n\n")}`;
|
|
|
5991
5996
|
} else if (message.type === "agent-status" || message.type === "agent-done" || message.type === "agent-error") {
|
|
5992
5997
|
const messageQueue = sessionMessageQueues.get(message.sessionId);
|
|
5993
5998
|
if (messageQueue) {
|
|
5994
|
-
const
|
|
5999
|
+
const getQueueMessageType = (handlerMessageType) => {
|
|
6000
|
+
if (handlerMessageType === "agent-status") return "status";
|
|
6001
|
+
if (handlerMessageType === "agent-done") return "done";
|
|
6002
|
+
return "error";
|
|
6003
|
+
};
|
|
5995
6004
|
messageQueue.push({
|
|
5996
|
-
type:
|
|
6005
|
+
type: getQueueMessageType(message.type),
|
|
5997
6006
|
content: message.content ?? ""
|
|
5998
6007
|
});
|
|
5999
6008
|
if (message.type === "agent-done" || message.type === "agent-error") {
|
|
@@ -6016,7 +6025,12 @@ ${context.content.join("\n\n")}`;
|
|
|
6016
6025
|
}
|
|
6017
6026
|
}
|
|
6018
6027
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6019
|
-
res.end(
|
|
6028
|
+
res.end(
|
|
6029
|
+
JSON.stringify({
|
|
6030
|
+
status: "ok",
|
|
6031
|
+
handlers: getRegisteredHandlerIds()
|
|
6032
|
+
})
|
|
6033
|
+
);
|
|
6020
6034
|
return;
|
|
6021
6035
|
}
|
|
6022
6036
|
res.writeHead(404);
|
|
@@ -6031,7 +6045,10 @@ ${context.content.join("\n\n")}`;
|
|
|
6031
6045
|
});
|
|
6032
6046
|
webSocketServer.on("connection", (socket, request) => {
|
|
6033
6047
|
if (token) {
|
|
6034
|
-
const connectionUrl = new URL(
|
|
6048
|
+
const connectionUrl = new URL(
|
|
6049
|
+
request.url ?? "",
|
|
6050
|
+
`http://localhost:${port}`
|
|
6051
|
+
);
|
|
6035
6052
|
const clientToken = connectionUrl.searchParams.get(RELAY_TOKEN_PARAM);
|
|
6036
6053
|
if (clientToken !== token) {
|
|
6037
6054
|
socket.close(4001, "Unauthorized");
|
|
@@ -6072,7 +6089,9 @@ ${context.content.join("\n\n")}`;
|
|
|
6072
6089
|
});
|
|
6073
6090
|
socket.on("message", (data) => {
|
|
6074
6091
|
try {
|
|
6075
|
-
const message = JSON.parse(
|
|
6092
|
+
const message = JSON.parse(
|
|
6093
|
+
data.toString()
|
|
6094
|
+
);
|
|
6076
6095
|
handleBrowserMessage(socket, message);
|
|
6077
6096
|
} catch {
|
|
6078
6097
|
}
|
|
@@ -6117,7 +6136,10 @@ ${context.content.join("\n\n")}`;
|
|
|
6117
6136
|
httpServer?.close();
|
|
6118
6137
|
};
|
|
6119
6138
|
const registerHandler = (handler) => {
|
|
6120
|
-
registeredHandlers.set(handler.agentId, {
|
|
6139
|
+
registeredHandlers.set(handler.agentId, {
|
|
6140
|
+
agentId: handler.agentId,
|
|
6141
|
+
handler
|
|
6142
|
+
});
|
|
6121
6143
|
broadcastHandlerList();
|
|
6122
6144
|
};
|
|
6123
6145
|
const unregisterHandler = (agentId) => {
|
|
@@ -8678,7 +8700,7 @@ async function fkill(inputs, options = {}) {
|
|
|
8678
8700
|
}
|
|
8679
8701
|
}
|
|
8680
8702
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8681
|
-
var VERSION = "0.1.0
|
|
8703
|
+
var VERSION = "0.1.0";
|
|
8682
8704
|
var checkIfRelayServerIsRunning = async (port, token) => {
|
|
8683
8705
|
try {
|
|
8684
8706
|
const healthUrl = token ? `http://localhost:${port}/health?${RELAY_TOKEN_PARAM}=${encodeURIComponent(token)}` : `http://localhost:${port}/health`;
|
|
@@ -8696,7 +8718,10 @@ var connectRelay = async (options) => {
|
|
|
8696
8718
|
const { handler, token } = options;
|
|
8697
8719
|
let relayServer = null;
|
|
8698
8720
|
let isRelayHost = false;
|
|
8699
|
-
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
8721
|
+
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
8722
|
+
relayPort,
|
|
8723
|
+
token
|
|
8724
|
+
);
|
|
8700
8725
|
if (isRelayServerRunning) {
|
|
8701
8726
|
relayServer = await connectToExistingRelay(relayPort, handler, token);
|
|
8702
8727
|
} else {
|
package/dist/cli.js
CHANGED
|
@@ -5777,8 +5777,13 @@ ${context.content.join("\n\n")}`;
|
|
|
5777
5777
|
signal
|
|
5778
5778
|
})) {
|
|
5779
5779
|
if (signal.aborted) break;
|
|
5780
|
+
const getBrowserMessageType = (messageType) => {
|
|
5781
|
+
if (messageType === "status") return "agent-status";
|
|
5782
|
+
if (messageType === "error") return "agent-error";
|
|
5783
|
+
return "agent-done";
|
|
5784
|
+
};
|
|
5780
5785
|
sendToBrowser(browserSocket, {
|
|
5781
|
-
type: message.type
|
|
5786
|
+
type: getBrowserMessageType(message.type),
|
|
5782
5787
|
agentId: handler.agentId,
|
|
5783
5788
|
sessionId,
|
|
5784
5789
|
content: message.content
|
|
@@ -5981,9 +5986,13 @@ ${context.content.join("\n\n")}`;
|
|
|
5981
5986
|
} else if (message.type === "agent-status" || message.type === "agent-done" || message.type === "agent-error") {
|
|
5982
5987
|
const messageQueue = sessionMessageQueues.get(message.sessionId);
|
|
5983
5988
|
if (messageQueue) {
|
|
5984
|
-
const
|
|
5989
|
+
const getQueueMessageType = (handlerMessageType) => {
|
|
5990
|
+
if (handlerMessageType === "agent-status") return "status";
|
|
5991
|
+
if (handlerMessageType === "agent-done") return "done";
|
|
5992
|
+
return "error";
|
|
5993
|
+
};
|
|
5985
5994
|
messageQueue.push({
|
|
5986
|
-
type:
|
|
5995
|
+
type: getQueueMessageType(message.type),
|
|
5987
5996
|
content: message.content ?? ""
|
|
5988
5997
|
});
|
|
5989
5998
|
if (message.type === "agent-done" || message.type === "agent-error") {
|
|
@@ -6006,7 +6015,12 @@ ${context.content.join("\n\n")}`;
|
|
|
6006
6015
|
}
|
|
6007
6016
|
}
|
|
6008
6017
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
6009
|
-
res.end(
|
|
6018
|
+
res.end(
|
|
6019
|
+
JSON.stringify({
|
|
6020
|
+
status: "ok",
|
|
6021
|
+
handlers: getRegisteredHandlerIds()
|
|
6022
|
+
})
|
|
6023
|
+
);
|
|
6010
6024
|
return;
|
|
6011
6025
|
}
|
|
6012
6026
|
res.writeHead(404);
|
|
@@ -6021,7 +6035,10 @@ ${context.content.join("\n\n")}`;
|
|
|
6021
6035
|
});
|
|
6022
6036
|
webSocketServer.on("connection", (socket, request) => {
|
|
6023
6037
|
if (token) {
|
|
6024
|
-
const connectionUrl = new URL(
|
|
6038
|
+
const connectionUrl = new URL(
|
|
6039
|
+
request.url ?? "",
|
|
6040
|
+
`http://localhost:${port}`
|
|
6041
|
+
);
|
|
6025
6042
|
const clientToken = connectionUrl.searchParams.get(RELAY_TOKEN_PARAM);
|
|
6026
6043
|
if (clientToken !== token) {
|
|
6027
6044
|
socket.close(4001, "Unauthorized");
|
|
@@ -6062,7 +6079,9 @@ ${context.content.join("\n\n")}`;
|
|
|
6062
6079
|
});
|
|
6063
6080
|
socket.on("message", (data) => {
|
|
6064
6081
|
try {
|
|
6065
|
-
const message = JSON.parse(
|
|
6082
|
+
const message = JSON.parse(
|
|
6083
|
+
data.toString()
|
|
6084
|
+
);
|
|
6066
6085
|
handleBrowserMessage(socket, message);
|
|
6067
6086
|
} catch {
|
|
6068
6087
|
}
|
|
@@ -6107,7 +6126,10 @@ ${context.content.join("\n\n")}`;
|
|
|
6107
6126
|
httpServer?.close();
|
|
6108
6127
|
};
|
|
6109
6128
|
const registerHandler = (handler) => {
|
|
6110
|
-
registeredHandlers.set(handler.agentId, {
|
|
6129
|
+
registeredHandlers.set(handler.agentId, {
|
|
6130
|
+
agentId: handler.agentId,
|
|
6131
|
+
handler
|
|
6132
|
+
});
|
|
6111
6133
|
broadcastHandlerList();
|
|
6112
6134
|
};
|
|
6113
6135
|
const unregisterHandler = (agentId) => {
|
|
@@ -8668,7 +8690,7 @@ async function fkill(inputs, options = {}) {
|
|
|
8668
8690
|
}
|
|
8669
8691
|
}
|
|
8670
8692
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
8671
|
-
var VERSION = "0.1.0
|
|
8693
|
+
var VERSION = "0.1.0";
|
|
8672
8694
|
var checkIfRelayServerIsRunning = async (port, token) => {
|
|
8673
8695
|
try {
|
|
8674
8696
|
const healthUrl = token ? `http://localhost:${port}/health?${RELAY_TOKEN_PARAM}=${encodeURIComponent(token)}` : `http://localhost:${port}/health`;
|
|
@@ -8686,7 +8708,10 @@ var connectRelay = async (options) => {
|
|
|
8686
8708
|
const { handler, token } = options;
|
|
8687
8709
|
let relayServer = null;
|
|
8688
8710
|
let isRelayHost = false;
|
|
8689
|
-
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
8711
|
+
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
8712
|
+
relayPort,
|
|
8713
|
+
token
|
|
8714
|
+
);
|
|
8690
8715
|
if (isRelayServerRunning) {
|
|
8691
8716
|
relayServer = await connectToExistingRelay(relayPort, handler, token);
|
|
8692
8717
|
} else {
|
package/dist/client.cjs
CHANGED
|
@@ -210,7 +210,7 @@ var createRelayAgentProvider = (options) => {
|
|
|
210
210
|
rejectNextMessage = null;
|
|
211
211
|
}
|
|
212
212
|
};
|
|
213
|
-
signal.addEventListener("abort", handleAbort);
|
|
213
|
+
signal.addEventListener("abort", handleAbort, { once: true });
|
|
214
214
|
const handleConnectionChange = (connected) => {
|
|
215
215
|
if (!connected && !isDone) {
|
|
216
216
|
errorMessage = "Relay connection lost";
|
|
@@ -260,7 +260,10 @@ var createRelayAgentProvider = (options) => {
|
|
|
260
260
|
signal.removeEventListener("abort", handleAbort);
|
|
261
261
|
throw new Error("Relay connection is not open");
|
|
262
262
|
}
|
|
263
|
-
const didSendRequest = relayClient.sendAgentRequest(
|
|
263
|
+
const didSendRequest = relayClient.sendAgentRequest(
|
|
264
|
+
agentId,
|
|
265
|
+
contextWithSession
|
|
266
|
+
);
|
|
264
267
|
if (!didSendRequest) {
|
|
265
268
|
unsubscribeConnection();
|
|
266
269
|
unsubscribeMessage();
|
|
@@ -318,12 +321,16 @@ var createRelayAgentProvider = (options) => {
|
|
|
318
321
|
reject(new Error(message.content ?? "Operation failed"));
|
|
319
322
|
}
|
|
320
323
|
});
|
|
321
|
-
const unsubscribeConnection = relayClient.onConnectionChange(
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
324
|
+
const unsubscribeConnection = relayClient.onConnectionChange(
|
|
325
|
+
(connected) => {
|
|
326
|
+
if (!connected) {
|
|
327
|
+
cleanup();
|
|
328
|
+
reject(
|
|
329
|
+
new Error("Connection lost while waiting for operation response")
|
|
330
|
+
);
|
|
331
|
+
}
|
|
325
332
|
}
|
|
326
|
-
|
|
333
|
+
);
|
|
327
334
|
});
|
|
328
335
|
};
|
|
329
336
|
const undo = async () => {
|
package/dist/client.global.js
CHANGED
|
@@ -1,2 +1,449 @@
|
|
|
1
|
-
var ReactGrabOpenCode
|
|
2
|
-
|
|
1
|
+
var ReactGrabOpenCode = (function (exports) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
// ../relay/dist/client.js
|
|
5
|
+
var DEFAULT_RELAY_PORT = 4722;
|
|
6
|
+
var DEFAULT_RECONNECT_INTERVAL_MS = 3e3;
|
|
7
|
+
var RELAY_TOKEN_PARAM = "token";
|
|
8
|
+
var createRelayClient = (options = {}) => {
|
|
9
|
+
const serverUrl = options.serverUrl ?? `ws://localhost:${DEFAULT_RELAY_PORT}`;
|
|
10
|
+
const autoReconnect = options.autoReconnect ?? true;
|
|
11
|
+
const reconnectIntervalMs = options.reconnectIntervalMs ?? DEFAULT_RECONNECT_INTERVAL_MS;
|
|
12
|
+
const token = options.token;
|
|
13
|
+
let webSocketConnection = null;
|
|
14
|
+
let isConnectedState = false;
|
|
15
|
+
let availableHandlers = [];
|
|
16
|
+
let reconnectTimeoutId = null;
|
|
17
|
+
let pendingConnectionPromise = null;
|
|
18
|
+
let pendingConnectionReject = null;
|
|
19
|
+
let isIntentionalDisconnect = false;
|
|
20
|
+
const messageCallbacks = /* @__PURE__ */ new Set();
|
|
21
|
+
const handlersChangeCallbacks = /* @__PURE__ */ new Set();
|
|
22
|
+
const connectionChangeCallbacks = /* @__PURE__ */ new Set();
|
|
23
|
+
const scheduleReconnect = () => {
|
|
24
|
+
if (!autoReconnect || reconnectTimeoutId || isIntentionalDisconnect) return;
|
|
25
|
+
reconnectTimeoutId = setTimeout(() => {
|
|
26
|
+
reconnectTimeoutId = null;
|
|
27
|
+
connect().catch(() => {
|
|
28
|
+
});
|
|
29
|
+
}, reconnectIntervalMs);
|
|
30
|
+
};
|
|
31
|
+
const handleMessage = (event) => {
|
|
32
|
+
try {
|
|
33
|
+
const message = JSON.parse(event.data);
|
|
34
|
+
if (message.type === "handlers" && message.handlers) {
|
|
35
|
+
availableHandlers = message.handlers;
|
|
36
|
+
for (const callback of handlersChangeCallbacks) {
|
|
37
|
+
callback(availableHandlers);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const callback of messageCallbacks) {
|
|
41
|
+
callback(message);
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
const connect = () => {
|
|
47
|
+
if (webSocketConnection?.readyState === WebSocket.OPEN) {
|
|
48
|
+
return Promise.resolve();
|
|
49
|
+
}
|
|
50
|
+
if (pendingConnectionPromise) {
|
|
51
|
+
return pendingConnectionPromise;
|
|
52
|
+
}
|
|
53
|
+
isIntentionalDisconnect = false;
|
|
54
|
+
pendingConnectionPromise = new Promise((resolve, reject) => {
|
|
55
|
+
pendingConnectionReject = reject;
|
|
56
|
+
const connectionUrl = token ? `${serverUrl}?${RELAY_TOKEN_PARAM}=${encodeURIComponent(token)}` : serverUrl;
|
|
57
|
+
webSocketConnection = new WebSocket(connectionUrl);
|
|
58
|
+
webSocketConnection.onopen = () => {
|
|
59
|
+
pendingConnectionPromise = null;
|
|
60
|
+
pendingConnectionReject = null;
|
|
61
|
+
isConnectedState = true;
|
|
62
|
+
for (const callback of connectionChangeCallbacks) {
|
|
63
|
+
callback(true);
|
|
64
|
+
}
|
|
65
|
+
resolve();
|
|
66
|
+
};
|
|
67
|
+
webSocketConnection.onmessage = handleMessage;
|
|
68
|
+
webSocketConnection.onclose = () => {
|
|
69
|
+
if (pendingConnectionReject) {
|
|
70
|
+
pendingConnectionReject(new Error("WebSocket connection closed"));
|
|
71
|
+
pendingConnectionReject = null;
|
|
72
|
+
}
|
|
73
|
+
pendingConnectionPromise = null;
|
|
74
|
+
isConnectedState = false;
|
|
75
|
+
availableHandlers = [];
|
|
76
|
+
for (const callback of handlersChangeCallbacks) {
|
|
77
|
+
callback(availableHandlers);
|
|
78
|
+
}
|
|
79
|
+
for (const callback of connectionChangeCallbacks) {
|
|
80
|
+
callback(false);
|
|
81
|
+
}
|
|
82
|
+
scheduleReconnect();
|
|
83
|
+
};
|
|
84
|
+
webSocketConnection.onerror = () => {
|
|
85
|
+
pendingConnectionPromise = null;
|
|
86
|
+
pendingConnectionReject = null;
|
|
87
|
+
isConnectedState = false;
|
|
88
|
+
reject(new Error("WebSocket connection failed"));
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
return pendingConnectionPromise;
|
|
92
|
+
};
|
|
93
|
+
const disconnect = () => {
|
|
94
|
+
isIntentionalDisconnect = true;
|
|
95
|
+
if (reconnectTimeoutId) {
|
|
96
|
+
clearTimeout(reconnectTimeoutId);
|
|
97
|
+
reconnectTimeoutId = null;
|
|
98
|
+
}
|
|
99
|
+
if (pendingConnectionReject) {
|
|
100
|
+
pendingConnectionReject(new Error("Connection aborted"));
|
|
101
|
+
pendingConnectionReject = null;
|
|
102
|
+
}
|
|
103
|
+
pendingConnectionPromise = null;
|
|
104
|
+
webSocketConnection?.close();
|
|
105
|
+
webSocketConnection = null;
|
|
106
|
+
isConnectedState = false;
|
|
107
|
+
availableHandlers = [];
|
|
108
|
+
};
|
|
109
|
+
const isConnected = () => isConnectedState;
|
|
110
|
+
const sendMessage = (message) => {
|
|
111
|
+
if (webSocketConnection?.readyState === WebSocket.OPEN) {
|
|
112
|
+
webSocketConnection.send(JSON.stringify(message));
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return false;
|
|
116
|
+
};
|
|
117
|
+
const sendAgentRequest = (agentId, context) => {
|
|
118
|
+
return sendMessage({
|
|
119
|
+
type: "agent-request",
|
|
120
|
+
agentId,
|
|
121
|
+
sessionId: context.sessionId,
|
|
122
|
+
context
|
|
123
|
+
});
|
|
124
|
+
};
|
|
125
|
+
const abortAgent = (agentId, sessionId) => {
|
|
126
|
+
sendMessage({
|
|
127
|
+
type: "agent-abort",
|
|
128
|
+
agentId,
|
|
129
|
+
sessionId
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
const undoAgent = (agentId, sessionId) => {
|
|
133
|
+
return sendMessage({
|
|
134
|
+
type: "agent-undo",
|
|
135
|
+
agentId,
|
|
136
|
+
sessionId
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
const redoAgent = (agentId, sessionId) => {
|
|
140
|
+
return sendMessage({
|
|
141
|
+
type: "agent-redo",
|
|
142
|
+
agentId,
|
|
143
|
+
sessionId
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
const onMessage = (callback) => {
|
|
147
|
+
messageCallbacks.add(callback);
|
|
148
|
+
return () => messageCallbacks.delete(callback);
|
|
149
|
+
};
|
|
150
|
+
const onHandlersChange = (callback) => {
|
|
151
|
+
handlersChangeCallbacks.add(callback);
|
|
152
|
+
return () => handlersChangeCallbacks.delete(callback);
|
|
153
|
+
};
|
|
154
|
+
const onConnectionChange = (callback) => {
|
|
155
|
+
connectionChangeCallbacks.add(callback);
|
|
156
|
+
queueMicrotask(() => {
|
|
157
|
+
if (connectionChangeCallbacks.has(callback)) {
|
|
158
|
+
callback(isConnectedState);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
return () => connectionChangeCallbacks.delete(callback);
|
|
162
|
+
};
|
|
163
|
+
const getAvailableHandlers = () => availableHandlers;
|
|
164
|
+
return {
|
|
165
|
+
connect,
|
|
166
|
+
disconnect,
|
|
167
|
+
isConnected,
|
|
168
|
+
sendAgentRequest,
|
|
169
|
+
abortAgent,
|
|
170
|
+
undoAgent,
|
|
171
|
+
redoAgent,
|
|
172
|
+
onMessage,
|
|
173
|
+
onHandlersChange,
|
|
174
|
+
onConnectionChange,
|
|
175
|
+
getAvailableHandlers
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
var createRelayAgentProvider = (options) => {
|
|
179
|
+
const { relayClient, agentId } = options;
|
|
180
|
+
const checkConnection = async () => {
|
|
181
|
+
if (!relayClient.isConnected()) {
|
|
182
|
+
try {
|
|
183
|
+
await relayClient.connect();
|
|
184
|
+
} catch {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return relayClient.getAvailableHandlers().includes(agentId);
|
|
189
|
+
};
|
|
190
|
+
const send = async function* (context, signal) {
|
|
191
|
+
if (signal.aborted) {
|
|
192
|
+
throw new DOMException("Aborted", "AbortError");
|
|
193
|
+
}
|
|
194
|
+
yield "Connecting\u2026";
|
|
195
|
+
const sessionId = context.sessionId ?? `session-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
196
|
+
const contextWithSession = {
|
|
197
|
+
...context,
|
|
198
|
+
sessionId
|
|
199
|
+
};
|
|
200
|
+
const messageQueue = [];
|
|
201
|
+
let resolveNextMessage = null;
|
|
202
|
+
let rejectNextMessage = null;
|
|
203
|
+
let isDone = false;
|
|
204
|
+
let errorMessage = null;
|
|
205
|
+
const handleAbort = () => {
|
|
206
|
+
relayClient.abortAgent(agentId, sessionId);
|
|
207
|
+
isDone = true;
|
|
208
|
+
if (resolveNextMessage) {
|
|
209
|
+
resolveNextMessage({ value: void 0, done: true });
|
|
210
|
+
resolveNextMessage = null;
|
|
211
|
+
rejectNextMessage = null;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
signal.addEventListener("abort", handleAbort, { once: true });
|
|
215
|
+
const handleConnectionChange = (connected) => {
|
|
216
|
+
if (!connected && !isDone) {
|
|
217
|
+
errorMessage = "Relay connection lost";
|
|
218
|
+
isDone = true;
|
|
219
|
+
if (rejectNextMessage) {
|
|
220
|
+
rejectNextMessage(new Error(errorMessage));
|
|
221
|
+
resolveNextMessage = null;
|
|
222
|
+
rejectNextMessage = null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
const unsubscribeConnection = relayClient.onConnectionChange(
|
|
227
|
+
handleConnectionChange
|
|
228
|
+
);
|
|
229
|
+
const unsubscribeMessage = relayClient.onMessage((message) => {
|
|
230
|
+
if (message.sessionId !== sessionId) return;
|
|
231
|
+
if (message.type === "agent-status" && message.content) {
|
|
232
|
+
messageQueue.push(message.content);
|
|
233
|
+
if (resolveNextMessage) {
|
|
234
|
+
const nextMessage = messageQueue.shift();
|
|
235
|
+
if (nextMessage !== void 0) {
|
|
236
|
+
resolveNextMessage({ value: nextMessage, done: false });
|
|
237
|
+
resolveNextMessage = null;
|
|
238
|
+
rejectNextMessage = null;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
} else if (message.type === "agent-done") {
|
|
242
|
+
isDone = true;
|
|
243
|
+
if (resolveNextMessage) {
|
|
244
|
+
resolveNextMessage({ value: void 0, done: true });
|
|
245
|
+
resolveNextMessage = null;
|
|
246
|
+
rejectNextMessage = null;
|
|
247
|
+
}
|
|
248
|
+
} else if (message.type === "agent-error") {
|
|
249
|
+
errorMessage = message.content ?? "Unknown error";
|
|
250
|
+
isDone = true;
|
|
251
|
+
if (rejectNextMessage) {
|
|
252
|
+
rejectNextMessage(new Error(errorMessage));
|
|
253
|
+
resolveNextMessage = null;
|
|
254
|
+
rejectNextMessage = null;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
if (!relayClient.isConnected()) {
|
|
259
|
+
unsubscribeConnection();
|
|
260
|
+
unsubscribeMessage();
|
|
261
|
+
signal.removeEventListener("abort", handleAbort);
|
|
262
|
+
throw new Error("Relay connection is not open");
|
|
263
|
+
}
|
|
264
|
+
const didSendRequest = relayClient.sendAgentRequest(
|
|
265
|
+
agentId,
|
|
266
|
+
contextWithSession
|
|
267
|
+
);
|
|
268
|
+
if (!didSendRequest) {
|
|
269
|
+
unsubscribeConnection();
|
|
270
|
+
unsubscribeMessage();
|
|
271
|
+
signal.removeEventListener("abort", handleAbort);
|
|
272
|
+
throw new Error("Failed to send agent request: connection not open");
|
|
273
|
+
}
|
|
274
|
+
try {
|
|
275
|
+
while (true) {
|
|
276
|
+
if (messageQueue.length > 0) {
|
|
277
|
+
const next = messageQueue.shift();
|
|
278
|
+
if (next !== void 0) {
|
|
279
|
+
yield next;
|
|
280
|
+
}
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (isDone || signal.aborted) {
|
|
284
|
+
break;
|
|
285
|
+
}
|
|
286
|
+
const result = await new Promise(
|
|
287
|
+
(resolve, reject) => {
|
|
288
|
+
resolveNextMessage = resolve;
|
|
289
|
+
rejectNextMessage = reject;
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
if (result.done) break;
|
|
293
|
+
yield result.value;
|
|
294
|
+
}
|
|
295
|
+
if (errorMessage) {
|
|
296
|
+
throw new Error(errorMessage);
|
|
297
|
+
}
|
|
298
|
+
} finally {
|
|
299
|
+
signal.removeEventListener("abort", handleAbort);
|
|
300
|
+
unsubscribeConnection();
|
|
301
|
+
unsubscribeMessage();
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
const abort = async (sessionId) => {
|
|
305
|
+
relayClient.abortAgent(agentId, sessionId);
|
|
306
|
+
};
|
|
307
|
+
const waitForOperationResponse = (sessionId) => {
|
|
308
|
+
return new Promise((resolve, reject) => {
|
|
309
|
+
let didCleanup = false;
|
|
310
|
+
const cleanup = () => {
|
|
311
|
+
if (didCleanup) return;
|
|
312
|
+
didCleanup = true;
|
|
313
|
+
unsubscribeMessage();
|
|
314
|
+
unsubscribeConnection();
|
|
315
|
+
};
|
|
316
|
+
const unsubscribeMessage = relayClient.onMessage((message) => {
|
|
317
|
+
if (message.sessionId !== sessionId) return;
|
|
318
|
+
cleanup();
|
|
319
|
+
if (message.type === "agent-done") {
|
|
320
|
+
resolve();
|
|
321
|
+
} else if (message.type === "agent-error") {
|
|
322
|
+
reject(new Error(message.content ?? "Operation failed"));
|
|
323
|
+
}
|
|
324
|
+
});
|
|
325
|
+
const unsubscribeConnection = relayClient.onConnectionChange(
|
|
326
|
+
(connected) => {
|
|
327
|
+
if (!connected) {
|
|
328
|
+
cleanup();
|
|
329
|
+
reject(
|
|
330
|
+
new Error("Connection lost while waiting for operation response")
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
});
|
|
336
|
+
};
|
|
337
|
+
const undo = async () => {
|
|
338
|
+
const sessionId = `undo-${agentId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
339
|
+
const didSend = relayClient.undoAgent(agentId, sessionId);
|
|
340
|
+
if (!didSend) {
|
|
341
|
+
throw new Error("Failed to send undo request: connection not open");
|
|
342
|
+
}
|
|
343
|
+
return waitForOperationResponse(sessionId);
|
|
344
|
+
};
|
|
345
|
+
const redo = async () => {
|
|
346
|
+
const sessionId = `redo-${agentId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
347
|
+
const didSend = relayClient.redoAgent(agentId, sessionId);
|
|
348
|
+
if (!didSend) {
|
|
349
|
+
throw new Error("Failed to send redo request: connection not open");
|
|
350
|
+
}
|
|
351
|
+
return waitForOperationResponse(sessionId);
|
|
352
|
+
};
|
|
353
|
+
return {
|
|
354
|
+
send,
|
|
355
|
+
abort,
|
|
356
|
+
undo,
|
|
357
|
+
redo,
|
|
358
|
+
checkConnection,
|
|
359
|
+
supportsResume: true,
|
|
360
|
+
supportsFollowUp: true
|
|
361
|
+
};
|
|
362
|
+
};
|
|
363
|
+
var defaultRelayClient = null;
|
|
364
|
+
var getDefaultRelayClient = () => {
|
|
365
|
+
if (typeof window === "undefined") {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
if (window.__REACT_GRAB_RELAY__) {
|
|
369
|
+
defaultRelayClient = window.__REACT_GRAB_RELAY__;
|
|
370
|
+
return defaultRelayClient;
|
|
371
|
+
}
|
|
372
|
+
if (!defaultRelayClient) {
|
|
373
|
+
defaultRelayClient = createRelayClient();
|
|
374
|
+
window.__REACT_GRAB_RELAY__ = defaultRelayClient;
|
|
375
|
+
}
|
|
376
|
+
return defaultRelayClient;
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
// src/client.ts
|
|
380
|
+
var AGENT_ID = "opencode";
|
|
381
|
+
var isReactGrabApi = (value) => typeof value === "object" && value !== null && "registerPlugin" in value;
|
|
382
|
+
var createOpenCodeAgentProvider = (providerOptions = {}) => {
|
|
383
|
+
const relayClient = providerOptions.relayClient ?? getDefaultRelayClient();
|
|
384
|
+
if (!relayClient) {
|
|
385
|
+
throw new Error("RelayClient is required in browser environments");
|
|
386
|
+
}
|
|
387
|
+
return createRelayAgentProvider({
|
|
388
|
+
relayClient,
|
|
389
|
+
agentId: AGENT_ID
|
|
390
|
+
});
|
|
391
|
+
};
|
|
392
|
+
var attachAgent = async () => {
|
|
393
|
+
if (typeof window === "undefined") return;
|
|
394
|
+
const relayClient = getDefaultRelayClient();
|
|
395
|
+
if (!relayClient) return;
|
|
396
|
+
try {
|
|
397
|
+
await relayClient.connect();
|
|
398
|
+
} catch {
|
|
399
|
+
return;
|
|
400
|
+
}
|
|
401
|
+
const provider = createRelayAgentProvider({
|
|
402
|
+
relayClient,
|
|
403
|
+
agentId: AGENT_ID
|
|
404
|
+
});
|
|
405
|
+
const attach = (api) => {
|
|
406
|
+
const agent = { provider, storage: sessionStorage };
|
|
407
|
+
const plugin = {
|
|
408
|
+
name: "opencode-agent",
|
|
409
|
+
actions: [
|
|
410
|
+
{
|
|
411
|
+
id: "edit-with-opencode",
|
|
412
|
+
label: "Edit with OpenCode",
|
|
413
|
+
shortcut: "Enter",
|
|
414
|
+
onAction: (actionContext) => {
|
|
415
|
+
actionContext.enterPromptMode?.(agent);
|
|
416
|
+
},
|
|
417
|
+
agent
|
|
418
|
+
}
|
|
419
|
+
]
|
|
420
|
+
};
|
|
421
|
+
api.registerPlugin(plugin);
|
|
422
|
+
};
|
|
423
|
+
const existingApi = window.__REACT_GRAB__;
|
|
424
|
+
if (isReactGrabApi(existingApi)) {
|
|
425
|
+
attach(existingApi);
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
window.addEventListener(
|
|
429
|
+
"react-grab:init",
|
|
430
|
+
(event) => {
|
|
431
|
+
if (!(event instanceof CustomEvent)) return;
|
|
432
|
+
if (!isReactGrabApi(event.detail)) return;
|
|
433
|
+
attach(event.detail);
|
|
434
|
+
},
|
|
435
|
+
{ once: true }
|
|
436
|
+
);
|
|
437
|
+
const apiAfterListener = window.__REACT_GRAB__;
|
|
438
|
+
if (isReactGrabApi(apiAfterListener)) {
|
|
439
|
+
attach(apiAfterListener);
|
|
440
|
+
}
|
|
441
|
+
};
|
|
442
|
+
attachAgent();
|
|
443
|
+
|
|
444
|
+
exports.attachAgent = attachAgent;
|
|
445
|
+
exports.createOpenCodeAgentProvider = createOpenCodeAgentProvider;
|
|
446
|
+
|
|
447
|
+
return exports;
|
|
448
|
+
|
|
449
|
+
})({});
|
package/dist/client.js
CHANGED
|
@@ -208,7 +208,7 @@ var createRelayAgentProvider = (options) => {
|
|
|
208
208
|
rejectNextMessage = null;
|
|
209
209
|
}
|
|
210
210
|
};
|
|
211
|
-
signal.addEventListener("abort", handleAbort);
|
|
211
|
+
signal.addEventListener("abort", handleAbort, { once: true });
|
|
212
212
|
const handleConnectionChange = (connected) => {
|
|
213
213
|
if (!connected && !isDone) {
|
|
214
214
|
errorMessage = "Relay connection lost";
|
|
@@ -258,7 +258,10 @@ var createRelayAgentProvider = (options) => {
|
|
|
258
258
|
signal.removeEventListener("abort", handleAbort);
|
|
259
259
|
throw new Error("Relay connection is not open");
|
|
260
260
|
}
|
|
261
|
-
const didSendRequest = relayClient.sendAgentRequest(
|
|
261
|
+
const didSendRequest = relayClient.sendAgentRequest(
|
|
262
|
+
agentId,
|
|
263
|
+
contextWithSession
|
|
264
|
+
);
|
|
262
265
|
if (!didSendRequest) {
|
|
263
266
|
unsubscribeConnection();
|
|
264
267
|
unsubscribeMessage();
|
|
@@ -316,12 +319,16 @@ var createRelayAgentProvider = (options) => {
|
|
|
316
319
|
reject(new Error(message.content ?? "Operation failed"));
|
|
317
320
|
}
|
|
318
321
|
});
|
|
319
|
-
const unsubscribeConnection = relayClient.onConnectionChange(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
322
|
+
const unsubscribeConnection = relayClient.onConnectionChange(
|
|
323
|
+
(connected) => {
|
|
324
|
+
if (!connected) {
|
|
325
|
+
cleanup();
|
|
326
|
+
reject(
|
|
327
|
+
new Error("Connection lost while waiting for operation response")
|
|
328
|
+
);
|
|
329
|
+
}
|
|
323
330
|
}
|
|
324
|
-
|
|
331
|
+
);
|
|
325
332
|
});
|
|
326
333
|
};
|
|
327
334
|
const undo = async () => {
|
package/package.json
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@react-grab/opencode",
|
|
3
|
-
"version": "0.1.0
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "0.1.0",
|
|
5
4
|
"bin": {
|
|
6
5
|
"react-grab-opencode": "./dist/cli.cjs"
|
|
7
6
|
},
|
|
7
|
+
"files": [
|
|
8
|
+
"dist"
|
|
9
|
+
],
|
|
10
|
+
"type": "module",
|
|
11
|
+
"browser": "dist/client.global.js",
|
|
8
12
|
"exports": {
|
|
9
13
|
"./client": {
|
|
10
14
|
"types": "./dist/client.d.ts",
|
|
@@ -19,20 +23,16 @@
|
|
|
19
23
|
"./dist/*": "./dist/*.js",
|
|
20
24
|
"./dist/*.js": "./dist/*.js"
|
|
21
25
|
},
|
|
22
|
-
"browser": "dist/client.global.js",
|
|
23
|
-
"files": [
|
|
24
|
-
"dist"
|
|
25
|
-
],
|
|
26
|
-
"devDependencies": {
|
|
27
|
-
"@types/node": "^22.10.7",
|
|
28
|
-
"tsup": "^8.4.0",
|
|
29
|
-
"@react-grab/utils": "0.1.0-beta.8"
|
|
30
|
-
},
|
|
31
26
|
"dependencies": {
|
|
32
27
|
"@opencode-ai/sdk": "^1.0.132",
|
|
33
28
|
"fkill": "^9.0.0",
|
|
34
|
-
"@react-grab/relay": "0.1.0
|
|
35
|
-
"react-grab": "0.1.0
|
|
29
|
+
"@react-grab/relay": "0.1.0",
|
|
30
|
+
"react-grab": "0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^22.10.7",
|
|
34
|
+
"tsup": "^8.4.0",
|
|
35
|
+
"@react-grab/utils": "0.1.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"dev": "tsup --watch",
|