@aion0/forge 0.5.28 → 0.5.29

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/RELEASE_NOTES.md CHANGED
@@ -1,17 +1,11 @@
1
- # Forge v0.5.28
1
+ # Forge v0.5.29
2
2
 
3
3
  Released: 2026-04-09
4
4
 
5
- ## Changes since v0.5.27
5
+ ## Changes since v0.5.28
6
6
 
7
7
  ### Bug Fixes
8
- - fix: restore notification polling for Telegram, add Suspense wrappers
8
+ - fix: auto-reconnect workspace terminal WebSocket on disconnect
9
9
 
10
- ### Performance
11
- - perf: notifications fetch on-demand instead of polling
12
- - perf: remove task completion polling (replaced by hook stop)
13
- - perf: reduce polling frequency and lazy-load non-essential components
14
- - perf: async terminal-cwd to avoid blocking event loop
15
10
 
16
-
17
- **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.5.27...v0.5.28
11
+ **Full Changelog**: https://github.com/aiwatching/forge/compare/v0.5.28...v0.5.29
@@ -2292,11 +2292,36 @@ function FloatingTerminal({ agentLabel, agentIcon, projectPath, agentCliId, cliC
2292
2292
  }
2293
2293
  };
2294
2294
 
2295
+ let reconnectTimer: ReturnType<typeof setTimeout> | null = null;
2296
+ const reconnect = () => {
2297
+ if (disposed || reconnectTimer) return;
2298
+ term.write('\r\n\x1b[93m[Reconnecting...]\x1b[0m\r\n');
2299
+ reconnectTimer = setTimeout(() => {
2300
+ reconnectTimer = null;
2301
+ if (disposed) return;
2302
+ const newWs = new WebSocket(getWsUrl());
2303
+ wsRef.current = newWs;
2304
+ const sn = sessionNameRef.current || preferredSessionName;
2305
+ newWs.onopen = () => {
2306
+ newWs.send(JSON.stringify({ type: 'attach', sessionName: sn, cols: term.cols, rows: term.rows }));
2307
+ };
2308
+ newWs.onerror = () => { if (!disposed) reconnect(); };
2309
+ newWs.onclose = () => { if (!disposed) reconnect(); };
2310
+ newWs.onmessage = ws.onmessage;
2311
+ }, 2000);
2312
+ };
2313
+
2295
2314
  ws.onerror = () => {
2296
- if (!disposed) term.write('\r\n\x1b[91m[Connection error]\x1b[0m\r\n');
2315
+ if (!disposed) {
2316
+ term.write('\r\n\x1b[91m[Connection error]\x1b[0m\r\n');
2317
+ reconnect();
2318
+ }
2297
2319
  };
2298
2320
  ws.onclose = () => {
2299
- if (!disposed) term.write('\r\n\x1b[90m[Disconnected]\x1b[0m\r\n');
2321
+ if (!disposed) {
2322
+ term.write('\r\n\x1b[90m[Disconnected]\x1b[0m\r\n');
2323
+ reconnect();
2324
+ }
2300
2325
  };
2301
2326
 
2302
2327
  let launched = false;
@@ -2390,16 +2415,19 @@ function FloatingTerminal({ agentLabel, agentIcon, projectPath, agentCliId, cliC
2390
2415
  };
2391
2416
 
2392
2417
  term.onData(data => {
2393
- if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'input', data }));
2418
+ const activeWs = wsRef.current;
2419
+ if (activeWs?.readyState === WebSocket.OPEN) activeWs.send(JSON.stringify({ type: 'input', data }));
2394
2420
  });
2395
2421
  term.onResize(({ cols, rows }) => {
2396
- if (ws.readyState === WebSocket.OPEN) ws.send(JSON.stringify({ type: 'resize', cols, rows }));
2422
+ const activeWs = wsRef.current;
2423
+ if (activeWs?.readyState === WebSocket.OPEN) activeWs.send(JSON.stringify({ type: 'resize', cols, rows }));
2397
2424
  });
2398
2425
 
2399
2426
  return () => {
2400
2427
  disposed = true;
2428
+ if (reconnectTimer) clearTimeout(reconnectTimer);
2401
2429
  ro.disconnect();
2402
- ws.close();
2430
+ (wsRef.current || ws).close();
2403
2431
  term.dispose();
2404
2432
  };
2405
2433
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aion0/forge",
3
- "version": "0.5.28",
3
+ "version": "0.5.29",
4
4
  "description": "Unified AI workflow platform — multi-model task orchestration, persistent sessions, web terminal, remote access",
5
5
  "type": "module",
6
6
  "scripts": {