@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.
@@ -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(`OAuth callback server listening on http://127.0.0.1:${port}${OAUTH_CONFIG.CALLBACK_PATH}`);
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
- `Failed to open browser automatically. Please open this URL manually:
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
- const extendedOptions = options;
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 headers = {
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
- headers.Authorization = `Bearer ${token}`;
1093
+ newHeaders.Authorization = `Bearer ${token}`;
1080
1094
  }
1081
1095
  if (options.method && ["POST", "PUT", "PATCH"].includes(options.method)) {
1082
- headers["Content-Type"] = "application/json";
1096
+ newHeaders["Content-Type"] = "application/json";
1083
1097
  }
1084
- options.headers = 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 ({ response, options }) => {
1105
+ onResponseError: async ({ request, response }) => {
1092
1106
  const status = response.status;
1093
- const extendedOptions = options;
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('Your session has expired. Please run "bragduck init" to login again.');
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 commits using AI
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
- API_ENDPOINTS.COMMITS.REFINE,
1159
- {
1160
- method: "POST",
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
- API_ENDPOINTS.BRAGS.CREATE,
1179
- {
1180
- method: "POST",
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(`Successfully fetched ${response.brags.length} brags (total: ${response.total})`);
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
- API_ENDPOINTS.VERSION,
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(`${chalk3.yellow("Not currently authenticated")}
1445
+ boxen2(
1446
+ `${chalk3.yellow("Not currently authenticated")}
1399
1447
 
1400
- ${chalk3.dim("Nothing to logout from")}`, {
1401
- padding: 1,
1402
- margin: 1,
1403
- borderStyle: "round",
1404
- borderColor: "yellow"
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(`Commit ${sha}: ${stats.filesChanged} files, +${stats.insertions} -${stats.deletions}`);
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(commits) {
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
- commits.forEach((commit, index) => {
2159
+ brags.forEach((brag, index) => {
2160
+ const isNewBragType = !("sha" in brag);
2102
2161
  let displaySha;
2103
- if (commit.sha.startsWith("pr-")) {
2104
- displaySha = commit.sha.replace("pr-", "#");
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 = commit.sha.substring(0, 7);
2177
+ displaySha = `#${index + 1}`;
2107
2178
  }
2108
- const original = commit.original_message.split("\n")[0] || "";
2109
- const title = commit.refined_title;
2110
- const description = commit.refined_description.length > 100 ? commit.refined_description.substring(0, 97) + "..." : commit.refined_description;
2111
- const tags = (commit.suggested_tags || []).join(", ") || "none";
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
- { name: "By date (newest first)", value: "date", description: "Most recent PRs first" },
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(refinedCommits) {
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 < refinedCommits.length; i++) {
2231
- const commit = refinedCommits[i];
2305
+ for (let i = 0; i < refinedBrags.length; i++) {
2306
+ const brag = refinedBrags[i];
2232
2307
  const current = i + 1;
2233
- const total = refinedCommits.length;
2234
- const displaySha = commit.sha.startsWith("pr-") ? commit.sha.replace("pr-", "#") : commit.sha.substring(0, 7);
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(commit.refined_title)}
2323
+ ${theme.label("Title")} ${colors.white(brag.refined_title)}
2238
2324
 
2239
2325
  ${theme.label("Description")}
2240
- ${colors.white(commit.refined_description)}
2326
+ ${colors.white(brag.refined_description)}
2241
2327
 
2242
- ${theme.label("Tags")} ${colors.primary((commit.suggested_tags || []).join(", ") || "none")}
2328
+ ${theme.label("Tags")} ${colors.primary((brag.suggested_tags || []).join(", ") || "none")}
2243
2329
 
2244
- ${theme.label("Impact Score")} ${colors.highlight(commit.impact_score?.toString() || "N/A")}`;
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 ? [{ name: "\u2713 Accept all remaining", value: "accept-all", description: "Accept this and all remaining brags" }] : [],
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(commit);
2264
- for (let j = i + 1; j < refinedCommits.length; j++) {
2265
- acceptedBrags.push(refinedCommits[j]);
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 editedCommit = { ...commit };
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: commit.refined_title
2368
+ default: brag.refined_title
2277
2369
  });
2278
- editedCommit.refined_title = newTitle;
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: commit.refined_description
2375
+ default: brag.refined_description
2284
2376
  });
2285
- editedCommit.refined_description = newDesc;
2377
+ editedBrag.refined_description = newDesc;
2286
2378
  }
2287
- acceptedBrags.push(editedCommit);
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(2, TOTAL_STEPS, `Fetching merged PRs from the last ${days} days`);
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(prSpinner, 2, TOTAL_STEPS, `Found ${theme.count(commits.length)} PR${commits.length > 1 ? "s" : ""}`);
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.warning("No PRs selected");
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
- commits: selectedCommits.map((c) => ({
2446
- sha: c.sha,
2447
- message: c.message,
2448
- author: c.author,
2588
+ brags: selectedCommits.map((c) => ({
2589
+ text: c.message,
2449
2590
  date: c.date,
2450
- diff_stats: c.diffStats ? {
2451
- files_changed: c.diffStats.filesChanged,
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.refineCommits(refineRequest);
2458
- let refinedCommits = refineResponse.refined_commits;
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(refinedCommits));
2601
+ logger.log(formatRefinedCommitsTable(refinedBrags, selectedCommits));
2464
2602
  logger.log("");
2465
- const acceptedBrags = await promptReviewBrags(refinedCommits);
2603
+ const acceptedBrags = await promptReviewBrags(refinedBrags, selectedCommits);
2466
2604
  if (acceptedBrags.length === 0) {
2467
- logger.warning("No brags selected for creation");
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.find((c) => c.sha === refined.sha);
2618
+ brags: acceptedBrags.map((refined, index) => {
2619
+ const originalCommit = selectedCommits[index];
2480
2620
  return {
2481
- commit_sha: refined.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: originalCommit?.date || (/* @__PURE__ */ new Date()).toISOString(),
2487
- commit_url: refined.commit_url,
2488
- impact_score: refined.impact_score,
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(createSpinner2, 4, TOTAL_STEPS, `Created ${theme.count(createResponse.created)} brag${createResponse.created > 1 ? "s" : ""}`);
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(theme.secondary("Run ") + theme.command("bragduck scan") + theme.secondary(" to create your first brag!"));
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
  }