@dosu/cli 0.13.0 → 0.13.2

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/dosu.js +133 -9
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -4341,7 +4341,7 @@ function getSupabaseAnonKey() {
4341
4341
  function getVersionString() {
4342
4342
  return `v${VERSION}`;
4343
4343
  }
4344
- var VERSION = "0.13.0";
4344
+ var VERSION = "0.13.2";
4345
4345
 
4346
4346
  // src/debug/logger.ts
4347
4347
  import {
@@ -8659,15 +8659,16 @@ async function createDeploymentForRepo(trpc, orgID, spaceID, repo) {
8659
8659
  await deleteOrphanDeployment(trpc, deployment.deployment_id, repo.slug);
8660
8660
  return null;
8661
8661
  }
8662
- await trpc.dataSource.syncDataSource.mutate(dataSource.data_source_id);
8662
+ const dataSourceID = dataSource.data_source_id;
8663
+ await trpc.dataSource.syncDataSource.mutate(dataSourceID);
8663
8664
  const spaceDeployments = await trpc.workspaces.listForSpace.query(spaceID);
8664
8665
  await Promise.all(spaceDeployments.map((d3) => trpc.deploymentDataSource.create.mutate({
8665
8666
  deployment_id: d3.deployment_id,
8666
- data_source_id: dataSource.data_source_id
8667
+ data_source_id: dataSourceID
8667
8668
  })));
8668
8669
  return {
8669
8670
  deployment_id: deployment.deployment_id,
8670
- data_source_id: dataSource.data_source_id
8671
+ data_source_id: dataSourceID
8671
8672
  };
8672
8673
  } catch (err) {
8673
8674
  const msg = err instanceof Error ? err.message : String(err);
@@ -9473,7 +9474,85 @@ var init_github_doc_import_step = __esm(() => {
9473
9474
  init_github_doc_import_prompt();
9474
9475
  });
9475
9476
 
9477
+ // src/auth/errors.ts
9478
+ var exports_errors = {};
9479
+ __export(exports_errors, {
9480
+ OAuthCallbackError: () => OAuthCallbackError
9481
+ });
9482
+ var OAuthCallbackError;
9483
+ var init_errors = __esm(() => {
9484
+ OAuthCallbackError = class OAuthCallbackError extends Error {
9485
+ error;
9486
+ errorCode;
9487
+ errorDescription;
9488
+ constructor(message, details = {}) {
9489
+ super(message);
9490
+ this.name = "OAuthCallbackError";
9491
+ this.error = details.error;
9492
+ this.errorCode = details.errorCode;
9493
+ this.errorDescription = details.errorDescription;
9494
+ }
9495
+ get userMessage() {
9496
+ const desc = this.errorDescription ?? this.message;
9497
+ if (this.errorCode === "bad_oauth_state" || /state/i.test(desc)) {
9498
+ return `Authentication failed: ${desc}. Run \`dosu login\` again.`;
9499
+ }
9500
+ return `Authentication failed: ${desc}`;
9501
+ }
9502
+ };
9503
+ });
9504
+
9476
9505
  // src/auth/server.ts
9506
+ function escapeHtml(value) {
9507
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
9508
+ }
9509
+ function buildErrorHtml(message) {
9510
+ const safe = escapeHtml(message);
9511
+ return `<!DOCTYPE html>
9512
+ <html lang="en">
9513
+ <head>
9514
+ <meta charset="UTF-8">
9515
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
9516
+ <title>Dosu CLI - Authentication Failed</title>
9517
+ <style>
9518
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9519
+ body {
9520
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
9521
+ background: #fafafa;
9522
+ color: #171717;
9523
+ min-height: 100vh;
9524
+ display: flex;
9525
+ align-items: center;
9526
+ justify-content: center;
9527
+ padding: 20px;
9528
+ }
9529
+ .container {
9530
+ max-width: 480px;
9531
+ width: 100%;
9532
+ text-align: center;
9533
+ background: white;
9534
+ border: 1px solid #e5e7eb;
9535
+ border-radius: 12px;
9536
+ padding: 40px 32px;
9537
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
9538
+ }
9539
+ h1 { font-size: 20px; font-weight: 600; color: #b91c1c; margin-bottom: 12px; }
9540
+ p { font-size: 14px; color: #4b5563; line-height: 1.5; }
9541
+ .detail { margin-top: 16px; padding: 12px; background: #fef2f2; border-radius: 8px; color: #991b1b; font-size: 13px; }
9542
+ .next { margin-top: 20px; color: #6b7280; font-size: 13px; }
9543
+ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: #f3f4f6; padding: 2px 6px; border-radius: 4px; color: #111827; }
9544
+ </style>
9545
+ </head>
9546
+ <body>
9547
+ <div class="container">
9548
+ <h1>Authentication Failed</h1>
9549
+ <p>The OAuth flow could not be completed.</p>
9550
+ <div class="detail">${safe}</div>
9551
+ <p class="next">You can close this tab. In your terminal, run <code>dosu login</code> again.</p>
9552
+ </div>
9553
+ </body>
9554
+ </html>`;
9555
+ }
9477
9556
  function buildSuccessHtml(email) {
9478
9557
  const emailLine = email ? `<p class="email">Signed in as <strong>${email.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</strong></p>` : "";
9479
9558
  return `<!DOCTYPE html>
@@ -9597,8 +9676,10 @@ h1 {
9597
9676
  }
9598
9677
  async function startCallbackServer() {
9599
9678
  let resolveToken;
9600
- const tokenPromise = new Promise((resolve) => {
9679
+ let rejectToken;
9680
+ const tokenPromise = new Promise((resolve, reject) => {
9601
9681
  resolveToken = resolve;
9682
+ rejectToken = reject;
9602
9683
  });
9603
9684
  const http = __require("node:http");
9604
9685
  const httpServer = http.createServer((req, res) => {
@@ -9612,6 +9693,22 @@ async function startCallbackServer() {
9612
9693
  res.end("Not Found");
9613
9694
  return;
9614
9695
  }
9696
+ const errorParam = url.searchParams.get("error");
9697
+ const errorCodeParam = url.searchParams.get("error_code");
9698
+ const errorDescriptionParam = url.searchParams.get("error_description");
9699
+ if (errorParam || errorCodeParam || errorDescriptionParam) {
9700
+ const rawDescription = errorDescriptionParam ?? errorCodeParam ?? errorParam ?? "OAuth authentication failed";
9701
+ const sanitized = rawDescription.replace(/<[^>]*>/g, "");
9702
+ logger.warn("auth.server", `OAuth callback received error: code=${errorCodeParam ?? "n/a"} description=${sanitized}`);
9703
+ rejectToken?.(new OAuthCallbackError(sanitized, {
9704
+ error: errorParam ?? undefined,
9705
+ errorCode: errorCodeParam ?? undefined,
9706
+ errorDescription: sanitized
9707
+ }));
9708
+ res.writeHead(200, { "Content-Type": "text/html" });
9709
+ res.end(buildErrorHtml(rawDescription));
9710
+ return;
9711
+ }
9615
9712
  const accessToken = url.searchParams.get("access_token");
9616
9713
  const refreshToken = url.searchParams.get("refresh_token");
9617
9714
  const expiresIn = url.searchParams.get("expires_in");
@@ -9719,6 +9816,7 @@ if (hash) {
9719
9816
  </html>`;
9720
9817
  var init_server = __esm(() => {
9721
9818
  init_logger();
9819
+ init_errors();
9722
9820
  });
9723
9821
 
9724
9822
  // src/auth/flow.ts
@@ -9739,9 +9837,9 @@ async function startOAuthFlow(signal, path2 = "/cli/auth", params = {}) {
9739
9837
  logger.info("auth.flow", "Browser open command executed");
9740
9838
  const timeout = new Promise((_3, reject) => {
9741
9839
  timeoutId = setTimeout(() => {
9742
- logger.warn("auth.flow", "Authentication timed out (15min)");
9743
- reject(new Error("authentication timeout - please try again"));
9744
- }, 900000);
9840
+ logger.warn("auth.flow", "Authentication timed out (8min)");
9841
+ reject(new Error("Authentication did not complete within 8 minutes. The OAuth state may have expired — please run `dosu login` again."));
9842
+ }, 480000);
9745
9843
  });
9746
9844
  const abort = signal ? new Promise((_3, reject) => {
9747
9845
  signal.addEventListener("abort", () => {
@@ -10106,6 +10204,16 @@ async function openBrowserForSetup(cfg, onboardingRunID) {
10106
10204
  } catch (err) {
10107
10205
  const msg = err instanceof Error ? err.stack ?? err.message : String(err);
10108
10206
  logger.error("setup", `Auth failed: ${msg}`);
10207
+ const { OAuthCallbackError: OAuthCallbackError2 } = await Promise.resolve().then(() => (init_errors(), exports_errors));
10208
+ if (err instanceof OAuthCallbackError2) {
10209
+ M2.error(err.userMessage);
10210
+ if (onboardingRunID) {
10211
+ await trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_failed", {
10212
+ reason: err.errorCode ?? err.errorDescription ?? "oauth_callback_error"
10213
+ });
10214
+ }
10215
+ return null;
10216
+ }
10109
10217
  M2.error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`);
10110
10218
  if (onboardingRunID) {
10111
10219
  await trackCliOnboardingPreAuthEvent(onboardingRunID, "cli_onboarding_auth_failed", {
@@ -10791,6 +10899,11 @@ async function handleAuthenticate(cfg) {
10791
10899
  cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
10792
10900
  saveConfig(cfg);
10793
10901
  } catch (err) {
10902
+ const { OAuthCallbackError: OAuthCallbackError2 } = await Promise.resolve().then(() => (init_errors(), exports_errors));
10903
+ if (err instanceof OAuthCallbackError2) {
10904
+ M2.error(err.userMessage);
10905
+ return;
10906
+ }
10794
10907
  M2.error(`Authentication failed: ${err instanceof Error ? err.message : String(err)}`);
10795
10908
  }
10796
10909
  }
@@ -12383,7 +12496,18 @@ function createProgram() {
12383
12496
  }
12384
12497
  console.log("Opening browser for authentication...");
12385
12498
  const { startOAuthFlow: startOAuthFlow2 } = await Promise.resolve().then(() => (init_flow(), exports_flow));
12386
- const token = await startOAuthFlow2();
12499
+ const { OAuthCallbackError: OAuthCallbackError2 } = await Promise.resolve().then(() => (init_errors(), exports_errors));
12500
+ let token;
12501
+ try {
12502
+ token = await startOAuthFlow2();
12503
+ } catch (err) {
12504
+ if (err instanceof OAuthCallbackError2) {
12505
+ console.error(err.userMessage);
12506
+ process.exitCode = 1;
12507
+ return;
12508
+ }
12509
+ throw err;
12510
+ }
12387
12511
  cfg.access_token = token.access_token;
12388
12512
  cfg.refresh_token = token.refresh_token;
12389
12513
  cfg.expires_at = Math.floor(Date.now() / 1000) + token.expires_in;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.13.0",
3
+ "version": "0.13.2",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Manage MCP servers for AI tools",
6
6
  "license": "MIT",