@react-grab/claude-code 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 +12 -12
package/dist/cli.cjs
CHANGED
|
@@ -4964,8 +4964,13 @@ ${context.content.join("\n\n")}`;
|
|
|
4964
4964
|
signal
|
|
4965
4965
|
})) {
|
|
4966
4966
|
if (signal.aborted) break;
|
|
4967
|
+
const getBrowserMessageType = (messageType) => {
|
|
4968
|
+
if (messageType === "status") return "agent-status";
|
|
4969
|
+
if (messageType === "error") return "agent-error";
|
|
4970
|
+
return "agent-done";
|
|
4971
|
+
};
|
|
4967
4972
|
sendToBrowser(browserSocket, {
|
|
4968
|
-
type: message.type
|
|
4973
|
+
type: getBrowserMessageType(message.type),
|
|
4969
4974
|
agentId: handler.agentId,
|
|
4970
4975
|
sessionId,
|
|
4971
4976
|
content: message.content
|
|
@@ -5168,9 +5173,13 @@ ${context.content.join("\n\n")}`;
|
|
|
5168
5173
|
} else if (message.type === "agent-status" || message.type === "agent-done" || message.type === "agent-error") {
|
|
5169
5174
|
const messageQueue = sessionMessageQueues.get(message.sessionId);
|
|
5170
5175
|
if (messageQueue) {
|
|
5171
|
-
const
|
|
5176
|
+
const getQueueMessageType = (handlerMessageType) => {
|
|
5177
|
+
if (handlerMessageType === "agent-status") return "status";
|
|
5178
|
+
if (handlerMessageType === "agent-done") return "done";
|
|
5179
|
+
return "error";
|
|
5180
|
+
};
|
|
5172
5181
|
messageQueue.push({
|
|
5173
|
-
type:
|
|
5182
|
+
type: getQueueMessageType(message.type),
|
|
5174
5183
|
content: message.content ?? ""
|
|
5175
5184
|
});
|
|
5176
5185
|
if (message.type === "agent-done" || message.type === "agent-error") {
|
|
@@ -5193,7 +5202,12 @@ ${context.content.join("\n\n")}`;
|
|
|
5193
5202
|
}
|
|
5194
5203
|
}
|
|
5195
5204
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5196
|
-
res.end(
|
|
5205
|
+
res.end(
|
|
5206
|
+
JSON.stringify({
|
|
5207
|
+
status: "ok",
|
|
5208
|
+
handlers: getRegisteredHandlerIds()
|
|
5209
|
+
})
|
|
5210
|
+
);
|
|
5197
5211
|
return;
|
|
5198
5212
|
}
|
|
5199
5213
|
res.writeHead(404);
|
|
@@ -5208,7 +5222,10 @@ ${context.content.join("\n\n")}`;
|
|
|
5208
5222
|
});
|
|
5209
5223
|
webSocketServer.on("connection", (socket, request) => {
|
|
5210
5224
|
if (token) {
|
|
5211
|
-
const connectionUrl = new URL(
|
|
5225
|
+
const connectionUrl = new URL(
|
|
5226
|
+
request.url ?? "",
|
|
5227
|
+
`http://localhost:${port}`
|
|
5228
|
+
);
|
|
5212
5229
|
const clientToken = connectionUrl.searchParams.get(RELAY_TOKEN_PARAM);
|
|
5213
5230
|
if (clientToken !== token) {
|
|
5214
5231
|
socket.close(4001, "Unauthorized");
|
|
@@ -5249,7 +5266,9 @@ ${context.content.join("\n\n")}`;
|
|
|
5249
5266
|
});
|
|
5250
5267
|
socket.on("message", (data) => {
|
|
5251
5268
|
try {
|
|
5252
|
-
const message = JSON.parse(
|
|
5269
|
+
const message = JSON.parse(
|
|
5270
|
+
data.toString()
|
|
5271
|
+
);
|
|
5253
5272
|
handleBrowserMessage(socket, message);
|
|
5254
5273
|
} catch {
|
|
5255
5274
|
}
|
|
@@ -5294,7 +5313,10 @@ ${context.content.join("\n\n")}`;
|
|
|
5294
5313
|
httpServer?.close();
|
|
5295
5314
|
};
|
|
5296
5315
|
const registerHandler = (handler) => {
|
|
5297
|
-
registeredHandlers.set(handler.agentId, {
|
|
5316
|
+
registeredHandlers.set(handler.agentId, {
|
|
5317
|
+
agentId: handler.agentId,
|
|
5318
|
+
handler
|
|
5319
|
+
});
|
|
5298
5320
|
broadcastHandlerList();
|
|
5299
5321
|
};
|
|
5300
5322
|
const unregisterHandler = (agentId) => {
|
|
@@ -7855,7 +7877,7 @@ async function fkill(inputs, options = {}) {
|
|
|
7855
7877
|
}
|
|
7856
7878
|
}
|
|
7857
7879
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
7858
|
-
var VERSION = "0.1.0
|
|
7880
|
+
var VERSION = "0.1.0";
|
|
7859
7881
|
var checkIfRelayServerIsRunning = async (port, token) => {
|
|
7860
7882
|
try {
|
|
7861
7883
|
const healthUrl = token ? `http://localhost:${port}/health?${RELAY_TOKEN_PARAM}=${encodeURIComponent(token)}` : `http://localhost:${port}/health`;
|
|
@@ -7873,7 +7895,10 @@ var connectRelay = async (options) => {
|
|
|
7873
7895
|
const { handler, token } = options;
|
|
7874
7896
|
let relayServer = null;
|
|
7875
7897
|
let isRelayHost = false;
|
|
7876
|
-
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
7898
|
+
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
7899
|
+
relayPort,
|
|
7900
|
+
token
|
|
7901
|
+
);
|
|
7877
7902
|
if (isRelayServerRunning) {
|
|
7878
7903
|
relayServer = await connectToExistingRelay(relayPort, handler, token);
|
|
7879
7904
|
} else {
|
package/dist/cli.js
CHANGED
|
@@ -4936,8 +4936,13 @@ ${context.content.join("\n\n")}`;
|
|
|
4936
4936
|
signal
|
|
4937
4937
|
})) {
|
|
4938
4938
|
if (signal.aborted) break;
|
|
4939
|
+
const getBrowserMessageType = (messageType) => {
|
|
4940
|
+
if (messageType === "status") return "agent-status";
|
|
4941
|
+
if (messageType === "error") return "agent-error";
|
|
4942
|
+
return "agent-done";
|
|
4943
|
+
};
|
|
4939
4944
|
sendToBrowser(browserSocket, {
|
|
4940
|
-
type: message.type
|
|
4945
|
+
type: getBrowserMessageType(message.type),
|
|
4941
4946
|
agentId: handler.agentId,
|
|
4942
4947
|
sessionId,
|
|
4943
4948
|
content: message.content
|
|
@@ -5140,9 +5145,13 @@ ${context.content.join("\n\n")}`;
|
|
|
5140
5145
|
} else if (message.type === "agent-status" || message.type === "agent-done" || message.type === "agent-error") {
|
|
5141
5146
|
const messageQueue = sessionMessageQueues.get(message.sessionId);
|
|
5142
5147
|
if (messageQueue) {
|
|
5143
|
-
const
|
|
5148
|
+
const getQueueMessageType = (handlerMessageType) => {
|
|
5149
|
+
if (handlerMessageType === "agent-status") return "status";
|
|
5150
|
+
if (handlerMessageType === "agent-done") return "done";
|
|
5151
|
+
return "error";
|
|
5152
|
+
};
|
|
5144
5153
|
messageQueue.push({
|
|
5145
|
-
type:
|
|
5154
|
+
type: getQueueMessageType(message.type),
|
|
5146
5155
|
content: message.content ?? ""
|
|
5147
5156
|
});
|
|
5148
5157
|
if (message.type === "agent-done" || message.type === "agent-error") {
|
|
@@ -5165,7 +5174,12 @@ ${context.content.join("\n\n")}`;
|
|
|
5165
5174
|
}
|
|
5166
5175
|
}
|
|
5167
5176
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
5168
|
-
res.end(
|
|
5177
|
+
res.end(
|
|
5178
|
+
JSON.stringify({
|
|
5179
|
+
status: "ok",
|
|
5180
|
+
handlers: getRegisteredHandlerIds()
|
|
5181
|
+
})
|
|
5182
|
+
);
|
|
5169
5183
|
return;
|
|
5170
5184
|
}
|
|
5171
5185
|
res.writeHead(404);
|
|
@@ -5180,7 +5194,10 @@ ${context.content.join("\n\n")}`;
|
|
|
5180
5194
|
});
|
|
5181
5195
|
webSocketServer.on("connection", (socket, request) => {
|
|
5182
5196
|
if (token) {
|
|
5183
|
-
const connectionUrl = new URL(
|
|
5197
|
+
const connectionUrl = new URL(
|
|
5198
|
+
request.url ?? "",
|
|
5199
|
+
`http://localhost:${port}`
|
|
5200
|
+
);
|
|
5184
5201
|
const clientToken = connectionUrl.searchParams.get(RELAY_TOKEN_PARAM);
|
|
5185
5202
|
if (clientToken !== token) {
|
|
5186
5203
|
socket.close(4001, "Unauthorized");
|
|
@@ -5221,7 +5238,9 @@ ${context.content.join("\n\n")}`;
|
|
|
5221
5238
|
});
|
|
5222
5239
|
socket.on("message", (data) => {
|
|
5223
5240
|
try {
|
|
5224
|
-
const message = JSON.parse(
|
|
5241
|
+
const message = JSON.parse(
|
|
5242
|
+
data.toString()
|
|
5243
|
+
);
|
|
5225
5244
|
handleBrowserMessage(socket, message);
|
|
5226
5245
|
} catch {
|
|
5227
5246
|
}
|
|
@@ -5266,7 +5285,10 @@ ${context.content.join("\n\n")}`;
|
|
|
5266
5285
|
httpServer?.close();
|
|
5267
5286
|
};
|
|
5268
5287
|
const registerHandler = (handler) => {
|
|
5269
|
-
registeredHandlers.set(handler.agentId, {
|
|
5288
|
+
registeredHandlers.set(handler.agentId, {
|
|
5289
|
+
agentId: handler.agentId,
|
|
5290
|
+
handler
|
|
5291
|
+
});
|
|
5270
5292
|
broadcastHandlerList();
|
|
5271
5293
|
};
|
|
5272
5294
|
const unregisterHandler = (agentId) => {
|
|
@@ -7827,7 +7849,7 @@ async function fkill(inputs, options = {}) {
|
|
|
7827
7849
|
}
|
|
7828
7850
|
}
|
|
7829
7851
|
var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
7830
|
-
var VERSION = "0.1.0
|
|
7852
|
+
var VERSION = "0.1.0";
|
|
7831
7853
|
var checkIfRelayServerIsRunning = async (port, token) => {
|
|
7832
7854
|
try {
|
|
7833
7855
|
const healthUrl = token ? `http://localhost:${port}/health?${RELAY_TOKEN_PARAM}=${encodeURIComponent(token)}` : `http://localhost:${port}/health`;
|
|
@@ -7845,7 +7867,10 @@ var connectRelay = async (options) => {
|
|
|
7845
7867
|
const { handler, token } = options;
|
|
7846
7868
|
let relayServer = null;
|
|
7847
7869
|
let isRelayHost = false;
|
|
7848
|
-
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
7870
|
+
const isRelayServerRunning = await checkIfRelayServerIsRunning(
|
|
7871
|
+
relayPort,
|
|
7872
|
+
token
|
|
7873
|
+
);
|
|
7849
7874
|
if (isRelayServerRunning) {
|
|
7850
7875
|
relayServer = await connectToExistingRelay(relayPort, handler, token);
|
|
7851
7876
|
} 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 ReactGrabClaudeCode
|
|
2
|
-
|
|
1
|
+
var ReactGrabClaudeCode = (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 = "claude-code";
|
|
381
|
+
var isReactGrabApi = (value) => typeof value === "object" && value !== null && "registerPlugin" in value;
|
|
382
|
+
var createClaudeAgentProvider = (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: "claude-code-agent",
|
|
409
|
+
actions: [
|
|
410
|
+
{
|
|
411
|
+
id: "edit-with-claude-code",
|
|
412
|
+
label: "Edit with Claude",
|
|
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.createClaudeAgentProvider = createClaudeAgentProvider;
|
|
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/claude-code",
|
|
3
|
-
"version": "0.1.0
|
|
4
|
-
"type": "module",
|
|
3
|
+
"version": "0.1.0",
|
|
5
4
|
"bin": {
|
|
6
5
|
"react-grab-claude-code": "./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,19 +23,15 @@
|
|
|
19
23
|
"./dist/*": "./dist/*.js",
|
|
20
24
|
"./dist/*.js": "./dist/*.js"
|
|
21
25
|
},
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@anthropic-ai/claude-agent-sdk": "^0.1.0",
|
|
28
|
+
"@react-grab/relay": "0.1.0",
|
|
29
|
+
"react-grab": "0.1.0"
|
|
30
|
+
},
|
|
26
31
|
"devDependencies": {
|
|
27
32
|
"@types/node": "^22.10.7",
|
|
28
33
|
"tsup": "^8.4.0",
|
|
29
|
-
"@react-grab/utils": "0.1.0
|
|
30
|
-
},
|
|
31
|
-
"dependencies": {
|
|
32
|
-
"@anthropic-ai/claude-agent-sdk": "^0.1.0",
|
|
33
|
-
"@react-grab/relay": "0.1.0-beta.8",
|
|
34
|
-
"react-grab": "0.1.0-beta.8"
|
|
34
|
+
"@react-grab/utils": "0.1.0"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"dev": "tsup --watch",
|