@holin-work/holin-cli 1.1.1 → 1.1.3
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 +50 -29
- package/package.json +1 -1
package/bin/holin-cli.js
CHANGED
|
@@ -123,9 +123,30 @@ async function pingVerify(apiKey) {
|
|
|
123
123
|
|
|
124
124
|
function createProxyServer() {
|
|
125
125
|
const server = http.createServer((req, res) => {
|
|
126
|
+
// Block OAuth discovery probes — return 401 so platform knows auth is required
|
|
127
|
+
if (req.url.startsWith("/.well-known/")) {
|
|
128
|
+
const body = JSON.stringify({ error: "unauthorized" });
|
|
129
|
+
res.writeHead(401, { "Content-Type": "application/json", "Content-Length": Buffer.byteLength(body) });
|
|
130
|
+
res.end(body);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Read credentials on every request (hot-reload support)
|
|
135
|
+
const creds = readCredentials();
|
|
136
|
+
if (!creds?.api_key) {
|
|
137
|
+
// No credentials: return 401 so platform knows auth is required (not "no auth needed")
|
|
138
|
+
const body = JSON.stringify({ error: "unauthorized", message: "Run 'holin-cli auth login' first." });
|
|
139
|
+
res.writeHead(401, {
|
|
140
|
+
"Content-Type": "application/json",
|
|
141
|
+
"Content-Length": Buffer.byteLength(body),
|
|
142
|
+
"WWW-Authenticate": "Bearer realm=\"Holin API\"",
|
|
143
|
+
});
|
|
144
|
+
res.end(body);
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
|
|
126
148
|
// Health check endpoint
|
|
127
149
|
if (req.method === "GET" && req.url === "/health") {
|
|
128
|
-
const creds = readCredentials();
|
|
129
150
|
const body = JSON.stringify({
|
|
130
151
|
status: "ok",
|
|
131
152
|
authenticated: !!(creds && creds.api_key),
|
|
@@ -142,18 +163,6 @@ function createProxyServer() {
|
|
|
142
163
|
return;
|
|
143
164
|
}
|
|
144
165
|
|
|
145
|
-
// Read credentials on every request (hot-reload support)
|
|
146
|
-
const creds = readCredentials();
|
|
147
|
-
if (!creds?.api_key) {
|
|
148
|
-
const body = JSON.stringify({ error: "not_authenticated", message: "Run 'holin-cli auth login' first." });
|
|
149
|
-
res.writeHead(401, {
|
|
150
|
-
"Content-Type": "application/json",
|
|
151
|
-
"Content-Length": Buffer.byteLength(body),
|
|
152
|
-
});
|
|
153
|
-
res.end(body);
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
166
|
// Build upstream request
|
|
158
167
|
// MCP streamable-http has a single endpoint; forward directly to upstream path.
|
|
159
168
|
// Accio requests http://127.0.0.1:18787/mcp → upstream https://api.holin.work/icbu/mcp
|
|
@@ -246,9 +255,9 @@ async function cmdAuthLogin() {
|
|
|
246
255
|
writeCredentials(creds);
|
|
247
256
|
console.log(`[holin-cli] Connected: ${creds.customer_name || creds.customer_id} (${creds.plan})`);
|
|
248
257
|
|
|
249
|
-
// Auto-start proxy in background (detached)
|
|
258
|
+
// Auto-start proxy in background (detached), wait until it's listening
|
|
250
259
|
try {
|
|
251
|
-
startProxyDaemon();
|
|
260
|
+
await startProxyDaemon();
|
|
252
261
|
console.log("[holin-cli] Local proxy started at http://127.0.0.1:18787/mcp");
|
|
253
262
|
} catch (err) {
|
|
254
263
|
console.error(`[holin-cli] Warning: Failed to start local proxy — ${err.message}`);
|
|
@@ -329,23 +338,35 @@ function cmdProxyStart() {
|
|
|
329
338
|
}
|
|
330
339
|
|
|
331
340
|
function startProxyDaemon() {
|
|
332
|
-
|
|
341
|
+
return new Promise((resolve, reject) => {
|
|
342
|
+
if (isProxyRunning()) {
|
|
343
|
+
resolve();
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
333
346
|
|
|
334
|
-
|
|
335
|
-
|
|
347
|
+
ensureConfigDir();
|
|
348
|
+
const logFd = openSync(LOG_FILE, "a");
|
|
336
349
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
350
|
+
const child = spawn(process.execPath, [process.argv[1], "proxy", "start", "--daemon"], {
|
|
351
|
+
detached: true,
|
|
352
|
+
stdio: ["ignore", logFd, logFd],
|
|
353
|
+
});
|
|
341
354
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
355
|
+
child.unref();
|
|
356
|
+
|
|
357
|
+
// Poll for pid file up to 3s to confirm proxy is listening
|
|
358
|
+
let attempts = 0;
|
|
359
|
+
const poll = setInterval(() => {
|
|
360
|
+
attempts++;
|
|
361
|
+
if (isProxyRunning()) {
|
|
362
|
+
clearInterval(poll);
|
|
363
|
+
resolve();
|
|
364
|
+
} else if (attempts >= 15) {
|
|
365
|
+
clearInterval(poll);
|
|
366
|
+
reject(new Error(`Proxy did not start within 3s. Check log: ${LOG_FILE}`));
|
|
367
|
+
}
|
|
368
|
+
}, 200);
|
|
369
|
+
});
|
|
349
370
|
}
|
|
350
371
|
|
|
351
372
|
function cmdProxyStop() {
|