@bragduck/cli 2.4.0 → 2.5.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/bin/bragduck.js +382 -8
- package/dist/bin/bragduck.js.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/bragduck.js
CHANGED
|
@@ -392,7 +392,7 @@ var init_storage_service = __esm({
|
|
|
392
392
|
});
|
|
393
393
|
|
|
394
394
|
// src/utils/errors.ts
|
|
395
|
-
var BragduckError, AuthenticationError, GitError, ApiError, NetworkError, ValidationError, OAuthError, TokenExpiredError, GitHubError;
|
|
395
|
+
var BragduckError, AuthenticationError, GitError, ApiError, NetworkError, ValidationError, OAuthError, TokenExpiredError, GitHubError, BitbucketError;
|
|
396
396
|
var init_errors = __esm({
|
|
397
397
|
"src/utils/errors.ts"() {
|
|
398
398
|
"use strict";
|
|
@@ -459,6 +459,12 @@ var init_errors = __esm({
|
|
|
459
459
|
this.name = "GitHubError";
|
|
460
460
|
}
|
|
461
461
|
};
|
|
462
|
+
BitbucketError = class extends BragduckError {
|
|
463
|
+
constructor(message, details) {
|
|
464
|
+
super(message, "BITBUCKET_ERROR", details);
|
|
465
|
+
this.name = "BitbucketError";
|
|
466
|
+
}
|
|
467
|
+
};
|
|
462
468
|
}
|
|
463
469
|
});
|
|
464
470
|
|
|
@@ -1437,6 +1443,7 @@ init_storage_service();
|
|
|
1437
1443
|
init_logger();
|
|
1438
1444
|
import boxen from "boxen";
|
|
1439
1445
|
import chalk3 from "chalk";
|
|
1446
|
+
import { input } from "@inquirer/prompts";
|
|
1440
1447
|
|
|
1441
1448
|
// src/ui/theme.ts
|
|
1442
1449
|
init_esm_shims();
|
|
@@ -1604,9 +1611,11 @@ async function authCommand(subcommand) {
|
|
|
1604
1611
|
await authLogin();
|
|
1605
1612
|
} else if (subcommand === "status") {
|
|
1606
1613
|
await authStatus();
|
|
1614
|
+
} else if (subcommand === "bitbucket") {
|
|
1615
|
+
await authBitbucket();
|
|
1607
1616
|
} else {
|
|
1608
1617
|
logger.error(`Unknown auth subcommand: ${subcommand}`);
|
|
1609
|
-
logger.info("Available subcommands: login, status");
|
|
1618
|
+
logger.info("Available subcommands: login, status, bitbucket");
|
|
1610
1619
|
process.exit(1);
|
|
1611
1620
|
}
|
|
1612
1621
|
}
|
|
@@ -1700,6 +1709,84 @@ async function authStatus() {
|
|
|
1700
1709
|
}
|
|
1701
1710
|
logger.log("");
|
|
1702
1711
|
}
|
|
1712
|
+
async function authBitbucket() {
|
|
1713
|
+
logger.log("");
|
|
1714
|
+
logger.log(
|
|
1715
|
+
boxen(
|
|
1716
|
+
theme.info("Bitbucket API Token Authentication") + "\n\nCreate an API Token at:\n" + colors.highlight("https://bitbucket.org/account/settings/api-token/new") + "\n\nRequired scopes:\n \u2022 pullrequest:read\n \u2022 repository:read\n \u2022 account:read\n\n" + theme.warning("Note: API tokens expire (max 1 year)"),
|
|
1717
|
+
boxStyles.info
|
|
1718
|
+
)
|
|
1719
|
+
);
|
|
1720
|
+
logger.log("");
|
|
1721
|
+
try {
|
|
1722
|
+
const email = await input({
|
|
1723
|
+
message: "Atlassian account email:",
|
|
1724
|
+
validate: (value) => value.includes("@") ? true : "Please enter a valid email address"
|
|
1725
|
+
});
|
|
1726
|
+
const apiToken = await input({
|
|
1727
|
+
message: "API Token:",
|
|
1728
|
+
validate: (value) => value.length > 0 ? true : "API token cannot be empty"
|
|
1729
|
+
});
|
|
1730
|
+
const tokenExpiry = await input({
|
|
1731
|
+
message: "Token expiry date (YYYY-MM-DD, optional):",
|
|
1732
|
+
default: "",
|
|
1733
|
+
validate: (value) => {
|
|
1734
|
+
if (!value) return true;
|
|
1735
|
+
const date = new Date(value);
|
|
1736
|
+
return !isNaN(date.getTime()) ? true : "Please enter a valid date (YYYY-MM-DD)";
|
|
1737
|
+
}
|
|
1738
|
+
});
|
|
1739
|
+
const auth = Buffer.from(`${email}:${apiToken}`).toString("base64");
|
|
1740
|
+
const response = await fetch("https://api.bitbucket.org/2.0/user", {
|
|
1741
|
+
headers: { Authorization: `Basic ${auth}` }
|
|
1742
|
+
});
|
|
1743
|
+
if (!response.ok) {
|
|
1744
|
+
logger.log("");
|
|
1745
|
+
logger.log(
|
|
1746
|
+
boxen(
|
|
1747
|
+
theme.error("\u2717 Authentication Failed") + "\n\nInvalid email or API token",
|
|
1748
|
+
boxStyles.error
|
|
1749
|
+
)
|
|
1750
|
+
);
|
|
1751
|
+
logger.log("");
|
|
1752
|
+
process.exit(1);
|
|
1753
|
+
}
|
|
1754
|
+
const user = await response.json();
|
|
1755
|
+
const credentials = {
|
|
1756
|
+
accessToken: apiToken,
|
|
1757
|
+
username: email
|
|
1758
|
+
// Store email in username field
|
|
1759
|
+
};
|
|
1760
|
+
if (tokenExpiry) {
|
|
1761
|
+
const expiryDate = new Date(tokenExpiry);
|
|
1762
|
+
credentials.expiresAt = expiryDate.getTime();
|
|
1763
|
+
}
|
|
1764
|
+
await storageService.setServiceCredentials("bitbucket", credentials);
|
|
1765
|
+
logger.log("");
|
|
1766
|
+
logger.log(
|
|
1767
|
+
boxen(
|
|
1768
|
+
theme.success("\u2713 Successfully authenticated with Bitbucket") + `
|
|
1769
|
+
|
|
1770
|
+
Email: ${email}
|
|
1771
|
+
User: ${user.display_name}
|
|
1772
|
+
` + (tokenExpiry ? `Expires: ${tokenExpiry}` : ""),
|
|
1773
|
+
boxStyles.success
|
|
1774
|
+
)
|
|
1775
|
+
);
|
|
1776
|
+
logger.log("");
|
|
1777
|
+
} catch (error) {
|
|
1778
|
+
const err = error;
|
|
1779
|
+
logger.log("");
|
|
1780
|
+
logger.log(
|
|
1781
|
+
boxen(
|
|
1782
|
+
theme.error("\u2717 Authentication Failed") + "\n\n" + (err.message || "Unknown error"),
|
|
1783
|
+
boxStyles.error
|
|
1784
|
+
)
|
|
1785
|
+
);
|
|
1786
|
+
logger.log("");
|
|
1787
|
+
process.exit(1);
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1703
1790
|
|
|
1704
1791
|
// src/commands/sync.ts
|
|
1705
1792
|
init_esm_shims();
|
|
@@ -1720,6 +1807,7 @@ import boxen6 from "boxen";
|
|
|
1720
1807
|
// src/utils/source-detector.ts
|
|
1721
1808
|
init_esm_shims();
|
|
1722
1809
|
init_errors();
|
|
1810
|
+
init_storage_service();
|
|
1723
1811
|
import { exec as exec2 } from "child_process";
|
|
1724
1812
|
import { promisify as promisify2 } from "util";
|
|
1725
1813
|
var execAsync2 = promisify2(exec2);
|
|
@@ -1821,6 +1909,8 @@ var SourceDetector = class {
|
|
|
1821
1909
|
if (type === "github") {
|
|
1822
1910
|
await execAsync2("command gh auth status");
|
|
1823
1911
|
return true;
|
|
1912
|
+
} else if (type === "bitbucket" || type === "atlassian") {
|
|
1913
|
+
return await storageService.isServiceAuthenticated("bitbucket");
|
|
1824
1914
|
}
|
|
1825
1915
|
return false;
|
|
1826
1916
|
} catch {
|
|
@@ -2318,6 +2408,288 @@ var GitHubSyncAdapter = class {
|
|
|
2318
2408
|
};
|
|
2319
2409
|
var githubSyncAdapter = new GitHubSyncAdapter();
|
|
2320
2410
|
|
|
2411
|
+
// src/sync/bitbucket-adapter.ts
|
|
2412
|
+
init_esm_shims();
|
|
2413
|
+
|
|
2414
|
+
// src/services/bitbucket.service.ts
|
|
2415
|
+
init_esm_shims();
|
|
2416
|
+
init_errors();
|
|
2417
|
+
init_logger();
|
|
2418
|
+
init_storage_service();
|
|
2419
|
+
import { exec as exec4 } from "child_process";
|
|
2420
|
+
import { promisify as promisify4 } from "util";
|
|
2421
|
+
var execAsync4 = promisify4(exec4);
|
|
2422
|
+
var BitbucketService = class {
|
|
2423
|
+
BITBUCKET_API_BASE = "https://api.bitbucket.org/2.0";
|
|
2424
|
+
MAX_DESCRIPTION_LENGTH = 5e3;
|
|
2425
|
+
/**
|
|
2426
|
+
* Get stored Bitbucket credentials
|
|
2427
|
+
*/
|
|
2428
|
+
async getCredentials() {
|
|
2429
|
+
const creds = await storageService.getServiceCredentials("bitbucket");
|
|
2430
|
+
if (!creds || !creds.username || !creds.accessToken) {
|
|
2431
|
+
throw new BitbucketError("Not authenticated with Bitbucket", {
|
|
2432
|
+
hint: "Run: bragduck auth bitbucket"
|
|
2433
|
+
});
|
|
2434
|
+
}
|
|
2435
|
+
if (creds.expiresAt && creds.expiresAt < Date.now()) {
|
|
2436
|
+
throw new BitbucketError("API token has expired", {
|
|
2437
|
+
hint: "Run: bragduck auth bitbucket"
|
|
2438
|
+
});
|
|
2439
|
+
}
|
|
2440
|
+
return {
|
|
2441
|
+
email: creds.username,
|
|
2442
|
+
// username field stores email
|
|
2443
|
+
apiToken: creds.accessToken
|
|
2444
|
+
};
|
|
2445
|
+
}
|
|
2446
|
+
/**
|
|
2447
|
+
* Make authenticated request to Bitbucket API
|
|
2448
|
+
*/
|
|
2449
|
+
async request(endpoint) {
|
|
2450
|
+
const { email, apiToken } = await this.getCredentials();
|
|
2451
|
+
const auth = Buffer.from(`${email}:${apiToken}`).toString("base64");
|
|
2452
|
+
logger.debug(`Bitbucket API: GET ${endpoint}`);
|
|
2453
|
+
const response = await fetch(`${this.BITBUCKET_API_BASE}${endpoint}`, {
|
|
2454
|
+
headers: {
|
|
2455
|
+
Authorization: `Basic ${auth}`,
|
|
2456
|
+
Accept: "application/json"
|
|
2457
|
+
}
|
|
2458
|
+
});
|
|
2459
|
+
if (!response.ok) {
|
|
2460
|
+
const statusText = response.statusText;
|
|
2461
|
+
const status = response.status;
|
|
2462
|
+
if (status === 401) {
|
|
2463
|
+
throw new BitbucketError("Invalid or expired API token", {
|
|
2464
|
+
hint: "Run: bragduck auth bitbucket",
|
|
2465
|
+
originalError: statusText
|
|
2466
|
+
});
|
|
2467
|
+
} else if (status === 403) {
|
|
2468
|
+
throw new BitbucketError("Forbidden - check token permissions", {
|
|
2469
|
+
hint: "Token needs: pullrequest:read, repository:read, account:read",
|
|
2470
|
+
originalError: statusText
|
|
2471
|
+
});
|
|
2472
|
+
} else if (status === 404) {
|
|
2473
|
+
throw new BitbucketError("Repository or resource not found", {
|
|
2474
|
+
originalError: statusText
|
|
2475
|
+
});
|
|
2476
|
+
} else if (status === 429) {
|
|
2477
|
+
throw new BitbucketError("Rate limit exceeded", {
|
|
2478
|
+
hint: "Wait a few minutes before trying again",
|
|
2479
|
+
originalError: statusText
|
|
2480
|
+
});
|
|
2481
|
+
}
|
|
2482
|
+
throw new BitbucketError(`API request failed: ${statusText}`, {
|
|
2483
|
+
originalError: statusText
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
2486
|
+
return response.json();
|
|
2487
|
+
}
|
|
2488
|
+
/**
|
|
2489
|
+
* Extract workspace and repo from git remote URL
|
|
2490
|
+
*/
|
|
2491
|
+
parseRemoteUrl(url) {
|
|
2492
|
+
const match = url.match(/bitbucket\.org[:/]([^/]+)\/([^/.]+)/);
|
|
2493
|
+
if (match && match[1] && match[2]) {
|
|
2494
|
+
return {
|
|
2495
|
+
workspace: match[1],
|
|
2496
|
+
repo: match[2].replace(/\.git$/, "")
|
|
2497
|
+
};
|
|
2498
|
+
}
|
|
2499
|
+
return null;
|
|
2500
|
+
}
|
|
2501
|
+
/**
|
|
2502
|
+
* Get repository info from git remote
|
|
2503
|
+
*/
|
|
2504
|
+
async getRepoFromGit() {
|
|
2505
|
+
try {
|
|
2506
|
+
const { stdout } = await execAsync4("command git remote get-url origin");
|
|
2507
|
+
const remoteUrl = stdout.trim();
|
|
2508
|
+
const parsed = this.parseRemoteUrl(remoteUrl);
|
|
2509
|
+
if (!parsed) {
|
|
2510
|
+
throw new BitbucketError("Could not parse Bitbucket repository from git remote", {
|
|
2511
|
+
hint: "Ensure this is a Bitbucket repository"
|
|
2512
|
+
});
|
|
2513
|
+
}
|
|
2514
|
+
return parsed;
|
|
2515
|
+
} catch (error) {
|
|
2516
|
+
if (error instanceof BitbucketError) {
|
|
2517
|
+
throw error;
|
|
2518
|
+
}
|
|
2519
|
+
throw new GitError("Could not get git remote URL");
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
/**
|
|
2523
|
+
* Validate that this is a Bitbucket repository and credentials work
|
|
2524
|
+
*/
|
|
2525
|
+
async validateBitbucketRepository() {
|
|
2526
|
+
await gitService.validateRepository();
|
|
2527
|
+
const { workspace, repo } = await this.getRepoFromGit();
|
|
2528
|
+
try {
|
|
2529
|
+
await this.request(`/repositories/${workspace}/${repo}`);
|
|
2530
|
+
} catch (error) {
|
|
2531
|
+
if (error instanceof BitbucketError) {
|
|
2532
|
+
throw error;
|
|
2533
|
+
}
|
|
2534
|
+
throw new BitbucketError("Could not access Bitbucket repository via API", {
|
|
2535
|
+
hint: "Check that this is a Bitbucket repository and your credentials are valid",
|
|
2536
|
+
originalError: error instanceof Error ? error.message : String(error)
|
|
2537
|
+
});
|
|
2538
|
+
}
|
|
2539
|
+
}
|
|
2540
|
+
/**
|
|
2541
|
+
* Get repository information
|
|
2542
|
+
*/
|
|
2543
|
+
async getRepositoryInfo() {
|
|
2544
|
+
const { workspace, repo } = await this.getRepoFromGit();
|
|
2545
|
+
const bitbucketRepo = await this.request(
|
|
2546
|
+
`/repositories/${workspace}/${repo}`
|
|
2547
|
+
);
|
|
2548
|
+
return {
|
|
2549
|
+
owner: workspace,
|
|
2550
|
+
name: bitbucketRepo.name,
|
|
2551
|
+
fullName: bitbucketRepo.full_name,
|
|
2552
|
+
url: bitbucketRepo.links.html.href
|
|
2553
|
+
};
|
|
2554
|
+
}
|
|
2555
|
+
/**
|
|
2556
|
+
* Get current user's account ID
|
|
2557
|
+
*/
|
|
2558
|
+
async getCurrentUserAccountId() {
|
|
2559
|
+
const user = await this.request("/user");
|
|
2560
|
+
return user.account_id;
|
|
2561
|
+
}
|
|
2562
|
+
/**
|
|
2563
|
+
* Get current user's username (nickname)
|
|
2564
|
+
*/
|
|
2565
|
+
async getCurrentGitHubUser() {
|
|
2566
|
+
try {
|
|
2567
|
+
const user = await this.request("/user");
|
|
2568
|
+
return user.nickname;
|
|
2569
|
+
} catch {
|
|
2570
|
+
return null;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
/**
|
|
2574
|
+
* Fetch merged pull requests with optional filtering
|
|
2575
|
+
*/
|
|
2576
|
+
async getMergedPRs(options = {}) {
|
|
2577
|
+
const { workspace, repo } = await this.getRepoFromGit();
|
|
2578
|
+
const queries = ['state="MERGED"'];
|
|
2579
|
+
if (options.days) {
|
|
2580
|
+
const since = /* @__PURE__ */ new Date();
|
|
2581
|
+
since.setDate(since.getDate() - options.days);
|
|
2582
|
+
queries.push(`updated_on>=${since.toISOString()}`);
|
|
2583
|
+
}
|
|
2584
|
+
if (options.author) {
|
|
2585
|
+
queries.push(`author.account_id="${options.author}"`);
|
|
2586
|
+
}
|
|
2587
|
+
const queryString = queries.join(" AND ");
|
|
2588
|
+
const allPRs = [];
|
|
2589
|
+
let endpoint = `/repositories/${workspace}/${repo}/pullrequests?q=${encodeURIComponent(queryString)}&pagelen=100`;
|
|
2590
|
+
while (endpoint) {
|
|
2591
|
+
const response = await this.request(endpoint);
|
|
2592
|
+
allPRs.push(...response.values);
|
|
2593
|
+
logger.debug(
|
|
2594
|
+
`Fetched ${response.values.length} PRs (total: ${allPRs.length})${response.next ? ", fetching next page..." : ""}`
|
|
2595
|
+
);
|
|
2596
|
+
if (options.limit && allPRs.length >= options.limit) {
|
|
2597
|
+
return allPRs.slice(0, options.limit);
|
|
2598
|
+
}
|
|
2599
|
+
if (response.next) {
|
|
2600
|
+
const url = new URL(response.next);
|
|
2601
|
+
endpoint = url.pathname + url.search;
|
|
2602
|
+
} else {
|
|
2603
|
+
endpoint = "";
|
|
2604
|
+
}
|
|
2605
|
+
}
|
|
2606
|
+
return allPRs;
|
|
2607
|
+
}
|
|
2608
|
+
/**
|
|
2609
|
+
* Fetch PRs for the current authenticated user
|
|
2610
|
+
*/
|
|
2611
|
+
async getPRsByCurrentUser(options = {}) {
|
|
2612
|
+
const accountId = await this.getCurrentUserAccountId();
|
|
2613
|
+
return this.getMergedPRs({
|
|
2614
|
+
...options,
|
|
2615
|
+
author: accountId
|
|
2616
|
+
});
|
|
2617
|
+
}
|
|
2618
|
+
/**
|
|
2619
|
+
* Transform Bitbucket PR to GitCommit format
|
|
2620
|
+
*/
|
|
2621
|
+
transformPRToCommit(pr) {
|
|
2622
|
+
let message = pr.title;
|
|
2623
|
+
if (pr.description) {
|
|
2624
|
+
const truncatedDesc = pr.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
|
|
2625
|
+
message = `${pr.title}
|
|
2626
|
+
|
|
2627
|
+
${truncatedDesc}`;
|
|
2628
|
+
}
|
|
2629
|
+
return {
|
|
2630
|
+
sha: `pr-${pr.id}`,
|
|
2631
|
+
message,
|
|
2632
|
+
author: pr.author.nickname,
|
|
2633
|
+
authorEmail: "",
|
|
2634
|
+
// Not available in Bitbucket API
|
|
2635
|
+
date: pr.created_on,
|
|
2636
|
+
url: pr.links.html.href,
|
|
2637
|
+
diffStats: {
|
|
2638
|
+
filesChanged: 0,
|
|
2639
|
+
// Would require separate API call to diffstat endpoint
|
|
2640
|
+
insertions: 0,
|
|
2641
|
+
deletions: 0
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
}
|
|
2645
|
+
};
|
|
2646
|
+
var bitbucketService = new BitbucketService();
|
|
2647
|
+
|
|
2648
|
+
// src/sync/bitbucket-adapter.ts
|
|
2649
|
+
var BitbucketSyncAdapter = class {
|
|
2650
|
+
name = "bitbucket";
|
|
2651
|
+
async validate() {
|
|
2652
|
+
await bitbucketService.validateBitbucketRepository();
|
|
2653
|
+
}
|
|
2654
|
+
async getRepositoryInfo() {
|
|
2655
|
+
const info = await bitbucketService.getRepositoryInfo();
|
|
2656
|
+
return {
|
|
2657
|
+
owner: info.owner,
|
|
2658
|
+
name: info.name,
|
|
2659
|
+
fullName: info.fullName,
|
|
2660
|
+
url: info.url
|
|
2661
|
+
};
|
|
2662
|
+
}
|
|
2663
|
+
async fetchWorkItems(options) {
|
|
2664
|
+
let prs;
|
|
2665
|
+
if (options.author) {
|
|
2666
|
+
prs = await bitbucketService.getMergedPRs({
|
|
2667
|
+
days: options.days,
|
|
2668
|
+
limit: options.limit,
|
|
2669
|
+
author: options.author
|
|
2670
|
+
});
|
|
2671
|
+
} else {
|
|
2672
|
+
prs = await bitbucketService.getPRsByCurrentUser({
|
|
2673
|
+
days: options.days,
|
|
2674
|
+
limit: options.limit
|
|
2675
|
+
});
|
|
2676
|
+
}
|
|
2677
|
+
return prs.map((pr) => bitbucketService.transformPRToCommit(pr));
|
|
2678
|
+
}
|
|
2679
|
+
async isAuthenticated() {
|
|
2680
|
+
try {
|
|
2681
|
+
await bitbucketService.validateBitbucketRepository();
|
|
2682
|
+
return true;
|
|
2683
|
+
} catch {
|
|
2684
|
+
return false;
|
|
2685
|
+
}
|
|
2686
|
+
}
|
|
2687
|
+
async getCurrentUser() {
|
|
2688
|
+
return bitbucketService.getCurrentGitHubUser();
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
var bitbucketSyncAdapter = new BitbucketSyncAdapter();
|
|
2692
|
+
|
|
2321
2693
|
// src/sync/adapter-factory.ts
|
|
2322
2694
|
var AdapterFactory = class {
|
|
2323
2695
|
/**
|
|
@@ -2327,9 +2699,11 @@ var AdapterFactory = class {
|
|
|
2327
2699
|
switch (source) {
|
|
2328
2700
|
case "github":
|
|
2329
2701
|
return githubSyncAdapter;
|
|
2330
|
-
case "gitlab":
|
|
2331
2702
|
case "bitbucket":
|
|
2332
2703
|
case "atlassian":
|
|
2704
|
+
return bitbucketSyncAdapter;
|
|
2705
|
+
// Bitbucket Cloud and Server use same adapter
|
|
2706
|
+
case "gitlab":
|
|
2333
2707
|
throw new Error(`${source} adapter not yet implemented`);
|
|
2334
2708
|
default:
|
|
2335
2709
|
throw new Error(`Unknown source type: ${source}`);
|
|
@@ -2339,7 +2713,7 @@ var AdapterFactory = class {
|
|
|
2339
2713
|
* Check if adapter is available for source
|
|
2340
2714
|
*/
|
|
2341
2715
|
static isSupported(source) {
|
|
2342
|
-
return source === "github";
|
|
2716
|
+
return source === "github" || source === "bitbucket" || source === "atlassian";
|
|
2343
2717
|
}
|
|
2344
2718
|
};
|
|
2345
2719
|
|
|
@@ -2479,7 +2853,7 @@ init_logger();
|
|
|
2479
2853
|
|
|
2480
2854
|
// src/ui/prompts.ts
|
|
2481
2855
|
init_esm_shims();
|
|
2482
|
-
import { checkbox, confirm, input, select, editor } from "@inquirer/prompts";
|
|
2856
|
+
import { checkbox, confirm, input as input2, select, editor } from "@inquirer/prompts";
|
|
2483
2857
|
import boxen4 from "boxen";
|
|
2484
2858
|
|
|
2485
2859
|
// src/ui/formatters.ts
|
|
@@ -2641,7 +3015,7 @@ async function promptDaysToScan(defaultDays = 30) {
|
|
|
2641
3015
|
default: "30"
|
|
2642
3016
|
});
|
|
2643
3017
|
if (selected === "custom") {
|
|
2644
|
-
const customDays = await
|
|
3018
|
+
const customDays = await input2({
|
|
2645
3019
|
message: "Enter number of days:",
|
|
2646
3020
|
default: defaultDays.toString(),
|
|
2647
3021
|
validate: (value) => {
|
|
@@ -2777,7 +3151,7 @@ ${theme.label("PR Link")} ${colors.link(prUrl)}`;
|
|
|
2777
3151
|
let editedBrag = { ...currentBrag };
|
|
2778
3152
|
if (action === "edit-title" || action === "edit-both") {
|
|
2779
3153
|
console.log("");
|
|
2780
|
-
const newTitle = await
|
|
3154
|
+
const newTitle = await input2({
|
|
2781
3155
|
message: "Enter new title:",
|
|
2782
3156
|
default: currentBrag.refined_title
|
|
2783
3157
|
});
|
|
@@ -3784,7 +4158,7 @@ var packageJsonPath = join7(__dirname6, "../../package.json");
|
|
|
3784
4158
|
var packageJson = JSON.parse(readFileSync5(packageJsonPath, "utf-8"));
|
|
3785
4159
|
var program = new Command();
|
|
3786
4160
|
program.name("bragduck").description("CLI tool for managing developer achievements and brags\nAliases: bd, duck, brag").version(packageJson.version, "-v, --version", "Display version number").helpOption("-h, --help", "Display help information").option("--skip-version-check", "Skip automatic version check on startup").option("--debug", "Enable debug mode (shows detailed logs)");
|
|
3787
|
-
program.command("auth [subcommand]").description("Manage authentication (subcommands: login, status)").action(async (subcommand) => {
|
|
4161
|
+
program.command("auth [subcommand]").description("Manage authentication (subcommands: login, status, bitbucket)").action(async (subcommand) => {
|
|
3788
4162
|
try {
|
|
3789
4163
|
await authCommand(subcommand);
|
|
3790
4164
|
} catch (error) {
|