@pilatos/bitbucket-cli 1.10.1 → 1.11.0

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/dist/index.js +1262 -42
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -26,6 +26,7 @@ var __export = (target, all) => {
26
26
  set: (newValue) => all[name] = () => newValue
27
27
  });
28
28
  };
29
+ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
29
30
  var __require = import.meta.require;
30
31
 
31
32
  // node_modules/commander/lib/error.js
@@ -13522,6 +13523,660 @@ var require_follow_redirects = __commonJS((exports, module) => {
13522
13523
  module.exports.wrap = wrap;
13523
13524
  });
13524
13525
 
13526
+ // node_modules/is-docker/index.js
13527
+ import fs from "fs";
13528
+ function hasDockerEnv() {
13529
+ try {
13530
+ fs.statSync("/.dockerenv");
13531
+ return true;
13532
+ } catch {
13533
+ return false;
13534
+ }
13535
+ }
13536
+ function hasDockerCGroup() {
13537
+ try {
13538
+ return fs.readFileSync("/proc/self/cgroup", "utf8").includes("docker");
13539
+ } catch {
13540
+ return false;
13541
+ }
13542
+ }
13543
+ function isDocker() {
13544
+ if (isDockerCached === undefined) {
13545
+ isDockerCached = hasDockerEnv() || hasDockerCGroup();
13546
+ }
13547
+ return isDockerCached;
13548
+ }
13549
+ var isDockerCached;
13550
+ var init_is_docker = () => {};
13551
+
13552
+ // node_modules/is-inside-container/index.js
13553
+ import fs2 from "fs";
13554
+ function isInsideContainer() {
13555
+ if (cachedResult === undefined) {
13556
+ cachedResult = hasContainerEnv() || isDocker();
13557
+ }
13558
+ return cachedResult;
13559
+ }
13560
+ var cachedResult, hasContainerEnv = () => {
13561
+ try {
13562
+ fs2.statSync("/run/.containerenv");
13563
+ return true;
13564
+ } catch {
13565
+ return false;
13566
+ }
13567
+ };
13568
+ var init_is_inside_container = __esm(() => {
13569
+ init_is_docker();
13570
+ });
13571
+
13572
+ // node_modules/is-wsl/index.js
13573
+ import process3 from "process";
13574
+ import os2 from "os";
13575
+ import fs3 from "fs";
13576
+ var isWsl = () => {
13577
+ if (process3.platform !== "linux") {
13578
+ return false;
13579
+ }
13580
+ if (os2.release().toLowerCase().includes("microsoft")) {
13581
+ if (isInsideContainer()) {
13582
+ return false;
13583
+ }
13584
+ return true;
13585
+ }
13586
+ try {
13587
+ if (fs3.readFileSync("/proc/version", "utf8").toLowerCase().includes("microsoft")) {
13588
+ return !isInsideContainer();
13589
+ }
13590
+ } catch {}
13591
+ if (fs3.existsSync("/proc/sys/fs/binfmt_misc/WSLInterop") || fs3.existsSync("/run/WSL")) {
13592
+ return !isInsideContainer();
13593
+ }
13594
+ return false;
13595
+ }, is_wsl_default;
13596
+ var init_is_wsl = __esm(() => {
13597
+ init_is_inside_container();
13598
+ is_wsl_default = process3.env.__IS_WSL_TEST__ ? isWsl : isWsl();
13599
+ });
13600
+
13601
+ // node_modules/powershell-utils/index.js
13602
+ import process4 from "process";
13603
+ import { Buffer as Buffer2 } from "buffer";
13604
+ import { promisify } from "util";
13605
+ import childProcess from "child_process";
13606
+ var execFile, powerShellPath = () => `${process4.env.SYSTEMROOT || process4.env.windir || String.raw`C:\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`, executePowerShell = async (command, options = {}) => {
13607
+ const {
13608
+ powerShellPath: psPath,
13609
+ ...execFileOptions
13610
+ } = options;
13611
+ const encodedCommand = executePowerShell.encodeCommand(command);
13612
+ return execFile(psPath ?? powerShellPath(), [
13613
+ ...executePowerShell.argumentsPrefix,
13614
+ encodedCommand
13615
+ ], {
13616
+ encoding: "utf8",
13617
+ ...execFileOptions
13618
+ });
13619
+ };
13620
+ var init_powershell_utils = __esm(() => {
13621
+ execFile = promisify(childProcess.execFile);
13622
+ executePowerShell.argumentsPrefix = [
13623
+ "-NoProfile",
13624
+ "-NonInteractive",
13625
+ "-ExecutionPolicy",
13626
+ "Bypass",
13627
+ "-EncodedCommand"
13628
+ ];
13629
+ executePowerShell.encodeCommand = (command) => Buffer2.from(command, "utf16le").toString("base64");
13630
+ executePowerShell.escapeArgument = (value) => `'${String(value).replaceAll("'", "''")}'`;
13631
+ });
13632
+
13633
+ // node_modules/wsl-utils/utilities.js
13634
+ function parseMountPointFromConfig(content) {
13635
+ for (const line of content.split(`
13636
+ `)) {
13637
+ if (/^\s*#/.test(line)) {
13638
+ continue;
13639
+ }
13640
+ const match = /^\s*root\s*=\s*(?<mountPoint>"[^"]*"|'[^']*'|[^#]*)/.exec(line);
13641
+ if (!match) {
13642
+ continue;
13643
+ }
13644
+ return match.groups.mountPoint.trim().replaceAll(/^["']|["']$/g, "");
13645
+ }
13646
+ }
13647
+
13648
+ // node_modules/wsl-utils/index.js
13649
+ import { promisify as promisify2 } from "util";
13650
+ import childProcess2 from "child_process";
13651
+ import fs4, { constants as fsConstants } from "fs/promises";
13652
+ var execFile2, wslDrivesMountPoint, powerShellPathFromWsl = async () => {
13653
+ const mountPoint = await wslDrivesMountPoint();
13654
+ return `${mountPoint}c/Windows/System32/WindowsPowerShell/v1.0/powershell.exe`;
13655
+ }, powerShellPath2, canAccessPowerShellPromise, canAccessPowerShell = async () => {
13656
+ canAccessPowerShellPromise ??= (async () => {
13657
+ try {
13658
+ const psPath = await powerShellPath2();
13659
+ await fs4.access(psPath, fsConstants.X_OK);
13660
+ return true;
13661
+ } catch {
13662
+ return false;
13663
+ }
13664
+ })();
13665
+ return canAccessPowerShellPromise;
13666
+ }, wslDefaultBrowser = async () => {
13667
+ const psPath = await powerShellPath2();
13668
+ const command = String.raw`(Get-ItemProperty -Path "HKCU:\Software\Microsoft\Windows\Shell\Associations\UrlAssociations\http\UserChoice").ProgId`;
13669
+ const { stdout } = await executePowerShell(command, { powerShellPath: psPath });
13670
+ return stdout.trim();
13671
+ }, convertWslPathToWindows = async (path) => {
13672
+ if (/^[a-z]+:\/\//i.test(path)) {
13673
+ return path;
13674
+ }
13675
+ try {
13676
+ const { stdout } = await execFile2("wslpath", ["-aw", path], { encoding: "utf8" });
13677
+ return stdout.trim();
13678
+ } catch {
13679
+ return path;
13680
+ }
13681
+ };
13682
+ var init_wsl_utils = __esm(() => {
13683
+ init_is_wsl();
13684
+ init_powershell_utils();
13685
+ init_is_wsl();
13686
+ execFile2 = promisify2(childProcess2.execFile);
13687
+ wslDrivesMountPoint = (() => {
13688
+ const defaultMountPoint = "/mnt/";
13689
+ let mountPoint;
13690
+ return async function() {
13691
+ if (mountPoint) {
13692
+ return mountPoint;
13693
+ }
13694
+ const configFilePath = "/etc/wsl.conf";
13695
+ let isConfigFileExists = false;
13696
+ try {
13697
+ await fs4.access(configFilePath, fsConstants.F_OK);
13698
+ isConfigFileExists = true;
13699
+ } catch {}
13700
+ if (!isConfigFileExists) {
13701
+ return defaultMountPoint;
13702
+ }
13703
+ const configContent = await fs4.readFile(configFilePath, { encoding: "utf8" });
13704
+ const parsedMountPoint = parseMountPointFromConfig(configContent);
13705
+ if (parsedMountPoint === undefined) {
13706
+ return defaultMountPoint;
13707
+ }
13708
+ mountPoint = parsedMountPoint;
13709
+ mountPoint = mountPoint.endsWith("/") ? mountPoint : `${mountPoint}/`;
13710
+ return mountPoint;
13711
+ };
13712
+ })();
13713
+ powerShellPath2 = is_wsl_default ? powerShellPathFromWsl : powerShellPath;
13714
+ });
13715
+
13716
+ // node_modules/define-lazy-prop/index.js
13717
+ function defineLazyProperty(object, propertyName, valueGetter) {
13718
+ const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true });
13719
+ Object.defineProperty(object, propertyName, {
13720
+ configurable: true,
13721
+ enumerable: true,
13722
+ get() {
13723
+ const result = valueGetter();
13724
+ define(result);
13725
+ return result;
13726
+ },
13727
+ set(value) {
13728
+ define(value);
13729
+ }
13730
+ });
13731
+ return object;
13732
+ }
13733
+
13734
+ // node_modules/default-browser-id/index.js
13735
+ import { promisify as promisify3 } from "util";
13736
+ import process5 from "process";
13737
+ import { execFile as execFile3 } from "child_process";
13738
+ async function defaultBrowserId() {
13739
+ if (process5.platform !== "darwin") {
13740
+ throw new Error("macOS only");
13741
+ }
13742
+ const { stdout } = await execFileAsync("defaults", ["read", "com.apple.LaunchServices/com.apple.launchservices.secure", "LSHandlers"]);
13743
+ const match = /LSHandlerRoleAll = "(?!-)(?<id>[^"]+?)";\s+?LSHandlerURLScheme = (?:http|https);/.exec(stdout);
13744
+ const browserId = match?.groups.id ?? "com.apple.Safari";
13745
+ if (browserId === "com.apple.safari") {
13746
+ return "com.apple.Safari";
13747
+ }
13748
+ return browserId;
13749
+ }
13750
+ var execFileAsync;
13751
+ var init_default_browser_id = __esm(() => {
13752
+ execFileAsync = promisify3(execFile3);
13753
+ });
13754
+
13755
+ // node_modules/run-applescript/index.js
13756
+ import process6 from "process";
13757
+ import { promisify as promisify4 } from "util";
13758
+ import { execFile as execFile4, execFileSync } from "child_process";
13759
+ async function runAppleScript(script, { humanReadableOutput = true, signal } = {}) {
13760
+ if (process6.platform !== "darwin") {
13761
+ throw new Error("macOS only");
13762
+ }
13763
+ const outputArguments = humanReadableOutput ? [] : ["-ss"];
13764
+ const execOptions = {};
13765
+ if (signal) {
13766
+ execOptions.signal = signal;
13767
+ }
13768
+ const { stdout } = await execFileAsync2("osascript", ["-e", script, outputArguments], execOptions);
13769
+ return stdout.trim();
13770
+ }
13771
+ var execFileAsync2;
13772
+ var init_run_applescript = __esm(() => {
13773
+ execFileAsync2 = promisify4(execFile4);
13774
+ });
13775
+
13776
+ // node_modules/bundle-name/index.js
13777
+ async function bundleName(bundleId) {
13778
+ return runAppleScript(`tell application "Finder" to set app_path to application file id "${bundleId}" as string
13779
+ tell application "System Events" to get value of property list item "CFBundleName" of property list file (app_path & ":Contents:Info.plist")`);
13780
+ }
13781
+ var init_bundle_name = __esm(() => {
13782
+ init_run_applescript();
13783
+ });
13784
+
13785
+ // node_modules/default-browser/windows.js
13786
+ import { promisify as promisify5 } from "util";
13787
+ import { execFile as execFile5 } from "child_process";
13788
+ async function defaultBrowser(_execFileAsync = execFileAsync3) {
13789
+ const { stdout } = await _execFileAsync("reg", [
13790
+ "QUERY",
13791
+ " HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\http\\UserChoice",
13792
+ "/v",
13793
+ "ProgId"
13794
+ ]);
13795
+ const match = /ProgId\s*REG_SZ\s*(?<id>\S+)/.exec(stdout);
13796
+ if (!match) {
13797
+ throw new UnknownBrowserError(`Cannot find Windows browser in stdout: ${JSON.stringify(stdout)}`);
13798
+ }
13799
+ const { id } = match.groups;
13800
+ const dotIndex = id.lastIndexOf(".");
13801
+ const hyphenIndex = id.lastIndexOf("-");
13802
+ const baseIdByDot = dotIndex === -1 ? undefined : id.slice(0, dotIndex);
13803
+ const baseIdByHyphen = hyphenIndex === -1 ? undefined : id.slice(0, hyphenIndex);
13804
+ return windowsBrowserProgIds[id] ?? windowsBrowserProgIds[baseIdByDot] ?? windowsBrowserProgIds[baseIdByHyphen] ?? { name: id, id };
13805
+ }
13806
+ var execFileAsync3, windowsBrowserProgIds, _windowsBrowserProgIdMap, UnknownBrowserError;
13807
+ var init_windows = __esm(() => {
13808
+ execFileAsync3 = promisify5(execFile5);
13809
+ windowsBrowserProgIds = {
13810
+ MSEdgeHTM: { name: "Edge", id: "com.microsoft.edge" },
13811
+ MSEdgeBHTML: { name: "Edge Beta", id: "com.microsoft.edge.beta" },
13812
+ MSEdgeDHTML: { name: "Edge Dev", id: "com.microsoft.edge.dev" },
13813
+ AppXq0fevzme2pys62n3e0fbqa7peapykr8v: { name: "Edge", id: "com.microsoft.edge.old" },
13814
+ ChromeHTML: { name: "Chrome", id: "com.google.chrome" },
13815
+ ChromeBHTML: { name: "Chrome Beta", id: "com.google.chrome.beta" },
13816
+ ChromeDHTML: { name: "Chrome Dev", id: "com.google.chrome.dev" },
13817
+ ChromiumHTM: { name: "Chromium", id: "org.chromium.Chromium" },
13818
+ BraveHTML: { name: "Brave", id: "com.brave.Browser" },
13819
+ BraveBHTML: { name: "Brave Beta", id: "com.brave.Browser.beta" },
13820
+ BraveDHTML: { name: "Brave Dev", id: "com.brave.Browser.dev" },
13821
+ BraveSSHTM: { name: "Brave Nightly", id: "com.brave.Browser.nightly" },
13822
+ FirefoxURL: { name: "Firefox", id: "org.mozilla.firefox" },
13823
+ OperaStable: { name: "Opera", id: "com.operasoftware.Opera" },
13824
+ VivaldiHTM: { name: "Vivaldi", id: "com.vivaldi.Vivaldi" },
13825
+ "IE.HTTP": { name: "Internet Explorer", id: "com.microsoft.ie" }
13826
+ };
13827
+ _windowsBrowserProgIdMap = new Map(Object.entries(windowsBrowserProgIds));
13828
+ UnknownBrowserError = class UnknownBrowserError extends Error {
13829
+ };
13830
+ });
13831
+
13832
+ // node_modules/default-browser/index.js
13833
+ import { promisify as promisify6 } from "util";
13834
+ import process7 from "process";
13835
+ import { execFile as execFile6 } from "child_process";
13836
+ async function defaultBrowser2() {
13837
+ if (process7.platform === "darwin") {
13838
+ const id = await defaultBrowserId();
13839
+ const name = await bundleName(id);
13840
+ return { name, id };
13841
+ }
13842
+ if (process7.platform === "linux") {
13843
+ const { stdout } = await execFileAsync4("xdg-mime", ["query", "default", "x-scheme-handler/http"]);
13844
+ const id = stdout.trim();
13845
+ const name = titleize(id.replace(/.desktop$/, "").replace("-", " "));
13846
+ return { name, id };
13847
+ }
13848
+ if (process7.platform === "win32") {
13849
+ return defaultBrowser();
13850
+ }
13851
+ throw new Error("Only macOS, Linux, and Windows are supported");
13852
+ }
13853
+ var execFileAsync4, titleize = (string) => string.toLowerCase().replaceAll(/(?:^|\s|-)\S/g, (x) => x.toUpperCase());
13854
+ var init_default_browser = __esm(() => {
13855
+ init_default_browser_id();
13856
+ init_bundle_name();
13857
+ init_windows();
13858
+ init_windows();
13859
+ execFileAsync4 = promisify6(execFile6);
13860
+ });
13861
+
13862
+ // node_modules/is-in-ssh/index.js
13863
+ import process8 from "process";
13864
+ var isInSsh, is_in_ssh_default;
13865
+ var init_is_in_ssh = __esm(() => {
13866
+ isInSsh = Boolean(process8.env.SSH_CONNECTION || process8.env.SSH_CLIENT || process8.env.SSH_TTY);
13867
+ is_in_ssh_default = isInSsh;
13868
+ });
13869
+
13870
+ // node_modules/open/index.js
13871
+ var exports_open = {};
13872
+ __export(exports_open, {
13873
+ openApp: () => openApp,
13874
+ default: () => open_default,
13875
+ apps: () => apps
13876
+ });
13877
+ import process9 from "process";
13878
+ import path from "path";
13879
+ import { fileURLToPath } from "url";
13880
+ import childProcess3 from "child_process";
13881
+ import fs5, { constants as fsConstants2 } from "fs/promises";
13882
+ function detectArchBinary(binary) {
13883
+ if (typeof binary === "string" || Array.isArray(binary)) {
13884
+ return binary;
13885
+ }
13886
+ const { [arch]: archBinary } = binary;
13887
+ if (!archBinary) {
13888
+ throw new Error(`${arch} is not supported`);
13889
+ }
13890
+ return archBinary;
13891
+ }
13892
+ function detectPlatformBinary({ [platform]: platformBinary }, { wsl } = {}) {
13893
+ if (wsl && is_wsl_default) {
13894
+ return detectArchBinary(wsl);
13895
+ }
13896
+ if (!platformBinary) {
13897
+ throw new Error(`${platform} is not supported`);
13898
+ }
13899
+ return detectArchBinary(platformBinary);
13900
+ }
13901
+ var fallbackAttemptSymbol, __dirname2, localXdgOpenPath, platform, arch, tryEachApp = async (apps, opener) => {
13902
+ if (apps.length === 0) {
13903
+ return;
13904
+ }
13905
+ const errors = [];
13906
+ for (const app of apps) {
13907
+ try {
13908
+ return await opener(app);
13909
+ } catch (error) {
13910
+ errors.push(error);
13911
+ }
13912
+ }
13913
+ throw new AggregateError(errors, "Failed to open in all supported apps");
13914
+ }, baseOpen = async (options) => {
13915
+ options = {
13916
+ wait: false,
13917
+ background: false,
13918
+ newInstance: false,
13919
+ allowNonzeroExitCode: false,
13920
+ ...options
13921
+ };
13922
+ const isFallbackAttempt = options[fallbackAttemptSymbol] === true;
13923
+ delete options[fallbackAttemptSymbol];
13924
+ if (Array.isArray(options.app)) {
13925
+ return tryEachApp(options.app, (singleApp) => baseOpen({
13926
+ ...options,
13927
+ app: singleApp,
13928
+ [fallbackAttemptSymbol]: true
13929
+ }));
13930
+ }
13931
+ let { name: app, arguments: appArguments = [] } = options.app ?? {};
13932
+ appArguments = [...appArguments];
13933
+ if (Array.isArray(app)) {
13934
+ return tryEachApp(app, (appName) => baseOpen({
13935
+ ...options,
13936
+ app: {
13937
+ name: appName,
13938
+ arguments: appArguments
13939
+ },
13940
+ [fallbackAttemptSymbol]: true
13941
+ }));
13942
+ }
13943
+ if (app === "browser" || app === "browserPrivate") {
13944
+ const ids = {
13945
+ "com.google.chrome": "chrome",
13946
+ "google-chrome.desktop": "chrome",
13947
+ "com.brave.browser": "brave",
13948
+ "org.mozilla.firefox": "firefox",
13949
+ "firefox.desktop": "firefox",
13950
+ "com.microsoft.msedge": "edge",
13951
+ "com.microsoft.edge": "edge",
13952
+ "com.microsoft.edgemac": "edge",
13953
+ "microsoft-edge.desktop": "edge",
13954
+ "com.apple.safari": "safari"
13955
+ };
13956
+ const flags = {
13957
+ chrome: "--incognito",
13958
+ brave: "--incognito",
13959
+ firefox: "--private-window",
13960
+ edge: "--inPrivate"
13961
+ };
13962
+ let browser;
13963
+ if (is_wsl_default) {
13964
+ const progId = await wslDefaultBrowser();
13965
+ const browserInfo = _windowsBrowserProgIdMap.get(progId);
13966
+ browser = browserInfo ?? {};
13967
+ } else {
13968
+ browser = await defaultBrowser2();
13969
+ }
13970
+ if (browser.id in ids) {
13971
+ const browserName = ids[browser.id.toLowerCase()];
13972
+ if (app === "browserPrivate") {
13973
+ if (browserName === "safari") {
13974
+ throw new Error("Safari doesn't support opening in private mode via command line");
13975
+ }
13976
+ appArguments.push(flags[browserName]);
13977
+ }
13978
+ return baseOpen({
13979
+ ...options,
13980
+ app: {
13981
+ name: apps[browserName],
13982
+ arguments: appArguments
13983
+ }
13984
+ });
13985
+ }
13986
+ throw new Error(`${browser.name} is not supported as a default browser`);
13987
+ }
13988
+ let command;
13989
+ const cliArguments = [];
13990
+ const childProcessOptions = {};
13991
+ let shouldUseWindowsInWsl = false;
13992
+ if (is_wsl_default && !isInsideContainer() && !is_in_ssh_default && !app) {
13993
+ shouldUseWindowsInWsl = await canAccessPowerShell();
13994
+ }
13995
+ if (platform === "darwin") {
13996
+ command = "open";
13997
+ if (options.wait) {
13998
+ cliArguments.push("--wait-apps");
13999
+ }
14000
+ if (options.background) {
14001
+ cliArguments.push("--background");
14002
+ }
14003
+ if (options.newInstance) {
14004
+ cliArguments.push("--new");
14005
+ }
14006
+ if (app) {
14007
+ cliArguments.push("-a", app);
14008
+ }
14009
+ } else if (platform === "win32" || shouldUseWindowsInWsl) {
14010
+ command = await powerShellPath2();
14011
+ cliArguments.push(...executePowerShell.argumentsPrefix);
14012
+ if (!is_wsl_default) {
14013
+ childProcessOptions.windowsVerbatimArguments = true;
14014
+ }
14015
+ if (is_wsl_default && options.target) {
14016
+ options.target = await convertWslPathToWindows(options.target);
14017
+ }
14018
+ const encodedArguments = ["$ProgressPreference = 'SilentlyContinue';", "Start"];
14019
+ if (options.wait) {
14020
+ encodedArguments.push("-Wait");
14021
+ }
14022
+ if (app) {
14023
+ encodedArguments.push(executePowerShell.escapeArgument(app));
14024
+ if (options.target) {
14025
+ appArguments.push(options.target);
14026
+ }
14027
+ } else if (options.target) {
14028
+ encodedArguments.push(executePowerShell.escapeArgument(options.target));
14029
+ }
14030
+ if (appArguments.length > 0) {
14031
+ appArguments = appArguments.map((argument) => executePowerShell.escapeArgument(argument));
14032
+ encodedArguments.push("-ArgumentList", appArguments.join(","));
14033
+ }
14034
+ options.target = executePowerShell.encodeCommand(encodedArguments.join(" "));
14035
+ if (!options.wait) {
14036
+ childProcessOptions.stdio = "ignore";
14037
+ }
14038
+ } else {
14039
+ if (app) {
14040
+ command = app;
14041
+ } else {
14042
+ const isBundled = !__dirname2 || __dirname2 === "/";
14043
+ let exeLocalXdgOpen = false;
14044
+ try {
14045
+ await fs5.access(localXdgOpenPath, fsConstants2.X_OK);
14046
+ exeLocalXdgOpen = true;
14047
+ } catch {}
14048
+ const useSystemXdgOpen = process9.versions.electron ?? (platform === "android" || isBundled || !exeLocalXdgOpen);
14049
+ command = useSystemXdgOpen ? "xdg-open" : localXdgOpenPath;
14050
+ }
14051
+ if (appArguments.length > 0) {
14052
+ cliArguments.push(...appArguments);
14053
+ }
14054
+ if (!options.wait) {
14055
+ childProcessOptions.stdio = "ignore";
14056
+ childProcessOptions.detached = true;
14057
+ }
14058
+ }
14059
+ if (platform === "darwin" && appArguments.length > 0) {
14060
+ cliArguments.push("--args", ...appArguments);
14061
+ }
14062
+ if (options.target) {
14063
+ cliArguments.push(options.target);
14064
+ }
14065
+ const subprocess = childProcess3.spawn(command, cliArguments, childProcessOptions);
14066
+ if (options.wait) {
14067
+ return new Promise((resolve, reject) => {
14068
+ subprocess.once("error", reject);
14069
+ subprocess.once("close", (exitCode) => {
14070
+ if (!options.allowNonzeroExitCode && exitCode !== 0) {
14071
+ reject(new Error(`Exited with code ${exitCode}`));
14072
+ return;
14073
+ }
14074
+ resolve(subprocess);
14075
+ });
14076
+ });
14077
+ }
14078
+ if (isFallbackAttempt) {
14079
+ return new Promise((resolve, reject) => {
14080
+ subprocess.once("error", reject);
14081
+ subprocess.once("spawn", () => {
14082
+ subprocess.once("close", (exitCode) => {
14083
+ subprocess.off("error", reject);
14084
+ if (exitCode !== 0) {
14085
+ reject(new Error(`Exited with code ${exitCode}`));
14086
+ return;
14087
+ }
14088
+ subprocess.unref();
14089
+ resolve(subprocess);
14090
+ });
14091
+ });
14092
+ });
14093
+ }
14094
+ subprocess.unref();
14095
+ return new Promise((resolve, reject) => {
14096
+ subprocess.once("error", reject);
14097
+ subprocess.once("spawn", () => {
14098
+ subprocess.off("error", reject);
14099
+ resolve(subprocess);
14100
+ });
14101
+ });
14102
+ }, open = (target, options) => {
14103
+ if (typeof target !== "string") {
14104
+ throw new TypeError("Expected a `target`");
14105
+ }
14106
+ return baseOpen({
14107
+ ...options,
14108
+ target
14109
+ });
14110
+ }, openApp = (name, options) => {
14111
+ if (typeof name !== "string" && !Array.isArray(name)) {
14112
+ throw new TypeError("Expected a valid `name`");
14113
+ }
14114
+ const { arguments: appArguments = [] } = options ?? {};
14115
+ if (appArguments !== undefined && appArguments !== null && !Array.isArray(appArguments)) {
14116
+ throw new TypeError("Expected `appArguments` as Array type");
14117
+ }
14118
+ return baseOpen({
14119
+ ...options,
14120
+ app: {
14121
+ name,
14122
+ arguments: appArguments
14123
+ }
14124
+ });
14125
+ }, apps, open_default;
14126
+ var init_open = __esm(() => {
14127
+ init_wsl_utils();
14128
+ init_powershell_utils();
14129
+ init_default_browser();
14130
+ init_is_inside_container();
14131
+ init_is_in_ssh();
14132
+ fallbackAttemptSymbol = Symbol("fallbackAttempt");
14133
+ __dirname2 = import.meta.url ? path.dirname(fileURLToPath(import.meta.url)) : "";
14134
+ localXdgOpenPath = path.join(__dirname2, "xdg-open");
14135
+ ({ platform, arch } = process9);
14136
+ apps = {
14137
+ browser: "browser",
14138
+ browserPrivate: "browserPrivate"
14139
+ };
14140
+ defineLazyProperty(apps, "chrome", () => detectPlatformBinary({
14141
+ darwin: "google chrome",
14142
+ win32: "chrome",
14143
+ linux: ["google-chrome", "google-chrome-stable", "chromium", "chromium-browser"]
14144
+ }, {
14145
+ wsl: {
14146
+ ia32: "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe",
14147
+ x64: ["/mnt/c/Program Files/Google/Chrome/Application/chrome.exe", "/mnt/c/Program Files (x86)/Google/Chrome/Application/chrome.exe"]
14148
+ }
14149
+ }));
14150
+ defineLazyProperty(apps, "brave", () => detectPlatformBinary({
14151
+ darwin: "brave browser",
14152
+ win32: "brave",
14153
+ linux: ["brave-browser", "brave"]
14154
+ }, {
14155
+ wsl: {
14156
+ ia32: "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe",
14157
+ x64: ["/mnt/c/Program Files/BraveSoftware/Brave-Browser/Application/brave.exe", "/mnt/c/Program Files (x86)/BraveSoftware/Brave-Browser/Application/brave.exe"]
14158
+ }
14159
+ }));
14160
+ defineLazyProperty(apps, "firefox", () => detectPlatformBinary({
14161
+ darwin: "firefox",
14162
+ win32: String.raw`C:\Program Files\Mozilla Firefox\firefox.exe`,
14163
+ linux: "firefox"
14164
+ }, {
14165
+ wsl: "/mnt/c/Program Files/Mozilla Firefox/firefox.exe"
14166
+ }));
14167
+ defineLazyProperty(apps, "edge", () => detectPlatformBinary({
14168
+ darwin: "microsoft edge",
14169
+ win32: "msedge",
14170
+ linux: ["microsoft-edge", "microsoft-edge-dev"]
14171
+ }, {
14172
+ wsl: "/mnt/c/Program Files (x86)/Microsoft/Edge/Application/msedge.exe"
14173
+ }));
14174
+ defineLazyProperty(apps, "safari", () => detectPlatformBinary({
14175
+ darwin: "Safari"
14176
+ }));
14177
+ open_default = open;
14178
+ });
14179
+
13525
14180
  // node_modules/commander/esm.mjs
13526
14181
  var import__ = __toESM(require_commander(), 1);
13527
14182
  var {
@@ -13606,6 +14261,7 @@ var ServiceTokens = {
13606
14261
  ContextService: "ContextService",
13607
14262
  OutputService: "OutputService",
13608
14263
  HttpClient: "HttpClient",
14264
+ OAuthService: "OAuthService",
13609
14265
  VersionService: "VersionService",
13610
14266
  PullrequestsApi: "PullrequestsApi",
13611
14267
  RepositoriesApi: "RepositoriesApi",
@@ -13801,6 +14457,7 @@ class ConfigService {
13801
14457
  const config = await this.getConfig();
13802
14458
  await this.setConfig({
13803
14459
  ...config,
14460
+ authMethod: "basic",
13804
14461
  username: credentials.username,
13805
14462
  apiToken: credentials.apiToken
13806
14463
  });
@@ -13828,6 +14485,56 @@ class ConfigService {
13828
14485
  getConfigPath() {
13829
14486
  return this.configFile;
13830
14487
  }
14488
+ async getAuthMethod() {
14489
+ const config = await this.getConfig();
14490
+ return config.authMethod ?? "basic";
14491
+ }
14492
+ async getOAuthCredentials() {
14493
+ const config = await this.getConfig();
14494
+ const { oauthAccessToken, oauthRefreshToken, oauthExpiresAt } = config;
14495
+ if (!oauthAccessToken || !oauthRefreshToken || !oauthExpiresAt) {
14496
+ throw new BBError({
14497
+ code: 1001 /* AUTH_REQUIRED */,
14498
+ message: "OAuth authentication required. Run 'bb auth login' to authenticate."
14499
+ });
14500
+ }
14501
+ return {
14502
+ accessToken: oauthAccessToken,
14503
+ refreshToken: oauthRefreshToken,
14504
+ expiresAt: oauthExpiresAt
14505
+ };
14506
+ }
14507
+ async setOAuthCredentials(credentials) {
14508
+ const config = await this.getConfig();
14509
+ const { username: _u, apiToken: _t, ...rest } = config;
14510
+ await this.setConfig({
14511
+ ...rest,
14512
+ authMethod: "oauth",
14513
+ oauthAccessToken: credentials.accessToken,
14514
+ oauthRefreshToken: credentials.refreshToken,
14515
+ oauthExpiresAt: credentials.expiresAt
14516
+ });
14517
+ }
14518
+ async clearOAuthCredentials() {
14519
+ const config = await this.getConfig();
14520
+ const {
14521
+ authMethod: _am,
14522
+ oauthAccessToken: _at,
14523
+ oauthRefreshToken: _rt,
14524
+ oauthExpiresAt: _ea,
14525
+ oauthClientId: _ci,
14526
+ oauthClientSecret: _cs,
14527
+ ...rest
14528
+ } = config;
14529
+ await this.setConfig(rest);
14530
+ }
14531
+ async isOAuthTokenExpired() {
14532
+ const config = await this.getConfig();
14533
+ if (!config.oauthExpiresAt) {
14534
+ return true;
14535
+ }
14536
+ return Date.now() >= (config.oauthExpiresAt - 60) * 1000;
14537
+ }
13831
14538
  clearCache() {
13832
14539
  this.configCache = null;
13833
14540
  }
@@ -18205,7 +18912,7 @@ function getRetryDelay(error, attempt) {
18205
18912
  function sleep(ms) {
18206
18913
  return new Promise((resolve) => setTimeout(resolve, ms));
18207
18914
  }
18208
- function createApiClient(configService) {
18915
+ function createApiClient(configService, oauthService) {
18209
18916
  const instance = axios_default.create({
18210
18917
  baseURL: BASE_URL,
18211
18918
  headers: {
@@ -18217,9 +18924,15 @@ function createApiClient(configService) {
18217
18924
  if (process.env.DEBUG === "true") {
18218
18925
  console.debug(`[HTTP] ${config.method?.toUpperCase()} ${config.url}`);
18219
18926
  }
18220
- const credentials = await configService.getCredentials();
18221
- const authString = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
18222
- config.headers.Authorization = `Basic ${authString}`;
18927
+ const authMethod = await configService.getAuthMethod();
18928
+ if (authMethod === "oauth" && oauthService) {
18929
+ const accessToken = await oauthService.getValidAccessToken();
18930
+ config.headers.Authorization = `Bearer ${accessToken}`;
18931
+ } else {
18932
+ const credentials = await configService.getCredentials();
18933
+ const authString = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
18934
+ config.headers.Authorization = `Basic ${authString}`;
18935
+ }
18223
18936
  return config;
18224
18937
  }, (error) => Promise.reject(error));
18225
18938
  instance.interceptors.response.use((response) => {
@@ -18235,6 +18948,25 @@ function createApiClient(configService) {
18235
18948
  console.debug(`[HTTP] Error Response Body:`, JSON.stringify(error.response.data, null, 2));
18236
18949
  }
18237
18950
  }
18951
+ if (error.response?.status === 401 && oauthService) {
18952
+ const config = error.config;
18953
+ if (config && !config.__tokenRefreshed) {
18954
+ const authMethod = await configService.getAuthMethod();
18955
+ if (authMethod === "oauth") {
18956
+ try {
18957
+ config.__tokenRefreshed = true;
18958
+ const newToken = await oauthService.refreshAccessToken();
18959
+ config.headers.Authorization = `Bearer ${newToken}`;
18960
+ return instance(config);
18961
+ } catch {
18962
+ throw new BBError({
18963
+ code: 1003 /* AUTH_EXPIRED */,
18964
+ message: `OAuth token expired. Run 'bb auth login' to re-authenticate.`
18965
+ });
18966
+ }
18967
+ }
18968
+ }
18969
+ }
18238
18970
  if (error.response && RETRYABLE_STATUS_CODES.has(error.response.status)) {
18239
18971
  const config = error.config;
18240
18972
  if (config) {
@@ -18285,6 +19017,405 @@ function extractErrorMessage(data) {
18285
19017
  }
18286
19018
  return;
18287
19019
  }
19020
+ // src/services/oauth.service.ts
19021
+ import { createServer } from "http";
19022
+ import { randomBytes } from "crypto";
19023
+ var BITBUCKET_AUTHORIZE_URL = "https://bitbucket.org/site/oauth2/authorize";
19024
+ var BITBUCKET_TOKEN_URL = "https://bitbucket.org/site/oauth2/access_token";
19025
+ var CALLBACK_PORT = 19872;
19026
+ var CALLBACK_PATH = "/callback";
19027
+ var CALLBACK_URL = `http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`;
19028
+ var AUTH_TIMEOUT_MS = 5 * 60 * 1000;
19029
+ var DEFAULT_CLIENT_ID = "ErUBvNmdYtfVHgW6J4";
19030
+ var DEFAULT_CLIENT_SECRET = "QnrWypuKXv7YvU7WJwQRza2n2QfHCEw5";
19031
+ var OAUTH_SCOPES = [
19032
+ "account",
19033
+ "repository",
19034
+ "repository:admin",
19035
+ "pullrequest",
19036
+ "pullrequest:write"
19037
+ ].join(" ");
19038
+ function generateState() {
19039
+ return randomBytes(16).toString("hex");
19040
+ }
19041
+
19042
+ class OAuthService {
19043
+ configService;
19044
+ constructor(configService) {
19045
+ this.configService = configService;
19046
+ }
19047
+ async authorize(clientId, clientSecret) {
19048
+ const resolvedClientId = clientId ?? await this.getClientId();
19049
+ const state = generateState();
19050
+ const authUrl = this.buildAuthUrl(resolvedClientId, state);
19051
+ const { code } = await this.waitForCallback(authUrl, state);
19052
+ const tokenResponse = await this.exchangeCode(code, resolvedClientId, clientSecret);
19053
+ const expiresAt = Math.floor(Date.now() / 1000) + tokenResponse.expires_in;
19054
+ await this.configService.setOAuthCredentials({
19055
+ accessToken: tokenResponse.access_token,
19056
+ refreshToken: tokenResponse.refresh_token,
19057
+ expiresAt
19058
+ });
19059
+ if (clientId) {
19060
+ await this.configService.setValue("oauthClientId", clientId);
19061
+ }
19062
+ if (clientSecret) {
19063
+ await this.configService.setValue("oauthClientSecret", clientSecret);
19064
+ }
19065
+ const userInfo = await this.fetchUserInfo(tokenResponse.access_token);
19066
+ return userInfo;
19067
+ }
19068
+ async refreshAccessToken() {
19069
+ const credentials = await this.configService.getOAuthCredentials();
19070
+ const clientId = await this.getClientId();
19071
+ const clientSecret = await this.getClientSecret();
19072
+ const params = new URLSearchParams({
19073
+ grant_type: "refresh_token",
19074
+ refresh_token: credentials.refreshToken
19075
+ });
19076
+ const response = await fetch(BITBUCKET_TOKEN_URL, {
19077
+ method: "POST",
19078
+ headers: {
19079
+ "Content-Type": "application/x-www-form-urlencoded",
19080
+ Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`
19081
+ },
19082
+ body: params.toString()
19083
+ });
19084
+ if (!response.ok) {
19085
+ const errorBody = await response.text();
19086
+ throw new BBError({
19087
+ code: 1003 /* AUTH_EXPIRED */,
19088
+ message: `Failed to refresh OAuth token. Run 'bb auth login' to re-authenticate.`,
19089
+ context: { status: response.status, body: errorBody }
19090
+ });
19091
+ }
19092
+ const tokenResponse = await response.json();
19093
+ const expiresAt = Math.floor(Date.now() / 1000) + tokenResponse.expires_in;
19094
+ await this.configService.setOAuthCredentials({
19095
+ accessToken: tokenResponse.access_token,
19096
+ refreshToken: tokenResponse.refresh_token,
19097
+ expiresAt
19098
+ });
19099
+ return tokenResponse.access_token;
19100
+ }
19101
+ async revokeToken() {
19102
+ try {
19103
+ const credentials = await this.configService.getOAuthCredentials();
19104
+ const clientId = await this.getClientId();
19105
+ const clientSecret = await this.getClientSecret();
19106
+ const params = new URLSearchParams({
19107
+ token: credentials.accessToken
19108
+ });
19109
+ await fetch("https://bitbucket.org/site/oauth2/revoke", {
19110
+ method: "POST",
19111
+ headers: {
19112
+ "Content-Type": "application/x-www-form-urlencoded",
19113
+ Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`
19114
+ },
19115
+ body: params.toString()
19116
+ });
19117
+ } catch {}
19118
+ }
19119
+ async getValidAccessToken() {
19120
+ const isExpired = await this.configService.isOAuthTokenExpired();
19121
+ if (isExpired) {
19122
+ return this.refreshAccessToken();
19123
+ }
19124
+ const credentials = await this.configService.getOAuthCredentials();
19125
+ return credentials.accessToken;
19126
+ }
19127
+ async getClientId() {
19128
+ const customClientId = await this.configService.getValue("oauthClientId");
19129
+ return customClientId ?? DEFAULT_CLIENT_ID;
19130
+ }
19131
+ async getClientSecret() {
19132
+ const customSecret = await this.configService.getValue("oauthClientSecret");
19133
+ return customSecret ?? DEFAULT_CLIENT_SECRET;
19134
+ }
19135
+ buildAuthUrl(clientId, state) {
19136
+ const params = new URLSearchParams({
19137
+ client_id: clientId,
19138
+ response_type: "code",
19139
+ redirect_uri: CALLBACK_URL,
19140
+ scope: OAUTH_SCOPES,
19141
+ state
19142
+ });
19143
+ return `${BITBUCKET_AUTHORIZE_URL}?${params.toString()}`;
19144
+ }
19145
+ async waitForCallback(authUrl, expectedState) {
19146
+ return new Promise((resolve, reject) => {
19147
+ let server;
19148
+ let timeout;
19149
+ const cleanup = () => {
19150
+ clearTimeout(timeout);
19151
+ server?.close();
19152
+ };
19153
+ timeout = setTimeout(() => {
19154
+ cleanup();
19155
+ reject(new BBError({
19156
+ code: 1002 /* AUTH_INVALID */,
19157
+ message: "Authorization timed out. Please try again."
19158
+ }));
19159
+ }, AUTH_TIMEOUT_MS);
19160
+ server = createServer((req, res) => {
19161
+ const url2 = new URL(req.url ?? "/", `http://localhost:${CALLBACK_PORT}`);
19162
+ if (url2.pathname !== CALLBACK_PATH) {
19163
+ res.writeHead(404);
19164
+ res.end("Not found");
19165
+ return;
19166
+ }
19167
+ const code = url2.searchParams.get("code");
19168
+ const state = url2.searchParams.get("state");
19169
+ const error = url2.searchParams.get("error");
19170
+ const errorDescription = url2.searchParams.get("error_description");
19171
+ if (error) {
19172
+ res.writeHead(200, { "Content-Type": "text/html" });
19173
+ res.end(this.buildErrorPage(errorDescription ?? error));
19174
+ cleanup();
19175
+ reject(new BBError({
19176
+ code: 1002 /* AUTH_INVALID */,
19177
+ message: `Authorization was denied: ${errorDescription ?? error}. Run "bb auth login --app-password" to use an API token instead.`
19178
+ }));
19179
+ return;
19180
+ }
19181
+ if (!code || state !== expectedState) {
19182
+ res.writeHead(400, { "Content-Type": "text/html" });
19183
+ res.end(this.buildErrorPage("Invalid callback parameters"));
19184
+ cleanup();
19185
+ reject(new BBError({
19186
+ code: 1002 /* AUTH_INVALID */,
19187
+ message: "Invalid authorization callback. Please try again."
19188
+ }));
19189
+ return;
19190
+ }
19191
+ res.writeHead(200, { "Content-Type": "text/html" });
19192
+ res.end(this.buildSuccessPage());
19193
+ cleanup();
19194
+ resolve({ code });
19195
+ });
19196
+ server.on("error", (err) => {
19197
+ cleanup();
19198
+ if (err.code === "EADDRINUSE") {
19199
+ reject(new BBError({
19200
+ code: 1002 /* AUTH_INVALID */,
19201
+ message: `Port ${CALLBACK_PORT} is already in use. Close the application using it and try again.`
19202
+ }));
19203
+ } else {
19204
+ reject(new BBError({
19205
+ code: 7001 /* NETWORK_ERROR */,
19206
+ message: `Failed to start callback server: ${err.message}`,
19207
+ cause: err
19208
+ }));
19209
+ }
19210
+ });
19211
+ server.listen(CALLBACK_PORT, async () => {
19212
+ try {
19213
+ const open2 = (await Promise.resolve().then(() => (init_open(), exports_open))).default;
19214
+ await open2(authUrl);
19215
+ } catch {}
19216
+ console.error(`If the browser doesn't open, visit:
19217
+ ${authUrl}
19218
+ `);
19219
+ });
19220
+ });
19221
+ }
19222
+ async exchangeCode(code, clientId, clientSecretOverride) {
19223
+ const clientSecret = clientSecretOverride ?? await this.getClientSecret();
19224
+ const params = new URLSearchParams({
19225
+ grant_type: "authorization_code",
19226
+ code,
19227
+ redirect_uri: CALLBACK_URL
19228
+ });
19229
+ const response = await fetch(BITBUCKET_TOKEN_URL, {
19230
+ method: "POST",
19231
+ headers: {
19232
+ "Content-Type": "application/x-www-form-urlencoded",
19233
+ Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`
19234
+ },
19235
+ body: params.toString()
19236
+ });
19237
+ if (!response.ok) {
19238
+ const errorBody = await response.text();
19239
+ throw new BBError({
19240
+ code: 1002 /* AUTH_INVALID */,
19241
+ message: `Failed to exchange authorization code. Please try again.`,
19242
+ context: { status: response.status, body: errorBody }
19243
+ });
19244
+ }
19245
+ return await response.json();
19246
+ }
19247
+ async fetchUserInfo(accessToken) {
19248
+ const response = await fetch("https://api.bitbucket.org/2.0/user", {
19249
+ headers: { Authorization: `Bearer ${accessToken}` }
19250
+ });
19251
+ if (!response.ok) {
19252
+ throw new BBError({
19253
+ code: 1002 /* AUTH_INVALID */,
19254
+ message: "Failed to verify OAuth credentials."
19255
+ });
19256
+ }
19257
+ const user = await response.json();
19258
+ return {
19259
+ username: user.username,
19260
+ displayName: user.display_name,
19261
+ accountId: user.account_id
19262
+ };
19263
+ }
19264
+ buildPageShell(content) {
19265
+ return `<!DOCTYPE html>
19266
+ <html lang="en"><head>
19267
+ <meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
19268
+ <title>Bitbucket CLI</title>
19269
+ <link rel="preconnect" href="https://fonts.googleapis.com">
19270
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
19271
+ <link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:wght@400;500;600&family=Space+Grotesk:wght@400;500;600;700&display=swap" rel="stylesheet">
19272
+ <style>
19273
+ *,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
19274
+ :root{
19275
+ --bg:#181c24;
19276
+ --surface:#1e2330;
19277
+ --border:hsl(216,24%,27%);
19278
+ --text:#e0e4ec;
19279
+ --text-dim:#8892a4;
19280
+ --accent:hsl(216,100%,50%);
19281
+ --accent-glow:hsla(216,100%,52%,0.2);
19282
+ --accent-soft:hsla(216,100%,52%,0.09);
19283
+ --font:'Space Grotesk',sans-serif;
19284
+ --mono:'IBM Plex Mono',monospace;
19285
+ }
19286
+ body{
19287
+ font-family:var(--font);
19288
+ background:var(--bg);
19289
+ color:var(--text);
19290
+ min-height:100vh;
19291
+ display:flex;
19292
+ align-items:center;
19293
+ justify-content:center;
19294
+ background-image:
19295
+ radial-gradient(ellipse 80% 60% at 50% 0%,var(--accent-glow),transparent),
19296
+ radial-gradient(circle at 100% 100%,var(--accent-soft),transparent 50%);
19297
+ }
19298
+ .scene{
19299
+ display:flex;
19300
+ flex-direction:column;
19301
+ align-items:center;
19302
+ gap:2rem;
19303
+ animation:enter 600ms cubic-bezier(.16,1,.3,1) both;
19304
+ }
19305
+ @keyframes enter{
19306
+ from{opacity:0;transform:translateY(16px) scale(.97)}
19307
+ to{opacity:1;transform:translateY(0) scale(1)}
19308
+ }
19309
+ .logo{
19310
+ width:56px;height:56px;
19311
+ background:var(--accent);
19312
+ border-radius:14px;
19313
+ display:flex;align-items:center;justify-content:center;
19314
+ font-family:var(--mono);font-weight:700;font-size:24px;
19315
+ color:#fff;
19316
+ box-shadow:0 0 0 1px hsla(216,100%,70%,0.15),0 8px 32px hsla(216,100%,40%,0.25);
19317
+ animation:logo-in 700ms cubic-bezier(.16,1,.3,1) both;
19318
+ animation-delay:100ms;
19319
+ }
19320
+ @keyframes logo-in{
19321
+ from{opacity:0;transform:scale(.6) rotate(-8deg)}
19322
+ to{opacity:1;transform:scale(1) rotate(0)}
19323
+ }
19324
+ .card{
19325
+ background:var(--surface);
19326
+ border:1px solid var(--border);
19327
+ border-radius:16px;
19328
+ padding:2.5rem 3rem;
19329
+ text-align:center;
19330
+ max-width:420px;
19331
+ width:100%;
19332
+ box-shadow:0 1px 2px rgba(0,0,0,0.2),0 16px 48px rgba(0,0,0,0.15);
19333
+ animation:card-in 600ms cubic-bezier(.16,1,.3,1) both;
19334
+ animation-delay:200ms;
19335
+ }
19336
+ @keyframes card-in{
19337
+ from{opacity:0;transform:translateY(12px)}
19338
+ to{opacity:1;transform:translateY(0)}
19339
+ }
19340
+ .icon-ring{
19341
+ width:52px;height:52px;
19342
+ border-radius:50%;
19343
+ display:flex;align-items:center;justify-content:center;
19344
+ margin:0 auto 1.25rem;
19345
+ animation:ring-pop 500ms cubic-bezier(.16,1,.3,1) both;
19346
+ animation-delay:450ms;
19347
+ }
19348
+ @keyframes ring-pop{
19349
+ from{opacity:0;transform:scale(.5)}
19350
+ to{opacity:1;transform:scale(1)}
19351
+ }
19352
+ .icon-ring svg{width:28px;height:28px}
19353
+ .icon-ring.success{background:hsla(152,68%,46%,0.12);color:hsl(152,68%,46%)}
19354
+ .icon-ring.error{background:hsla(0,72%,56%,0.12);color:hsl(0,72%,56%)}
19355
+ h1{
19356
+ font-size:1.35rem;font-weight:700;
19357
+ letter-spacing:-0.02em;
19358
+ margin-bottom:0.5rem;
19359
+ animation:text-in 500ms ease both;animation-delay:500ms;
19360
+ }
19361
+ .subtitle{
19362
+ font-size:0.9rem;color:var(--text-dim);
19363
+ line-height:1.5;
19364
+ animation:text-in 500ms ease both;animation-delay:580ms;
19365
+ }
19366
+ @keyframes text-in{
19367
+ from{opacity:0;transform:translateY(6px)}
19368
+ to{opacity:1;transform:translateY(0)}
19369
+ }
19370
+ .hint{
19371
+ font-family:var(--mono);font-size:0.72rem;
19372
+ color:var(--text-dim);letter-spacing:0.02em;
19373
+ opacity:0;animation:text-in 500ms ease forwards;animation-delay:700ms;
19374
+ }
19375
+ .hint a{
19376
+ color:var(--accent);text-decoration:none;
19377
+ text-underline-offset:0.2em;
19378
+ }
19379
+ .hint a:hover{text-decoration:underline}
19380
+ .hint kbd{
19381
+ background:var(--surface);border:1px solid var(--border);
19382
+ border-radius:4px;padding:0.15em 0.45em;
19383
+ font-family:var(--mono);font-size:0.72rem;
19384
+ }
19385
+ </style>
19386
+ </head><body>
19387
+ <div class="scene">
19388
+ <div class="logo">bb</div>
19389
+ <div class="card">${content}</div>
19390
+ </div>
19391
+ </body></html>`;
19392
+ }
19393
+ buildSuccessPage() {
19394
+ return this.buildPageShell(`
19395
+ <div class="icon-ring success">
19396
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
19397
+ <polyline points="20 6 9 17 4 12"/>
19398
+ </svg>
19399
+ </div>
19400
+ <h1>Authenticated</h1>
19401
+ <p class="subtitle">You're all set. Close this tab and return to your terminal.</p>
19402
+ <p class="hint"><a href="https://bitbucket-cli.paulvanderlei.com" target="_blank" rel="noopener">View documentation</a></p>
19403
+ `);
19404
+ }
19405
+ buildErrorPage(message) {
19406
+ const escaped = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
19407
+ return this.buildPageShell(`
19408
+ <div class="icon-ring error">
19409
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round">
19410
+ <line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>
19411
+ </svg>
19412
+ </div>
19413
+ <h1>Authentication Failed</h1>
19414
+ <p class="subtitle">${escaped}</p>
19415
+ <p class="hint"><a href="https://bitbucket-cli.paulvanderlei.com/help/troubleshooting/" target="_blank" rel="noopener">Troubleshooting guide</a></p>
19416
+ `);
19417
+ }
19418
+ }
18288
19419
  // src/services/reviewer.service.ts
18289
19420
  function extractReviewerUuids(reviewers) {
18290
19421
  if (!reviewers) {
@@ -20035,12 +21166,12 @@ var RepositoriesApiAxiosParamCreator = function(configuration) {
20035
21166
  options: localVarRequestOptions
20036
21167
  };
20037
21168
  },
20038
- repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet: async (commit, path, repoSlug, workspace, renames, q, sort, options = {}) => {
21169
+ repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet: async (commit, path2, repoSlug, workspace, renames, q, sort, options = {}) => {
20039
21170
  assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "commit", commit);
20040
- assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "path", path);
21171
+ assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "path", path2);
20041
21172
  assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "repoSlug", repoSlug);
20042
21173
  assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "workspace", workspace);
20043
- const localVarPath = `/repositories/{workspace}/{repo_slug}/filehistory/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(path))).replace(`{${"repo_slug"}}`, encodeURIComponent(String(repoSlug))).replace(`{${"workspace"}}`, encodeURIComponent(String(workspace)));
21174
+ const localVarPath = `/repositories/{workspace}/{repo_slug}/filehistory/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(path2))).replace(`{${"repo_slug"}}`, encodeURIComponent(String(repoSlug))).replace(`{${"workspace"}}`, encodeURIComponent(String(workspace)));
20044
21175
  const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
20045
21176
  let baseOptions;
20046
21177
  if (configuration) {
@@ -20580,12 +21711,12 @@ var RepositoriesApiAxiosParamCreator = function(configuration) {
20580
21711
  options: localVarRequestOptions
20581
21712
  };
20582
21713
  },
20583
- repositoriesWorkspaceRepoSlugSrcCommitPathGet: async (commit, path, repoSlug, workspace, format, q, sort, maxDepth, options = {}) => {
21714
+ repositoriesWorkspaceRepoSlugSrcCommitPathGet: async (commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options = {}) => {
20584
21715
  assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "commit", commit);
20585
- assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "path", path);
21716
+ assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "path", path2);
20586
21717
  assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "repoSlug", repoSlug);
20587
21718
  assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "workspace", workspace);
20588
- const localVarPath = `/repositories/{workspace}/{repo_slug}/src/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(path))).replace(`{${"repo_slug"}}`, encodeURIComponent(String(repoSlug))).replace(`{${"workspace"}}`, encodeURIComponent(String(workspace)));
21719
+ const localVarPath = `/repositories/{workspace}/{repo_slug}/src/{commit}/{path}`.replace(`{${"commit"}}`, encodeURIComponent(String(commit))).replace(`{${"path"}}`, encodeURIComponent(String(path2))).replace(`{${"repo_slug"}}`, encodeURIComponent(String(repoSlug))).replace(`{${"workspace"}}`, encodeURIComponent(String(workspace)));
20589
21720
  const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
20590
21721
  let baseOptions;
20591
21722
  if (configuration) {
@@ -20759,8 +21890,8 @@ var RepositoriesApiFp = function(configuration) {
20759
21890
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugDelete"]?.[localVarOperationServerIndex]?.url;
20760
21891
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
20761
21892
  },
20762
- async repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path, repoSlug, workspace, renames, q, sort, options) {
20763
- const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path, repoSlug, workspace, renames, q, sort, options);
21893
+ async repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path2, repoSlug, workspace, renames, q, sort, options) {
21894
+ const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path2, repoSlug, workspace, renames, q, sort, options);
20764
21895
  const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
20765
21896
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet"]?.[localVarOperationServerIndex]?.url;
20766
21897
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
@@ -20885,8 +22016,8 @@ var RepositoriesApiFp = function(configuration) {
20885
22016
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugPut"]?.[localVarOperationServerIndex]?.url;
20886
22017
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
20887
22018
  },
20888
- async repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path, repoSlug, workspace, format, q, sort, maxDepth, options) {
20889
- const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path, repoSlug, workspace, format, q, sort, maxDepth, options);
22019
+ async repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options) {
22020
+ const localVarAxiosArgs = await localVarAxiosParamCreator.repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options);
20890
22021
  const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
20891
22022
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugSrcCommitPathGet"]?.[localVarOperationServerIndex]?.url;
20892
22023
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
@@ -21223,14 +22354,45 @@ class BaseCommand {
21223
22354
  class LoginCommand extends BaseCommand {
21224
22355
  configService;
21225
22356
  usersApi;
22357
+ oauthService;
21226
22358
  name = "login";
21227
- description = "Authenticate with Bitbucket using an API token";
21228
- constructor(configService, usersApi, output) {
22359
+ description = "Authenticate with Bitbucket";
22360
+ constructor(configService, usersApi, oauthService, output) {
21229
22361
  super(output);
21230
22362
  this.configService = configService;
21231
22363
  this.usersApi = usersApi;
22364
+ this.oauthService = oauthService;
21232
22365
  }
21233
22366
  async execute(options, context) {
22367
+ const useAppPassword = options.appPassword || options.username !== undefined || options.password !== undefined || process.env.BB_API_TOKEN !== undefined;
22368
+ if (useAppPassword) {
22369
+ return this.loginWithApiToken(options, context);
22370
+ }
22371
+ return this.loginWithOAuth(options, context);
22372
+ }
22373
+ async loginWithOAuth(options, context) {
22374
+ this.output.info("Opening browser to authenticate with Bitbucket...");
22375
+ try {
22376
+ const userInfo = await this.oauthService.authorize(options.clientId, options.clientSecret);
22377
+ if (context.globalOptions.json) {
22378
+ this.output.json({
22379
+ authenticated: true,
22380
+ method: "oauth",
22381
+ user: {
22382
+ username: userInfo.username,
22383
+ displayName: userInfo.displayName,
22384
+ accountId: userInfo.accountId
22385
+ }
22386
+ });
22387
+ return;
22388
+ }
22389
+ this.output.success(`Logged in as ${userInfo.displayName} (${userInfo.username})`);
22390
+ } catch (error) {
22391
+ await this.configService.clearOAuthCredentials();
22392
+ throw error;
22393
+ }
22394
+ }
22395
+ async loginWithApiToken(options, context) {
21234
22396
  const username = options.username || process.env.BB_USERNAME;
21235
22397
  const apiToken = options.password || process.env.BB_API_TOKEN;
21236
22398
  if (!username) {
@@ -21245,6 +22407,7 @@ class LoginCommand extends BaseCommand {
21245
22407
  message: "API token is required. Use --password option or set BB_API_TOKEN environment variable."
21246
22408
  });
21247
22409
  }
22410
+ await this.configService.clearOAuthCredentials();
21248
22411
  await this.configService.setCredentials({ username, apiToken });
21249
22412
  try {
21250
22413
  const response = await this.usersApi.userGet();
@@ -21252,6 +22415,7 @@ class LoginCommand extends BaseCommand {
21252
22415
  if (context.globalOptions.json) {
21253
22416
  this.output.json({
21254
22417
  authenticated: true,
22418
+ method: "api_token",
21255
22419
  user: {
21256
22420
  username: user.username,
21257
22421
  displayName: user.display_name,
@@ -21274,14 +22438,22 @@ class LoginCommand extends BaseCommand {
21274
22438
  // src/commands/auth/logout.command.ts
21275
22439
  class LogoutCommand extends BaseCommand {
21276
22440
  configService;
22441
+ oauthService;
21277
22442
  name = "logout";
21278
22443
  description = "Log out of Bitbucket";
21279
- constructor(configService, output) {
22444
+ constructor(configService, oauthService, output) {
21280
22445
  super(output);
21281
22446
  this.configService = configService;
22447
+ this.oauthService = oauthService;
21282
22448
  }
21283
22449
  async execute(_options, context) {
21284
- await this.configService.clearCredentials();
22450
+ const authMethod = await this.configService.getAuthMethod();
22451
+ if (authMethod === "oauth") {
22452
+ await this.oauthService.revokeToken();
22453
+ await this.configService.clearOAuthCredentials();
22454
+ } else {
22455
+ await this.configService.clearCredentials();
22456
+ }
21285
22457
  if (context.globalOptions.json) {
21286
22458
  this.output.json({ authenticated: false, success: true });
21287
22459
  return;
@@ -21303,7 +22475,10 @@ class StatusCommand extends BaseCommand {
21303
22475
  }
21304
22476
  async execute(_options, context) {
21305
22477
  const config = await this.configService.getConfig();
21306
- if (!config.username || !config.apiToken) {
22478
+ const authMethod = await this.configService.getAuthMethod();
22479
+ const hasBasicAuth = config.username && config.apiToken;
22480
+ const hasOAuth = config.oauthAccessToken && config.oauthRefreshToken;
22481
+ if (!hasBasicAuth && !hasOAuth) {
21307
22482
  if (context.globalOptions.json) {
21308
22483
  this.output.json({ authenticated: false });
21309
22484
  return;
@@ -21316,21 +22491,41 @@ class StatusCommand extends BaseCommand {
21316
22491
  const response = await this.usersApi.userGet();
21317
22492
  const user = response.data;
21318
22493
  if (context.globalOptions.json) {
21319
- this.output.json({
22494
+ const jsonOutput = {
21320
22495
  authenticated: true,
22496
+ method: authMethod,
21321
22497
  user: {
21322
22498
  username: user.username,
21323
22499
  displayName: user.display_name,
21324
22500
  accountId: user.account_id
21325
22501
  },
21326
22502
  defaultWorkspace: config.defaultWorkspace
21327
- });
22503
+ };
22504
+ if (authMethod === "oauth" && config.oauthExpiresAt) {
22505
+ jsonOutput.tokenExpiresAt = config.oauthExpiresAt;
22506
+ }
22507
+ this.output.json(jsonOutput);
21328
22508
  return;
21329
22509
  }
21330
22510
  this.output.success("Logged in to Bitbucket");
22511
+ this.output.text(` Authentication: ${this.output.highlight(authMethod === "oauth" ? "OAuth" : "API Token")}`);
21331
22512
  this.output.text(` Username: ${this.output.highlight(user.username ?? "")}`);
21332
22513
  this.output.text(` Display name: ${user.display_name}`);
21333
22514
  this.output.text(` Account ID: ${user.account_id}`);
22515
+ if (authMethod === "oauth" && config.oauthExpiresAt) {
22516
+ const expiresIn = config.oauthExpiresAt - Math.floor(Date.now() / 1000);
22517
+ if (expiresIn > 0) {
22518
+ const hours = Math.floor(expiresIn / 3600);
22519
+ const minutes = Math.floor(expiresIn % 3600 / 60);
22520
+ const parts = [];
22521
+ if (hours > 0)
22522
+ parts.push(`${hours}h`);
22523
+ parts.push(`${minutes}m`);
22524
+ this.output.text(` Token expires: in ${parts.join(" ")}`);
22525
+ } else {
22526
+ this.output.text(` Token expires: ${this.output.yellow("expired (will refresh automatically)")}`);
22527
+ }
22528
+ }
21334
22529
  if (config.defaultWorkspace) {
21335
22530
  this.output.text(` Default workspace: ${this.output.highlight(config.defaultWorkspace)}`);
21336
22531
  }
@@ -21347,13 +22542,25 @@ class StatusCommand extends BaseCommand {
21347
22542
  // src/commands/auth/token.command.ts
21348
22543
  class TokenCommand extends BaseCommand {
21349
22544
  configService;
22545
+ oauthService;
21350
22546
  name = "token";
21351
22547
  description = "Print the current access token";
21352
- constructor(configService, output) {
22548
+ constructor(configService, oauthService, output) {
21353
22549
  super(output);
21354
22550
  this.configService = configService;
22551
+ this.oauthService = oauthService;
21355
22552
  }
21356
22553
  async execute(_options, context) {
22554
+ const authMethod = await this.configService.getAuthMethod();
22555
+ if (authMethod === "oauth") {
22556
+ const accessToken = await this.oauthService.getValidAccessToken();
22557
+ if (context.globalOptions.json) {
22558
+ this.output.json({ token: accessToken, type: "bearer" });
22559
+ return;
22560
+ }
22561
+ this.output.text(accessToken);
22562
+ return;
22563
+ }
21357
22564
  const credentials = await this.configService.getCredentials();
21358
22565
  if (!credentials.username || !credentials.apiToken) {
21359
22566
  throw new BBError({
@@ -21363,7 +22570,7 @@ class TokenCommand extends BaseCommand {
21363
22570
  }
21364
22571
  const token = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
21365
22572
  if (context.globalOptions.json) {
21366
- this.output.json({ token });
22573
+ this.output.json({ token, type: "basic" });
21367
22574
  return;
21368
22575
  }
21369
22576
  this.output.text(token);
@@ -21488,8 +22695,8 @@ function getCommitFilePath(file) {
21488
22695
  if (!isRecord(file)) {
21489
22696
  return;
21490
22697
  }
21491
- const path = file.path;
21492
- return typeof path === "string" && path.length > 0 ? path : undefined;
22698
+ const path2 = file.path;
22699
+ return typeof path2 === "string" && path2.length > 0 ? path2 : undefined;
21493
22700
  }
21494
22701
  function parseDiffstatFile(value) {
21495
22702
  if (!isRecord(value)) {
@@ -22270,7 +23477,7 @@ class ViewPRCommand extends BaseCommand {
22270
23477
  }
22271
23478
 
22272
23479
  // src/commands/pr/edit.command.ts
22273
- import * as fs from "fs";
23480
+ import * as fs6 from "fs";
22274
23481
  class EditPRCommand extends BaseCommand {
22275
23482
  pullrequestsApi;
22276
23483
  contextService;
@@ -22324,7 +23531,7 @@ class EditPRCommand extends BaseCommand {
22324
23531
  let body = options.body;
22325
23532
  if (options.bodyFile) {
22326
23533
  try {
22327
- body = fs.readFileSync(options.bodyFile, "utf-8");
23534
+ body = fs6.readFileSync(options.bodyFile, "utf-8");
22328
23535
  } catch (err) {
22329
23536
  throw new BBError({
22330
23537
  code: 9999 /* UNKNOWN */,
@@ -22596,8 +23803,8 @@ class CheckoutPRCommand extends BaseCommand {
22596
23803
 
22597
23804
  // src/commands/pr/diff.command.ts
22598
23805
  import { exec } from "child_process";
22599
- import { promisify } from "util";
22600
- var execAsync = promisify(exec);
23806
+ import { promisify as promisify7 } from "util";
23807
+ var execAsync = promisify7(exec);
22601
23808
 
22602
23809
  class DiffPRCommand extends BaseCommand {
22603
23810
  pullrequestsApi;
@@ -22709,11 +23916,11 @@ class DiffPRCommand extends BaseCommand {
22709
23916
  }
22710
23917
  async openInBrowser(url2) {
22711
23918
  this.output.info(`Opening ${url2} in your browser...`);
22712
- const platform = process.platform;
23919
+ const platform2 = process.platform;
22713
23920
  let command;
22714
- if (platform === "darwin") {
23921
+ if (platform2 === "darwin") {
22715
23922
  command = `open "${url2}"`;
22716
- } else if (platform === "win32") {
23923
+ } else if (platform2 === "win32") {
22717
23924
  command = `start "" "${url2}"`;
22718
23925
  } else {
22719
23926
  command = `xdg-open "${url2}"`;
@@ -23676,24 +24883,32 @@ function bootstrap(options = {}) {
23676
24883
  container.register(ServiceTokens.ConfigService, () => new ConfigService);
23677
24884
  container.register(ServiceTokens.GitService, () => new GitService);
23678
24885
  container.register(ServiceTokens.OutputService, () => new OutputService({ noColor: options.noColor }));
24886
+ container.register(ServiceTokens.OAuthService, () => {
24887
+ const configService = container.resolve(ServiceTokens.ConfigService);
24888
+ return new OAuthService(configService);
24889
+ });
23679
24890
  container.register(ServiceTokens.PullrequestsApi, () => {
23680
24891
  const configService = container.resolve(ServiceTokens.ConfigService);
23681
- const axiosInstance = createApiClient(configService);
24892
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24893
+ const axiosInstance = createApiClient(configService, oauthService);
23682
24894
  return new PullrequestsApi(undefined, undefined, axiosInstance);
23683
24895
  });
23684
24896
  container.register(ServiceTokens.RepositoriesApi, () => {
23685
24897
  const configService = container.resolve(ServiceTokens.ConfigService);
23686
- const axiosInstance = createApiClient(configService);
24898
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24899
+ const axiosInstance = createApiClient(configService, oauthService);
23687
24900
  return new RepositoriesApi(undefined, undefined, axiosInstance);
23688
24901
  });
23689
24902
  container.register(ServiceTokens.UsersApi, () => {
23690
24903
  const configService = container.resolve(ServiceTokens.ConfigService);
23691
- const axiosInstance = createApiClient(configService);
24904
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24905
+ const axiosInstance = createApiClient(configService, oauthService);
23692
24906
  return new UsersApi(undefined, undefined, axiosInstance);
23693
24907
  });
23694
24908
  container.register(ServiceTokens.CommitStatusesApi, () => {
23695
24909
  const configService = container.resolve(ServiceTokens.ConfigService);
23696
- const axiosInstance = createApiClient(configService);
24910
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24911
+ const axiosInstance = createApiClient(configService, oauthService);
23697
24912
  return new CommitStatusesApi(undefined, undefined, axiosInstance);
23698
24913
  });
23699
24914
  container.register(ServiceTokens.ContextService, () => {
@@ -23704,13 +24919,15 @@ function bootstrap(options = {}) {
23704
24919
  container.register(ServiceTokens.LoginCommand, () => {
23705
24920
  const configService = container.resolve(ServiceTokens.ConfigService);
23706
24921
  const usersApi = container.resolve(ServiceTokens.UsersApi);
24922
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
23707
24923
  const output = container.resolve(ServiceTokens.OutputService);
23708
- return new LoginCommand(configService, usersApi, output);
24924
+ return new LoginCommand(configService, usersApi, oauthService, output);
23709
24925
  });
23710
24926
  container.register(ServiceTokens.LogoutCommand, () => {
23711
24927
  const configService = container.resolve(ServiceTokens.ConfigService);
24928
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
23712
24929
  const output = container.resolve(ServiceTokens.OutputService);
23713
- return new LogoutCommand(configService, output);
24930
+ return new LogoutCommand(configService, oauthService, output);
23714
24931
  });
23715
24932
  container.register(ServiceTokens.StatusCommand, () => {
23716
24933
  const configService = container.resolve(ServiceTokens.ConfigService);
@@ -23720,8 +24937,9 @@ function bootstrap(options = {}) {
23720
24937
  });
23721
24938
  container.register(ServiceTokens.TokenCommand, () => {
23722
24939
  const configService = container.resolve(ServiceTokens.ConfigService);
24940
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
23723
24941
  const output = container.resolve(ServiceTokens.OutputService);
23724
- return new TokenCommand(configService, output);
24942
+ return new TokenCommand(configService, oauthService, output);
23725
24943
  });
23726
24944
  container.register(ServiceTokens.CloneCommand, () => {
23727
24945
  const gitService = container.resolve(ServiceTokens.GitService);
@@ -24064,14 +25282,16 @@ cli.name("bb").description("A command-line interface for Bitbucket Cloud").versi
24064
25282
  } catch {}
24065
25283
  });
24066
25284
  var authCmd = new Command("auth").description("Authenticate with Bitbucket");
24067
- authCmd.command("login").description("Authenticate with Bitbucket using an API token").option("-u, --username <username>", "Bitbucket username").option("-p, --password <password>", "Bitbucket API token").addHelpText("after", buildHelpText({
25285
+ authCmd.command("login").description("Authenticate with Bitbucket (OAuth or API token)").option("-u, --username <username>", "Bitbucket username (implies API token auth)").option("-p, --password <password>", "Bitbucket API token (implies API token auth)").option("--app-password", "Use API token authentication instead of OAuth").option("--client-id <clientId>", "Custom OAuth consumer client ID").option("--client-secret <clientSecret>", "Custom OAuth consumer client secret").addHelpText("after", buildHelpText({
24068
25286
  examples: [
24069
- "bb auth login -u myuser -p mytoken",
25287
+ "bb auth login",
25288
+ "bb auth login --app-password -u myuser -p mytoken",
25289
+ "bb auth login --client-id <id>",
24070
25290
  "BB_USERNAME=myuser BB_API_TOKEN=mytoken bb auth login"
24071
25291
  ],
24072
25292
  envVars: {
24073
25293
  BB_USERNAME: "Used when --username is not provided",
24074
- BB_API_TOKEN: "Used when --password is not provided"
25294
+ BB_API_TOKEN: "Used when --password is not provided (implies API token auth)"
24075
25295
  }
24076
25296
  })).action(async (options) => {
24077
25297
  await runCommand(ServiceTokens.LoginCommand, options, cli);