@pilatos/bitbucket-cli 1.10.0 → 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 +1308 -79
  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,444 @@ 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
+ }
19419
+ // src/services/reviewer.service.ts
19420
+ function extractReviewerUuids(reviewers) {
19421
+ if (!reviewers) {
19422
+ return [];
19423
+ }
19424
+ const list = Array.from(reviewers);
19425
+ const uuids = [];
19426
+ for (const reviewer of list) {
19427
+ if (reviewer.uuid) {
19428
+ uuids.push(reviewer.uuid);
19429
+ }
19430
+ }
19431
+ return uuids;
19432
+ }
19433
+ function buildReviewersUpdateBody(uuids) {
19434
+ const body = {
19435
+ type: "pullrequest",
19436
+ reviewers: uuids.map((uuid) => ({ type: "user", uuid }))
19437
+ };
19438
+ return body;
19439
+ }
19440
+ async function updatePullRequestReviewers(pullrequestsApi, repoContext, prId, transformUuids) {
19441
+ const prResponse = await pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
19442
+ workspace: repoContext.workspace,
19443
+ repoSlug: repoContext.repoSlug,
19444
+ pullRequestId: prId
19445
+ });
19446
+ const pr = prResponse.data;
19447
+ const currentUuids = extractReviewerUuids(pr.reviewers);
19448
+ const updatedUuids = transformUuids(currentUuids);
19449
+ const body = buildReviewersUpdateBody(updatedUuids);
19450
+ const response = await pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
19451
+ workspace: repoContext.workspace,
19452
+ repoSlug: repoContext.repoSlug,
19453
+ pullRequestId: prId,
19454
+ body
19455
+ });
19456
+ return response.data;
19457
+ }
18288
19458
  // src/bootstrap.ts
18289
19459
  import { createRequire } from "module";
18290
19460
 
@@ -19996,12 +21166,12 @@ var RepositoriesApiAxiosParamCreator = function(configuration) {
19996
21166
  options: localVarRequestOptions
19997
21167
  };
19998
21168
  },
19999
- repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet: async (commit, path, repoSlug, workspace, renames, q, sort, options = {}) => {
21169
+ repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet: async (commit, path2, repoSlug, workspace, renames, q, sort, options = {}) => {
20000
21170
  assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "commit", commit);
20001
- assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "path", path);
21171
+ assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "path", path2);
20002
21172
  assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "repoSlug", repoSlug);
20003
21173
  assertParamExists("repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet", "workspace", workspace);
20004
- 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)));
20005
21175
  const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
20006
21176
  let baseOptions;
20007
21177
  if (configuration) {
@@ -20541,12 +21711,12 @@ var RepositoriesApiAxiosParamCreator = function(configuration) {
20541
21711
  options: localVarRequestOptions
20542
21712
  };
20543
21713
  },
20544
- repositoriesWorkspaceRepoSlugSrcCommitPathGet: async (commit, path, repoSlug, workspace, format, q, sort, maxDepth, options = {}) => {
21714
+ repositoriesWorkspaceRepoSlugSrcCommitPathGet: async (commit, path2, repoSlug, workspace, format, q, sort, maxDepth, options = {}) => {
20545
21715
  assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "commit", commit);
20546
- assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "path", path);
21716
+ assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "path", path2);
20547
21717
  assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "repoSlug", repoSlug);
20548
21718
  assertParamExists("repositoriesWorkspaceRepoSlugSrcCommitPathGet", "workspace", workspace);
20549
- 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)));
20550
21720
  const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
20551
21721
  let baseOptions;
20552
21722
  if (configuration) {
@@ -20720,8 +21890,8 @@ var RepositoriesApiFp = function(configuration) {
20720
21890
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugDelete"]?.[localVarOperationServerIndex]?.url;
20721
21891
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
20722
21892
  },
20723
- async repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet(commit, path, repoSlug, workspace, renames, q, sort, options) {
20724
- 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);
20725
21895
  const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
20726
21896
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugFilehistoryCommitPathGet"]?.[localVarOperationServerIndex]?.url;
20727
21897
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
@@ -20846,8 +22016,8 @@ var RepositoriesApiFp = function(configuration) {
20846
22016
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugPut"]?.[localVarOperationServerIndex]?.url;
20847
22017
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
20848
22018
  },
20849
- async repositoriesWorkspaceRepoSlugSrcCommitPathGet(commit, path, repoSlug, workspace, format, q, sort, maxDepth, options) {
20850
- 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);
20851
22021
  const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
20852
22022
  const localVarOperationServerBasePath = operationServerMap["RepositoriesApi.repositoriesWorkspaceRepoSlugSrcCommitPathGet"]?.[localVarOperationServerIndex]?.url;
20853
22023
  return (axios2, basePath) => createRequestFunction(localVarAxiosArgs, axios_default, BASE_PATH, configuration)(axios2, localVarOperationServerBasePath || basePath);
@@ -21184,14 +22354,45 @@ class BaseCommand {
21184
22354
  class LoginCommand extends BaseCommand {
21185
22355
  configService;
21186
22356
  usersApi;
22357
+ oauthService;
21187
22358
  name = "login";
21188
- description = "Authenticate with Bitbucket using an API token";
21189
- constructor(configService, usersApi, output) {
22359
+ description = "Authenticate with Bitbucket";
22360
+ constructor(configService, usersApi, oauthService, output) {
21190
22361
  super(output);
21191
22362
  this.configService = configService;
21192
22363
  this.usersApi = usersApi;
22364
+ this.oauthService = oauthService;
21193
22365
  }
21194
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) {
21195
22396
  const username = options.username || process.env.BB_USERNAME;
21196
22397
  const apiToken = options.password || process.env.BB_API_TOKEN;
21197
22398
  if (!username) {
@@ -21206,6 +22407,7 @@ class LoginCommand extends BaseCommand {
21206
22407
  message: "API token is required. Use --password option or set BB_API_TOKEN environment variable."
21207
22408
  });
21208
22409
  }
22410
+ await this.configService.clearOAuthCredentials();
21209
22411
  await this.configService.setCredentials({ username, apiToken });
21210
22412
  try {
21211
22413
  const response = await this.usersApi.userGet();
@@ -21213,6 +22415,7 @@ class LoginCommand extends BaseCommand {
21213
22415
  if (context.globalOptions.json) {
21214
22416
  this.output.json({
21215
22417
  authenticated: true,
22418
+ method: "api_token",
21216
22419
  user: {
21217
22420
  username: user.username,
21218
22421
  displayName: user.display_name,
@@ -21235,14 +22438,22 @@ class LoginCommand extends BaseCommand {
21235
22438
  // src/commands/auth/logout.command.ts
21236
22439
  class LogoutCommand extends BaseCommand {
21237
22440
  configService;
22441
+ oauthService;
21238
22442
  name = "logout";
21239
22443
  description = "Log out of Bitbucket";
21240
- constructor(configService, output) {
22444
+ constructor(configService, oauthService, output) {
21241
22445
  super(output);
21242
22446
  this.configService = configService;
22447
+ this.oauthService = oauthService;
21243
22448
  }
21244
22449
  async execute(_options, context) {
21245
- 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
+ }
21246
22457
  if (context.globalOptions.json) {
21247
22458
  this.output.json({ authenticated: false, success: true });
21248
22459
  return;
@@ -21264,7 +22475,10 @@ class StatusCommand extends BaseCommand {
21264
22475
  }
21265
22476
  async execute(_options, context) {
21266
22477
  const config = await this.configService.getConfig();
21267
- 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) {
21268
22482
  if (context.globalOptions.json) {
21269
22483
  this.output.json({ authenticated: false });
21270
22484
  return;
@@ -21277,21 +22491,41 @@ class StatusCommand extends BaseCommand {
21277
22491
  const response = await this.usersApi.userGet();
21278
22492
  const user = response.data;
21279
22493
  if (context.globalOptions.json) {
21280
- this.output.json({
22494
+ const jsonOutput = {
21281
22495
  authenticated: true,
22496
+ method: authMethod,
21282
22497
  user: {
21283
22498
  username: user.username,
21284
22499
  displayName: user.display_name,
21285
22500
  accountId: user.account_id
21286
22501
  },
21287
22502
  defaultWorkspace: config.defaultWorkspace
21288
- });
22503
+ };
22504
+ if (authMethod === "oauth" && config.oauthExpiresAt) {
22505
+ jsonOutput.tokenExpiresAt = config.oauthExpiresAt;
22506
+ }
22507
+ this.output.json(jsonOutput);
21289
22508
  return;
21290
22509
  }
21291
22510
  this.output.success("Logged in to Bitbucket");
22511
+ this.output.text(` Authentication: ${this.output.highlight(authMethod === "oauth" ? "OAuth" : "API Token")}`);
21292
22512
  this.output.text(` Username: ${this.output.highlight(user.username ?? "")}`);
21293
22513
  this.output.text(` Display name: ${user.display_name}`);
21294
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
+ }
21295
22529
  if (config.defaultWorkspace) {
21296
22530
  this.output.text(` Default workspace: ${this.output.highlight(config.defaultWorkspace)}`);
21297
22531
  }
@@ -21308,13 +22542,25 @@ class StatusCommand extends BaseCommand {
21308
22542
  // src/commands/auth/token.command.ts
21309
22543
  class TokenCommand extends BaseCommand {
21310
22544
  configService;
22545
+ oauthService;
21311
22546
  name = "token";
21312
22547
  description = "Print the current access token";
21313
- constructor(configService, output) {
22548
+ constructor(configService, oauthService, output) {
21314
22549
  super(output);
21315
22550
  this.configService = configService;
22551
+ this.oauthService = oauthService;
21316
22552
  }
21317
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
+ }
21318
22564
  const credentials = await this.configService.getCredentials();
21319
22565
  if (!credentials.username || !credentials.apiToken) {
21320
22566
  throw new BBError({
@@ -21324,7 +22570,7 @@ class TokenCommand extends BaseCommand {
21324
22570
  }
21325
22571
  const token = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
21326
22572
  if (context.globalOptions.json) {
21327
- this.output.json({ token });
22573
+ this.output.json({ token, type: "basic" });
21328
22574
  return;
21329
22575
  }
21330
22576
  this.output.text(token);
@@ -21449,8 +22695,8 @@ function getCommitFilePath(file) {
21449
22695
  if (!isRecord(file)) {
21450
22696
  return;
21451
22697
  }
21452
- const path = file.path;
21453
- return typeof path === "string" && path.length > 0 ? path : undefined;
22698
+ const path2 = file.path;
22699
+ return typeof path2 === "string" && path2.length > 0 ? path2 : undefined;
21454
22700
  }
21455
22701
  function parseDiffstatFile(value) {
21456
22702
  if (!isRecord(value)) {
@@ -22231,7 +23477,7 @@ class ViewPRCommand extends BaseCommand {
22231
23477
  }
22232
23478
 
22233
23479
  // src/commands/pr/edit.command.ts
22234
- import * as fs from "fs";
23480
+ import * as fs6 from "fs";
22235
23481
  class EditPRCommand extends BaseCommand {
22236
23482
  pullrequestsApi;
22237
23483
  contextService;
@@ -22285,7 +23531,7 @@ class EditPRCommand extends BaseCommand {
22285
23531
  let body = options.body;
22286
23532
  if (options.bodyFile) {
22287
23533
  try {
22288
- body = fs.readFileSync(options.bodyFile, "utf-8");
23534
+ body = fs6.readFileSync(options.bodyFile, "utf-8");
22289
23535
  } catch (err) {
22290
23536
  throw new BBError({
22291
23537
  code: 9999 /* UNKNOWN */,
@@ -22557,8 +23803,8 @@ class CheckoutPRCommand extends BaseCommand {
22557
23803
 
22558
23804
  // src/commands/pr/diff.command.ts
22559
23805
  import { exec } from "child_process";
22560
- import { promisify } from "util";
22561
- var execAsync = promisify(exec);
23806
+ import { promisify as promisify7 } from "util";
23807
+ var execAsync = promisify7(exec);
22562
23808
 
22563
23809
  class DiffPRCommand extends BaseCommand {
22564
23810
  pullrequestsApi;
@@ -22670,11 +23916,11 @@ class DiffPRCommand extends BaseCommand {
22670
23916
  }
22671
23917
  async openInBrowser(url2) {
22672
23918
  this.output.info(`Opening ${url2} in your browser...`);
22673
- const platform = process.platform;
23919
+ const platform2 = process.platform;
22674
23920
  let command;
22675
- if (platform === "darwin") {
23921
+ if (platform2 === "darwin") {
22676
23922
  command = `open "${url2}"`;
22677
- } else if (platform === "win32") {
23923
+ } else if (platform2 === "win32") {
22678
23924
  command = `start "" "${url2}"`;
22679
23925
  } else {
22680
23926
  command = `xdg-open "${url2}"`;
@@ -23197,25 +24443,11 @@ class AddReviewerPRCommand extends BaseCommand {
23197
24443
  selectedUser: options.username
23198
24444
  });
23199
24445
  const user = userResponse.data;
23200
- const prResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
23201
- workspace: repoContext.workspace,
23202
- repoSlug: repoContext.repoSlug,
23203
- pullRequestId: prId
23204
- });
23205
- const pr = prResponse.data;
23206
- const existingReviewers = pr.reviewers ? Array.from(pr.reviewers) : [];
23207
- const reviewerUuids = existingReviewers.map((r) => r.uuid).filter(Boolean);
23208
- if (!reviewerUuids.includes(user.uuid)) {
23209
- reviewerUuids.push(user.uuid);
23210
- }
23211
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
23212
- workspace: repoContext.workspace,
23213
- repoSlug: repoContext.repoSlug,
23214
- pullRequestId: prId,
23215
- body: {
23216
- type: "pullrequest",
23217
- reviewers: reviewerUuids.map((uuid) => ({ uuid }))
24446
+ const updatedPr = await updatePullRequestReviewers(this.pullrequestsApi, repoContext, prId, (uuids) => {
24447
+ if (!uuids.includes(user.uuid)) {
24448
+ return [...uuids, user.uuid];
23218
24449
  }
24450
+ return uuids;
23219
24451
  });
23220
24452
  if (context.globalOptions.json) {
23221
24453
  this.output.json({
@@ -23225,7 +24457,7 @@ class AddReviewerPRCommand extends BaseCommand {
23225
24457
  username: options.username,
23226
24458
  uuid: user.uuid
23227
24459
  },
23228
- pullRequest: response.data
24460
+ pullRequest: updatedPr
23229
24461
  });
23230
24462
  return;
23231
24463
  }
@@ -23256,23 +24488,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
23256
24488
  selectedUser: options.username
23257
24489
  });
23258
24490
  const user = userResponse.data;
23259
- const prResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
23260
- workspace: repoContext.workspace,
23261
- repoSlug: repoContext.repoSlug,
23262
- pullRequestId: prId
23263
- });
23264
- const pr = prResponse.data;
23265
- const existingReviewers = pr.reviewers ? Array.from(pr.reviewers) : [];
23266
- const reviewerUuids = existingReviewers.map((r) => r.uuid).filter((uuid) => uuid && uuid !== user.uuid);
23267
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
23268
- workspace: repoContext.workspace,
23269
- repoSlug: repoContext.repoSlug,
23270
- pullRequestId: prId,
23271
- body: {
23272
- type: "pullrequest",
23273
- reviewers: reviewerUuids.map((uuid) => ({ uuid }))
23274
- }
23275
- });
24491
+ const updatedPr = await updatePullRequestReviewers(this.pullrequestsApi, repoContext, prId, (uuids) => uuids.filter((uuid) => uuid !== user.uuid));
23276
24492
  if (context.globalOptions.json) {
23277
24493
  this.output.json({
23278
24494
  success: true,
@@ -23281,7 +24497,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
23281
24497
  username: options.username,
23282
24498
  uuid: user.uuid
23283
24499
  },
23284
- pullRequest: response.data
24500
+ pullRequest: updatedPr
23285
24501
  });
23286
24502
  return;
23287
24503
  }
@@ -23667,24 +24883,32 @@ function bootstrap(options = {}) {
23667
24883
  container.register(ServiceTokens.ConfigService, () => new ConfigService);
23668
24884
  container.register(ServiceTokens.GitService, () => new GitService);
23669
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
+ });
23670
24890
  container.register(ServiceTokens.PullrequestsApi, () => {
23671
24891
  const configService = container.resolve(ServiceTokens.ConfigService);
23672
- const axiosInstance = createApiClient(configService);
24892
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24893
+ const axiosInstance = createApiClient(configService, oauthService);
23673
24894
  return new PullrequestsApi(undefined, undefined, axiosInstance);
23674
24895
  });
23675
24896
  container.register(ServiceTokens.RepositoriesApi, () => {
23676
24897
  const configService = container.resolve(ServiceTokens.ConfigService);
23677
- const axiosInstance = createApiClient(configService);
24898
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24899
+ const axiosInstance = createApiClient(configService, oauthService);
23678
24900
  return new RepositoriesApi(undefined, undefined, axiosInstance);
23679
24901
  });
23680
24902
  container.register(ServiceTokens.UsersApi, () => {
23681
24903
  const configService = container.resolve(ServiceTokens.ConfigService);
23682
- const axiosInstance = createApiClient(configService);
24904
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24905
+ const axiosInstance = createApiClient(configService, oauthService);
23683
24906
  return new UsersApi(undefined, undefined, axiosInstance);
23684
24907
  });
23685
24908
  container.register(ServiceTokens.CommitStatusesApi, () => {
23686
24909
  const configService = container.resolve(ServiceTokens.ConfigService);
23687
- const axiosInstance = createApiClient(configService);
24910
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
24911
+ const axiosInstance = createApiClient(configService, oauthService);
23688
24912
  return new CommitStatusesApi(undefined, undefined, axiosInstance);
23689
24913
  });
23690
24914
  container.register(ServiceTokens.ContextService, () => {
@@ -23695,13 +24919,15 @@ function bootstrap(options = {}) {
23695
24919
  container.register(ServiceTokens.LoginCommand, () => {
23696
24920
  const configService = container.resolve(ServiceTokens.ConfigService);
23697
24921
  const usersApi = container.resolve(ServiceTokens.UsersApi);
24922
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
23698
24923
  const output = container.resolve(ServiceTokens.OutputService);
23699
- return new LoginCommand(configService, usersApi, output);
24924
+ return new LoginCommand(configService, usersApi, oauthService, output);
23700
24925
  });
23701
24926
  container.register(ServiceTokens.LogoutCommand, () => {
23702
24927
  const configService = container.resolve(ServiceTokens.ConfigService);
24928
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
23703
24929
  const output = container.resolve(ServiceTokens.OutputService);
23704
- return new LogoutCommand(configService, output);
24930
+ return new LogoutCommand(configService, oauthService, output);
23705
24931
  });
23706
24932
  container.register(ServiceTokens.StatusCommand, () => {
23707
24933
  const configService = container.resolve(ServiceTokens.ConfigService);
@@ -23711,8 +24937,9 @@ function bootstrap(options = {}) {
23711
24937
  });
23712
24938
  container.register(ServiceTokens.TokenCommand, () => {
23713
24939
  const configService = container.resolve(ServiceTokens.ConfigService);
24940
+ const oauthService = container.resolve(ServiceTokens.OAuthService);
23714
24941
  const output = container.resolve(ServiceTokens.OutputService);
23715
- return new TokenCommand(configService, output);
24942
+ return new TokenCommand(configService, oauthService, output);
23716
24943
  });
23717
24944
  container.register(ServiceTokens.CloneCommand, () => {
23718
24945
  const gitService = container.resolve(ServiceTokens.GitService);
@@ -24055,14 +25282,16 @@ cli.name("bb").description("A command-line interface for Bitbucket Cloud").versi
24055
25282
  } catch {}
24056
25283
  });
24057
25284
  var authCmd = new Command("auth").description("Authenticate with Bitbucket");
24058
- 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({
24059
25286
  examples: [
24060
- "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>",
24061
25290
  "BB_USERNAME=myuser BB_API_TOKEN=mytoken bb auth login"
24062
25291
  ],
24063
25292
  envVars: {
24064
25293
  BB_USERNAME: "Used when --username is not provided",
24065
- BB_API_TOKEN: "Used when --password is not provided"
25294
+ BB_API_TOKEN: "Used when --password is not provided (implies API token auth)"
24066
25295
  }
24067
25296
  })).action(async (options) => {
24068
25297
  await runCommand(ServiceTokens.LoginCommand, options, cli);