@pilatos/bitbucket-cli 1.16.0 → 1.17.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.
package/dist/index.js CHANGED
@@ -17633,7 +17633,16 @@ class ConfigService {
17633
17633
  await this.verifyPermissions(this.configDir, CONFIG_DIR_MODE, "directory");
17634
17634
  await this.verifyPermissions(this.configFile, CONFIG_FILE_MODE, "file");
17635
17635
  const data = await fs.readFile(this.configFile, "utf-8");
17636
- this.configCache = JSON.parse(data);
17636
+ try {
17637
+ this.configCache = JSON.parse(data);
17638
+ } catch (parseError) {
17639
+ throw new BBError({
17640
+ code: 4001 /* CONFIG_READ_FAILED */,
17641
+ message: `Config file is not valid JSON: ${this.configFile}. Fix the file by hand or remove it and run \`bb auth login\` again.`,
17642
+ cause: parseError instanceof Error ? parseError : undefined,
17643
+ context: { configFile: this.configFile }
17644
+ });
17645
+ }
17637
17646
  return this.configCache;
17638
17647
  } catch (error) {
17639
17648
  if (error.code === "ENOENT") {
@@ -17771,10 +17780,14 @@ class ConfigService {
17771
17780
  }
17772
17781
  }
17773
17782
  // src/services/git.service.ts
17783
+ var DEFAULT_GIT_TIMEOUT_MS = 60000;
17784
+
17774
17785
  class GitService {
17775
17786
  cwd;
17776
- constructor(cwd) {
17787
+ timeoutMs;
17788
+ constructor(cwd, options = {}) {
17777
17789
  this.cwd = cwd ?? process.cwd();
17790
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_GIT_TIMEOUT_MS;
17778
17791
  }
17779
17792
  async exec(args, cwd) {
17780
17793
  const proc = Bun.spawn(["git", ...args], {
@@ -17782,14 +17795,28 @@ class GitService {
17782
17795
  stdout: "pipe",
17783
17796
  stderr: "pipe"
17784
17797
  });
17785
- const stdout = await new Response(proc.stdout).text();
17786
- const stderr = await new Response(proc.stderr).text();
17787
- const exitCode = await proc.exited;
17788
- return {
17789
- stdout: stdout.trim(),
17790
- stderr: stderr.trim(),
17791
- exitCode
17792
- };
17798
+ let timedOut = false;
17799
+ const timer = setTimeout(() => {
17800
+ timedOut = true;
17801
+ try {
17802
+ proc.kill();
17803
+ } catch {}
17804
+ }, this.timeoutMs);
17805
+ try {
17806
+ const stdout = await new Response(proc.stdout).text();
17807
+ const stderr = await new Response(proc.stderr).text();
17808
+ const exitCode = await proc.exited;
17809
+ if (timedOut) {
17810
+ throw new GitError(`git ${args.join(" ")} timed out after ${this.timeoutMs}ms`, `git ${args.join(" ")}`, exitCode);
17811
+ }
17812
+ return {
17813
+ stdout: stdout.trim(),
17814
+ stderr: stderr.trim(),
17815
+ exitCode
17816
+ };
17817
+ } finally {
17818
+ clearTimeout(timer);
17819
+ }
17793
17820
  }
17794
17821
  async execOrError(args, cwd) {
17795
17822
  const result = await this.exec(args, cwd);
@@ -17840,7 +17867,7 @@ class GitService {
17840
17867
  return result.stdout;
17841
17868
  }
17842
17869
  withCwd(cwd) {
17843
- return new GitService(cwd);
17870
+ return new GitService(cwd, { timeoutMs: this.timeoutMs });
17844
17871
  }
17845
17872
  }
17846
17873
  // src/services/context.service.ts
@@ -17940,6 +17967,12 @@ class ContextService {
17940
17967
  }
17941
17968
  return result.context;
17942
17969
  }
17970
+ async requireRepoContextFor(options, context) {
17971
+ return this.requireRepoContext({
17972
+ ...context.globalOptions,
17973
+ ...options
17974
+ });
17975
+ }
17943
17976
  buildRepoNotFoundMessage(reason, remoteUrl) {
17944
17977
  const fallback = "Use --workspace and --repo options, or run this command from within a Bitbucket repository.";
17945
17978
  switch (reason) {
@@ -18462,6 +18495,54 @@ var chalk = createChalk();
18462
18495
  var chalkStderr = createChalk({ level: stderrColor ? stderrColor.level : 0 });
18463
18496
  var source_default = chalk;
18464
18497
 
18498
+ // src/services/locale.ts
18499
+ var DEFAULT_LOCALE = "en-US";
18500
+ function normalizePosixLocale(value) {
18501
+ const trimmed = value.trim();
18502
+ if (trimmed.length === 0) {
18503
+ return;
18504
+ }
18505
+ const base = trimmed.split(/[.@]/, 1)[0];
18506
+ if (base.length === 0) {
18507
+ return;
18508
+ }
18509
+ const upper = base.toUpperCase();
18510
+ if (upper === "C" || upper === "POSIX") {
18511
+ return DEFAULT_LOCALE;
18512
+ }
18513
+ return base.replace(/_/g, "-");
18514
+ }
18515
+ function detectSystemLocale(env2 = process.env) {
18516
+ const candidates = [env2.LC_TIME, env2.LC_ALL, env2.LANG];
18517
+ for (const candidate of candidates) {
18518
+ if (typeof candidate !== "string") {
18519
+ continue;
18520
+ }
18521
+ const normalized = normalizePosixLocale(candidate);
18522
+ if (normalized) {
18523
+ return normalized;
18524
+ }
18525
+ }
18526
+ return DEFAULT_LOCALE;
18527
+ }
18528
+ function resolveLocale(options) {
18529
+ const env2 = options.env ?? process.env;
18530
+ if (typeof options.explicit === "string") {
18531
+ const trimmed = options.explicit.trim();
18532
+ if (trimmed.length > 0) {
18533
+ return trimmed;
18534
+ }
18535
+ }
18536
+ const fromEnvVar = env2.BB_LOCALE;
18537
+ if (typeof fromEnvVar === "string") {
18538
+ const trimmed = fromEnvVar.trim();
18539
+ if (trimmed.length > 0) {
18540
+ return trimmed;
18541
+ }
18542
+ }
18543
+ return detectSystemLocale(env2);
18544
+ }
18545
+
18465
18546
  // src/services/output.project.ts
18466
18547
  function projectFields(item, fields) {
18467
18548
  if (item === null || typeof item !== "object") {
@@ -18488,7 +18569,143 @@ function deepGet(source, path) {
18488
18569
  return current === undefined ? null : current;
18489
18570
  }
18490
18571
 
18572
+ // src/services/spinner.ts
18573
+ var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
18574
+ var FRAME_INTERVAL_MS = 80;
18575
+ var ESC = "\x1B";
18576
+ var CLEAR_LINE = `\r${ESC}[2K`;
18577
+ var HIDE_CURSOR = `${ESC}[?25l`;
18578
+ var SHOW_CURSOR = `${ESC}[?25h`;
18579
+ var COLOR_CYAN = `${ESC}[36m`;
18580
+ var COLOR_GREEN = `${ESC}[32m`;
18581
+ var COLOR_RED = `${ESC}[31m`;
18582
+ var COLOR_RESET = `${ESC}[0m`;
18583
+
18584
+ class Spinner {
18585
+ text;
18586
+ enabled;
18587
+ noColor;
18588
+ stream;
18589
+ onStop;
18590
+ timer = null;
18591
+ frameIndex = 0;
18592
+ active = false;
18593
+ exitHandler = null;
18594
+ constructor(text, options) {
18595
+ this.text = text;
18596
+ this.enabled = options.enabled;
18597
+ this.noColor = options.noColor;
18598
+ this.stream = options.stream;
18599
+ this.onStop = options.onStop;
18600
+ }
18601
+ start() {
18602
+ if (!this.enabled || this.active) {
18603
+ return this;
18604
+ }
18605
+ this.active = true;
18606
+ this.stream.write(HIDE_CURSOR);
18607
+ this.render();
18608
+ this.timer = setInterval(() => {
18609
+ this.frameIndex = (this.frameIndex + 1) % FRAMES.length;
18610
+ this.render();
18611
+ }, FRAME_INTERVAL_MS);
18612
+ this.timer.unref?.();
18613
+ this.exitHandler = () => {
18614
+ if (this.active) {
18615
+ this.active = false;
18616
+ if (this.timer) {
18617
+ clearInterval(this.timer);
18618
+ this.timer = null;
18619
+ }
18620
+ this.stream.write(`${CLEAR_LINE}${SHOW_CURSOR}`);
18621
+ }
18622
+ };
18623
+ process.once("SIGINT", this.exitHandler);
18624
+ process.once("SIGTERM", this.exitHandler);
18625
+ process.once("exit", this.exitHandler);
18626
+ return this;
18627
+ }
18628
+ stop() {
18629
+ if (!this.active) {
18630
+ return this.detach();
18631
+ }
18632
+ this.active = false;
18633
+ if (this.timer) {
18634
+ clearInterval(this.timer);
18635
+ this.timer = null;
18636
+ }
18637
+ this.stream.write(`${CLEAR_LINE}${SHOW_CURSOR}`);
18638
+ return this.detach();
18639
+ }
18640
+ succeed(message) {
18641
+ this.stop();
18642
+ if (this.enabled && message) {
18643
+ const symbol = this.colorize("\u2713", COLOR_GREEN);
18644
+ this.stream.write(`${symbol} ${message}
18645
+ `);
18646
+ }
18647
+ return this;
18648
+ }
18649
+ fail(message) {
18650
+ this.stop();
18651
+ if (this.enabled && message) {
18652
+ const symbol = this.colorize("\u2717", COLOR_RED);
18653
+ this.stream.write(`${symbol} ${message}
18654
+ `);
18655
+ }
18656
+ return this;
18657
+ }
18658
+ setText(text) {
18659
+ this.text = text;
18660
+ if (this.active) {
18661
+ this.render();
18662
+ }
18663
+ return this;
18664
+ }
18665
+ render() {
18666
+ if (!this.active)
18667
+ return;
18668
+ const frame = FRAMES[this.frameIndex] ?? FRAMES[0];
18669
+ const symbol = this.colorize(frame, COLOR_CYAN);
18670
+ this.stream.write(`${CLEAR_LINE}${symbol} ${this.text}`);
18671
+ }
18672
+ colorize(text, color) {
18673
+ return this.noColor ? text : `${color}${text}${COLOR_RESET}`;
18674
+ }
18675
+ detach() {
18676
+ if (this.exitHandler) {
18677
+ process.removeListener("SIGINT", this.exitHandler);
18678
+ process.removeListener("SIGTERM", this.exitHandler);
18679
+ process.removeListener("exit", this.exitHandler);
18680
+ this.exitHandler = null;
18681
+ }
18682
+ if (this.onStop) {
18683
+ const cb = this.onStop;
18684
+ this.onStop = undefined;
18685
+ cb();
18686
+ }
18687
+ return this;
18688
+ }
18689
+ }
18690
+ function createNoopSpinner() {
18691
+ const noop = {
18692
+ start: () => noop,
18693
+ stop: () => noop,
18694
+ succeed: () => noop,
18695
+ fail: () => noop,
18696
+ setText: () => noop
18697
+ };
18698
+ return noop;
18699
+ }
18700
+
18491
18701
  // src/services/output.service.ts
18702
+ var DATE_FORMAT_OPTIONS = {
18703
+ year: "numeric",
18704
+ month: "short",
18705
+ day: "numeric",
18706
+ hour: "2-digit",
18707
+ minute: "2-digit"
18708
+ };
18492
18709
  var CONTROL_CHARS = /(\x1b\[[0-9;?]*m)|\x1b\[[0-9;?]*[A-Za-ln-z]|\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)|[\x00-\x08\x0B\x0C\x0E-\x1F\x7F\x9B\x9D]/g;
18493
18710
  function stripControl(value) {
18494
18711
  return value.replace(CONTROL_CHARS, (_match, sgr) => sgr ?? "");
@@ -18507,14 +18724,42 @@ var WRAPPER_ARRAY_KEYS = [
18507
18724
 
18508
18725
  class OutputService {
18509
18726
  noColor;
18727
+ noUnicode;
18728
+ locale;
18510
18729
  jsonFormatOptions = {};
18730
+ activeSpinner = null;
18511
18731
  constructor(options) {
18512
18732
  this.noColor = options?.noColor ?? false;
18733
+ this.noUnicode = options?.noUnicode ?? false;
18734
+ this.locale = options?.locale ?? DEFAULT_LOCALE;
18513
18735
  }
18514
18736
  setJsonFormatOptions(options) {
18515
18737
  this.jsonFormatOptions = { ...options };
18516
18738
  }
18739
+ isJsonMode() {
18740
+ return this.jsonFormatOptions.json === true;
18741
+ }
18742
+ spinner(text) {
18743
+ const enabled = !this.isJsonMode() && !!process.stdout.isTTY && true;
18744
+ if (!enabled) {
18745
+ return createNoopSpinner();
18746
+ }
18747
+ this.activeSpinner?.stop();
18748
+ const spinner = new Spinner(text, {
18749
+ enabled: true,
18750
+ noColor: this.noColor,
18751
+ stream: process.stdout,
18752
+ onStop: () => {
18753
+ if (this.activeSpinner === spinner) {
18754
+ this.activeSpinner = null;
18755
+ }
18756
+ }
18757
+ });
18758
+ this.activeSpinner = spinner;
18759
+ return spinner;
18760
+ }
18517
18761
  async json(data) {
18762
+ this.stopActiveSpinner();
18518
18763
  const { fields, jq } = this.jsonFormatOptions;
18519
18764
  let result = data;
18520
18765
  if (fields && fields.length > 0) {
@@ -18532,9 +18777,11 @@ class OutputService {
18532
18777
  console.log(JSON.stringify(result, null, 2));
18533
18778
  }
18534
18779
  jsonError(data) {
18780
+ this.stopActiveSpinner();
18535
18781
  console.error(JSON.stringify(data));
18536
18782
  }
18537
18783
  table(headers, rows) {
18784
+ this.stopActiveSpinner();
18538
18785
  if (rows.length === 0) {
18539
18786
  return;
18540
18787
  }
@@ -18553,33 +18800,63 @@ class OutputService {
18553
18800
  }
18554
18801
  }
18555
18802
  success(message) {
18556
- const symbol = this.format("\u2713", source_default.green);
18803
+ this.stopActiveSpinner();
18804
+ const symbol = this.format(this.symbol("\u2713", "OK"), source_default.green);
18557
18805
  console.log(`${symbol} ${stripControl(message)}`);
18558
18806
  }
18559
18807
  error(message) {
18560
- const symbol = this.format("\u2717", source_default.red);
18808
+ this.stopActiveSpinner();
18809
+ const symbol = this.format(this.symbol("\u2717", "ERR"), source_default.red);
18561
18810
  console.error(`${symbol} ${stripControl(message)}`);
18562
18811
  }
18563
18812
  warning(message) {
18564
- const symbol = this.format("\u26A0", source_default.yellow);
18813
+ this.stopActiveSpinner();
18814
+ const symbol = this.format(this.symbol("\u26A0", "!!"), source_default.yellow);
18565
18815
  console.warn(`${symbol} ${stripControl(message)}`);
18566
18816
  }
18567
18817
  info(message) {
18568
- const symbol = this.format("\u2139", source_default.blue);
18818
+ this.stopActiveSpinner();
18819
+ const symbol = this.format(this.symbol("\u2139", "i"), source_default.blue);
18569
18820
  console.log(`${symbol} ${stripControl(message)}`);
18570
18821
  }
18822
+ symbol(unicode, ascii) {
18823
+ return this.noUnicode ? ascii : unicode;
18824
+ }
18571
18825
  text(message) {
18826
+ this.stopActiveSpinner();
18572
18827
  console.log(stripControl(message));
18573
18828
  }
18829
+ separator(width = 60) {
18830
+ this.stopActiveSpinner();
18831
+ if (width <= 0) {
18832
+ console.log("");
18833
+ return;
18834
+ }
18835
+ console.log(this.format(this.symbol("\u2500", "-").repeat(width), source_default.gray));
18836
+ }
18837
+ stopActiveSpinner() {
18838
+ if (this.activeSpinner) {
18839
+ const spinner = this.activeSpinner;
18840
+ this.activeSpinner = null;
18841
+ spinner.stop();
18842
+ }
18843
+ }
18844
+ truncate(text, maxLength, suffix = "...") {
18845
+ if (maxLength <= 0 || text.length <= maxLength) {
18846
+ return text;
18847
+ }
18848
+ if (suffix.length >= maxLength) {
18849
+ return text.slice(0, maxLength);
18850
+ }
18851
+ return text.slice(0, maxLength - suffix.length) + suffix;
18852
+ }
18574
18853
  formatDate(date) {
18575
18854
  const d = typeof date === "string" ? new Date(date) : date;
18576
- return d.toLocaleDateString("en-US", {
18577
- year: "numeric",
18578
- month: "short",
18579
- day: "numeric",
18580
- hour: "2-digit",
18581
- minute: "2-digit"
18582
- });
18855
+ try {
18856
+ return d.toLocaleDateString(this.locale, DATE_FORMAT_OPTIONS);
18857
+ } catch {
18858
+ return d.toLocaleDateString(DEFAULT_LOCALE, DATE_FORMAT_OPTIONS);
18859
+ }
18583
18860
  }
18584
18861
  format(text, formatter) {
18585
18862
  if (this.noColor) {
@@ -18640,7 +18917,17 @@ function projectByFieldsRespectingWrapper(data, fields) {
18640
18917
  return projectFields(data, fields);
18641
18918
  }
18642
18919
  async function runJq(data, expression) {
18643
- const jq = await Promise.resolve().then(() => __toESM(require_dist(), 1));
18920
+ let jq;
18921
+ try {
18922
+ jq = await Promise.resolve().then(() => __toESM(require_dist(), 1));
18923
+ } catch (error) {
18924
+ throw new BBError({
18925
+ code: 8001 /* JQ_FAILED */,
18926
+ message: "Failed to load the embedded jq runtime (jq-wasm). Reinstall the CLI or report this issue.",
18927
+ cause: error instanceof Error ? error : undefined,
18928
+ context: { expression }
18929
+ });
18930
+ }
18644
18931
  let result;
18645
18932
  try {
18646
18933
  result = await jq.raw(data, expression);
@@ -18812,7 +19099,11 @@ class VersionService {
18812
19099
  latestVersion,
18813
19100
  updateAvailable
18814
19101
  };
18815
- } catch {
19102
+ } catch (error) {
19103
+ if (process.env.DEBUG === "true") {
19104
+ const message = error instanceof Error ? error.message : String(error);
19105
+ console.error(`[version-check] skipped: ${message}`);
19106
+ }
18816
19107
  return null;
18817
19108
  }
18818
19109
  }
@@ -22594,7 +22885,7 @@ function redactRequestUrl(requestUrl, baseUrl) {
22594
22885
  return queryIdx === -1 ? raw : `${raw.slice(0, queryIdx)}?[redacted]`;
22595
22886
  }
22596
22887
  }
22597
- function createApiClient(credentialStore, oauthService) {
22888
+ function createApiClient(credentialStore, output, oauthService) {
22598
22889
  const instance = axios_default.create({
22599
22890
  baseURL: BASE_URL,
22600
22891
  headers: {
@@ -22658,7 +22949,9 @@ function createApiClient(credentialStore, oauthService) {
22658
22949
  const delay = getRetryDelay(error, config.__retryCount);
22659
22950
  const status = error.response.status;
22660
22951
  const label = status === 429 ? "Rate limited" : `Server error (${status})`;
22661
- console.error(`${label}, retrying in ${(delay / 1000).toFixed(1)}s (attempt ${config.__retryCount}/${MAX_RETRIES})...`);
22952
+ if (!output.isJsonMode()) {
22953
+ output.warning(`${label}, retrying in ${(delay / 1000).toFixed(1)}s (attempt ${config.__retryCount}/${MAX_RETRIES})...`);
22954
+ }
22662
22955
  await sleep(delay);
22663
22956
  return instance(config);
22664
22957
  }
@@ -22946,7 +23239,12 @@ class OAuthService {
22946
23239
  try {
22947
23240
  const open2 = (await Promise.resolve().then(() => (init_open(), exports_open))).default;
22948
23241
  await open2(authUrl);
22949
- } catch {}
23242
+ } catch (err) {
23243
+ if (process.env.DEBUG === "true") {
23244
+ const message = err instanceof Error ? err.message : String(err);
23245
+ console.error(`[oauth] could not open browser: ${message}`);
23246
+ }
23247
+ }
22950
23248
  console.error(`If the browser doesn't open, visit:
22951
23249
  ${authUrl}
22952
23250
  `);
@@ -27184,6 +27482,7 @@ class BaseCommand {
27184
27482
  }
27185
27483
  async run(options, context) {
27186
27484
  this.output.setJsonFormatOptions({
27485
+ json: !!context.globalOptions.json,
27187
27486
  fields: context.globalOptions.jsonFields,
27188
27487
  jq: context.globalOptions.jq
27189
27488
  });
@@ -27267,6 +27566,33 @@ class BaseCommand {
27267
27566
  }
27268
27567
  return parsed;
27269
27568
  }
27569
+ parsePositiveInt(value, name) {
27570
+ const trimmed = value.trim();
27571
+ const parsed = Number.parseInt(trimmed, 10);
27572
+ if (!Number.isFinite(parsed) || parsed < 1 || String(parsed) !== trimmed) {
27573
+ throw new BBError({
27574
+ code: 5002 /* VALIDATION_INVALID */,
27575
+ message: this.appendHelpHint(`--${name} must be a positive integer.`),
27576
+ context: { [name]: value }
27577
+ });
27578
+ }
27579
+ return parsed;
27580
+ }
27581
+ truncateText(text, maxLength, opts = {}) {
27582
+ if (opts.noTruncate) {
27583
+ return text;
27584
+ }
27585
+ return this.output.truncate(text, maxLength);
27586
+ }
27587
+ requireConfirmation(confirmed, warning) {
27588
+ if (confirmed)
27589
+ return;
27590
+ throw new BBError({
27591
+ code: 5001 /* VALIDATION_REQUIRED */,
27592
+ message: `${warning}
27593
+ Use --yes to confirm.`
27594
+ });
27595
+ }
27270
27596
  parseEnumOption(value, name, allowed) {
27271
27597
  if (!allowed.includes(value)) {
27272
27598
  throw new BBError({
@@ -27555,7 +27881,12 @@ class CloneCommand extends BaseCommand {
27555
27881
  async execute(options, context) {
27556
27882
  const { repository, directory } = options;
27557
27883
  const repoUrl = await this.resolveRepositoryUrl(repository);
27558
- await this.gitService.clone(repoUrl, directory);
27884
+ const spinner = this.output.spinner(`Cloning ${repository}...`).start();
27885
+ try {
27886
+ await this.gitService.clone(repoUrl, directory);
27887
+ } finally {
27888
+ spinner.stop();
27889
+ }
27559
27890
  const targetDir = directory || this.extractRepoName(repository);
27560
27891
  if (context.globalOptions.json) {
27561
27892
  await this.output.json({
@@ -27968,13 +28299,13 @@ class ListReposCommand extends BaseCommand {
27968
28299
  return;
27969
28300
  }
27970
28301
  if (repos.length === 0) {
27971
- this.output.text("No repositories found");
28302
+ this.output.info("No repositories found");
27972
28303
  return;
27973
28304
  }
27974
28305
  const rows = repos.map((repo) => [
27975
28306
  repo.full_name ?? "",
27976
28307
  repo.is_private ? "private" : "public",
27977
- (repo.description || "").substring(0, 50)
28308
+ this.truncateText(repo.description ?? "", 50, context.globalOptions)
27978
28309
  ]);
27979
28310
  this.output.table(["REPOSITORY", "VISIBILITY", "DESCRIPTION"], rows);
27980
28311
  }
@@ -28059,13 +28390,7 @@ class DeleteRepoCommand extends BaseCommand {
28059
28390
  contextOptions.repo = repository;
28060
28391
  }
28061
28392
  const repoContext = await this.contextService.requireRepoContext(contextOptions);
28062
- if (!yes) {
28063
- throw new BBError({
28064
- code: 5001 /* VALIDATION_REQUIRED */,
28065
- message: `This will permanently delete ${repoContext.workspace}/${repoContext.repoSlug}.
28066
- ` + "Use --yes to confirm deletion."
28067
- });
28068
- }
28393
+ this.requireConfirmation(yes, `This will permanently delete ${repoContext.workspace}/${repoContext.repoSlug}.`);
28069
28394
  await this.repositoriesApi.repositoriesWorkspaceRepoSlugDelete({
28070
28395
  workspace: repoContext.workspace,
28071
28396
  repoSlug: repoContext.repoSlug
@@ -28094,10 +28419,7 @@ class ListDefaultReviewersCommand extends BaseCommand {
28094
28419
  this.contextService = contextService;
28095
28420
  }
28096
28421
  async execute(options, context) {
28097
- const repoContext = await this.contextService.requireRepoContext({
28098
- ...context.globalOptions,
28099
- ...options
28100
- });
28422
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28101
28423
  const mode = options.repoOnly ? "direct" : "effective";
28102
28424
  const reviewers = await this.defaultReviewerService.list(repoContext, mode);
28103
28425
  if (context.globalOptions.json) {
@@ -28140,10 +28462,7 @@ class AddDefaultReviewerCommand extends BaseCommand {
28140
28462
  this.contextService = contextService;
28141
28463
  }
28142
28464
  async execute(options, context) {
28143
- const repoContext = await this.contextService.requireRepoContext({
28144
- ...context.globalOptions,
28145
- ...options
28146
- });
28465
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28147
28466
  const userResponse = await this.usersApi.usersSelectedUserGet({
28148
28467
  selectedUser: options.username
28149
28468
  });
@@ -28177,17 +28496,8 @@ class RemoveDefaultReviewerCommand extends BaseCommand {
28177
28496
  this.contextService = contextService;
28178
28497
  }
28179
28498
  async execute(options, context) {
28180
- const repoContext = await this.contextService.requireRepoContext({
28181
- ...context.globalOptions,
28182
- ...options
28183
- });
28184
- if (!options.yes) {
28185
- throw new BBError({
28186
- code: 5001 /* VALIDATION_REQUIRED */,
28187
- message: `This will remove ${options.username} from the default reviewers of ` + `${repoContext.workspace}/${repoContext.repoSlug}.
28188
- ` + "Use --yes to confirm."
28189
- });
28190
- }
28499
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28500
+ this.requireConfirmation(options.yes, `This will remove ${options.username} from the default reviewers of ` + `${repoContext.workspace}/${repoContext.repoSlug}.`);
28191
28501
  const userResponse = await this.usersApi.usersSelectedUserGet({
28192
28502
  selectedUser: options.username
28193
28503
  });
@@ -28232,10 +28542,7 @@ class CreatePRCommand extends BaseCommand {
28232
28542
  message: this.appendHelpHint("Pull request title is required. Use --title option.")
28233
28543
  });
28234
28544
  }
28235
- const repoContext = await this.contextService.requireRepoContext({
28236
- ...context.globalOptions,
28237
- ...options
28238
- });
28545
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28239
28546
  let sourceBranch = options.source;
28240
28547
  if (!sourceBranch) {
28241
28548
  sourceBranch = await this.gitService.getCurrentBranch();
@@ -28266,12 +28573,18 @@ class CreatePRCommand extends BaseCommand {
28266
28573
  if (reviewers.length > 0) {
28267
28574
  request.reviewers = reviewers.map((r) => ({ type: "user", uuid: r.uuid }));
28268
28575
  }
28269
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPost({
28270
- workspace: repoContext.workspace,
28271
- repoSlug: repoContext.repoSlug,
28272
- pullrequest: request
28273
- });
28274
- const pr = response.data;
28576
+ const spinner = this.output.spinner("Creating pull request...").start();
28577
+ let pr;
28578
+ try {
28579
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPost({
28580
+ workspace: repoContext.workspace,
28581
+ repoSlug: repoContext.repoSlug,
28582
+ pullrequest: request
28583
+ });
28584
+ pr = response.data;
28585
+ } finally {
28586
+ spinner.stop();
28587
+ }
28275
28588
  const links = pr.links;
28276
28589
  if (context.globalOptions.json) {
28277
28590
  await this.output.json(pr);
@@ -28360,10 +28673,7 @@ class ListPRsCommand extends BaseCommand {
28360
28673
  this.contextService = contextService;
28361
28674
  }
28362
28675
  async execute(options, context) {
28363
- const repoContext = await this.contextService.requireRepoContext({
28364
- ...context.globalOptions,
28365
- ...options
28366
- });
28676
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28367
28677
  const state = options.state ? this.parseEnumOption(options.state, "state", PR_STATES) : "OPEN";
28368
28678
  const limit = parseLimit(options.limit);
28369
28679
  const reviewerQuery = options.mine ? await this.buildMineFilter() : undefined;
@@ -28398,28 +28708,23 @@ class ListPRsCommand extends BaseCommand {
28398
28708
  return;
28399
28709
  }
28400
28710
  if (values.length === 0) {
28401
- this.output.text(`No ${state.toLowerCase()} pull requests found`);
28711
+ this.output.info(`No ${state.toLowerCase()} pull requests found`);
28402
28712
  return;
28403
28713
  }
28714
+ const arrow = this.output.symbol("\u2192", "->");
28404
28715
  const rows = values.map((pr) => {
28405
28716
  const title = pr.draft ? `[DRAFT] ${pr.title}` : pr.title;
28406
28717
  const source = pr.source;
28407
28718
  const destination = pr.destination;
28408
28719
  return [
28409
28720
  `#${pr.id}`,
28410
- this.truncate(title ?? "", 50),
28721
+ this.truncateText(title ?? "", 50, context.globalOptions),
28411
28722
  pr.author?.display_name ?? "Unknown",
28412
- `${source?.branch?.name ?? "unknown"} \u2192 ${destination?.branch?.name ?? "unknown"}`
28723
+ `${source?.branch?.name ?? "unknown"} ${arrow} ${destination?.branch?.name ?? "unknown"}`
28413
28724
  ];
28414
28725
  });
28415
28726
  this.output.table(["ID", "TITLE", "AUTHOR", "BRANCHES"], rows);
28416
28727
  }
28417
- truncate(text, maxLength) {
28418
- if (text.length <= maxLength) {
28419
- return text;
28420
- }
28421
- return text.substring(0, maxLength - 3) + "...";
28422
- }
28423
28728
  async buildMineFilter() {
28424
28729
  const response = await this.usersApi.userGet();
28425
28730
  const userUuid = response.data.uuid;
@@ -28443,11 +28748,8 @@ class ViewPRCommand extends BaseCommand {
28443
28748
  this.contextService = contextService;
28444
28749
  }
28445
28750
  async execute(options, context) {
28446
- const repoContext = await this.contextService.requireRepoContext({
28447
- ...context.globalOptions,
28448
- ...options
28449
- });
28450
- const prId = this.parseIntOption(options.id, "id");
28751
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28752
+ const prId = this.parsePositiveInt(options.id, "id");
28451
28753
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
28452
28754
  workspace: repoContext.workspace,
28453
28755
  repoSlug: repoContext.repoSlug,
@@ -28470,7 +28772,7 @@ class ViewPRCommand extends BaseCommand {
28470
28772
  const draftLabel = pr.draft ? this.output.yellow(" [DRAFT]") : "";
28471
28773
  this.output.text("");
28472
28774
  this.output.text(`${this.output.bold(`#${pr.id}`)} ${pr.title}${draftLabel} ${stateColor(`[${pr.state}]`)}`);
28473
- this.output.text(this.output.gray("\u2500".repeat(60)));
28775
+ this.output.separator();
28474
28776
  }
28475
28777
  renderDescription(pr) {
28476
28778
  if (pr.description) {
@@ -28483,7 +28785,7 @@ class ViewPRCommand extends BaseCommand {
28483
28785
  const destination = pr.destination;
28484
28786
  const sourceBranch = this.output.cyan(source?.branch?.name ?? "unknown");
28485
28787
  const destBranch = this.output.cyan(destination?.branch?.name ?? "unknown");
28486
- const arrow = this.output.gray(" \u2192 ");
28788
+ const arrow = this.output.gray(this.output.symbol(" \u2192 ", " -> "));
28487
28789
  this.output.text(`${this.output.dim("Branch:")} ${sourceBranch}${arrow}${destBranch}`);
28488
28790
  if (source?.commit?.hash || destination?.commit?.hash) {
28489
28791
  const sourceHash = source?.commit?.hash ? this.output.gray(source.commit.hash.slice(0, 7)) : this.output.gray("unknown");
@@ -28505,7 +28807,7 @@ class ViewPRCommand extends BaseCommand {
28505
28807
  if (mergeCommit?.hash) {
28506
28808
  this.output.text(`${this.output.dim("Merge:")} ${this.output.magenta(mergeCommit.hash.slice(0, 7))}`);
28507
28809
  }
28508
- const closeBranchIndicator = pr.close_source_branch ? this.output.green("\u2713") : this.output.gray("\u2717");
28810
+ const closeBranchIndicator = pr.close_source_branch ? this.output.green(this.output.symbol("\u2713", "yes")) : this.output.gray(this.output.symbol("\u2717", "no"));
28509
28811
  this.output.text(`${this.output.dim("Close Src:")} ${closeBranchIndicator} ${this.output.gray("(close source branch on merge)")}`);
28510
28812
  this.output.text(`${this.output.dim("Activity:")} ${pr.comment_count ?? 0} comments \xB7 ${pr.task_count ?? 0} tasks`);
28511
28813
  }
@@ -28514,7 +28816,7 @@ class ViewPRCommand extends BaseCommand {
28514
28816
  const reviewers = participants.filter((p) => p.role === "REVIEWER");
28515
28817
  if (reviewers.length === 0) {
28516
28818
  this.output.text("");
28517
- this.output.text(this.output.gray("No reviewers assigned"));
28819
+ this.output.info("No reviewers assigned");
28518
28820
  return;
28519
28821
  }
28520
28822
  this.output.text("");
@@ -28529,17 +28831,26 @@ class ViewPRCommand extends BaseCommand {
28529
28831
  }
28530
28832
  getReviewerStatus(reviewer) {
28531
28833
  if (reviewer.approved) {
28532
- return { icon: this.output.green("\u2713"), label: "approved" };
28834
+ return {
28835
+ icon: this.output.green(this.output.symbol("\u2713", "[OK]")),
28836
+ label: "approved"
28837
+ };
28533
28838
  }
28534
28839
  if (reviewer.state === "changes_requested") {
28535
- return { icon: this.output.red("\u2717"), label: "changes requested" };
28840
+ return {
28841
+ icon: this.output.red(this.output.symbol("\u2717", "[X]")),
28842
+ label: "changes requested"
28843
+ };
28536
28844
  }
28537
- return { icon: this.output.yellow("\u25CB"), label: "pending" };
28845
+ return {
28846
+ icon: this.output.yellow(this.output.symbol("\u25CB", "[ ]")),
28847
+ label: "pending"
28848
+ };
28538
28849
  }
28539
28850
  renderFooter(pr) {
28540
28851
  const links = pr.links;
28541
28852
  this.output.text("");
28542
- this.output.text(this.output.gray("\u2500".repeat(60)));
28853
+ this.output.separator();
28543
28854
  this.output.text(`${this.output.dim("URL:")} ${this.output.underline(this.output.blue(links?.html?.href ?? ""))}`);
28544
28855
  this.output.text("");
28545
28856
  }
@@ -28572,13 +28883,10 @@ class EditPRCommand extends BaseCommand {
28572
28883
  this.gitService = gitService;
28573
28884
  }
28574
28885
  async execute(options, context) {
28575
- const repoContext = await this.contextService.requireRepoContext({
28576
- ...context.globalOptions,
28577
- ...options
28578
- });
28886
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28579
28887
  let prId;
28580
28888
  if (options.id) {
28581
- prId = Number.parseInt(options.id, 10);
28889
+ prId = this.parsePositiveInt(options.id, "id");
28582
28890
  } else {
28583
28891
  const currentBranch = await this.gitService.getCurrentBranch();
28584
28892
  const matches = await collectPages({
@@ -28653,7 +28961,7 @@ class EditPRCommand extends BaseCommand {
28653
28961
  this.output.success(`Updated pull request #${pr.id}`);
28654
28962
  this.output.text(` ${this.output.dim("Title:")} ${pr.title}`);
28655
28963
  if (pr.description) {
28656
- const truncatedDesc = pr.description.length > 100 ? pr.description.substring(0, 100) + "..." : pr.description;
28964
+ const truncatedDesc = this.truncateText(pr.description, 100, context.globalOptions);
28657
28965
  this.output.text(` ${this.output.dim("Description:")} ${truncatedDesc}`);
28658
28966
  }
28659
28967
  this.output.text(` ${this.output.dim("URL:")} ${links?.html?.href}`);
@@ -28674,11 +28982,8 @@ class MergePRCommand extends BaseCommand {
28674
28982
  this.contextService = contextService;
28675
28983
  }
28676
28984
  async execute(options, context) {
28677
- const repoContext = await this.contextService.requireRepoContext({
28678
- ...context.globalOptions,
28679
- ...options
28680
- });
28681
- const prId = this.parseIntOption(options.id, "id");
28985
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28986
+ const prId = this.parsePositiveInt(options.id, "id");
28682
28987
  const request = {
28683
28988
  type: "pullrequest_merge_parameters"
28684
28989
  };
@@ -28691,13 +28996,19 @@ class MergePRCommand extends BaseCommand {
28691
28996
  if (options.strategy) {
28692
28997
  request.merge_strategy = this.parseEnumOption(options.strategy, "strategy", VALID_STRATEGIES);
28693
28998
  }
28694
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergePost({
28695
- workspace: repoContext.workspace,
28696
- repoSlug: repoContext.repoSlug,
28697
- pullRequestId: prId,
28698
- pullrequestMergeParameters: request
28699
- });
28700
- const pr = response.data;
28999
+ const spinner = this.output.spinner(`Merging pull request #${prId}...`).start();
29000
+ let pr;
29001
+ try {
29002
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergePost({
29003
+ workspace: repoContext.workspace,
29004
+ repoSlug: repoContext.repoSlug,
29005
+ pullRequestId: prId,
29006
+ pullrequestMergeParameters: request
29007
+ });
29008
+ pr = response.data;
29009
+ } finally {
29010
+ spinner.stop();
29011
+ }
28701
29012
  if (context.globalOptions.json) {
28702
29013
  await this.output.json({
28703
29014
  success: true,
@@ -28722,11 +29033,8 @@ class ApprovePRCommand extends BaseCommand {
28722
29033
  this.contextService = contextService;
28723
29034
  }
28724
29035
  async execute(options, context) {
28725
- const repoContext = await this.contextService.requireRepoContext({
28726
- ...context.globalOptions,
28727
- ...options
28728
- });
28729
- const prId = Number.parseInt(options.id, 10);
29036
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29037
+ const prId = this.parsePositiveInt(options.id, "id");
28730
29038
  await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdApprovePost({
28731
29039
  workspace: repoContext.workspace,
28732
29040
  repoSlug: repoContext.repoSlug,
@@ -28755,11 +29063,8 @@ class DeclinePRCommand extends BaseCommand {
28755
29063
  this.contextService = contextService;
28756
29064
  }
28757
29065
  async execute(options, context) {
28758
- const repoContext = await this.contextService.requireRepoContext({
28759
- ...context.globalOptions,
28760
- ...options
28761
- });
28762
- const prId = Number.parseInt(options.id, 10);
29066
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29067
+ const prId = this.parsePositiveInt(options.id, "id");
28763
29068
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdDeclinePost({
28764
29069
  workspace: repoContext.workspace,
28765
29070
  repoSlug: repoContext.repoSlug,
@@ -28790,11 +29095,8 @@ class ReadyPRCommand extends BaseCommand {
28790
29095
  this.contextService = contextService;
28791
29096
  }
28792
29097
  async execute(options, context) {
28793
- const repoContext = await this.contextService.requireRepoContext({
28794
- ...context.globalOptions,
28795
- ...options
28796
- });
28797
- const prId = Number.parseInt(options.id, 10);
29098
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29099
+ const prId = this.parsePositiveInt(options.id, "id");
28798
29100
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
28799
29101
  workspace: repoContext.workspace,
28800
29102
  repoSlug: repoContext.repoSlug,
@@ -28832,11 +29134,8 @@ class CheckoutPRCommand extends BaseCommand {
28832
29134
  this.gitService = gitService;
28833
29135
  }
28834
29136
  async execute(options, context) {
28835
- const repoContext = await this.contextService.requireRepoContext({
28836
- ...context.globalOptions,
28837
- ...options
28838
- });
28839
- const prId = Number.parseInt(options.id, 10);
29137
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29138
+ const prId = this.parsePositiveInt(options.id, "id");
28840
29139
  const prResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
28841
29140
  workspace: repoContext.workspace,
28842
29141
  repoSlug: repoContext.repoSlug,
@@ -28899,20 +29198,10 @@ class DiffPRCommand extends BaseCommand {
28899
29198
  this.gitService = gitService;
28900
29199
  }
28901
29200
  async execute(options, context) {
28902
- const repoContext = await this.contextService.requireRepoContext({
28903
- ...context.globalOptions,
28904
- ...options
28905
- });
29201
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
28906
29202
  let prId;
28907
29203
  if (options.id) {
28908
- prId = Number.parseInt(options.id, 10);
28909
- if (Number.isNaN(prId)) {
28910
- throw new BBError({
28911
- code: 5002 /* VALIDATION_INVALID */,
28912
- message: "Invalid PR ID",
28913
- context: { id: options.id }
28914
- });
28915
- }
29204
+ prId = this.parsePositiveInt(options.id, "id");
28916
29205
  } else {
28917
29206
  const currentBranch = await this.gitService.getCurrentBranch();
28918
29207
  const matches = await collectPages({
@@ -29129,11 +29418,8 @@ class ActivityPRCommand extends BaseCommand {
29129
29418
  this.contextService = contextService;
29130
29419
  }
29131
29420
  async execute(options, context) {
29132
- const repoContext = await this.contextService.requireRepoContext({
29133
- ...context.globalOptions,
29134
- ...options
29135
- });
29136
- const prId = this.parseIntOption(options.id, "id");
29421
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29422
+ const prId = this.parsePositiveInt(options.id, "id");
29137
29423
  const filterTypes = this.parseTypeFilter(options.type);
29138
29424
  const limit = parseLimit(options.limit);
29139
29425
  const activities = await collectPages({
@@ -29182,7 +29468,7 @@ class ActivityPRCommand extends BaseCommand {
29182
29468
  activityType.toUpperCase(),
29183
29469
  this.getActorName(activity),
29184
29470
  this.formatActivityDate(activity),
29185
- this.buildActivityDetails(activity, activityType)
29471
+ this.buildActivityDetails(activity, activityType, context.globalOptions)
29186
29472
  ];
29187
29473
  });
29188
29474
  this.output.table(["TYPE", "ACTOR", "DATE", "DETAILS"], rows);
@@ -29237,19 +29523,19 @@ class ActivityPRCommand extends BaseCommand {
29237
29523
  }
29238
29524
  return this.output.formatDate(date);
29239
29525
  }
29240
- buildActivityDetails(activity, type) {
29526
+ buildActivityDetails(activity, type, globalOptions) {
29241
29527
  switch (type) {
29242
29528
  case "comment": {
29243
29529
  const content = getRawContent(activity.comment?.content) ?? "";
29244
29530
  const id = activity.comment?.id ? `#${activity.comment.id}` : "";
29245
- const snippet = this.truncate(content, 80);
29531
+ const snippet = this.truncateText(content, 80, globalOptions);
29246
29532
  return [id, snippet].filter(Boolean).join(" ");
29247
29533
  }
29248
29534
  case "approval":
29249
29535
  return "approved";
29250
29536
  case "changes_requested": {
29251
29537
  const reason = activity.changes_requested?.reason;
29252
- return reason ? this.truncate(reason, 80) : "changes requested";
29538
+ return reason ? this.truncateText(reason, 80, globalOptions) : "changes requested";
29253
29539
  }
29254
29540
  case "merge":
29255
29541
  return this.formatCommitDetail(activity.merge?.commit?.hash, "merged");
@@ -29262,7 +29548,7 @@ class ActivityPRCommand extends BaseCommand {
29262
29548
  return `state: ${activity.update.state}`;
29263
29549
  }
29264
29550
  if (activity.update?.title) {
29265
- return `title: ${this.truncate(activity.update.title, 60)}`;
29551
+ return `title: ${this.truncateText(activity.update.title, 60, globalOptions)}`;
29266
29552
  }
29267
29553
  if (activity.update?.description) {
29268
29554
  return "description updated";
@@ -29280,12 +29566,6 @@ class ActivityPRCommand extends BaseCommand {
29280
29566
  const shortHash = hash.slice(0, 7);
29281
29567
  return label ? `${label} ${shortHash}` : shortHash;
29282
29568
  }
29283
- truncate(text, maxLength) {
29284
- if (text.length <= maxLength) {
29285
- return text;
29286
- }
29287
- return text.substring(0, maxLength - 3) + "...";
29288
- }
29289
29569
  }
29290
29570
 
29291
29571
  // src/commands/pr/comment.command.ts
@@ -29319,33 +29599,14 @@ class CommentPRCommand extends BaseCommand {
29319
29599
  }
29320
29600
  });
29321
29601
  }
29322
- if (options.lineTo) {
29323
- const parsed = Number.parseInt(options.lineTo, 10);
29324
- if (Number.isNaN(parsed) || parsed < 1) {
29325
- throw new BBError({
29326
- code: 5002 /* VALIDATION_INVALID */,
29327
- message: "--line-to must be a positive integer"
29328
- });
29329
- }
29330
- }
29331
- if (options.lineFrom) {
29332
- const parsed = Number.parseInt(options.lineFrom, 10);
29333
- if (Number.isNaN(parsed) || parsed < 1) {
29334
- throw new BBError({
29335
- code: 5002 /* VALIDATION_INVALID */,
29336
- message: "--line-from must be a positive integer"
29337
- });
29338
- }
29339
- }
29340
- const repoContext = await this.contextService.requireRepoContext({
29341
- ...context.globalOptions,
29342
- ...options
29343
- });
29344
- const prId = Number.parseInt(options.id, 10);
29602
+ const lineTo = options.lineTo ? this.parsePositiveInt(options.lineTo, "line-to") : undefined;
29603
+ const lineFrom = options.lineFrom ? this.parsePositiveInt(options.lineFrom, "line-from") : undefined;
29604
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29605
+ const prId = this.parsePositiveInt(options.id, "id");
29345
29606
  const inline = options.file ? {
29346
29607
  path: options.file,
29347
- ...options.lineTo ? { to: Number.parseInt(options.lineTo, 10) } : {},
29348
- ...options.lineFrom ? { from: Number.parseInt(options.lineFrom, 10) } : {}
29608
+ ...lineTo !== undefined ? { to: lineTo } : {},
29609
+ ...lineFrom !== undefined ? { from: lineFrom } : {}
29349
29610
  } : undefined;
29350
29611
  const body = {
29351
29612
  content: {
@@ -29395,11 +29656,8 @@ class ListCommentsPRCommand extends BaseCommand {
29395
29656
  this.contextService = contextService;
29396
29657
  }
29397
29658
  async execute(options, context) {
29398
- const repoContext = await this.contextService.requireRepoContext({
29399
- ...context.globalOptions,
29400
- ...options
29401
- });
29402
- const prId = this.parseIntOption(options.id, "id");
29659
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29660
+ const prId = this.parsePositiveInt(options.id, "id");
29403
29661
  const limit = parseLimit(options.limit);
29404
29662
  const values = await collectPages({
29405
29663
  limit,
@@ -29416,6 +29674,8 @@ class ListCommentsPRCommand extends BaseCommand {
29416
29674
  });
29417
29675
  if (context.globalOptions.json) {
29418
29676
  await this.output.json({
29677
+ workspace: repoContext.workspace,
29678
+ repoSlug: repoContext.repoSlug,
29419
29679
  pullRequestId: prId,
29420
29680
  count: values.length,
29421
29681
  comments: values
@@ -29431,7 +29691,7 @@ class ListCommentsPRCommand extends BaseCommand {
29431
29691
  return [
29432
29692
  comment.id?.toString() ?? "",
29433
29693
  getUserDisplayName(comment.user) ?? "Unknown",
29434
- comment.deleted ? "[deleted]" : options.truncate === false ? content : content.slice(0, 60) + (content.length > 60 ? "..." : ""),
29694
+ comment.deleted ? "[deleted]" : this.truncateText(content, 60, context.globalOptions),
29435
29695
  this.output.formatDate(comment.created_on ?? "")
29436
29696
  ];
29437
29697
  });
@@ -29451,12 +29711,9 @@ class EditCommentPRCommand extends BaseCommand {
29451
29711
  this.contextService = contextService;
29452
29712
  }
29453
29713
  async execute(options, context) {
29454
- const repoContext = await this.contextService.requireRepoContext({
29455
- ...context.globalOptions,
29456
- ...options
29457
- });
29458
- const prId = this.parseIntOption(options.prId, "pr-id");
29459
- const commentId = this.parseIntOption(options.commentId, "comment-id");
29714
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29715
+ const prId = this.parsePositiveInt(options.prId, "pr-id");
29716
+ const commentId = this.parsePositiveInt(options.commentId, "comment-id");
29460
29717
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsCommentIdPut({
29461
29718
  workspace: repoContext.workspace,
29462
29719
  repoSlug: repoContext.repoSlug,
@@ -29494,19 +29751,10 @@ class DeleteCommentPRCommand extends BaseCommand {
29494
29751
  this.contextService = contextService;
29495
29752
  }
29496
29753
  async execute(options, context) {
29497
- const repoContext = await this.contextService.requireRepoContext({
29498
- ...context.globalOptions,
29499
- ...options
29500
- });
29501
- const prId = this.parseIntOption(options.prId, "pr-id");
29502
- const commentId = this.parseIntOption(options.commentId, "comment-id");
29503
- if (!options.yes) {
29504
- throw new BBError({
29505
- code: 5001 /* VALIDATION_REQUIRED */,
29506
- message: `This will permanently delete comment #${commentId} on PR #${prId}.
29507
- ` + "Use --yes to confirm deletion."
29508
- });
29509
- }
29754
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29755
+ const prId = this.parsePositiveInt(options.prId, "pr-id");
29756
+ const commentId = this.parsePositiveInt(options.commentId, "comment-id");
29757
+ this.requireConfirmation(options.yes, `This will permanently delete comment #${commentId} on PR #${prId}.`);
29510
29758
  await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsCommentIdDelete({
29511
29759
  workspace: repoContext.workspace,
29512
29760
  repoSlug: repoContext.repoSlug,
@@ -29539,11 +29787,8 @@ class AddReviewerPRCommand extends BaseCommand {
29539
29787
  this.contextService = contextService;
29540
29788
  }
29541
29789
  async execute(options, context) {
29542
- const repoContext = await this.contextService.requireRepoContext({
29543
- ...context.globalOptions,
29544
- ...options
29545
- });
29546
- const prId = this.parseIntOption(options.id, "id");
29790
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29791
+ const prId = this.parsePositiveInt(options.id, "id");
29547
29792
  const userResponse = await this.usersApi.usersSelectedUserGet({
29548
29793
  selectedUser: options.username
29549
29794
  });
@@ -29584,11 +29829,8 @@ class RemoveReviewerPRCommand extends BaseCommand {
29584
29829
  this.contextService = contextService;
29585
29830
  }
29586
29831
  async execute(options, context) {
29587
- const repoContext = await this.contextService.requireRepoContext({
29588
- ...context.globalOptions,
29589
- ...options
29590
- });
29591
- const prId = this.parseIntOption(options.id, "id");
29832
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29833
+ const prId = this.parsePositiveInt(options.id, "id");
29592
29834
  const userResponse = await this.usersApi.usersSelectedUserGet({
29593
29835
  selectedUser: options.username
29594
29836
  });
@@ -29622,11 +29864,8 @@ class ListReviewersPRCommand extends BaseCommand {
29622
29864
  this.contextService = contextService;
29623
29865
  }
29624
29866
  async execute(options, context) {
29625
- const repoContext = await this.contextService.requireRepoContext({
29626
- ...context.globalOptions,
29627
- ...options
29628
- });
29629
- const prId = this.parseIntOption(options.id, "id");
29867
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29868
+ const prId = this.parsePositiveInt(options.id, "id");
29630
29869
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
29631
29870
  workspace: repoContext.workspace,
29632
29871
  repoSlug: repoContext.repoSlug,
@@ -29636,6 +29875,8 @@ class ListReviewersPRCommand extends BaseCommand {
29636
29875
  const reviewers = Array.from(pr.reviewers ?? []);
29637
29876
  if (context.globalOptions.json) {
29638
29877
  await this.output.json({
29878
+ workspace: repoContext.workspace,
29879
+ repoSlug: repoContext.repoSlug,
29639
29880
  pullRequestId: prId,
29640
29881
  count: reviewers.length,
29641
29882
  reviewers
@@ -29662,11 +29903,8 @@ class ChecksPRCommand extends BaseCommand {
29662
29903
  this.contextService = contextService;
29663
29904
  }
29664
29905
  async execute(options, context) {
29665
- const repoContext = await this.contextService.requireRepoContext({
29666
- ...context.globalOptions,
29667
- ...options
29668
- });
29669
- const prId = this.parseIntOption(options.id, "id");
29906
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
29907
+ const prId = this.parsePositiveInt(options.id, "id");
29670
29908
  const response = await this.commitStatusesApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdStatusesGet({
29671
29909
  workspace: repoContext.workspace,
29672
29910
  repoSlug: repoContext.repoSlug,
@@ -29690,7 +29928,7 @@ class ChecksPRCommand extends BaseCommand {
29690
29928
  return;
29691
29929
  }
29692
29930
  this.renderHeader(prId, statuses.length);
29693
- this.renderStatuses(statuses, summary);
29931
+ this.renderStatuses(statuses, summary, context.globalOptions);
29694
29932
  }
29695
29933
  formatStatusForJson(status) {
29696
29934
  return {
@@ -29709,9 +29947,9 @@ class ChecksPRCommand extends BaseCommand {
29709
29947
  this.output.text("");
29710
29948
  const title = this.output.bold("Pull Request #" + prId);
29711
29949
  this.output.text(`${title} - ${count} check${count === 1 ? "" : "s"}`);
29712
- this.output.text(this.output.gray("-".repeat(60)));
29950
+ this.output.separator();
29713
29951
  }
29714
- renderStatuses(statuses, summary) {
29952
+ renderStatuses(statuses, summary, globalOptions) {
29715
29953
  const rows = statuses.map((status) => {
29716
29954
  const stateIcon = this.getStateIcon(status.state);
29717
29955
  const stateLabel = this.getStateLabel(status.state);
@@ -29720,7 +29958,7 @@ class ChecksPRCommand extends BaseCommand {
29720
29958
  return [
29721
29959
  `${stateIcon} ${stateLabel}`,
29722
29960
  this.output.bold(name),
29723
- this.truncate(description, 40),
29961
+ this.truncateText(description, 40, globalOptions),
29724
29962
  status.updated_on ? this.output.formatDate(status.updated_on) : "-"
29725
29963
  ];
29726
29964
  });
@@ -29770,12 +30008,6 @@ class ChecksPRCommand extends BaseCommand {
29770
30008
  return acc;
29771
30009
  }, { successful: 0, failed: 0, pending: 0 });
29772
30010
  }
29773
- truncate(text, maxLength) {
29774
- if (text.length <= maxLength) {
29775
- return text;
29776
- }
29777
- return text.substring(0, maxLength - 3) + "...";
29778
- }
29779
30011
  }
29780
30012
 
29781
30013
  // src/commands/snippet/list.command.ts
@@ -29816,7 +30048,7 @@ class ListSnippetsCommand extends BaseCommand {
29816
30048
  return;
29817
30049
  }
29818
30050
  if (snippets.length === 0) {
29819
- this.output.text("No snippets found");
30051
+ this.output.info("No snippets found");
29820
30052
  return;
29821
30053
  }
29822
30054
  const rows = snippets.map((snippet) => [
@@ -29877,9 +30109,10 @@ class ViewSnippetCommand extends BaseCommand {
29877
30109
  return;
29878
30110
  }
29879
30111
  this.renderSnippet(snippet, fileNames);
30112
+ const fileSep = this.output.symbol("\u2500\u2500", "--");
29880
30113
  for (const name of fileNames) {
29881
30114
  this.output.text("");
29882
- this.output.text(this.output.bold(`\u2500\u2500 ${name} \u2500\u2500`));
30115
+ this.output.text(this.output.bold(`${fileSep} ${name} ${fileSep}`));
29883
30116
  this.output.text(contents[name] ?? "");
29884
30117
  }
29885
30118
  return;
@@ -29901,7 +30134,7 @@ class ViewSnippetCommand extends BaseCommand {
29901
30134
  const visibility = snippet.is_private ? "private" : "public";
29902
30135
  this.output.text("");
29903
30136
  this.output.text(`${this.output.bold(String(snippet.id ?? ""))} ${snippet.title ?? "Untitled"} ${this.output.gray(`[${visibility}]`)}`);
29904
- this.output.text(this.output.gray("\u2500".repeat(60)));
30137
+ this.output.separator();
29905
30138
  const creator = getUserDisplayName(snippet.creator);
29906
30139
  if (creator) {
29907
30140
  this.output.text(`Creator: ${creator}`);
@@ -30062,13 +30295,7 @@ class DeleteSnippetCommand extends BaseCommand {
30062
30295
  }
30063
30296
  async execute(options, context) {
30064
30297
  const workspace = await this.contextService.requireWorkspace(options.workspace ?? context.globalOptions.workspace);
30065
- if (!options.yes) {
30066
- throw new BBError({
30067
- code: 5001 /* VALIDATION_REQUIRED */,
30068
- message: `This will permanently delete snippet ${options.id}.
30069
- ` + "Use --yes to confirm deletion."
30070
- });
30071
- }
30298
+ this.requireConfirmation(options.yes, `This will permanently delete snippet ${options.id}.`);
30072
30299
  await this.snippetsApi.snippetsWorkspaceEncodedIdDelete({
30073
30300
  workspace,
30074
30301
  encodedId: options.id
@@ -30188,7 +30415,7 @@ class ListSnippetCommentsCommand extends BaseCommand {
30188
30415
  String(comment.id ?? ""),
30189
30416
  getUserDisplayName(comment.user) ?? "Unknown",
30190
30417
  this.output.formatDate(comment.created_on ?? ""),
30191
- content.slice(0, 60) + (content.length > 60 ? "..." : "")
30418
+ this.truncateText(content, 60, context.globalOptions)
30192
30419
  ];
30193
30420
  });
30194
30421
  this.output.table(["ID", "AUTHOR", "DATE", "CONTENT"], rows);
@@ -30247,7 +30474,7 @@ class EditSnippetCommentCommand extends BaseCommand {
30247
30474
  }
30248
30475
  async execute(options, context) {
30249
30476
  const workspace = await this.contextService.requireWorkspace(options.workspace ?? context.globalOptions.workspace);
30250
- const commentId = this.parseIntOption(options.commentId, "comment-id");
30477
+ const commentId = this.parsePositiveInt(options.commentId, "comment-id");
30251
30478
  const body = {
30252
30479
  type: "snippet_comment",
30253
30480
  content: {
@@ -30285,14 +30512,8 @@ class DeleteSnippetCommentCommand extends BaseCommand {
30285
30512
  }
30286
30513
  async execute(options, context) {
30287
30514
  const workspace = await this.contextService.requireWorkspace(options.workspace ?? context.globalOptions.workspace);
30288
- const commentId = this.parseIntOption(options.commentId, "comment-id");
30289
- if (!options.yes) {
30290
- throw new BBError({
30291
- code: 5001 /* VALIDATION_REQUIRED */,
30292
- message: `This will permanently delete comment #${commentId} on snippet ${options.snippetId}.
30293
- ` + "Use --yes to confirm deletion."
30294
- });
30295
- }
30515
+ const commentId = this.parsePositiveInt(options.commentId, "comment-id");
30516
+ this.requireConfirmation(options.yes, `This will permanently delete comment #${commentId} on snippet ${options.snippetId}.`);
30296
30517
  await this.snippetsApi.snippetsWorkspaceEncodedIdCommentsCommentIdDelete({
30297
30518
  workspace,
30298
30519
  encodedId: options.snippetId,
@@ -30436,7 +30657,7 @@ class ListConfigCommand extends BaseCommand {
30436
30657
  String(value)
30437
30658
  ]);
30438
30659
  if (rows.length === 0) {
30439
- this.output.text("No configuration set");
30660
+ this.output.info("No configuration set");
30440
30661
  } else {
30441
30662
  this.output.table(["KEY", "VALUE"], rows);
30442
30663
  }
@@ -30535,10 +30756,7 @@ class BrowseCommand extends BaseCommand {
30535
30756
  this.urlBuilder = urlBuilder;
30536
30757
  }
30537
30758
  async execute(options, context) {
30538
- const repoContext = await this.contextService.requireRepoContext({
30539
- ...context.globalOptions,
30540
- ...options
30541
- });
30759
+ const repoContext = await this.contextService.requireRepoContextFor(options, context);
30542
30760
  this.validateFlagCombination(options);
30543
30761
  const url2 = await this.resolveUrl(options, repoContext);
30544
30762
  const useJson = Boolean(context.globalOptions.json);
@@ -30602,7 +30820,7 @@ class BrowseCommand extends BaseCommand {
30602
30820
  const target = options.target?.trim();
30603
30821
  if (target && target.length > 0) {
30604
30822
  if (PR_NUMBER_PATTERN.test(target)) {
30605
- return this.urlBuilder.pullRequest(ctx, Number.parseInt(target, 10));
30823
+ return this.urlBuilder.pullRequest(ctx, this.parsePositiveInt(target, "target"));
30606
30824
  }
30607
30825
  if (SHA_PATTERN.test(target)) {
30608
30826
  return this.urlBuilder.commit(ctx, target);
@@ -30686,17 +30904,6 @@ class BrowseCommand extends BaseCommand {
30686
30904
  return "HEAD";
30687
30905
  }
30688
30906
  }
30689
- parsePositiveInt(value, name) {
30690
- const parsed = Number.parseInt(value, 10);
30691
- if (!Number.isFinite(parsed) || parsed <= 0 || String(parsed) !== value.trim()) {
30692
- throw new BBError({
30693
- code: 5002 /* VALIDATION_INVALID */,
30694
- message: this.appendHelpHint(`--${name} must be a positive integer.`),
30695
- context: { [name]: value }
30696
- });
30697
- }
30698
- return parsed;
30699
- }
30700
30907
  async openInBrowser(url2) {
30701
30908
  this.output.info(`Opening ${url2} in your browser...`);
30702
30909
  const open2 = (await Promise.resolve().then(() => (init_open(), exports_open))).default;
@@ -30711,7 +30918,8 @@ function registerApiClient(container, token, ctor) {
30711
30918
  container.register(token, () => {
30712
30919
  const credentialStore = container.resolve(ServiceTokens.CredentialStore);
30713
30920
  const oauthService = container.resolve(ServiceTokens.OAuthService);
30714
- const axiosInstance = createApiClient(credentialStore, oauthService);
30921
+ const outputService = container.resolve(ServiceTokens.OutputService);
30922
+ const axiosInstance = createApiClient(credentialStore, outputService, oauthService);
30715
30923
  return new ctor(undefined, undefined, axiosInstance);
30716
30924
  });
30717
30925
  }
@@ -30726,7 +30934,11 @@ function bootstrap(options = {}) {
30726
30934
  container.register(ServiceTokens.ConfigService, () => new ConfigService);
30727
30935
  container.register(ServiceTokens.CredentialStore, () => container.resolve(ServiceTokens.ConfigService));
30728
30936
  container.register(ServiceTokens.GitService, () => new GitService);
30729
- container.register(ServiceTokens.OutputService, () => new OutputService({ noColor: options.noColor }));
30937
+ container.register(ServiceTokens.OutputService, () => new OutputService({
30938
+ noColor: options.noColor,
30939
+ noUnicode: options.noUnicode,
30940
+ locale: options.locale
30941
+ }));
30730
30942
  registerCommand(container, ServiceTokens.OAuthService, OAuthService, [
30731
30943
  ServiceTokens.ConfigService,
30732
30944
  ServiceTokens.CredentialStore
@@ -30742,7 +30954,8 @@ function bootstrap(options = {}) {
30742
30954
  container.register(ServiceTokens.SnippetsAxios, () => {
30743
30955
  const credentialStore = container.resolve(ServiceTokens.CredentialStore);
30744
30956
  const oauthService = container.resolve(ServiceTokens.OAuthService);
30745
- return createApiClient(credentialStore, oauthService);
30957
+ const outputService = container.resolve(ServiceTokens.OutputService);
30958
+ return createApiClient(credentialStore, outputService, oauthService);
30746
30959
  });
30747
30960
  container.register(ServiceTokens.SnippetsApi, () => {
30748
30961
  const axiosInstance = container.resolve(ServiceTokens.SnippetsAxios);
@@ -31087,8 +31300,11 @@ var ROOT_COMPLETIONS = [
31087
31300
  "--version",
31088
31301
  "--json",
31089
31302
  "--no-color",
31303
+ "--no-unicode",
31304
+ "--no-truncate",
31090
31305
  "--workspace",
31091
- "--repo"
31306
+ "--repo",
31307
+ "--locale"
31092
31308
  ];
31093
31309
  var SUBCOMMAND_COMPLETIONS = new Map([
31094
31310
  ["auth", ["login", "logout", "status", "token"]],
@@ -31155,6 +31371,25 @@ if (process.argv.includes("--get-yargs-completions") || process.env.COMP_LINE) {
31155
31371
  process.exit(0);
31156
31372
  }
31157
31373
  }
31374
+ function extractLocaleArg(argv) {
31375
+ for (let i = 0;i < argv.length; i++) {
31376
+ const arg = argv[i];
31377
+ if (arg === undefined) {
31378
+ continue;
31379
+ }
31380
+ if (arg === "--locale") {
31381
+ const next = argv[i + 1];
31382
+ if (typeof next === "string" && !next.startsWith("-")) {
31383
+ return next;
31384
+ }
31385
+ return;
31386
+ }
31387
+ if (arg.startsWith("--locale=")) {
31388
+ return arg.slice("--locale=".length);
31389
+ }
31390
+ }
31391
+ return;
31392
+ }
31158
31393
  function resolveNoColorSetting(argv, env2) {
31159
31394
  const hasColorArg = argv.includes("--color");
31160
31395
  const hasNoColorArg = argv.includes("--no-color");
@@ -31171,9 +31406,20 @@ function resolveNoColorSetting(argv, env2) {
31171
31406
  }
31172
31407
  return hasNoColorEnv;
31173
31408
  }
31409
+ function resolveNoUnicodeSetting(argv, env2) {
31410
+ if (argv.includes("--no-unicode")) {
31411
+ return true;
31412
+ }
31413
+ return env2.BB_NO_UNICODE !== undefined && env2.BB_NO_UNICODE !== "";
31414
+ }
31174
31415
  var noColor = resolveNoColorSetting(process.argv, process.env);
31416
+ var noUnicode = resolveNoUnicodeSetting(process.argv, process.env);
31175
31417
  var buildHelpText = createHelpTextBuilder(noColor);
31176
- var container = bootstrap({ noColor });
31418
+ var locale = resolveLocale({
31419
+ explicit: extractLocaleArg(process.argv),
31420
+ env: process.env
31421
+ });
31422
+ var container = bootstrap({ noColor, noUnicode, locale });
31177
31423
  function createContext(program2) {
31178
31424
  const opts = program2.opts();
31179
31425
  const jsonOpt = opts.json;
@@ -31204,6 +31450,8 @@ function createContext(program2) {
31204
31450
  jsonFields,
31205
31451
  jq: jqOpt,
31206
31452
  noColor: opts.color === false,
31453
+ noUnicode: opts.unicode === false || noUnicode,
31454
+ noTruncate: opts.truncate === false,
31207
31455
  workspace: opts.workspace,
31208
31456
  repo: opts.repo
31209
31457
  },
@@ -31233,13 +31481,15 @@ function withGlobalOptions(options, context) {
31233
31481
  };
31234
31482
  }
31235
31483
  var cli = new Command;
31236
- cli.name("bb").description("A command-line interface for Bitbucket Cloud").version(pkg2.version).option("--json [fields]", "Output as JSON; optionally project to a comma-separated field list (e.g. number,title,author.display_name)").option("--jq <expression>", `Filter the JSON output through a jq expression \u2014 runs in-process via embedded jq, requires --json (e.g. '.pullRequests[] | select(.state == "OPEN") | .title')`).option("--no-color", "Disable color output").option("-w, --workspace <workspace>", "Specify workspace").option("-r, --repo <repo>", "Specify repository").addHelpText("after", buildHelpText({
31484
+ cli.name("bb").description("A command-line interface for Bitbucket Cloud").version(pkg2.version).option("--json [fields]", "Output as JSON; optionally project to a comma-separated field list (e.g. number,title,author.display_name)").option("--jq <expression>", `Filter the JSON output through a jq expression \u2014 runs in-process via embedded jq, requires --json (e.g. '.pullRequests[] | select(.state == "OPEN") | .title')`).option("--no-color", "Disable color output").option("--no-unicode", "Use ASCII fallbacks for symbols (separators, arrows, status icons) \u2014 also enabled by BB_NO_UNICODE").option("--no-truncate", "Show full values in table output without truncation").option("--locale <locale>", "BCP-47 locale tag for date/time formatting (e.g. de-DE, ja-JP). Falls back to BB_LOCALE, then LC_TIME/LC_ALL/LANG, then en-US.").option("-w, --workspace <workspace>", "Specify workspace").option("-r, --repo <repo>", "Specify repository").addHelpText("after", buildHelpText({
31237
31485
  envVars: {
31238
31486
  BB_USERNAME: "Bitbucket username (fallback for auth login)",
31239
31487
  BB_API_TOKEN: "Bitbucket API token (fallback for auth login)",
31240
31488
  NO_COLOR: "Disable color output when set",
31241
31489
  FORCE_COLOR: "Force color output when set (and not '0')",
31242
- DEBUG: "Enable HTTP debug logging when 'true'"
31490
+ BB_NO_UNICODE: "Use ASCII fallbacks for symbols when set (any non-empty value)",
31491
+ DEBUG: "Enable HTTP debug logging when 'true'",
31492
+ BB_LOCALE: "BCP-47 locale tag for date/time formatting; --locale takes precedence"
31243
31493
  },
31244
31494
  seeAlso: [
31245
31495
  {
@@ -31263,11 +31513,11 @@ cli.name("bb").description("A command-line interface for Bitbucket Cloud").versi
31263
31513
  const result = await versionService.checkForUpdate();
31264
31514
  if (result?.updateAvailable) {
31265
31515
  output.text("");
31266
- output.text("\u2500".repeat(50));
31267
- output.text(`\u26A0 A new version is available: ${result.latestVersion} (you have ${result.currentVersion})`);
31268
- output.text(` Run '${versionService.getInstallCommand()}' to update`);
31269
- output.text(` Or disable with 'bb config set skipVersionCheck true'`);
31270
- output.text("\u2500".repeat(50));
31516
+ output.separator(50);
31517
+ output.warning(`A new version is available: ${result.latestVersion} (you have ${result.currentVersion})
31518
+ ` + ` Run '${versionService.getInstallCommand()}' to update
31519
+ ` + ` Or disable with 'bb config set skipVersionCheck true'`);
31520
+ output.separator(50);
31271
31521
  }
31272
31522
  } catch {}
31273
31523
  try {
@@ -31574,7 +31824,7 @@ prCmd.command("diff [id]").description("View pull request diff").option("--color
31574
31824
  await runCommand(ServiceTokens.DiffPRCommand, withGlobalOptions({ id, ...options }, context), cli, context);
31575
31825
  });
31576
31826
  var prCommentsCmd = new Command("comments").description("Manage pull request comments");
31577
- prCommentsCmd.command("list <id>").description("List comments on a pull request").option("--limit <number>", "Maximum number of comments (default: 25)").option("--no-truncate", "Show full comment content without truncation").addHelpText("after", buildHelpText({
31827
+ prCommentsCmd.command("list <id>").description("List comments on a pull request").option("--limit <number>", "Maximum number of comments (default: 25)").addHelpText("after", buildHelpText({
31578
31828
  examples: [
31579
31829
  "bb pr comments list 42",
31580
31830
  "bb pr comments list 42 --no-truncate",
@@ -31841,3 +32091,6 @@ if (typeof Bun === "undefined") {
31841
32091
  process.exit(1);
31842
32092
  }
31843
32093
  cli.parse(process.argv);
32094
+
32095
+ //# debugId=1F677A9695E119AD64756E2164756E21
32096
+ //# sourceMappingURL=index.js.map