zback 1.4.1 → 1.4.2
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/README.md +13 -0
- package/bin/zback.js +8 -6
- package/package.json +1 -1
- package/src/agent.js +3 -3
package/README.md
CHANGED
|
@@ -82,3 +82,16 @@ The npm package declares its remote administration capabilities as dual-use soft
|
|
|
82
82
|
```sh
|
|
83
83
|
npm test
|
|
84
84
|
```
|
|
85
|
+
|
|
86
|
+
## Connection health (1.2.6)
|
|
87
|
+
|
|
88
|
+
Normal WebSocket ping/pong checks update the local health timestamp silently. A
|
|
89
|
+
`Connection restored` message is printed **only after a real WebSocket
|
|
90
|
+
disconnection and a successful new handshake**, never after a routine pong.
|
|
91
|
+
A delayed pong has a 60-second grace period before the client reconnects.
|
|
92
|
+
The private session identifier remains derived from the local agent key and
|
|
93
|
+
does not change on reconnection. If the connection truly closes, the terminal
|
|
94
|
+
now reports the WebSocket close code and available server reason.
|
|
95
|
+
|
|
96
|
+
Update the backend to 1.2.4 for relaxed server heartbeat handling too. This
|
|
97
|
+
does not change `--timeout 0`, MCP tools, or interactive consent behavior.
|
package/bin/zback.js
CHANGED
|
@@ -10,9 +10,9 @@ import { createTerminal, createEventReporter } from '../src/terminal.js';
|
|
|
10
10
|
import { activeSession, agentKey, consentFile, hasConsent, initStateDir, logFile, readJson, resetKey, sameSession, saveJson, settingsFile, stateFile, alive } from '../src/runtime.js';
|
|
11
11
|
|
|
12
12
|
const ENTRY = fileURLToPath(import.meta.url);
|
|
13
|
-
const VERSION = '1.2.
|
|
13
|
+
const VERSION = '1.2.6';
|
|
14
14
|
const DEFAULT_URL = 'wss://zb.soymaycol.icu/ws';
|
|
15
|
-
const STALE_AFTER_MS =
|
|
15
|
+
const STALE_AFTER_MS = 120000;
|
|
16
16
|
|
|
17
17
|
function connectionStatus(state) {
|
|
18
18
|
if (state.status === 'connected' && (!Number.isFinite(Date.parse(state.updated)) || Date.now() - Date.parse(state.updated) > STALE_AFTER_MS)) return 'unresponsive';
|
|
@@ -113,8 +113,9 @@ async function worker() {
|
|
|
113
113
|
const mark = data => {
|
|
114
114
|
const previous = readJson(stateFile);
|
|
115
115
|
if (previous && previous.status !== 'stopped' && previous.pid !== process.pid && alive(previous.pid)) return;
|
|
116
|
-
|
|
117
|
-
|
|
116
|
+
const { heartbeat, ...state } = data;
|
|
117
|
+
saveJson(stateFile, { pid: process.pid, started, version: VERSION, updated: new Date().toISOString(), ...state });
|
|
118
|
+
if (data.status === 'connected' && !heartbeat) {
|
|
118
119
|
reporter.clearProblem();
|
|
119
120
|
if (!lastId) terminal.connected(data.id, mcpEndpoint(settings.url));
|
|
120
121
|
else terminal.restored();
|
|
@@ -242,8 +243,9 @@ async function start(options) {
|
|
|
242
243
|
let lastId = null;
|
|
243
244
|
const reporter = createEventReporter(terminal);
|
|
244
245
|
const mark = data => {
|
|
245
|
-
|
|
246
|
-
|
|
246
|
+
const { heartbeat, ...state } = data;
|
|
247
|
+
saveJson(stateFile, { pid: process.pid, started, version: VERSION, updated: new Date().toISOString(), ...state });
|
|
248
|
+
if (data.status === 'connected' && !heartbeat) {
|
|
247
249
|
reporter.clearProblem();
|
|
248
250
|
if (!lastId) terminal.connected(data.id, mcpEndpoint(options.url));
|
|
249
251
|
else terminal.restored();
|
package/package.json
CHANGED
package/src/agent.js
CHANGED
|
@@ -63,7 +63,7 @@ export async function connectAgent(options, onState, token, onEvent = () => {},
|
|
|
63
63
|
}
|
|
64
64
|
}
|
|
65
65
|
const heartbeatInterval = options.heartbeatIntervalMs ?? 20000;
|
|
66
|
-
const pongTimeout = options.pongTimeoutMs ??
|
|
66
|
+
const pongTimeout = options.pongTimeoutMs ?? 60000;
|
|
67
67
|
let stopped = false;
|
|
68
68
|
let retries = 0;
|
|
69
69
|
let socket = null;
|
|
@@ -136,7 +136,7 @@ export async function connectAgent(options, onState, token, onEvent = () => {},
|
|
|
136
136
|
const pong = () => {
|
|
137
137
|
clearTimeout(pongTimer);
|
|
138
138
|
pongTimer = null;
|
|
139
|
-
if (welcomed && !stopped) update('connected', { id: lastId });
|
|
139
|
+
if (welcomed && !stopped) update('connected', { id: lastId, heartbeat: true });
|
|
140
140
|
};
|
|
141
141
|
const checkConnection = () => {
|
|
142
142
|
if (current.readyState !== WebSocketClient.OPEN || pongTimer || stopped) return;
|
|
@@ -193,7 +193,7 @@ export async function connectAgent(options, onState, token, onEvent = () => {},
|
|
|
193
193
|
const failed = error => disconnected(error?.message || 'WebSocket connection failed');
|
|
194
194
|
const closed = (code, reason) => {
|
|
195
195
|
const detail = reason?.toString();
|
|
196
|
-
disconnected(welcomed ?
|
|
196
|
+
disconnected(welcomed ? `Connection lost (WebSocket ${code}${detail ? `: ${detail}` : ''})` : `Backend closed the connection (WebSocket ${code}${detail ? `: ${detail}` : ''})`);
|
|
197
197
|
};
|
|
198
198
|
current.on('open', opened);
|
|
199
199
|
current.on('message', received);
|