@agent-link/server 0.1.24 → 0.1.26
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/ws-agent.js +13 -2
- package/dist/ws-agent.js.map +1 -1
- package/package.json +1 -1
- package/web/app.js +41 -10
- package/web/style.css +5 -0
package/dist/ws-agent.js
CHANGED
|
@@ -8,7 +8,9 @@ export function handleAgentConnection(ws, req) {
|
|
|
8
8
|
const name = url.searchParams.get('name') || `Agent-${agentId.slice(0, 8)}`;
|
|
9
9
|
const workDir = url.searchParams.get('workDir') || 'unknown';
|
|
10
10
|
const hostname = url.searchParams.get('hostname') || '';
|
|
11
|
-
|
|
11
|
+
// Reuse requested sessionId (agent reconnecting) or generate a new one
|
|
12
|
+
const requestedSessionId = url.searchParams.get('sessionId');
|
|
13
|
+
const sessionId = requestedSessionId || generateSessionId();
|
|
12
14
|
const sessionKey = generateSessionKey();
|
|
13
15
|
const agent = {
|
|
14
16
|
ws,
|
|
@@ -23,7 +25,7 @@ export function handleAgentConnection(ws, req) {
|
|
|
23
25
|
};
|
|
24
26
|
agents.set(agentId, agent);
|
|
25
27
|
sessionToAgent.set(sessionId, agentId);
|
|
26
|
-
console.log(`[Agent] Registered: ${name} (${agentId}), session: ${sessionId}`);
|
|
28
|
+
console.log(`[Agent] Registered: ${name} (${agentId}), session: ${sessionId}${requestedSessionId ? ' (reconnect)' : ''}`);
|
|
27
29
|
// Send registration with session key (this initial message is plain text)
|
|
28
30
|
ws.send(JSON.stringify({
|
|
29
31
|
type: 'registered',
|
|
@@ -31,6 +33,15 @@ export function handleAgentConnection(ws, req) {
|
|
|
31
33
|
sessionId,
|
|
32
34
|
sessionKey: encodeKey(sessionKey),
|
|
33
35
|
}));
|
|
36
|
+
// Notify any web clients already connected to this session (reconnect scenario)
|
|
37
|
+
for (const [, client] of webClients) {
|
|
38
|
+
if (client.sessionId === sessionId && client.ws.readyState === WebSocket.OPEN) {
|
|
39
|
+
encryptAndSend(client.ws, {
|
|
40
|
+
type: 'agent_reconnected',
|
|
41
|
+
agent: { agentId, name, hostname, workDir },
|
|
42
|
+
}, client.sessionKey);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
34
45
|
ws.on('message', (data) => {
|
|
35
46
|
handleAgentMessage(agentId, data.toString());
|
|
36
47
|
});
|
package/dist/ws-agent.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ws-agent.js","sourceRoot":"","sources":["../src/ws-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACpC,OAAO,EACL,MAAM,EACN,cAAc,EACd,UAAU,EACV,iBAAiB,GAElB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE9F,MAAM,UAAU,qBAAqB,CAAC,EAAa,EAAE,GAAoB;IACvE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,UAAU,EAAE,CAAC;IAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,SAAS,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;IAC5E,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,SAAS,CAAC;IAC7D,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,EAAE,CAAC;IAExD,MAAM,SAAS,GAAG,iBAAiB,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ws-agent.js","sourceRoot":"","sources":["../src/ws-agent.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/web/app.js
CHANGED
|
@@ -825,6 +825,12 @@ const App = {
|
|
|
825
825
|
});
|
|
826
826
|
|
|
827
827
|
// ── WebSocket ──
|
|
828
|
+
let reconnectAttempts = 0;
|
|
829
|
+
const MAX_RECONNECT_ATTEMPTS = 50;
|
|
830
|
+
const RECONNECT_BASE_DELAY = 1000;
|
|
831
|
+
const RECONNECT_MAX_DELAY = 15000;
|
|
832
|
+
let reconnectTimer = null;
|
|
833
|
+
|
|
828
834
|
function connect() {
|
|
829
835
|
const sid = getSessionId();
|
|
830
836
|
if (!sid) {
|
|
@@ -833,12 +839,14 @@ const App = {
|
|
|
833
839
|
return;
|
|
834
840
|
}
|
|
835
841
|
sessionId.value = sid;
|
|
842
|
+
status.value = 'Connecting...';
|
|
843
|
+
error.value = '';
|
|
836
844
|
|
|
837
845
|
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
|
838
846
|
const wsUrl = `${protocol}//${window.location.host}/?type=web&sessionId=${sid}`;
|
|
839
847
|
ws = new WebSocket(wsUrl);
|
|
840
848
|
|
|
841
|
-
ws.onopen = () => { error.value = ''; };
|
|
849
|
+
ws.onopen = () => { error.value = ''; reconnectAttempts = 0; };
|
|
842
850
|
|
|
843
851
|
ws.onmessage = (event) => {
|
|
844
852
|
let msg;
|
|
@@ -878,13 +886,21 @@ const App = {
|
|
|
878
886
|
error.value = 'Agent is not connected yet.';
|
|
879
887
|
}
|
|
880
888
|
} else if (msg.type === 'agent_disconnected') {
|
|
881
|
-
status.value = '
|
|
889
|
+
status.value = 'Waiting';
|
|
882
890
|
agentName.value = '';
|
|
883
891
|
hostname.value = '';
|
|
884
|
-
|
|
885
|
-
error.value = 'Agent has disconnected.';
|
|
892
|
+
error.value = 'Agent disconnected. Waiting for reconnect...';
|
|
886
893
|
isProcessing.value = false;
|
|
887
894
|
isCompacting.value = false;
|
|
895
|
+
} else if (msg.type === 'agent_reconnected') {
|
|
896
|
+
status.value = 'Connected';
|
|
897
|
+
error.value = '';
|
|
898
|
+
if (msg.agent) {
|
|
899
|
+
agentName.value = msg.agent.name;
|
|
900
|
+
hostname.value = msg.agent.hostname || '';
|
|
901
|
+
workDir.value = msg.agent.workDir;
|
|
902
|
+
}
|
|
903
|
+
requestSessionList();
|
|
888
904
|
} else if (msg.type === 'error') {
|
|
889
905
|
status.value = 'Error';
|
|
890
906
|
error.value = msg.message;
|
|
@@ -1035,17 +1051,32 @@ const App = {
|
|
|
1035
1051
|
|
|
1036
1052
|
ws.onclose = () => {
|
|
1037
1053
|
sessionKey = null;
|
|
1038
|
-
|
|
1039
|
-
status.value = 'Disconnected';
|
|
1040
|
-
error.value = 'Connection to server lost.';
|
|
1041
|
-
}
|
|
1054
|
+
const wasConnected = status.value === 'Connected' || status.value === 'Connecting...';
|
|
1042
1055
|
isProcessing.value = false;
|
|
1043
1056
|
isCompacting.value = false;
|
|
1057
|
+
|
|
1058
|
+
if (wasConnected || reconnectAttempts > 0) {
|
|
1059
|
+
scheduleReconnect();
|
|
1060
|
+
}
|
|
1044
1061
|
};
|
|
1045
1062
|
|
|
1046
1063
|
ws.onerror = () => {};
|
|
1047
1064
|
}
|
|
1048
1065
|
|
|
1066
|
+
function scheduleReconnect() {
|
|
1067
|
+
if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
|
|
1068
|
+
status.value = 'Disconnected';
|
|
1069
|
+
error.value = 'Unable to reconnect. Please refresh the page.';
|
|
1070
|
+
return;
|
|
1071
|
+
}
|
|
1072
|
+
const delay = Math.min(RECONNECT_BASE_DELAY * Math.pow(1.5, reconnectAttempts), RECONNECT_MAX_DELAY);
|
|
1073
|
+
reconnectAttempts++;
|
|
1074
|
+
status.value = 'Reconnecting...';
|
|
1075
|
+
error.value = 'Connection lost. Reconnecting... (attempt ' + reconnectAttempts + ')';
|
|
1076
|
+
if (reconnectTimer) clearTimeout(reconnectTimer);
|
|
1077
|
+
reconnectTimer = setTimeout(() => { reconnectTimer = null; connect(); }, delay);
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1049
1080
|
function handleClaudeOutput(msg) {
|
|
1050
1081
|
const data = msg.data;
|
|
1051
1082
|
if (!data) return;
|
|
@@ -1111,7 +1142,7 @@ const App = {
|
|
|
1111
1142
|
watch(messageCount, () => { nextTick(scheduleHighlight); });
|
|
1112
1143
|
|
|
1113
1144
|
onMounted(() => { connect(); });
|
|
1114
|
-
onUnmounted(() => { if (ws) ws.close(); });
|
|
1145
|
+
onUnmounted(() => { if (reconnectTimer) clearTimeout(reconnectTimer); if (ws) ws.close(); });
|
|
1115
1146
|
|
|
1116
1147
|
return {
|
|
1117
1148
|
status, agentName, hostname, workDir, sessionId, error,
|
|
@@ -1158,7 +1189,7 @@ const App = {
|
|
|
1158
1189
|
</div>
|
|
1159
1190
|
</header>
|
|
1160
1191
|
|
|
1161
|
-
<div v-if="status === 'No Session' || (status !== 'Connected' && status !== 'Connecting...' && messages.length === 0)" class="center-card">
|
|
1192
|
+
<div v-if="status === 'No Session' || (status !== 'Connected' && status !== 'Connecting...' && status !== 'Reconnecting...' && messages.length === 0)" class="center-card">
|
|
1162
1193
|
<div class="status-card">
|
|
1163
1194
|
<p class="status">
|
|
1164
1195
|
<span class="label">Status:</span>
|
package/web/style.css
CHANGED
|
@@ -191,6 +191,11 @@ body {
|
|
|
191
191
|
background: rgba(245, 158, 11, 0.1);
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
+
.badge.reconnecting\.\.\. {
|
|
195
|
+
color: var(--warning);
|
|
196
|
+
background: rgba(245, 158, 11, 0.1);
|
|
197
|
+
}
|
|
198
|
+
|
|
194
199
|
.badge.waiting {
|
|
195
200
|
color: var(--warning);
|
|
196
201
|
background: rgba(245, 158, 11, 0.1);
|