@vendian/cli 0.0.39 → 0.0.41

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/cli-wrapper.mjs +77 -30
  2. package/package.json +1 -1
package/cli-wrapper.mjs CHANGED
@@ -43,7 +43,9 @@ __export(auth_exports, {
43
43
  buildWindowsOpenCommand: () => buildWindowsOpenCommand,
44
44
  cloudAuthStatus: () => cloudAuthStatus,
45
45
  cloudConfigPath: () => cloudConfigPath,
46
+ defaultOAuthRedirectUri: () => defaultOAuthRedirectUri,
46
47
  fetchPackageCredentials: () => fetchPackageCredentials,
48
+ formatOAuthError: () => formatOAuthError,
47
49
  loadCloudConfig: () => loadCloudConfig,
48
50
  loginWithVendianOAuth: () => loginWithVendianOAuth,
49
51
  resolveApiUrl: () => resolveApiUrl,
@@ -91,6 +93,11 @@ async function loginWithVendianOAuth({ backend, apiUrl, noBrowser = false, env =
91
93
  clerkToken
92
94
  });
93
95
  return { apiUrl: resolvedApiUrl, ...exchange };
96
+ } catch (error) {
97
+ throw new Error(formatOAuthError(error, {
98
+ apiUrl: resolvedApiUrl,
99
+ redirectUri: callback.redirectUri
100
+ }), { cause: error });
94
101
  } finally {
95
102
  await callback.close();
96
103
  }
@@ -175,6 +182,16 @@ function activateCloudProfile({ backend, apiUrl, env = process.env, platform = p
175
182
  profiles
176
183
  };
177
184
  }
185
+ function defaultOAuthRedirectUri(env = process.env) {
186
+ const port = Number(env.VENDIAN_CLI_OAUTH_REDIRECT_PORT || DEFAULT_OAUTH_REDIRECT_PORT);
187
+ return `http://127.0.0.1:${port}/callback`;
188
+ }
189
+ function formatOAuthError(error, { apiUrl, redirectUri } = {}) {
190
+ const message = error && typeof error.message === "string" ? error.message : String(error || "OAuth login failed");
191
+ const hint = oauthRedirectHint(message, { apiUrl, redirectUri });
192
+ return hint ? `${message}
193
+ ${hint}` : message;
194
+ }
178
195
  async function getOAuthConfig(apiUrl, redirectUri) {
179
196
  const url = new URL(`${apiUrl}/api/v1/cli/auth/oauth/config`);
180
197
  url.searchParams.set("redirectUri", redirectUri);
@@ -256,6 +273,7 @@ async function createCallbackServer(env) {
256
273
  const code = url.searchParams.get("code");
257
274
  const state = url.searchParams.get("state");
258
275
  const error = url.searchParams.get("error");
276
+ const errorDescription = url.searchParams.get("error_description");
259
277
  const body = code ? "Vendian CLI authentication complete. You can close this window." : "Vendian CLI authentication failed. Return to the terminal.";
260
278
  res.writeHead(code ? 200 : 400, {
261
279
  "Content-Type": "text/plain; charset=utf-8",
@@ -268,7 +286,8 @@ async function createCallbackServer(env) {
268
286
  }
269
287
  settled = true;
270
288
  if (error) {
271
- reject(new Error(`OAuth login failed: ${error}`));
289
+ const details = errorDescription ? `${error} (${errorDescription})` : error;
290
+ reject(new Error(`OAuth login failed: ${details}`));
272
291
  return;
273
292
  }
274
293
  if (!code) {
@@ -290,6 +309,18 @@ async function createCallbackServer(env) {
290
309
  close: () => new Promise((resolve) => server.close(resolve))
291
310
  };
292
311
  }
312
+ function oauthRedirectHint(message, { apiUrl, redirectUri } = {}) {
313
+ if (!redirectUri) {
314
+ return "";
315
+ }
316
+ const lower = String(message || "").toLowerCase();
317
+ const looksLikeRedirectMismatch = lower.includes("redirect_uri") || lower.includes("pre-registered redirect") || lower.includes("oauth login timed out before callback completed") || lower.includes("oauth callback did not include an authorization code");
318
+ if (!looksLikeRedirectMismatch) {
319
+ return "";
320
+ }
321
+ const target = apiUrl || "this backend";
322
+ return `If Clerk rejected the CLI callback for ${target}, add this redirect URL in Clerk: ${redirectUri}`;
323
+ }
293
324
  function openBrowser(url) {
294
325
  const platform = process.platform;
295
326
  if (platform === "win32") {
@@ -491,6 +522,29 @@ function spawnForward(command, args, options = {}) {
491
522
  });
492
523
  });
493
524
  }
525
+ function childProcessIsRunning(child) {
526
+ return Boolean(child) && child.exitCode == null && child.signalCode == null;
527
+ }
528
+ function killProcessTree(child, {
529
+ platform = process.platform,
530
+ signal = "SIGTERM",
531
+ spawnSyncFn = spawnSync
532
+ } = {}) {
533
+ if (!childProcessIsRunning(child)) return false;
534
+ if (platform === "win32") {
535
+ try {
536
+ spawnSyncFn("taskkill", ["/F", "/T", "/PID", String(child.pid)], { stdio: "ignore" });
537
+ } catch {
538
+ }
539
+ return true;
540
+ }
541
+ try {
542
+ child.kill(signal);
543
+ return true;
544
+ } catch {
545
+ return false;
546
+ }
547
+ }
494
548
 
495
549
  // src/python.js
496
550
  import fs2 from "node:fs";
@@ -2381,7 +2435,7 @@ function buildLocalServeEventStreamArgs({ agentsDir: agentsDir2 = "./agents", co
2381
2435
  }
2382
2436
 
2383
2437
  // src/version.js
2384
- var CLI_VERSION = true ? "0.0.39" : process.env.npm_package_version || "0.0.0-dev";
2438
+ var CLI_VERSION = true ? "0.0.41" : process.env.npm_package_version || "0.0.0-dev";
2385
2439
 
2386
2440
  // src/dev-server.js
2387
2441
  var __dirname = path8.dirname(fileURLToPath(import.meta.url));
@@ -2440,8 +2494,8 @@ async function startDevServer({
2440
2494
  }
2441
2495
  function shutdown(server) {
2442
2496
  console.log("\n \x1B[90mShutting down...\x1B[0m");
2443
- if (serveChild && !serveChild.killed) {
2444
- serveChild.kill("SIGTERM");
2497
+ if (childProcessIsRunning(serveChild)) {
2498
+ killProcessTree(serveChild, { signal: "SIGTERM" });
2445
2499
  }
2446
2500
  server.close();
2447
2501
  process.exit(0);
@@ -2530,7 +2584,7 @@ async function handleApi(req, res, pathname, parsed) {
2530
2584
  }
2531
2585
  }
2532
2586
  function apiStatus(req, res) {
2533
- const serving = serveChild !== null && !serveChild.killed;
2587
+ const serving = childProcessIsRunning(serveChild);
2534
2588
  jsonResponse(res, {
2535
2589
  serving,
2536
2590
  agentsDir,
@@ -2544,7 +2598,7 @@ function apiStatus(req, res) {
2544
2598
  });
2545
2599
  }
2546
2600
  function apiServeState(req, res) {
2547
- const serving = serveChild !== null && !serveChild.killed;
2601
+ const serving = childProcessIsRunning(serveChild);
2548
2602
  const agentStatuses = serveState.agents.map((agent) => {
2549
2603
  const relPath = agent.relativePath || ".";
2550
2604
  const runtime = agentRuntimeStatus(agent, serveState.agentRunState);
@@ -2718,7 +2772,7 @@ function devServerStateAfterServeStart(current = {}, target = {}) {
2718
2772
  };
2719
2773
  }
2720
2774
  async function apiServeStart(req, res, body) {
2721
- if (serveChild && !serveChild.killed) {
2775
+ if (childProcessIsRunning(serveChild)) {
2722
2776
  return jsonResponse(res, { ok: false, error: "Already serving" });
2723
2777
  }
2724
2778
  const target = resolveServeStartTarget(body, { agentsDir, collectionId });
@@ -2790,14 +2844,15 @@ async function apiServeStart(req, res, body) {
2790
2844
  }
2791
2845
  }
2792
2846
  function apiServeStop(req, res) {
2793
- if (!serveChild || serveChild.killed) {
2847
+ if (!childProcessIsRunning(serveChild)) {
2794
2848
  activeServeAgentsDir = "";
2795
2849
  return jsonResponse(res, { ok: true, wasRunning: false });
2796
2850
  }
2797
- serveChild.kill("SIGTERM");
2851
+ const stoppingChild = serveChild;
2852
+ killProcessTree(stoppingChild, { signal: "SIGTERM" });
2798
2853
  setTimeout(() => {
2799
- if (serveChild && !serveChild.killed) {
2800
- serveChild.kill("SIGKILL");
2854
+ if (childProcessIsRunning(stoppingChild)) {
2855
+ killProcessTree(stoppingChild, { signal: "SIGKILL" });
2801
2856
  }
2802
2857
  }, 3e3);
2803
2858
  jsonResponse(res, { ok: true, wasRunning: true });
@@ -2974,7 +3029,6 @@ function openUrl(url) {
2974
3029
  // src/tui.js
2975
3030
  init_constants();
2976
3031
  init_auth();
2977
- import { spawnSync as spawnSync4 } from "node:child_process";
2978
3032
  import fs12 from "node:fs";
2979
3033
  import path9 from "node:path";
2980
3034
  import readline from "node:readline";
@@ -3685,7 +3739,7 @@ async function runServeDashboard({ env, platform, agentsDir: agentsDir2, collect
3685
3739
  stopSignalAttempt += 1;
3686
3740
  const signal = stopSignalForAttempt(stopSignalAttempt);
3687
3741
  if (process.platform === "win32") {
3688
- killProcessTree(child);
3742
+ killProcessTree2(child);
3689
3743
  } else {
3690
3744
  try {
3691
3745
  child.kill(signal);
@@ -3707,7 +3761,7 @@ async function runServeDashboard({ env, platform, agentsDir: agentsDir2, collect
3707
3761
  clearTimeout(ctrlCArmTimer);
3708
3762
  ctrlCArmed = false;
3709
3763
  if (process.platform === "win32") {
3710
- killProcessTree(child);
3764
+ killProcessTree2(child);
3711
3765
  } else {
3712
3766
  try {
3713
3767
  child.kill(stopSignalForAttempt(stopSignalAttempt));
@@ -3721,9 +3775,13 @@ async function runServeDashboard({ env, platform, agentsDir: agentsDir2, collect
3721
3775
  if (!key) return;
3722
3776
  if (key.ctrl && key.name === "c") {
3723
3777
  if (ctrlCArmed) {
3724
- try {
3725
- child?.kill("SIGINT");
3726
- } catch (error) {
3778
+ if (process.platform === "win32") {
3779
+ killProcessTree2(child);
3780
+ } else {
3781
+ try {
3782
+ child?.kill("SIGINT");
3783
+ } catch (error) {
3784
+ }
3727
3785
  }
3728
3786
  finish("exit");
3729
3787
  return;
@@ -3962,19 +4020,8 @@ function stopSignalForAttempt(attempt = 0) {
3962
4020
  if (attempt === 1) return "SIGTERM";
3963
4021
  return "SIGKILL";
3964
4022
  }
3965
- function killProcessTree(child) {
3966
- if (!child || child.exitCode != null || child.signalCode != null) return;
3967
- if (process.platform === "win32") {
3968
- try {
3969
- spawnSync4("taskkill", ["/F", "/T", "/PID", String(child.pid)], { stdio: "ignore" });
3970
- } catch {
3971
- }
3972
- } else {
3973
- try {
3974
- child.kill("SIGTERM");
3975
- } catch {
3976
- }
3977
- }
4023
+ function killProcessTree2(child) {
4024
+ killProcessTree(child, { signal: "SIGTERM" });
3978
4025
  }
3979
4026
  function helpText() {
3980
4027
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vendian/cli",
3
- "version": "0.0.39",
3
+ "version": "0.0.41",
4
4
  "description": "Public Vendian CLI bootstrapper and launcher",
5
5
  "license": "UNLICENSED",
6
6
  "private": false,