@dosu/cli 0.68.4 → 0.68.5

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 +381 -378
  2. package/package.json +1 -1
package/bin/dosu.js CHANGED
@@ -1128,7 +1128,7 @@ function isNpxInvocation(channel = INSTALL_CHANNEL, env = process.env) {
1128
1128
  function getVersionString() {
1129
1129
  return `v${VERSION}`;
1130
1130
  }
1131
- var VERSION = "0.68.4", INSTALL_CHANNEL = "npm";
1131
+ var VERSION = "0.68.5", INSTALL_CHANNEL = "npm";
1132
1132
 
1133
1133
  // src/debug/logger.ts
1134
1134
  import {
@@ -8801,6 +8801,365 @@ var init_ask = __esm(() => {
8801
8801
  import_picocolors7 = __toESM(require_picocolors(), 1);
8802
8802
  });
8803
8803
 
8804
+ // src/auth/errors.ts
8805
+ var OAuthCallbackError;
8806
+ var init_errors = __esm(() => {
8807
+ OAuthCallbackError = class OAuthCallbackError extends Error {
8808
+ error;
8809
+ errorCode;
8810
+ errorDescription;
8811
+ constructor(message, details = {}) {
8812
+ super(message);
8813
+ this.name = "OAuthCallbackError";
8814
+ this.error = details.error;
8815
+ this.errorCode = details.errorCode;
8816
+ this.errorDescription = details.errorDescription;
8817
+ }
8818
+ get userMessage() {
8819
+ const desc = this.errorDescription ?? this.message;
8820
+ if (this.errorCode === "bad_oauth_state" || /state/i.test(desc)) {
8821
+ return `Authentication failed: ${desc}. Run \`dosu login\` again.`;
8822
+ }
8823
+ return `Authentication failed: ${desc}`;
8824
+ }
8825
+ };
8826
+ });
8827
+
8828
+ // src/auth/server.ts
8829
+ function escapeHtml(value) {
8830
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
8831
+ }
8832
+ function buildErrorHtml(message) {
8833
+ const safe = escapeHtml(message);
8834
+ return `<!DOCTYPE html>
8835
+ <html lang="en">
8836
+ <head>
8837
+ <meta charset="UTF-8">
8838
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8839
+ <title>Dosu CLI - Authentication Failed</title>
8840
+ <style>
8841
+ * { margin: 0; padding: 0; box-sizing: border-box; }
8842
+ body {
8843
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
8844
+ background: #fafafa;
8845
+ color: #171717;
8846
+ min-height: 100vh;
8847
+ display: flex;
8848
+ align-items: center;
8849
+ justify-content: center;
8850
+ padding: 20px;
8851
+ }
8852
+ .container {
8853
+ max-width: 480px;
8854
+ width: 100%;
8855
+ text-align: center;
8856
+ background: white;
8857
+ border: 1px solid #e5e7eb;
8858
+ border-radius: 12px;
8859
+ padding: 40px 32px;
8860
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
8861
+ }
8862
+ h1 { font-size: 20px; font-weight: 600; color: #b91c1c; margin-bottom: 12px; }
8863
+ p { font-size: 14px; color: #4b5563; line-height: 1.5; }
8864
+ .detail { margin-top: 16px; padding: 12px; background: #fef2f2; border-radius: 8px; color: #991b1b; font-size: 13px; }
8865
+ .next { margin-top: 20px; color: #6b7280; font-size: 13px; }
8866
+ code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: #f3f4f6; padding: 2px 6px; border-radius: 4px; color: #111827; }
8867
+ </style>
8868
+ </head>
8869
+ <body>
8870
+ <div class="container">
8871
+ <h1>Authentication Failed</h1>
8872
+ <p>The OAuth flow could not be completed.</p>
8873
+ <div class="detail">${safe}</div>
8874
+ <p class="next">You can close this tab. In your terminal, run <code>dosu login</code> again.</p>
8875
+ </div>
8876
+ </body>
8877
+ </html>`;
8878
+ }
8879
+ function buildSuccessHtml(email, variant = "auth") {
8880
+ const copy = SUCCESS_COPY[variant];
8881
+ const closeMsg = copy.close;
8882
+ const emailLine = email ? `<p class="email">Signed in as <strong>${email.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</strong></p>` : "";
8883
+ return `<!DOCTYPE html>
8884
+ <html lang="en">
8885
+ <head>
8886
+ <meta charset="UTF-8">
8887
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
8888
+ <title>${copy.title}</title>
8889
+ <style>
8890
+ * { margin: 0; padding: 0; box-sizing: border-box; }
8891
+ body {
8892
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
8893
+ background: #fafafa;
8894
+ color: #171717;
8895
+ min-height: 100vh;
8896
+ position: relative;
8897
+ padding: 20px;
8898
+ }
8899
+ .container {
8900
+ position: absolute;
8901
+ top: 50%;
8902
+ left: 50%;
8903
+ transform: translate(-50%, -50%);
8904
+ max-width: 420px;
8905
+ width: 100%;
8906
+ text-align: center;
8907
+ }
8908
+ .logo {
8909
+ width: 52px;
8910
+ height: 52px;
8911
+ margin: 0 auto 28px;
8912
+ }
8913
+ h1 {
8914
+ font-size: 24px;
8915
+ font-weight: 600;
8916
+ color: #171717;
8917
+ letter-spacing: -0.02em;
8918
+ margin-bottom: 18px;
8919
+ }
8920
+ .email {
8921
+ font-size: 14px;
8922
+ color: #999;
8923
+ margin-bottom: 18px;
8924
+ }
8925
+ .close-msg {
8926
+ font-size: 16px;
8927
+ color: #666;
8928
+ }
8929
+ .tip {
8930
+ position: fixed;
8931
+ left: 50%;
8932
+ bottom: 28px;
8933
+ transform: translateX(-50%);
8934
+ width: calc(100vw - 48px);
8935
+ text-align: center;
8936
+ font-size: 14px;
8937
+ line-height: 1.5;
8938
+ color: #666;
8939
+ white-space: nowrap;
8940
+ }
8941
+ .tip-rule {
8942
+ display: flex;
8943
+ align-items: center;
8944
+ gap: 12px;
8945
+ width: min(720px, 100%);
8946
+ margin-bottom: 14px;
8947
+ margin-left: auto;
8948
+ margin-right: auto;
8949
+ }
8950
+ .tip-rule::before,
8951
+ .tip-rule::after {
8952
+ content: "";
8953
+ flex: 1;
8954
+ height: 1px;
8955
+ background: #eeeeee;
8956
+ }
8957
+ .tip-dot {
8958
+ width: 3px;
8959
+ height: 3px;
8960
+ border-radius: 999px;
8961
+ background: #dddddd;
8962
+ }
8963
+ .tip-label {
8964
+ font-weight: 600;
8965
+ color: #171717;
8966
+ }
8967
+ @media (max-width: 900px) {
8968
+ .tip {
8969
+ white-space: normal;
8970
+ }
8971
+ }
8972
+ </style>
8973
+ </head>
8974
+ <body>
8975
+ <div class="container">
8976
+ <div class="logo">
8977
+ <svg width="52" height="54" viewBox="0 0 86 89" fill="none" xmlns="http://www.w3.org/2000/svg">
8978
+ <path d="M5.29236 12.7928L17.7593 6.68188V72.5667L5.29236 84.0618V12.7928Z" fill="#B4BB91"/>
8979
+ <path d="M18.2575 73.1196L59.1329 72.748L51.7011 82.4095L29.0338 86.291L6.23962 85.1554L18.2575 73.1196Z" fill="#778561"/>
8980
+ <path d="M17.4916 3.73633L3.58557 12.7099V83.5792C3.58557 84.7542 4.98563 85.3652 5.84705 84.566L19.6296 71.7801" stroke="black" stroke-width="6.42844" stroke-linecap="round"/>
8981
+ <mask id="path-4-inside-1_355_26707" fill="white">
8982
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M40.704 0.518066H17.0439V76.2221H40.704H42.5805H47.8013C68.7064 76.2221 85.6533 59.2752 85.6533 38.3701C85.6533 17.465 68.7063 0.518066 47.8013 0.518066H42.5805H40.704Z"/>
8983
+ </mask>
8984
+ <path fill-rule="evenodd" clip-rule="evenodd" d="M40.704 0.518066H17.0439V76.2221H40.704H42.5805H47.8013C68.7064 76.2221 85.6533 59.2752 85.6533 38.3701C85.6533 17.465 68.7063 0.518066 47.8013 0.518066H42.5805H40.704Z" fill="#F3F6F1"/>
8985
+ <path d="M17.0439 0.518066V-6.57919H9.94669V0.518066H17.0439ZM17.0439 76.2221H9.94669V83.3194H17.0439V76.2221ZM17.0439 7.61532H40.704V-6.57919H17.0439V7.61532ZM24.1412 76.2221V0.518066H9.94669V76.2221H24.1412ZM40.704 69.1249H17.0439V83.3194H40.704V69.1249ZM42.5805 69.1249H40.704V83.3194H42.5805V69.1249ZM47.8013 69.1249H42.5805V83.3194H47.8013V69.1249ZM78.556 38.3701C78.556 55.3555 64.7867 69.1249 47.8013 69.1249V83.3194C72.6261 83.3194 92.7505 63.1949 92.7505 38.3701H78.556ZM47.8013 7.61532C64.7866 7.61532 78.556 21.3847 78.556 38.3701H92.7505C92.7505 13.5453 72.626 -6.57919 47.8013 -6.57919V7.61532ZM42.5805 7.61532H47.8013V-6.57919H42.5805V7.61532ZM40.704 7.61532H42.5805V-6.57919H40.704V7.61532Z" fill="black" mask="url(#path-4-inside-1_355_26707)"/>
8986
+ <path d="M68.9215 36.0135C68.9215 36.0135 65.7369 49.4738 51.4231 49.4738C37.1093 49.4738 32.5787 37.3596 32.5787 36.0135" stroke="black" stroke-width="7.69161" stroke-linecap="round" stroke-linejoin="round"/>
8987
+ <path d="M0.348633 85.4946C0.348633 85.4946 29.4856 85.8309 34.809 85.698C44.8337 85.4477 51.2872 84.402 57.5269 78.9724C62.8129 74.3727 75.1342 59.6836 75.1342 59.6836" stroke="black" stroke-width="6.16482"/>
8988
+ </svg>
8989
+ </div>
8990
+ <h1 id="heading">${copy.heading}</h1>
8991
+ ${emailLine}
8992
+ <p class="close-msg" id="close-msg">${closeMsg}</p>
8993
+ </div>
8994
+ <div class="tip">
8995
+ <div class="tip-rule" aria-hidden="true"><span class="tip-dot"></span></div>
8996
+ <span class="tip-label">Did you know?</span>
8997
+ You can use Dosu to make your coding agents faster and cheaper. Just ask your agent to use Dosu to update your AGENTS.md.
8998
+ </div>
8999
+ </body>
9000
+ </html>`;
9001
+ }
9002
+ async function startCallbackServer(opts = {}) {
9003
+ let resolveToken;
9004
+ let rejectToken;
9005
+ const tokenPromise = new Promise((resolve, reject) => {
9006
+ resolveToken = resolve;
9007
+ rejectToken = reject;
9008
+ });
9009
+ const http = __require("node:http");
9010
+ const httpServer = http.createServer((req, res) => {
9011
+ const url = new URL(req.url ?? "/", `http://localhost`);
9012
+ const cookieLen = (req.headers.cookie ?? "").length;
9013
+ const ua = req.headers["user-agent"] ?? "none";
9014
+ logger.debug("auth.server", `Request: ${req.method} ${url.pathname} cookie-len=${cookieLen} ua=${ua} has-token=${url.searchParams.has("access_token")}`);
9015
+ if (url.pathname !== "/callback") {
9016
+ logger.debug("auth.server", `404: ${url.pathname}`);
9017
+ res.writeHead(404, { "Content-Type": "text/plain" });
9018
+ res.end("Not Found");
9019
+ return;
9020
+ }
9021
+ const errorParam = url.searchParams.get("error");
9022
+ const errorCodeParam = url.searchParams.get("error_code");
9023
+ const errorDescriptionParam = url.searchParams.get("error_description");
9024
+ if (errorParam || errorCodeParam || errorDescriptionParam) {
9025
+ const rawDescription = errorDescriptionParam ?? errorCodeParam ?? errorParam ?? "OAuth authentication failed";
9026
+ const sanitized = rawDescription.replace(/<[^>]*>/g, "");
9027
+ logger.warn("auth.server", `OAuth callback received error: code=${errorCodeParam ?? "n/a"} description=${sanitized}`);
9028
+ rejectToken?.(new OAuthCallbackError(sanitized, {
9029
+ error: errorParam ?? undefined,
9030
+ errorCode: errorCodeParam ?? undefined,
9031
+ errorDescription: sanitized
9032
+ }));
9033
+ res.writeHead(200, { "Content-Type": "text/html" });
9034
+ res.end(buildErrorHtml(rawDescription));
9035
+ return;
9036
+ }
9037
+ const accessToken = url.searchParams.get("access_token");
9038
+ const refreshToken = url.searchParams.get("refresh_token");
9039
+ const expiresIn = url.searchParams.get("expires_in");
9040
+ const email = url.searchParams.get("email");
9041
+ if (!accessToken) {
9042
+ logger.debug("auth.server", "Served extract HTML (no token in query)");
9043
+ res.writeHead(200, { "Content-Type": "text/html" });
9044
+ res.end(CALLBACK_HTML_EXTRACT);
9045
+ return;
9046
+ }
9047
+ let expiresInInt = 3600;
9048
+ if (expiresIn) {
9049
+ const parsed = parseInt(expiresIn, 10);
9050
+ if (!Number.isNaN(parsed))
9051
+ expiresInInt = parsed;
9052
+ }
9053
+ logger.info("auth.server", `Token resolved, email=${email ?? "none"}`);
9054
+ resolveToken?.({
9055
+ access_token: accessToken,
9056
+ refresh_token: refreshToken && refreshToken !== "null" ? refreshToken : "",
9057
+ expires_in: expiresInInt,
9058
+ email: email ?? undefined
9059
+ });
9060
+ logger.info("auth.server", "Served success HTML");
9061
+ res.writeHead(200, { "Content-Type": "text/html" });
9062
+ res.end(buildSuccessHtml(email ?? undefined, opts.successVariant ?? "auth"));
9063
+ });
9064
+ await new Promise((resolve) => {
9065
+ httpServer.listen(0, CALLBACK_HOST, () => resolve());
9066
+ });
9067
+ httpServer.unref();
9068
+ const addr = httpServer.address();
9069
+ logger.info("auth.server", `Callback server listening on port ${addr.port}`);
9070
+ return {
9071
+ server: {
9072
+ port: addr.port,
9073
+ close: () => {
9074
+ httpServer.close();
9075
+ httpServer.closeAllConnections?.();
9076
+ }
9077
+ },
9078
+ tokenPromise
9079
+ };
9080
+ }
9081
+ var CALLBACK_HTML_EXTRACT = `<!DOCTYPE html>
9082
+ <html lang="en">
9083
+ <head>
9084
+ <meta charset="UTF-8">
9085
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
9086
+ <title>Dosu CLI - Completing Authentication</title>
9087
+ <style>
9088
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9089
+ body {
9090
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
9091
+ background: #fafafa;
9092
+ min-height: 100vh;
9093
+ display: flex;
9094
+ align-items: center;
9095
+ justify-content: center;
9096
+ padding: 20px;
9097
+ }
9098
+ .container {
9099
+ background: white;
9100
+ border-radius: 12px;
9101
+ padding: 48px 40px;
9102
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
9103
+ max-width: 480px;
9104
+ width: 100%;
9105
+ text-align: center;
9106
+ border: 1px solid #e5e7eb;
9107
+ }
9108
+ .spinner {
9109
+ width: 48px;
9110
+ height: 48px;
9111
+ border: 4px solid #e5e7eb;
9112
+ border-top-color: #3b82f6;
9113
+ border-radius: 50%;
9114
+ animation: spin 0.8s linear infinite;
9115
+ margin: 0 auto 24px;
9116
+ }
9117
+ @keyframes spin { to { transform: rotate(360deg); } }
9118
+ h1 { font-size: 20px; font-weight: 600; color: #111827; margin-bottom: 8px; }
9119
+ p { font-size: 14px; color: #6b7280; }
9120
+ </style>
9121
+ </head>
9122
+ <body>
9123
+ <div class="container">
9124
+ <div class="spinner"></div>
9125
+ <h1>Completing authentication...</h1>
9126
+ <p>Please wait</p>
9127
+ </div>
9128
+ <script>
9129
+ const hash = window.location.hash.substring(1);
9130
+ if (hash) {
9131
+ const params = new URLSearchParams(hash);
9132
+ const token = params.get('access_token');
9133
+ const refresh = params.get('refresh_token') || '';
9134
+ const expires = params.get('expires_in') || '';
9135
+ const email = params.get('email');
9136
+ if (token) {
9137
+ window.location.href = '/callback?access_token=' + encodeURIComponent(token) +
9138
+ '&refresh_token=' + encodeURIComponent(refresh) +
9139
+ '&expires_in=' + encodeURIComponent(expires) +
9140
+ (email ? '&email=' + encodeURIComponent(email) : '');
9141
+ }
9142
+ }
9143
+ </script>
9144
+ </body>
9145
+ </html>`, SUCCESS_COPY, CALLBACK_HOST = "127.0.0.1";
9146
+ var init_server = __esm(() => {
9147
+ init_logger();
9148
+ init_errors();
9149
+ SUCCESS_COPY = {
9150
+ auth: {
9151
+ title: "Dosu CLI - Authentication Successful",
9152
+ heading: "Authentication Successful",
9153
+ close: "You can close this tab and return to your terminal."
9154
+ },
9155
+ onboarding: {
9156
+ title: "Dosu CLI - Onboarding Complete",
9157
+ heading: "Onboarding Complete",
9158
+ close: "You're all set. Return to your terminal, where Dosu is finishing your setup."
9159
+ }
9160
+ };
9161
+ });
9162
+
8804
9163
  // src/setup/styles.ts
8805
9164
  import { stripVTControlCharacters as stripVTControlCharacters4 } from "node:util";
8806
9165
  function hasTruecolor() {
@@ -9770,7 +10129,7 @@ async function startInstallationCallbackServer() {
9770
10129
  res.end(SUCCESS_HTML);
9771
10130
  });
9772
10131
  await new Promise((resolve) => {
9773
- httpServer.listen(0, "localhost", () => resolve());
10132
+ httpServer.listen(0, CALLBACK_HOST, () => resolve());
9774
10133
  });
9775
10134
  const addr = httpServer.address();
9776
10135
  logger.info("installation.server", `Listening on port ${addr.port}`);
@@ -9956,6 +10315,7 @@ var SUCCESS_HTML = `<!DOCTYPE html>
9956
10315
  </body>
9957
10316
  </html>`;
9958
10317
  var init_installation_server = __esm(() => {
10318
+ init_server();
9959
10319
  init_logger();
9960
10320
  });
9961
10321
 
@@ -10764,7 +11124,7 @@ async function openGitHubInstallFlow(onInstalled, opts) {
10764
11124
  const { server, installationPromise } = await startInstallationCallbackServer();
10765
11125
  let timeoutId;
10766
11126
  try {
10767
- const callbackURL = `http://localhost:${server.port}/callback`;
11127
+ const callbackURL = `http://${CALLBACK_HOST}:${server.port}/callback`;
10768
11128
  const webAppURL = getWebAppURL();
10769
11129
  const middleURL = new URL("/cli/connect-github", webAppURL);
10770
11130
  middleURL.searchParams.set("callback", callbackURL);
@@ -11043,6 +11403,7 @@ async function stepConnectGitHubRepo(cfg, detected = detectGitRepo(), opts = {})
11043
11403
  }
11044
11404
  var INSTALLATION_TIMEOUT_MS, REPO_REFRESH_POLL_INTERVAL_MS = 500, REPO_REFRESH_POLL_TIMEOUT_MS = 1e4, REPO_MULTISELECT_MAX_ITEMS = 10, DATA_SOURCE_VERIFY_POLL_INTERVAL_MS = 1000, DATA_SOURCE_VERIFY_POLL_TIMEOUT_MS = 1e4;
11045
11405
  var init_github_step = __esm(() => {
11406
+ init_server();
11046
11407
  init_trpc();
11047
11408
  init_logger();
11048
11409
  init_prompts();
@@ -11621,7 +11982,7 @@ var init_deployments = __esm(() => {
11621
11982
 
11622
11983
  // src/cli/errors.ts
11623
11984
  var CliUsageError;
11624
- var init_errors = __esm(() => {
11985
+ var init_errors2 = __esm(() => {
11625
11986
  CliUsageError = class CliUsageError extends Error {
11626
11987
  exitCode = 1;
11627
11988
  constructor(message) {
@@ -12061,7 +12422,7 @@ var init_docs = __esm(() => {
12061
12422
  init_dist8();
12062
12423
  init_dist();
12063
12424
  init_commander();
12064
- init_errors();
12425
+ init_errors2();
12065
12426
  init_client();
12066
12427
  init_trpc();
12067
12428
  init_logger();
@@ -14356,7 +14717,7 @@ var init_conflicts = __esm(() => {
14356
14717
  });
14357
14718
 
14358
14719
  // src/telemetry/debug-id.ts
14359
- var BUNDLE_DEBUG_ID_PLACEHOLDER = "ab9cda30-ed6a-345b-6475-6e2164756e21";
14720
+ var BUNDLE_DEBUG_ID_PLACEHOLDER = "af4149bf-b423-bc43-6475-6e2164756e21";
14360
14721
 
14361
14722
  // src/telemetry/telemetry.ts
14362
14723
  import { randomUUID as randomUUID2 } from "node:crypto";
@@ -54580,7 +54941,7 @@ var _messageDesc, _zodDesc2, _issuesDesc, _installedToString, initializer = (ins
54580
54941
  });
54581
54942
  }
54582
54943
  }, $ZodError, $ZodRealError;
54583
- var init_errors2 = __esm(() => {
54944
+ var init_errors3 = __esm(() => {
54584
54945
  init_core();
54585
54946
  init_util();
54586
54947
  _messageDesc = {
@@ -54689,7 +55050,7 @@ var _parse = (_Err) => {
54689
55050
  };
54690
55051
  var init_parse = __esm(() => {
54691
55052
  init_core();
54692
- init_errors2();
55053
+ init_errors3();
54693
55054
  init_util();
54694
55055
  safeParse = /* @__PURE__ */ _safeParse($ZodRealError);
54695
55056
  safeParseAsync = /* @__PURE__ */ _safeParseAsync($ZodRealError);
@@ -57691,7 +58052,7 @@ var init_core2 = __esm(() => {
57691
58052
  init_json_schema();
57692
58053
  init_core();
57693
58054
  init_parse();
57694
- init_errors2();
58055
+ init_errors3();
57695
58056
  init_schemas();
57696
58057
  init_memoizer();
57697
58058
  init_checks();
@@ -57747,7 +58108,7 @@ var _installedErrorProtos, initializer2 = (inst, issues) => {
57747
58108
  }
57748
58109
  });
57749
58110
  }, ZodRealError;
57750
- var init_errors3 = __esm(() => {
58111
+ var init_errors4 = __esm(() => {
57751
58112
  init_core2();
57752
58113
  init_core2();
57753
58114
  init_util();
@@ -57761,7 +58122,7 @@ var init_errors3 = __esm(() => {
57761
58122
  var parse6, parseAsync2, safeParse2, safeParseAsync2, encode, decode, encodeAsync, decodeAsync, safeEncode, safeDecode, safeEncodeAsync, safeDecodeAsync;
57762
58123
  var init_parse2 = __esm(() => {
57763
58124
  init_core2();
57764
- init_errors3();
58125
+ init_errors4();
57765
58126
  parse6 = /* @__PURE__ */ _parse(ZodRealError);
57766
58127
  parseAsync2 = /* @__PURE__ */ _parseAsync(ZodRealError);
57767
58128
  safeParse2 = /* @__PURE__ */ _safeParse(ZodRealError);
@@ -58510,7 +58871,7 @@ var init_external = __esm(() => {
58510
58871
  init_coerce();
58511
58872
  init_schemas2();
58512
58873
  init_checks2();
58513
- init_errors3();
58874
+ init_errors4();
58514
58875
  init_parse2();
58515
58876
  init_compat();
58516
58877
  });
@@ -61932,7 +62293,7 @@ function sourcesCommand() {
61932
62293
  let timeoutId;
61933
62294
  try {
61934
62295
  const connectURL = new URL("/cli/connect-github", getWebAppURL());
61935
- connectURL.searchParams.set("callback", `http://localhost:${server.port}/callback`);
62296
+ connectURL.searchParams.set("callback", `http://${CALLBACK_HOST}:${server.port}/callback`);
61936
62297
  const url = connectURL.toString();
61937
62298
  if (opts.json) {
61938
62299
  console.log(JSON.stringify({
@@ -62070,6 +62431,7 @@ function sourcesCommand() {
62070
62431
  var import_picocolors29, CONNECT_TIMEOUT_DEFAULT_SECONDS = 600;
62071
62432
  var init_sources = __esm(() => {
62072
62433
  init_commander();
62434
+ init_server();
62073
62435
  init_trpc();
62074
62436
  init_github_step();
62075
62437
  init_installation_server();
@@ -63690,30 +64052,6 @@ var init_skill_update_check = __esm(() => {
63690
64052
  import_picocolors33 = __toESM(require_picocolors(), 1);
63691
64053
  });
63692
64054
 
63693
- // src/auth/errors.ts
63694
- var OAuthCallbackError;
63695
- var init_errors4 = __esm(() => {
63696
- OAuthCallbackError = class OAuthCallbackError extends Error {
63697
- error;
63698
- errorCode;
63699
- errorDescription;
63700
- constructor(message, details = {}) {
63701
- super(message);
63702
- this.name = "OAuthCallbackError";
63703
- this.error = details.error;
63704
- this.errorCode = details.errorCode;
63705
- this.errorDescription = details.errorDescription;
63706
- }
63707
- get userMessage() {
63708
- const desc = this.errorDescription ?? this.message;
63709
- if (this.errorCode === "bad_oauth_state" || /state/i.test(desc)) {
63710
- return `Authentication failed: ${desc}. Run \`dosu login\` again.`;
63711
- }
63712
- return `Authentication failed: ${desc}`;
63713
- }
63714
- };
63715
- });
63716
-
63717
64055
  // src/mcp/constants.ts
63718
64056
  var MCP_PROVIDER_SLUG2 = "dosu_mcp";
63719
64057
 
@@ -65022,341 +65360,6 @@ var init_rules_step = __esm(() => {
65022
65360
  init_styles();
65023
65361
  });
65024
65362
 
65025
- // src/auth/server.ts
65026
- function escapeHtml(value) {
65027
- return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
65028
- }
65029
- function buildErrorHtml(message) {
65030
- const safe = escapeHtml(message);
65031
- return `<!DOCTYPE html>
65032
- <html lang="en">
65033
- <head>
65034
- <meta charset="UTF-8">
65035
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
65036
- <title>Dosu CLI - Authentication Failed</title>
65037
- <style>
65038
- * { margin: 0; padding: 0; box-sizing: border-box; }
65039
- body {
65040
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
65041
- background: #fafafa;
65042
- color: #171717;
65043
- min-height: 100vh;
65044
- display: flex;
65045
- align-items: center;
65046
- justify-content: center;
65047
- padding: 20px;
65048
- }
65049
- .container {
65050
- max-width: 480px;
65051
- width: 100%;
65052
- text-align: center;
65053
- background: white;
65054
- border: 1px solid #e5e7eb;
65055
- border-radius: 12px;
65056
- padding: 40px 32px;
65057
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
65058
- }
65059
- h1 { font-size: 20px; font-weight: 600; color: #b91c1c; margin-bottom: 12px; }
65060
- p { font-size: 14px; color: #4b5563; line-height: 1.5; }
65061
- .detail { margin-top: 16px; padding: 12px; background: #fef2f2; border-radius: 8px; color: #991b1b; font-size: 13px; }
65062
- .next { margin-top: 20px; color: #6b7280; font-size: 13px; }
65063
- code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: #f3f4f6; padding: 2px 6px; border-radius: 4px; color: #111827; }
65064
- </style>
65065
- </head>
65066
- <body>
65067
- <div class="container">
65068
- <h1>Authentication Failed</h1>
65069
- <p>The OAuth flow could not be completed.</p>
65070
- <div class="detail">${safe}</div>
65071
- <p class="next">You can close this tab. In your terminal, run <code>dosu login</code> again.</p>
65072
- </div>
65073
- </body>
65074
- </html>`;
65075
- }
65076
- function buildSuccessHtml(email, variant = "auth") {
65077
- const copy = SUCCESS_COPY[variant];
65078
- const closeMsg = copy.close;
65079
- const emailLine = email ? `<p class="email">Signed in as <strong>${email.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</strong></p>` : "";
65080
- return `<!DOCTYPE html>
65081
- <html lang="en">
65082
- <head>
65083
- <meta charset="UTF-8">
65084
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
65085
- <title>${copy.title}</title>
65086
- <style>
65087
- * { margin: 0; padding: 0; box-sizing: border-box; }
65088
- body {
65089
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
65090
- background: #fafafa;
65091
- color: #171717;
65092
- min-height: 100vh;
65093
- position: relative;
65094
- padding: 20px;
65095
- }
65096
- .container {
65097
- position: absolute;
65098
- top: 50%;
65099
- left: 50%;
65100
- transform: translate(-50%, -50%);
65101
- max-width: 420px;
65102
- width: 100%;
65103
- text-align: center;
65104
- }
65105
- .logo {
65106
- width: 52px;
65107
- height: 52px;
65108
- margin: 0 auto 28px;
65109
- }
65110
- h1 {
65111
- font-size: 24px;
65112
- font-weight: 600;
65113
- color: #171717;
65114
- letter-spacing: -0.02em;
65115
- margin-bottom: 18px;
65116
- }
65117
- .email {
65118
- font-size: 14px;
65119
- color: #999;
65120
- margin-bottom: 18px;
65121
- }
65122
- .close-msg {
65123
- font-size: 16px;
65124
- color: #666;
65125
- }
65126
- .tip {
65127
- position: fixed;
65128
- left: 50%;
65129
- bottom: 28px;
65130
- transform: translateX(-50%);
65131
- width: calc(100vw - 48px);
65132
- text-align: center;
65133
- font-size: 14px;
65134
- line-height: 1.5;
65135
- color: #666;
65136
- white-space: nowrap;
65137
- }
65138
- .tip-rule {
65139
- display: flex;
65140
- align-items: center;
65141
- gap: 12px;
65142
- width: min(720px, 100%);
65143
- margin-bottom: 14px;
65144
- margin-left: auto;
65145
- margin-right: auto;
65146
- }
65147
- .tip-rule::before,
65148
- .tip-rule::after {
65149
- content: "";
65150
- flex: 1;
65151
- height: 1px;
65152
- background: #eeeeee;
65153
- }
65154
- .tip-dot {
65155
- width: 3px;
65156
- height: 3px;
65157
- border-radius: 999px;
65158
- background: #dddddd;
65159
- }
65160
- .tip-label {
65161
- font-weight: 600;
65162
- color: #171717;
65163
- }
65164
- @media (max-width: 900px) {
65165
- .tip {
65166
- white-space: normal;
65167
- }
65168
- }
65169
- </style>
65170
- </head>
65171
- <body>
65172
- <div class="container">
65173
- <div class="logo">
65174
- <svg width="52" height="54" viewBox="0 0 86 89" fill="none" xmlns="http://www.w3.org/2000/svg">
65175
- <path d="M5.29236 12.7928L17.7593 6.68188V72.5667L5.29236 84.0618V12.7928Z" fill="#B4BB91"/>
65176
- <path d="M18.2575 73.1196L59.1329 72.748L51.7011 82.4095L29.0338 86.291L6.23962 85.1554L18.2575 73.1196Z" fill="#778561"/>
65177
- <path d="M17.4916 3.73633L3.58557 12.7099V83.5792C3.58557 84.7542 4.98563 85.3652 5.84705 84.566L19.6296 71.7801" stroke="black" stroke-width="6.42844" stroke-linecap="round"/>
65178
- <mask id="path-4-inside-1_355_26707" fill="white">
65179
- <path fill-rule="evenodd" clip-rule="evenodd" d="M40.704 0.518066H17.0439V76.2221H40.704H42.5805H47.8013C68.7064 76.2221 85.6533 59.2752 85.6533 38.3701C85.6533 17.465 68.7063 0.518066 47.8013 0.518066H42.5805H40.704Z"/>
65180
- </mask>
65181
- <path fill-rule="evenodd" clip-rule="evenodd" d="M40.704 0.518066H17.0439V76.2221H40.704H42.5805H47.8013C68.7064 76.2221 85.6533 59.2752 85.6533 38.3701C85.6533 17.465 68.7063 0.518066 47.8013 0.518066H42.5805H40.704Z" fill="#F3F6F1"/>
65182
- <path d="M17.0439 0.518066V-6.57919H9.94669V0.518066H17.0439ZM17.0439 76.2221H9.94669V83.3194H17.0439V76.2221ZM17.0439 7.61532H40.704V-6.57919H17.0439V7.61532ZM24.1412 76.2221V0.518066H9.94669V76.2221H24.1412ZM40.704 69.1249H17.0439V83.3194H40.704V69.1249ZM42.5805 69.1249H40.704V83.3194H42.5805V69.1249ZM47.8013 69.1249H42.5805V83.3194H47.8013V69.1249ZM78.556 38.3701C78.556 55.3555 64.7867 69.1249 47.8013 69.1249V83.3194C72.6261 83.3194 92.7505 63.1949 92.7505 38.3701H78.556ZM47.8013 7.61532C64.7866 7.61532 78.556 21.3847 78.556 38.3701H92.7505C92.7505 13.5453 72.626 -6.57919 47.8013 -6.57919V7.61532ZM42.5805 7.61532H47.8013V-6.57919H42.5805V7.61532ZM40.704 7.61532H42.5805V-6.57919H40.704V7.61532Z" fill="black" mask="url(#path-4-inside-1_355_26707)"/>
65183
- <path d="M68.9215 36.0135C68.9215 36.0135 65.7369 49.4738 51.4231 49.4738C37.1093 49.4738 32.5787 37.3596 32.5787 36.0135" stroke="black" stroke-width="7.69161" stroke-linecap="round" stroke-linejoin="round"/>
65184
- <path d="M0.348633 85.4946C0.348633 85.4946 29.4856 85.8309 34.809 85.698C44.8337 85.4477 51.2872 84.402 57.5269 78.9724C62.8129 74.3727 75.1342 59.6836 75.1342 59.6836" stroke="black" stroke-width="6.16482"/>
65185
- </svg>
65186
- </div>
65187
- <h1 id="heading">${copy.heading}</h1>
65188
- ${emailLine}
65189
- <p class="close-msg" id="close-msg">${closeMsg}</p>
65190
- </div>
65191
- <div class="tip">
65192
- <div class="tip-rule" aria-hidden="true"><span class="tip-dot"></span></div>
65193
- <span class="tip-label">Did you know?</span>
65194
- You can use Dosu to make your coding agents faster and cheaper. Just ask your agent to use Dosu to update your AGENTS.md.
65195
- </div>
65196
- </body>
65197
- </html>`;
65198
- }
65199
- async function startCallbackServer(opts = {}) {
65200
- let resolveToken;
65201
- let rejectToken;
65202
- const tokenPromise = new Promise((resolve, reject) => {
65203
- resolveToken = resolve;
65204
- rejectToken = reject;
65205
- });
65206
- const http = __require("node:http");
65207
- const httpServer = http.createServer((req, res) => {
65208
- const url = new URL(req.url ?? "/", `http://localhost`);
65209
- const cookieLen = (req.headers.cookie ?? "").length;
65210
- const ua = req.headers["user-agent"] ?? "none";
65211
- logger.debug("auth.server", `Request: ${req.method} ${url.pathname} cookie-len=${cookieLen} ua=${ua} has-token=${url.searchParams.has("access_token")}`);
65212
- if (url.pathname !== "/callback") {
65213
- logger.debug("auth.server", `404: ${url.pathname}`);
65214
- res.writeHead(404, { "Content-Type": "text/plain" });
65215
- res.end("Not Found");
65216
- return;
65217
- }
65218
- const errorParam = url.searchParams.get("error");
65219
- const errorCodeParam = url.searchParams.get("error_code");
65220
- const errorDescriptionParam = url.searchParams.get("error_description");
65221
- if (errorParam || errorCodeParam || errorDescriptionParam) {
65222
- const rawDescription = errorDescriptionParam ?? errorCodeParam ?? errorParam ?? "OAuth authentication failed";
65223
- const sanitized = rawDescription.replace(/<[^>]*>/g, "");
65224
- logger.warn("auth.server", `OAuth callback received error: code=${errorCodeParam ?? "n/a"} description=${sanitized}`);
65225
- rejectToken?.(new OAuthCallbackError(sanitized, {
65226
- error: errorParam ?? undefined,
65227
- errorCode: errorCodeParam ?? undefined,
65228
- errorDescription: sanitized
65229
- }));
65230
- res.writeHead(200, { "Content-Type": "text/html" });
65231
- res.end(buildErrorHtml(rawDescription));
65232
- return;
65233
- }
65234
- const accessToken = url.searchParams.get("access_token");
65235
- const refreshToken = url.searchParams.get("refresh_token");
65236
- const expiresIn = url.searchParams.get("expires_in");
65237
- const email = url.searchParams.get("email");
65238
- if (!accessToken) {
65239
- logger.debug("auth.server", "Served extract HTML (no token in query)");
65240
- res.writeHead(200, { "Content-Type": "text/html" });
65241
- res.end(CALLBACK_HTML_EXTRACT);
65242
- return;
65243
- }
65244
- let expiresInInt = 3600;
65245
- if (expiresIn) {
65246
- const parsed = parseInt(expiresIn, 10);
65247
- if (!Number.isNaN(parsed))
65248
- expiresInInt = parsed;
65249
- }
65250
- logger.info("auth.server", `Token resolved, email=${email ?? "none"}`);
65251
- resolveToken?.({
65252
- access_token: accessToken,
65253
- refresh_token: refreshToken && refreshToken !== "null" ? refreshToken : "",
65254
- expires_in: expiresInInt,
65255
- email: email ?? undefined
65256
- });
65257
- logger.info("auth.server", "Served success HTML");
65258
- res.writeHead(200, { "Content-Type": "text/html" });
65259
- res.end(buildSuccessHtml(email ?? undefined, opts.successVariant ?? "auth"));
65260
- });
65261
- await new Promise((resolve) => {
65262
- httpServer.listen(0, CALLBACK_HOST, () => resolve());
65263
- });
65264
- httpServer.unref();
65265
- const addr = httpServer.address();
65266
- logger.info("auth.server", `Callback server listening on port ${addr.port}`);
65267
- return {
65268
- server: {
65269
- port: addr.port,
65270
- close: () => {
65271
- httpServer.close();
65272
- httpServer.closeAllConnections?.();
65273
- }
65274
- },
65275
- tokenPromise
65276
- };
65277
- }
65278
- var CALLBACK_HTML_EXTRACT = `<!DOCTYPE html>
65279
- <html lang="en">
65280
- <head>
65281
- <meta charset="UTF-8">
65282
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
65283
- <title>Dosu CLI - Completing Authentication</title>
65284
- <style>
65285
- * { margin: 0; padding: 0; box-sizing: border-box; }
65286
- body {
65287
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
65288
- background: #fafafa;
65289
- min-height: 100vh;
65290
- display: flex;
65291
- align-items: center;
65292
- justify-content: center;
65293
- padding: 20px;
65294
- }
65295
- .container {
65296
- background: white;
65297
- border-radius: 12px;
65298
- padding: 48px 40px;
65299
- box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
65300
- max-width: 480px;
65301
- width: 100%;
65302
- text-align: center;
65303
- border: 1px solid #e5e7eb;
65304
- }
65305
- .spinner {
65306
- width: 48px;
65307
- height: 48px;
65308
- border: 4px solid #e5e7eb;
65309
- border-top-color: #3b82f6;
65310
- border-radius: 50%;
65311
- animation: spin 0.8s linear infinite;
65312
- margin: 0 auto 24px;
65313
- }
65314
- @keyframes spin { to { transform: rotate(360deg); } }
65315
- h1 { font-size: 20px; font-weight: 600; color: #111827; margin-bottom: 8px; }
65316
- p { font-size: 14px; color: #6b7280; }
65317
- </style>
65318
- </head>
65319
- <body>
65320
- <div class="container">
65321
- <div class="spinner"></div>
65322
- <h1>Completing authentication...</h1>
65323
- <p>Please wait</p>
65324
- </div>
65325
- <script>
65326
- const hash = window.location.hash.substring(1);
65327
- if (hash) {
65328
- const params = new URLSearchParams(hash);
65329
- const token = params.get('access_token');
65330
- const refresh = params.get('refresh_token') || '';
65331
- const expires = params.get('expires_in') || '';
65332
- const email = params.get('email');
65333
- if (token) {
65334
- window.location.href = '/callback?access_token=' + encodeURIComponent(token) +
65335
- '&refresh_token=' + encodeURIComponent(refresh) +
65336
- '&expires_in=' + encodeURIComponent(expires) +
65337
- (email ? '&email=' + encodeURIComponent(email) : '');
65338
- }
65339
- }
65340
- </script>
65341
- </body>
65342
- </html>`, SUCCESS_COPY, CALLBACK_HOST = "127.0.0.1";
65343
- var init_server = __esm(() => {
65344
- init_logger();
65345
- init_errors4();
65346
- SUCCESS_COPY = {
65347
- auth: {
65348
- title: "Dosu CLI - Authentication Successful",
65349
- heading: "Authentication Successful",
65350
- close: "You can close this tab and return to your terminal."
65351
- },
65352
- onboarding: {
65353
- title: "Dosu CLI - Onboarding Complete",
65354
- heading: "Onboarding Complete",
65355
- close: "You're all set. Return to your terminal, where Dosu is finishing your setup."
65356
- }
65357
- };
65358
- });
65359
-
65360
65363
  // src/auth/flow.ts
65361
65364
  async function startOAuthFlow(signal, path = "/cli/auth", params = {}, onAuthURL, options = {}) {
65362
65365
  const { server, tokenPromise } = await startCallbackServer({
@@ -65821,7 +65824,7 @@ async function stepSetupHandshake(cfg, onboardingRunID) {
65821
65824
  const msg = err instanceof Error ? err.message : String(err);
65822
65825
  logger.warn("setup", `Setup handshake did not complete: ${msg}`);
65823
65826
  s.stop("Setup not completed");
65824
- await Promise.resolve().then(() => init_errors4());
65827
+ await Promise.resolve().then(() => init_errors());
65825
65828
  if (err instanceof OAuthCallbackError) {
65826
65829
  log2.error(err.userMessage);
65827
65830
  return false;
@@ -66362,7 +66365,7 @@ ${dim(wrapLog("Type it in a chat to keep that chat out of Dosu. To keep a whole
66362
66365
  }
66363
66366
  var import_picocolors35, OAUTH_ANALYTICS_REASONS, SETUP_HANDSHAKE_TIMEOUT_MS = 1800000, LIBRARY_SELECT_CANCELLED;
66364
66367
  var init_flow2 = __esm(() => {
66365
- init_errors4();
66368
+ init_errors();
66366
66369
  init_client();
66367
66370
  init_skill();
66368
66371
  init_config();
@@ -68018,7 +68021,7 @@ async function handleAuthenticate(cfg) {
68018
68021
  });
68019
68022
  saveConfig(cfg);
68020
68023
  } catch (err) {
68021
- await Promise.resolve().then(() => init_errors4());
68024
+ await Promise.resolve().then(() => init_errors());
68022
68025
  if (err instanceof OAuthCallbackError) {
68023
68026
  log2.error(err.userMessage);
68024
68027
  return;
@@ -68847,7 +68850,7 @@ Run 'dosu --help' to see available commands.`;
68847
68850
  }
68848
68851
  await Promise.resolve();
68849
68852
  const useDeviceFlow = !opts.browser || isHeadless();
68850
- await Promise.resolve().then(() => init_errors4());
68853
+ await Promise.resolve().then(() => init_errors());
68851
68854
  let token;
68852
68855
  if (useDeviceFlow) {
68853
68856
  await Promise.resolve().then(() => init_device());
@@ -69223,7 +69226,7 @@ var init_cli = __esm(() => {
69223
69226
  init_pending_tasks_check();
69224
69227
  init_skill_update_check();
69225
69228
  init_update_check();
69226
- init_errors();
69229
+ init_errors2();
69227
69230
  init_fatal_error();
69228
69231
  });
69229
69232
 
@@ -69303,4 +69306,4 @@ main().catch((err) => {
69303
69306
  process.exit(1);
69304
69307
  });
69305
69308
 
69306
- //# debugId=ab9cda30-ed6a-345b-6475-6e2164756e21
69309
+ //# debugId=af4149bf-b423-bc43-6475-6e2164756e21
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dosu/cli",
3
- "version": "0.68.4",
3
+ "version": "0.68.5",
4
4
  "type": "module",
5
5
  "description": "Dosu CLI - Set up Dosu MCP for AI tools and work with Dosu Libraries, docs, and reviews",
6
6
  "license": "MIT",