@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 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
- const sessionId = generateSessionId();
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
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ws-agent.js","sourceRoot":"","sources":["../src/ws-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ws-agent.js","sourceRoot":"","sources":["../src/ws-agent.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-link/server",
3
- "version": "0.1.24",
3
+ "version": "0.1.26",
4
4
  "description": "AgentLink relay server",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
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 = 'Disconnected';
889
+ status.value = 'Waiting';
882
890
  agentName.value = '';
883
891
  hostname.value = '';
884
- workDir.value = '';
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
- if (status.value === 'Connected' || status.value === 'Connecting...') {
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);