@bragduck/cli 2.0.3 → 2.1.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 +264 -111
- package/dist/bin/bragduck.js.map +1 -1
- package/dist/index.js +93 -46
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/bin/bragduck.js
CHANGED
|
@@ -29,7 +29,7 @@ var init_constants = __esm({
|
|
|
29
29
|
init_esm_shims();
|
|
30
30
|
__filename = fileURLToPath2(import.meta.url);
|
|
31
31
|
__dirname = dirname(__filename);
|
|
32
|
-
config({ path: join(__dirname, "..", "..", ".env") });
|
|
32
|
+
config({ path: join(__dirname, "..", "..", ".env"), debug: false, quiet: true });
|
|
33
33
|
APP_NAME = "bragduck";
|
|
34
34
|
CONFIG_KEYS = {
|
|
35
35
|
DEFAULT_COMMIT_DAYS: "defaultCommitDays",
|
|
@@ -52,14 +52,21 @@ var init_constants = __esm({
|
|
|
52
52
|
INITIATE: "/v1/auth/cli/initiate",
|
|
53
53
|
TOKEN: "/v1/auth/cli/token"
|
|
54
54
|
},
|
|
55
|
-
COMMITS: {
|
|
56
|
-
REFINE: "/v1/commits/refine"
|
|
57
|
-
},
|
|
58
55
|
BRAGS: {
|
|
59
56
|
CREATE: "/v1/brags",
|
|
60
|
-
LIST: "/v1/brags"
|
|
57
|
+
LIST: "/v1/brags",
|
|
58
|
+
REFINE: "/v1/brags/refine"
|
|
59
|
+
},
|
|
60
|
+
SUBSCRIPTION: {
|
|
61
|
+
STATUS: "/v1/subscriptions/status"
|
|
61
62
|
},
|
|
62
|
-
VERSION: "/v1/cli/version"
|
|
63
|
+
VERSION: "/v1/cli/version",
|
|
64
|
+
/**
|
|
65
|
+
* @deprecated Use BRAGS.REFINE instead
|
|
66
|
+
*/
|
|
67
|
+
COMMITS: {
|
|
68
|
+
REFINE: "/v1/commits/refine"
|
|
69
|
+
}
|
|
63
70
|
};
|
|
64
71
|
ENCRYPTION_CONFIG = {
|
|
65
72
|
ALGORITHM: "aes-256-gcm",
|
|
@@ -522,7 +529,9 @@ async function startOAuthCallbackServer(expectedState) {
|
|
|
522
529
|
reject(new OAuthError(`OAuth server error: ${error.message}`));
|
|
523
530
|
});
|
|
524
531
|
server.listen(port, "127.0.0.1", () => {
|
|
525
|
-
logger.debug(
|
|
532
|
+
logger.debug(
|
|
533
|
+
`OAuth callback server listening on http://127.0.0.1:${port}${OAUTH_CONFIG.CALLBACK_PATH}`
|
|
534
|
+
);
|
|
526
535
|
});
|
|
527
536
|
timeoutId = globalThis.setTimeout(() => {
|
|
528
537
|
logger.debug("OAuth callback timeout");
|
|
@@ -683,10 +692,8 @@ async function openBrowser(url) {
|
|
|
683
692
|
logger.debug("Browser opened successfully");
|
|
684
693
|
} catch (error) {
|
|
685
694
|
logger.debug(`Failed to open browser: ${error}`);
|
|
686
|
-
throw new Error(
|
|
687
|
-
|
|
688
|
-
${url}`
|
|
689
|
-
);
|
|
695
|
+
throw new Error(`Failed to open browser automatically. Please open this URL manually:
|
|
696
|
+
${url}`);
|
|
690
697
|
}
|
|
691
698
|
}
|
|
692
699
|
var execAsync;
|
|
@@ -1064,35 +1071,40 @@ var init_api_service = __esm({
|
|
|
1064
1071
|
this.client = ofetch2.create({
|
|
1065
1072
|
baseURL: this.baseURL,
|
|
1066
1073
|
// Request interceptor
|
|
1067
|
-
onRequest: async ({ options }) => {
|
|
1068
|
-
|
|
1069
|
-
logger.debug(`API Request: ${options.method} ${extendedOptions.baseURL}${extendedOptions.url}`);
|
|
1074
|
+
onRequest: async ({ request, options }) => {
|
|
1075
|
+
logger.debug(`API Request: ${options.method || "GET"} ${request}`);
|
|
1070
1076
|
const cliVersion = getCliVersion();
|
|
1071
1077
|
const platform = getPlatformInfo();
|
|
1072
1078
|
const userAgent = `BragDuck-CLI/${cliVersion} (${platform})`;
|
|
1073
1079
|
const token = await authService.getAccessToken();
|
|
1074
|
-
const
|
|
1075
|
-
...options.headers,
|
|
1080
|
+
const newHeaders = {
|
|
1076
1081
|
"User-Agent": userAgent
|
|
1077
1082
|
};
|
|
1083
|
+
if (options.headers) {
|
|
1084
|
+
if (typeof options.headers === "object" && !Array.isArray(options.headers)) {
|
|
1085
|
+
Object.entries(options.headers).forEach(([key, value]) => {
|
|
1086
|
+
if (typeof value === "string") {
|
|
1087
|
+
newHeaders[key] = value;
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1078
1092
|
if (token) {
|
|
1079
|
-
|
|
1093
|
+
newHeaders.Authorization = `Bearer ${token}`;
|
|
1080
1094
|
}
|
|
1081
1095
|
if (options.method && ["POST", "PUT", "PATCH"].includes(options.method)) {
|
|
1082
|
-
|
|
1096
|
+
newHeaders["Content-Type"] = "application/json";
|
|
1083
1097
|
}
|
|
1084
|
-
options.headers =
|
|
1098
|
+
options.headers = newHeaders;
|
|
1085
1099
|
},
|
|
1086
1100
|
// Response interceptor for success
|
|
1087
1101
|
onResponse: ({ response }) => {
|
|
1088
1102
|
logger.debug(`API Response: ${response.status} ${response.statusText}`);
|
|
1089
1103
|
},
|
|
1090
1104
|
// Response interceptor for errors
|
|
1091
|
-
onResponseError: async ({
|
|
1105
|
+
onResponseError: async ({ request, response }) => {
|
|
1092
1106
|
const status = response.status;
|
|
1093
|
-
|
|
1094
|
-
const url = `${extendedOptions.baseURL}${extendedOptions.url}`;
|
|
1095
|
-
logger.debug(`API Error: ${status} ${response.statusText} - ${url}`);
|
|
1107
|
+
logger.debug(`API Error: ${status} ${response.statusText} - ${request}`);
|
|
1096
1108
|
if (status === HTTP_STATUS.UNAUTHORIZED) {
|
|
1097
1109
|
logger.debug("Token expired, attempting refresh");
|
|
1098
1110
|
try {
|
|
@@ -1103,7 +1115,9 @@ var init_api_service = __esm({
|
|
|
1103
1115
|
if (error.message === "RETRY_WITH_NEW_TOKEN") {
|
|
1104
1116
|
throw error;
|
|
1105
1117
|
}
|
|
1106
|
-
throw new TokenExpiredError(
|
|
1118
|
+
throw new TokenExpiredError(
|
|
1119
|
+
'Your session has expired. Please run "bragduck init" to login again.'
|
|
1120
|
+
);
|
|
1107
1121
|
}
|
|
1108
1122
|
}
|
|
1109
1123
|
let errorMessage = "An unexpected error occurred";
|
|
@@ -1149,18 +1163,34 @@ var init_api_service = __esm({
|
|
|
1149
1163
|
}
|
|
1150
1164
|
}
|
|
1151
1165
|
/**
|
|
1152
|
-
* Refine
|
|
1166
|
+
* Refine brags using AI
|
|
1167
|
+
*/
|
|
1168
|
+
async refineBrags(request) {
|
|
1169
|
+
logger.debug(`Refining ${request.brags.length} brags`);
|
|
1170
|
+
try {
|
|
1171
|
+
const response = await this.makeRequest(API_ENDPOINTS.BRAGS.REFINE, {
|
|
1172
|
+
method: "POST",
|
|
1173
|
+
body: request
|
|
1174
|
+
});
|
|
1175
|
+
logger.debug(`Successfully refined ${response.refined_brags.length} brags`);
|
|
1176
|
+
return response;
|
|
1177
|
+
} catch (_error) {
|
|
1178
|
+
logger.debug("Failed to refine brags");
|
|
1179
|
+
throw _error;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* @deprecated Use refineBrags() instead. Will be removed in v3.0.0
|
|
1184
|
+
* Refine commits using AI (legacy endpoint)
|
|
1153
1185
|
*/
|
|
1154
1186
|
async refineCommits(request) {
|
|
1187
|
+
logger.debug(`[DEPRECATED] Using legacy refineCommits - migrate to refineBrags`);
|
|
1155
1188
|
logger.debug(`Refining ${request.commits.length} commits`);
|
|
1156
1189
|
try {
|
|
1157
|
-
const response = await this.makeRequest(
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
body: request
|
|
1162
|
-
}
|
|
1163
|
-
);
|
|
1190
|
+
const response = await this.makeRequest(API_ENDPOINTS.COMMITS.REFINE, {
|
|
1191
|
+
method: "POST",
|
|
1192
|
+
body: request
|
|
1193
|
+
});
|
|
1164
1194
|
logger.debug(`Successfully refined ${response.refined_commits.length} commits`);
|
|
1165
1195
|
return response;
|
|
1166
1196
|
} catch (_error) {
|
|
@@ -1174,13 +1204,10 @@ var init_api_service = __esm({
|
|
|
1174
1204
|
async createBrags(request) {
|
|
1175
1205
|
logger.debug(`Creating ${request.brags.length} brags`);
|
|
1176
1206
|
try {
|
|
1177
|
-
const response = await this.makeRequest(
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
body: request
|
|
1182
|
-
}
|
|
1183
|
-
);
|
|
1207
|
+
const response = await this.makeRequest(API_ENDPOINTS.BRAGS.CREATE, {
|
|
1208
|
+
method: "POST",
|
|
1209
|
+
body: request
|
|
1210
|
+
});
|
|
1184
1211
|
logger.debug(`Successfully created ${response.created} brags`);
|
|
1185
1212
|
return response;
|
|
1186
1213
|
} catch (_error) {
|
|
@@ -1209,25 +1236,45 @@ var init_api_service = __esm({
|
|
|
1209
1236
|
const response = await this.makeRequest(url, {
|
|
1210
1237
|
method: "GET"
|
|
1211
1238
|
});
|
|
1212
|
-
logger.debug(
|
|
1239
|
+
logger.debug(
|
|
1240
|
+
`Successfully fetched ${response.brags.length} brags (total: ${response.total})`
|
|
1241
|
+
);
|
|
1213
1242
|
return response;
|
|
1214
1243
|
} catch (_error) {
|
|
1215
1244
|
logger.debug("Failed to list brags");
|
|
1216
1245
|
throw _error;
|
|
1217
1246
|
}
|
|
1218
1247
|
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Get user's subscription status
|
|
1250
|
+
*/
|
|
1251
|
+
async getSubscriptionStatus() {
|
|
1252
|
+
logger.debug(`Fetching subscription status from ${API_ENDPOINTS.SUBSCRIPTION.STATUS}`);
|
|
1253
|
+
try {
|
|
1254
|
+
const response = await this.makeRequest(API_ENDPOINTS.SUBSCRIPTION.STATUS, {
|
|
1255
|
+
method: "GET"
|
|
1256
|
+
});
|
|
1257
|
+
logger.debug(`Subscription API response: ${JSON.stringify(response)}`);
|
|
1258
|
+
const subscriptionData = response.data;
|
|
1259
|
+
logger.debug(
|
|
1260
|
+
`Subscription tier: ${subscriptionData.tier}, status: ${subscriptionData.status}`
|
|
1261
|
+
);
|
|
1262
|
+
return subscriptionData;
|
|
1263
|
+
} catch (error) {
|
|
1264
|
+
logger.debug(`Failed to fetch subscription status: ${error}`);
|
|
1265
|
+
logger.debug(`Error details: ${JSON.stringify(error, null, 2)}`);
|
|
1266
|
+
throw error;
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1219
1269
|
/**
|
|
1220
1270
|
* Check for CLI updates
|
|
1221
1271
|
*/
|
|
1222
1272
|
async checkVersion() {
|
|
1223
1273
|
logger.debug("Checking for CLI updates");
|
|
1224
1274
|
try {
|
|
1225
|
-
const response = await this.makeRequest(
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
method: "GET"
|
|
1229
|
-
}
|
|
1230
|
-
);
|
|
1275
|
+
const response = await this.makeRequest(API_ENDPOINTS.VERSION, {
|
|
1276
|
+
method: "GET"
|
|
1277
|
+
});
|
|
1231
1278
|
logger.debug(`Latest version: ${response.latest_version}`);
|
|
1232
1279
|
return response;
|
|
1233
1280
|
} catch {
|
|
@@ -1395,14 +1442,17 @@ async function logoutCommand() {
|
|
|
1395
1442
|
const isAuthenticated = await authService.isAuthenticated();
|
|
1396
1443
|
if (!isAuthenticated) {
|
|
1397
1444
|
logger.log(
|
|
1398
|
-
boxen2(
|
|
1445
|
+
boxen2(
|
|
1446
|
+
`${chalk3.yellow("Not currently authenticated")}
|
|
1399
1447
|
|
|
1400
|
-
${chalk3.dim("Nothing to logout from")}`,
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1448
|
+
${chalk3.dim("Nothing to logout from")}`,
|
|
1449
|
+
{
|
|
1450
|
+
padding: 1,
|
|
1451
|
+
margin: 1,
|
|
1452
|
+
borderStyle: "round",
|
|
1453
|
+
borderColor: "yellow"
|
|
1454
|
+
}
|
|
1455
|
+
)
|
|
1406
1456
|
);
|
|
1407
1457
|
return;
|
|
1408
1458
|
}
|
|
@@ -1448,6 +1498,13 @@ ${chalk3.dim("Run")} ${chalk3.cyan("bragduck init")} ${chalk3.dim("to login agai
|
|
|
1448
1498
|
init_esm_shims();
|
|
1449
1499
|
import boxen6 from "boxen";
|
|
1450
1500
|
|
|
1501
|
+
// node_modules/@inquirer/core/dist/esm/lib/errors.mjs
|
|
1502
|
+
init_esm_shims();
|
|
1503
|
+
var CancelPromptError = class extends Error {
|
|
1504
|
+
name = "CancelPromptError";
|
|
1505
|
+
message = "Prompt was canceled";
|
|
1506
|
+
};
|
|
1507
|
+
|
|
1451
1508
|
// src/services/github.service.ts
|
|
1452
1509
|
init_esm_shims();
|
|
1453
1510
|
init_errors();
|
|
@@ -1585,7 +1642,9 @@ var GitService = class {
|
|
|
1585
1642
|
insertions: diffSummary.insertions,
|
|
1586
1643
|
deletions: diffSummary.deletions
|
|
1587
1644
|
};
|
|
1588
|
-
logger.debug(
|
|
1645
|
+
logger.debug(
|
|
1646
|
+
`Commit ${sha}: ${stats.filesChanged} files, +${stats.insertions} -${stats.deletions}`
|
|
1647
|
+
);
|
|
1589
1648
|
return stats;
|
|
1590
1649
|
} catch (error) {
|
|
1591
1650
|
if (error.message && error.message.includes("unknown revision")) {
|
|
@@ -1876,6 +1935,7 @@ var githubService = new GitHubService();
|
|
|
1876
1935
|
init_api_service();
|
|
1877
1936
|
init_storage_service();
|
|
1878
1937
|
init_logger();
|
|
1938
|
+
init_browser();
|
|
1879
1939
|
|
|
1880
1940
|
// src/utils/auth-helper.ts
|
|
1881
1941
|
init_esm_shims();
|
|
@@ -2078,14 +2138,12 @@ function formatCommitChoice(commit) {
|
|
|
2078
2138
|
if (commit.diffStats) {
|
|
2079
2139
|
const { filesChanged, insertions, deletions } = commit.diffStats;
|
|
2080
2140
|
sizeIndicator = ` ${getSizeIndicator(insertions, deletions)}`;
|
|
2081
|
-
stats = colors.info(
|
|
2082
|
-
` [${filesChanged} files, ${formatDiffStats(insertions, deletions)}]`
|
|
2083
|
-
);
|
|
2141
|
+
stats = colors.info(` [${filesChanged} files, ${formatDiffStats(insertions, deletions)}]`);
|
|
2084
2142
|
}
|
|
2085
2143
|
return `${displaySha} ${title}${sizeIndicator}${stats}
|
|
2086
2144
|
${author} \u2022 ${date}${bodyPreview}`;
|
|
2087
2145
|
}
|
|
2088
|
-
function formatRefinedCommitsTable(
|
|
2146
|
+
function formatRefinedCommitsTable(brags, selectedCommits) {
|
|
2089
2147
|
const table = new Table({
|
|
2090
2148
|
head: [
|
|
2091
2149
|
colors.primary("SHA"),
|
|
@@ -2098,17 +2156,30 @@ function formatRefinedCommitsTable(commits) {
|
|
|
2098
2156
|
wordWrap: true,
|
|
2099
2157
|
style: tableStyles.default.style
|
|
2100
2158
|
});
|
|
2101
|
-
|
|
2159
|
+
brags.forEach((brag, index) => {
|
|
2160
|
+
const isNewBragType = !("sha" in brag);
|
|
2102
2161
|
let displaySha;
|
|
2103
|
-
if (
|
|
2104
|
-
|
|
2162
|
+
if (isNewBragType && selectedCommits) {
|
|
2163
|
+
const commit = selectedCommits[index];
|
|
2164
|
+
if (commit.sha.startsWith("pr-")) {
|
|
2165
|
+
displaySha = commit.sha.replace("pr-", "#");
|
|
2166
|
+
} else {
|
|
2167
|
+
displaySha = commit.sha.substring(0, 7);
|
|
2168
|
+
}
|
|
2169
|
+
} else if (!isNewBragType) {
|
|
2170
|
+
const commit = brag;
|
|
2171
|
+
if (commit.sha.startsWith("pr-")) {
|
|
2172
|
+
displaySha = commit.sha.replace("pr-", "#");
|
|
2173
|
+
} else {
|
|
2174
|
+
displaySha = commit.sha.substring(0, 7);
|
|
2175
|
+
}
|
|
2105
2176
|
} else {
|
|
2106
|
-
displaySha =
|
|
2177
|
+
displaySha = `#${index + 1}`;
|
|
2107
2178
|
}
|
|
2108
|
-
const original =
|
|
2109
|
-
const title =
|
|
2110
|
-
const description =
|
|
2111
|
-
const tags = (
|
|
2179
|
+
const original = isNewBragType ? typeof brag.original_input === "string" ? brag.original_input.split("\n")[0] || "" : "Raw input" : brag.original_message.split("\n")[0] || "";
|
|
2180
|
+
const title = brag.refined_title;
|
|
2181
|
+
const description = brag.refined_description.length > 100 ? brag.refined_description.substring(0, 97) + "..." : brag.refined_description;
|
|
2182
|
+
const tags = (brag.suggested_tags || []).join(", ") || "none";
|
|
2112
2183
|
const rowNum = colors.infoDim(`${index + 1}.`);
|
|
2113
2184
|
table.push([
|
|
2114
2185
|
`${rowNum} ${colors.highlight(displaySha)}`,
|
|
@@ -2213,7 +2284,11 @@ async function promptDaysToScan(defaultDays = 30) {
|
|
|
2213
2284
|
}
|
|
2214
2285
|
async function promptSortOption() {
|
|
2215
2286
|
const choices = [
|
|
2216
|
-
{
|
|
2287
|
+
{
|
|
2288
|
+
name: "By date (newest first)",
|
|
2289
|
+
value: "date",
|
|
2290
|
+
description: "Most recent PRs first"
|
|
2291
|
+
},
|
|
2217
2292
|
{ name: "By size (largest first)", value: "size", description: "Most lines changed" },
|
|
2218
2293
|
{ name: "By files (most files)", value: "files", description: "Most files changed" },
|
|
2219
2294
|
{ name: "No sorting", value: "none", description: "Keep original order" }
|
|
@@ -2224,24 +2299,35 @@ async function promptSortOption() {
|
|
|
2224
2299
|
default: "date"
|
|
2225
2300
|
});
|
|
2226
2301
|
}
|
|
2227
|
-
async function promptReviewBrags(
|
|
2302
|
+
async function promptReviewBrags(refinedBrags, selectedCommits) {
|
|
2228
2303
|
const acceptedBrags = [];
|
|
2229
2304
|
console.log("\n" + theme.info("Review each brag before creation:") + "\n");
|
|
2230
|
-
for (let i = 0; i <
|
|
2231
|
-
const
|
|
2305
|
+
for (let i = 0; i < refinedBrags.length; i++) {
|
|
2306
|
+
const brag = refinedBrags[i];
|
|
2232
2307
|
const current = i + 1;
|
|
2233
|
-
const total =
|
|
2234
|
-
const
|
|
2308
|
+
const total = refinedBrags.length;
|
|
2309
|
+
const isNewBragType = !("sha" in brag);
|
|
2310
|
+
let displaySha;
|
|
2311
|
+
if (isNewBragType && selectedCommits) {
|
|
2312
|
+
const commit = selectedCommits[i];
|
|
2313
|
+
displaySha = commit.sha.startsWith("pr-") ? commit.sha.replace("pr-", "#") : commit.sha.substring(0, 7);
|
|
2314
|
+
} else if (!isNewBragType) {
|
|
2315
|
+
const commit = brag;
|
|
2316
|
+
displaySha = commit.sha.startsWith("pr-") ? commit.sha.replace("pr-", "#") : commit.sha.substring(0, 7);
|
|
2317
|
+
} else {
|
|
2318
|
+
displaySha = `#${i + 1}`;
|
|
2319
|
+
}
|
|
2320
|
+
const impactScore = isNewBragType ? brag.suggested_impactLevel?.toString() || "N/A" : brag.impact_score?.toString() || "N/A";
|
|
2235
2321
|
const bragDetails = `${theme.step(current, total)} ${colors.highlight(displaySha)}
|
|
2236
2322
|
|
|
2237
|
-
${theme.label("Title")} ${colors.white(
|
|
2323
|
+
${theme.label("Title")} ${colors.white(brag.refined_title)}
|
|
2238
2324
|
|
|
2239
2325
|
${theme.label("Description")}
|
|
2240
|
-
${colors.white(
|
|
2326
|
+
${colors.white(brag.refined_description)}
|
|
2241
2327
|
|
|
2242
|
-
${theme.label("Tags")} ${colors.primary((
|
|
2328
|
+
${theme.label("Tags")} ${colors.primary((brag.suggested_tags || []).join(", ") || "none")}
|
|
2243
2329
|
|
|
2244
|
-
${theme.label("Impact Score")} ${colors.highlight(
|
|
2330
|
+
${theme.label("Impact Score")} ${colors.highlight(impactScore)}`;
|
|
2245
2331
|
console.log(boxen4(bragDetails, boxStyles.info));
|
|
2246
2332
|
console.log("");
|
|
2247
2333
|
const action = await select({
|
|
@@ -2252,7 +2338,13 @@ ${theme.label("Impact Score")} ${colors.highlight(commit.impact_score?.toString(
|
|
|
2252
2338
|
{ name: "\u270E Edit description", value: "edit-desc", description: "Modify the description" },
|
|
2253
2339
|
{ name: "\u270E Edit both", value: "edit-both", description: "Modify title and description" },
|
|
2254
2340
|
{ name: "\u2717 Skip", value: "skip", description: "Skip this brag" },
|
|
2255
|
-
...current < total ? [
|
|
2341
|
+
...current < total ? [
|
|
2342
|
+
{
|
|
2343
|
+
name: "\u2713 Accept all remaining",
|
|
2344
|
+
value: "accept-all",
|
|
2345
|
+
description: "Accept this and all remaining brags"
|
|
2346
|
+
}
|
|
2347
|
+
] : [],
|
|
2256
2348
|
{ name: "\u2717 Cancel", value: "cancel", description: "Cancel and discard all brags" }
|
|
2257
2349
|
]
|
|
2258
2350
|
});
|
|
@@ -2260,31 +2352,31 @@ ${theme.label("Impact Score")} ${colors.highlight(commit.impact_score?.toString(
|
|
|
2260
2352
|
return [];
|
|
2261
2353
|
}
|
|
2262
2354
|
if (action === "accept-all") {
|
|
2263
|
-
acceptedBrags.push(
|
|
2264
|
-
for (let j = i + 1; j <
|
|
2265
|
-
acceptedBrags.push(
|
|
2355
|
+
acceptedBrags.push(brag);
|
|
2356
|
+
for (let j = i + 1; j < refinedBrags.length; j++) {
|
|
2357
|
+
acceptedBrags.push(refinedBrags[j]);
|
|
2266
2358
|
}
|
|
2267
2359
|
break;
|
|
2268
2360
|
}
|
|
2269
2361
|
if (action === "skip") {
|
|
2270
2362
|
continue;
|
|
2271
2363
|
}
|
|
2272
|
-
let
|
|
2364
|
+
let editedBrag = { ...brag };
|
|
2273
2365
|
if (action === "edit-title" || action === "edit-both") {
|
|
2274
2366
|
const newTitle = await input({
|
|
2275
2367
|
message: "Enter new title:",
|
|
2276
|
-
default:
|
|
2368
|
+
default: brag.refined_title
|
|
2277
2369
|
});
|
|
2278
|
-
|
|
2370
|
+
editedBrag.refined_title = newTitle;
|
|
2279
2371
|
}
|
|
2280
2372
|
if (action === "edit-desc" || action === "edit-both") {
|
|
2281
2373
|
const newDesc = await editor({
|
|
2282
2374
|
message: "Edit description (will open your default editor):",
|
|
2283
|
-
default:
|
|
2375
|
+
default: brag.refined_description
|
|
2284
2376
|
});
|
|
2285
|
-
|
|
2377
|
+
editedBrag.refined_description = newDesc;
|
|
2286
2378
|
}
|
|
2287
|
-
acceptedBrags.push(
|
|
2379
|
+
acceptedBrags.push(editedBrag);
|
|
2288
2380
|
}
|
|
2289
2381
|
return acceptedBrags;
|
|
2290
2382
|
}
|
|
@@ -2373,6 +2465,46 @@ async function scanCommand(options = {}) {
|
|
|
2373
2465
|
if (!isAuthenticated) {
|
|
2374
2466
|
process.exit(1);
|
|
2375
2467
|
}
|
|
2468
|
+
logger.debug("Fetching subscription status...");
|
|
2469
|
+
const subscriptionStatus = await apiService.getSubscriptionStatus();
|
|
2470
|
+
logger.debug("Subscription status response:", JSON.stringify(subscriptionStatus, null, 2));
|
|
2471
|
+
logger.debug(
|
|
2472
|
+
`Checking tier: "${subscriptionStatus.tier}" (type: ${typeof subscriptionStatus.tier})`
|
|
2473
|
+
);
|
|
2474
|
+
logger.debug(`Tier === 'FREE': ${subscriptionStatus.tier === "FREE"}`);
|
|
2475
|
+
if (subscriptionStatus.tier === "FREE") {
|
|
2476
|
+
logger.debug("FREE tier detected - blocking scan command");
|
|
2477
|
+
logger.log("");
|
|
2478
|
+
logger.log(
|
|
2479
|
+
boxen6(
|
|
2480
|
+
theme.warning("CLI Access Requires Subscription") + "\n\nThe Bragduck CLI is available for Plus and Pro subscribers.\nUpgrade now to unlock:\n\n \u2022 Automatic PR scanning\n \u2022 AI-powered brag generation\n \u2022 Unlimited brags\n\n" + colors.highlight("Start your free trial today!"),
|
|
2481
|
+
{
|
|
2482
|
+
...boxStyles.warning,
|
|
2483
|
+
padding: 1,
|
|
2484
|
+
margin: 1
|
|
2485
|
+
}
|
|
2486
|
+
)
|
|
2487
|
+
);
|
|
2488
|
+
logger.log("");
|
|
2489
|
+
const shouldOpenBrowser = await promptConfirm(
|
|
2490
|
+
"Open subscription plans in your browser?",
|
|
2491
|
+
true
|
|
2492
|
+
);
|
|
2493
|
+
if (shouldOpenBrowser) {
|
|
2494
|
+
logger.log("");
|
|
2495
|
+
const plansUrl = "https://bragduck.com/app/settings/plans";
|
|
2496
|
+
try {
|
|
2497
|
+
await openBrowser(plansUrl);
|
|
2498
|
+
logger.info(theme.secondary("Opening browser..."));
|
|
2499
|
+
} catch {
|
|
2500
|
+
logger.warning("Could not open browser automatically");
|
|
2501
|
+
logger.info(`Please visit: ${theme.value(plansUrl)}`);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
logger.log("");
|
|
2505
|
+
return;
|
|
2506
|
+
}
|
|
2507
|
+
logger.debug(`Subscription tier "${subscriptionStatus.tier}" - proceeding with scan`);
|
|
2376
2508
|
const repoSpinner = createStepSpinner(1, TOTAL_STEPS, "Validating GitHub repository");
|
|
2377
2509
|
repoSpinner.start();
|
|
2378
2510
|
await githubService.validateGitHubRepository();
|
|
@@ -2390,7 +2522,11 @@ async function scanCommand(options = {}) {
|
|
|
2390
2522
|
days = await promptDaysToScan(defaultDays);
|
|
2391
2523
|
logger.log("");
|
|
2392
2524
|
}
|
|
2393
|
-
const prSpinner = createStepSpinner(
|
|
2525
|
+
const prSpinner = createStepSpinner(
|
|
2526
|
+
2,
|
|
2527
|
+
TOTAL_STEPS,
|
|
2528
|
+
`Fetching merged PRs from the last ${days} days`
|
|
2529
|
+
);
|
|
2394
2530
|
prSpinner.start();
|
|
2395
2531
|
let prs;
|
|
2396
2532
|
if (options.all) {
|
|
@@ -2405,7 +2541,12 @@ async function scanCommand(options = {}) {
|
|
|
2405
2541
|
logger.info("Try increasing the number of days or check your GitHub activity");
|
|
2406
2542
|
return;
|
|
2407
2543
|
}
|
|
2408
|
-
succeedStepSpinner(
|
|
2544
|
+
succeedStepSpinner(
|
|
2545
|
+
prSpinner,
|
|
2546
|
+
2,
|
|
2547
|
+
TOTAL_STEPS,
|
|
2548
|
+
`Found ${theme.count(commits.length)} PR${commits.length > 1 ? "s" : ""}`
|
|
2549
|
+
);
|
|
2409
2550
|
logger.log("");
|
|
2410
2551
|
logger.log(formatCommitStats(commits));
|
|
2411
2552
|
logger.log("");
|
|
@@ -2429,7 +2570,9 @@ async function scanCommand(options = {}) {
|
|
|
2429
2570
|
}
|
|
2430
2571
|
const selectedShas = await promptSelectCommits(sortedCommits);
|
|
2431
2572
|
if (selectedShas.length === 0) {
|
|
2432
|
-
logger.
|
|
2573
|
+
logger.log("");
|
|
2574
|
+
logger.info(theme.secondary("No PRs selected. Scan cancelled."));
|
|
2575
|
+
logger.log("");
|
|
2433
2576
|
return;
|
|
2434
2577
|
}
|
|
2435
2578
|
const selectedCommits = sortedCommits.filter((c) => selectedShas.includes(c.sha));
|
|
@@ -2442,29 +2585,26 @@ async function scanCommand(options = {}) {
|
|
|
2442
2585
|
);
|
|
2443
2586
|
refineSpinner.start();
|
|
2444
2587
|
const refineRequest = {
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
message: c.message,
|
|
2448
|
-
author: c.author,
|
|
2588
|
+
brags: selectedCommits.map((c) => ({
|
|
2589
|
+
text: c.message,
|
|
2449
2590
|
date: c.date,
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
insertions: c.diffStats.insertions,
|
|
2453
|
-
deletions: c.diffStats.deletions
|
|
2454
|
-
} : void 0
|
|
2591
|
+
title: c.message.split("\n")[0]
|
|
2592
|
+
// First line as initial title
|
|
2455
2593
|
}))
|
|
2456
2594
|
};
|
|
2457
|
-
const refineResponse = await apiService.
|
|
2458
|
-
let
|
|
2595
|
+
const refineResponse = await apiService.refineBrags(refineRequest);
|
|
2596
|
+
let refinedBrags = refineResponse.refined_brags;
|
|
2459
2597
|
succeedStepSpinner(refineSpinner, 3, TOTAL_STEPS, "PRs refined successfully");
|
|
2460
2598
|
logger.log("");
|
|
2461
2599
|
logger.info("Preview of refined brags:");
|
|
2462
2600
|
logger.log("");
|
|
2463
|
-
logger.log(formatRefinedCommitsTable(
|
|
2601
|
+
logger.log(formatRefinedCommitsTable(refinedBrags, selectedCommits));
|
|
2464
2602
|
logger.log("");
|
|
2465
|
-
const acceptedBrags = await promptReviewBrags(
|
|
2603
|
+
const acceptedBrags = await promptReviewBrags(refinedBrags, selectedCommits);
|
|
2466
2604
|
if (acceptedBrags.length === 0) {
|
|
2467
|
-
logger.
|
|
2605
|
+
logger.log("");
|
|
2606
|
+
logger.info(theme.secondary("No brags selected for creation. Scan cancelled."));
|
|
2607
|
+
logger.log("");
|
|
2468
2608
|
return;
|
|
2469
2609
|
}
|
|
2470
2610
|
logger.log("");
|
|
@@ -2475,26 +2615,37 @@ async function scanCommand(options = {}) {
|
|
|
2475
2615
|
);
|
|
2476
2616
|
createSpinner2.start();
|
|
2477
2617
|
const createRequest = {
|
|
2478
|
-
brags: acceptedBrags.map((refined) => {
|
|
2479
|
-
const originalCommit = selectedCommits
|
|
2618
|
+
brags: acceptedBrags.map((refined, index) => {
|
|
2619
|
+
const originalCommit = selectedCommits[index];
|
|
2480
2620
|
return {
|
|
2481
|
-
commit_sha:
|
|
2621
|
+
commit_sha: originalCommit?.sha || `brag-${index}`,
|
|
2482
2622
|
title: refined.refined_title,
|
|
2483
2623
|
description: refined.refined_description,
|
|
2484
2624
|
tags: refined.suggested_tags,
|
|
2485
2625
|
repository: repoInfo.url,
|
|
2486
|
-
date:
|
|
2487
|
-
commit_url:
|
|
2488
|
-
impact_score: refined.
|
|
2626
|
+
date: refined.date,
|
|
2627
|
+
commit_url: originalCommit?.url || "",
|
|
2628
|
+
impact_score: refined.suggested_impactLevel,
|
|
2489
2629
|
impact_description: refined.impact_description
|
|
2490
2630
|
};
|
|
2491
2631
|
})
|
|
2492
2632
|
};
|
|
2493
2633
|
const createResponse = await apiService.createBrags(createRequest);
|
|
2494
|
-
succeedStepSpinner(
|
|
2634
|
+
succeedStepSpinner(
|
|
2635
|
+
createSpinner2,
|
|
2636
|
+
4,
|
|
2637
|
+
TOTAL_STEPS,
|
|
2638
|
+
`Created ${theme.count(createResponse.created)} brag${createResponse.created > 1 ? "s" : ""}`
|
|
2639
|
+
);
|
|
2495
2640
|
logger.log("");
|
|
2496
2641
|
logger.log(boxen6(formatSuccessMessage(createResponse.created), boxStyles.success));
|
|
2497
2642
|
} catch (error) {
|
|
2643
|
+
if (error instanceof CancelPromptError) {
|
|
2644
|
+
logger.log("");
|
|
2645
|
+
logger.info(theme.secondary("Scan cancelled."));
|
|
2646
|
+
logger.log("");
|
|
2647
|
+
return;
|
|
2648
|
+
}
|
|
2498
2649
|
const err = error;
|
|
2499
2650
|
logger.log("");
|
|
2500
2651
|
logger.log(boxen6(formatErrorMessage(err.message, getErrorHint2(err)), boxStyles.error));
|
|
@@ -2551,7 +2702,9 @@ async function listCommand(options = {}) {
|
|
|
2551
2702
|
if (search || tags) {
|
|
2552
2703
|
logger.info("Try adjusting your filters or run without filters to see all brags");
|
|
2553
2704
|
} else {
|
|
2554
|
-
logger.info(
|
|
2705
|
+
logger.info(
|
|
2706
|
+
theme.secondary("Run ") + theme.command("bragduck scan") + theme.secondary(" to create your first brag!")
|
|
2707
|
+
);
|
|
2555
2708
|
}
|
|
2556
2709
|
return;
|
|
2557
2710
|
}
|