@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.
Files changed (2) hide show
  1. package/bin/holin-cli.js +50 -29
  2. 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
- if (isProxyRunning()) return;
341
+ return new Promise((resolve, reject) => {
342
+ if (isProxyRunning()) {
343
+ resolve();
344
+ return;
345
+ }
333
346
 
334
- ensureConfigDir();
335
- const logFd = openSync(LOG_FILE, "a");
347
+ ensureConfigDir();
348
+ const logFd = openSync(LOG_FILE, "a");
336
349
 
337
- const child = spawn(process.execPath, [process.argv[1], "proxy", "start", "--daemon"], {
338
- detached: true,
339
- stdio: ["ignore", logFd, logFd],
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
- child.unref();
343
- // Give it a moment to start and write pid file
344
- setTimeout(() => {
345
- if (!isProxyRunning()) {
346
- console.error("[holin-cli] Warning: Proxy failed to start. Check log:", LOG_FILE);
347
- }
348
- }, 1000);
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() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holin-work/holin-cli",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Holin CLI — Accio plugin authorization tool for ICBU batch listing",
5
5
  "type": "module",
6
6
  "bin": {