@mjasnikovs/pi-task 0.16.0 → 0.16.1

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.
@@ -109,14 +109,38 @@ export async function startServer(onMessage, getHtml) {
109
109
  }
110
110
  });
111
111
  const wss = new WebSocketServer({ server: httpServer, path: '/ws' });
112
+ // Track every accepted TCP socket so stop() can forcibly destroy lingering
113
+ // keep-alive / WebSocket connections. Without this, httpServer.close() only
114
+ // stops accepting new connections and waits for existing ones to drain — an
115
+ // open browser tab never drains, so the listening server and its sockets
116
+ // stay as active event-loop handles forever. In headless print mode the host
117
+ // exits by natural event-loop drain (it sets process.exitCode and returns,
118
+ // with no process.exit()), so these lingering handles keep the pi process
119
+ // alive indefinitely — which blocks `docker stop` / OS shutdown until the
120
+ // SIGKILL grace timeout fires. A/B-proven: terminating clients + destroying
121
+ // sockets here makes the loop drain in ~2ms instead of never.
122
+ const sockets = new Set();
123
+ httpServer.on('connection', s => {
124
+ sockets.add(s);
125
+ s.on('close', () => sockets.delete(s));
126
+ });
112
127
  const handle = {
113
128
  port,
114
129
  ip,
115
130
  ips,
116
131
  onFirstConnect: null,
117
132
  stop() {
133
+ // Terminate WebSocket clients (immediate close, no drain), then
134
+ // destroy any remaining raw sockets, then close the servers so the
135
+ // event loop has no lingering handles holding the process open.
136
+ for (const ws of wss.clients)
137
+ ws.terminate();
118
138
  wss.close();
139
+ for (const s of sockets)
140
+ s.destroy();
141
+ sockets.clear();
119
142
  httpServer.close();
143
+ httpServer.closeAllConnections?.();
120
144
  }
121
145
  };
122
146
  wss.on('connection', ws => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjasnikovs/pi-task",
3
- "version": "0.16.0",
3
+ "version": "0.16.1",
4
4
  "description": "Deterministic spec-orchestration for local models, with a bundled real-time remote web view and web/docs/fetch/worker subagent tools.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",