@holin-work/holin-cli 1.3.6 → 1.3.7
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/bin/holin-cli.js +40 -36
- package/package.json +1 -1
package/bin/holin-cli.js
CHANGED
|
@@ -234,6 +234,25 @@ function createProxyServer() {
|
|
|
234
234
|
return;
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
+
// Health check endpoint — must be before credential check so waitForPort probes always succeed
|
|
238
|
+
if (req.method === "GET" && req.url === "/health") {
|
|
239
|
+
const creds = readCredentials();
|
|
240
|
+
const body = JSON.stringify({
|
|
241
|
+
status: "ok",
|
|
242
|
+
authenticated: !!(creds?.api_key),
|
|
243
|
+
customer: creds?.customer_name || null,
|
|
244
|
+
plan: creds?.plan || null,
|
|
245
|
+
upstream: UPSTREAM_URL,
|
|
246
|
+
pid: process.pid,
|
|
247
|
+
});
|
|
248
|
+
res.writeHead(200, {
|
|
249
|
+
"Content-Type": "application/json",
|
|
250
|
+
"Content-Length": Buffer.byteLength(body),
|
|
251
|
+
});
|
|
252
|
+
res.end(body);
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
|
|
237
256
|
// Read credentials on every request (hot-reload support)
|
|
238
257
|
const creds = readCredentials();
|
|
239
258
|
if (!creds?.api_key) {
|
|
@@ -248,24 +267,6 @@ function createProxyServer() {
|
|
|
248
267
|
return;
|
|
249
268
|
}
|
|
250
269
|
|
|
251
|
-
// Health check endpoint
|
|
252
|
-
if (req.method === "GET" && req.url === "/health") {
|
|
253
|
-
const body = JSON.stringify({
|
|
254
|
-
status: "ok",
|
|
255
|
-
authenticated: !!(creds && creds.api_key),
|
|
256
|
-
customer: creds?.customer_name || null,
|
|
257
|
-
plan: creds?.plan || null,
|
|
258
|
-
upstream: UPSTREAM_URL,
|
|
259
|
-
pid: process.pid,
|
|
260
|
-
});
|
|
261
|
-
res.writeHead(200, {
|
|
262
|
-
"Content-Type": "application/json",
|
|
263
|
-
"Content-Length": Buffer.byteLength(body),
|
|
264
|
-
});
|
|
265
|
-
res.end(body);
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
270
|
// Build upstream request
|
|
270
271
|
// MCP streamable-http has a single endpoint; forward directly to upstream path.
|
|
271
272
|
// Accio requests http://127.0.0.1:18787/mcp → upstream https://api.holin.work/icbu/mcp
|
|
@@ -602,26 +603,29 @@ function waitForPort(port, host, timeoutMs) {
|
|
|
602
603
|
|
|
603
604
|
function startProxyDaemon() {
|
|
604
605
|
return new Promise((resolve, reject) => {
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
606
|
+
// Always verify the port is actually reachable first, regardless of pid file.
|
|
607
|
+
// The old proxy may have exited (idle timeout) while the pid file is stale.
|
|
608
|
+
waitForPort(PROXY_PORT, PROXY_HOST, 500)
|
|
609
|
+
.then(() => {
|
|
610
|
+
// Port is already up — existing proxy is healthy, no need to spawn.
|
|
611
|
+
resolve();
|
|
612
|
+
})
|
|
613
|
+
.catch(() => {
|
|
614
|
+
// Port not reachable — spawn a new proxy daemon regardless of pid file state.
|
|
615
|
+
ensureConfigDir();
|
|
616
|
+
const logFd = openSync(LOG_FILE, "a");
|
|
617
|
+
|
|
618
|
+
const child = spawn(process.execPath, [process.argv[1], "proxy", "start", "--daemon"], {
|
|
619
|
+
detached: true,
|
|
620
|
+
stdio: ["ignore", logFd, logFd],
|
|
621
|
+
});
|
|
618
622
|
|
|
619
|
-
|
|
623
|
+
child.unref();
|
|
620
624
|
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
+
// Wait until the proxy port is actually accepting connections (up to 10s).
|
|
626
|
+
// Only resolve after a real HTTP response from /health — never resolve on catch.
|
|
627
|
+
waitForPort(PROXY_PORT, PROXY_HOST, 10000).then(resolve).catch(reject);
|
|
628
|
+
});
|
|
625
629
|
});
|
|
626
630
|
}
|
|
627
631
|
|