@bragduck/cli 2.0.2 → 2.0.23
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 +701 -272
- package/dist/bin/bragduck.js.map +1 -1
- package/dist/index.js +118 -70
- 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"
|
|
61
59
|
},
|
|
62
|
-
|
|
60
|
+
SUBSCRIPTION: {
|
|
61
|
+
STATUS: "/v1/subscriptions/status"
|
|
62
|
+
},
|
|
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",
|
|
@@ -312,11 +319,13 @@ var init_errors = __esm({
|
|
|
312
319
|
"use strict";
|
|
313
320
|
init_esm_shims();
|
|
314
321
|
BragduckError = class extends Error {
|
|
322
|
+
code;
|
|
323
|
+
details;
|
|
315
324
|
constructor(message, code, details) {
|
|
316
325
|
super(message);
|
|
326
|
+
this.name = "BragduckError";
|
|
317
327
|
this.code = code;
|
|
318
328
|
this.details = details;
|
|
319
|
-
this.name = "BragduckError";
|
|
320
329
|
Error.captureStackTrace(this, this.constructor);
|
|
321
330
|
}
|
|
322
331
|
};
|
|
@@ -333,10 +342,11 @@ var init_errors = __esm({
|
|
|
333
342
|
}
|
|
334
343
|
};
|
|
335
344
|
ApiError = class extends BragduckError {
|
|
345
|
+
statusCode;
|
|
336
346
|
constructor(message, statusCode, details) {
|
|
337
347
|
super(message, "API_ERROR", details);
|
|
338
|
-
this.statusCode = statusCode;
|
|
339
348
|
this.name = "ApiError";
|
|
349
|
+
this.statusCode = statusCode;
|
|
340
350
|
}
|
|
341
351
|
};
|
|
342
352
|
NetworkError = class extends BragduckError {
|
|
@@ -439,7 +449,7 @@ async function findAvailablePort() {
|
|
|
439
449
|
testServer.listen(port, "127.0.0.1");
|
|
440
450
|
});
|
|
441
451
|
return port;
|
|
442
|
-
} catch
|
|
452
|
+
} catch {
|
|
443
453
|
continue;
|
|
444
454
|
}
|
|
445
455
|
}
|
|
@@ -450,10 +460,10 @@ async function startOAuthCallbackServer(expectedState) {
|
|
|
450
460
|
const timeout = OAUTH_CONFIG.TIMEOUT_MS;
|
|
451
461
|
return new Promise((resolve, reject) => {
|
|
452
462
|
let server = null;
|
|
453
|
-
let timeoutId;
|
|
463
|
+
let timeoutId = null;
|
|
454
464
|
const cleanup = () => {
|
|
455
465
|
if (timeoutId) {
|
|
456
|
-
clearTimeout(timeoutId);
|
|
466
|
+
globalThis.clearTimeout(timeoutId);
|
|
457
467
|
}
|
|
458
468
|
if (server) {
|
|
459
469
|
if (typeof server.closeAllConnections === "function") {
|
|
@@ -499,7 +509,7 @@ async function startOAuthCallbackServer(expectedState) {
|
|
|
499
509
|
}
|
|
500
510
|
res.writeHead(200, { "Content-Type": "text/html" });
|
|
501
511
|
res.end(SUCCESS_HTML);
|
|
502
|
-
setTimeout(() => {
|
|
512
|
+
globalThis.setTimeout(() => {
|
|
503
513
|
cleanup();
|
|
504
514
|
resolve({
|
|
505
515
|
code: String(code),
|
|
@@ -519,9 +529,11 @@ async function startOAuthCallbackServer(expectedState) {
|
|
|
519
529
|
reject(new OAuthError(`OAuth server error: ${error.message}`));
|
|
520
530
|
});
|
|
521
531
|
server.listen(port, "127.0.0.1", () => {
|
|
522
|
-
logger.debug(
|
|
532
|
+
logger.debug(
|
|
533
|
+
`OAuth callback server listening on http://127.0.0.1:${port}${OAUTH_CONFIG.CALLBACK_PATH}`
|
|
534
|
+
);
|
|
523
535
|
});
|
|
524
|
-
timeoutId = setTimeout(() => {
|
|
536
|
+
timeoutId = globalThis.setTimeout(() => {
|
|
525
537
|
logger.debug("OAuth callback timeout");
|
|
526
538
|
cleanup();
|
|
527
539
|
reject(new OAuthError("Authentication timeout - no callback received within 2 minutes"));
|
|
@@ -680,10 +692,8 @@ async function openBrowser(url) {
|
|
|
680
692
|
logger.debug("Browser opened successfully");
|
|
681
693
|
} catch (error) {
|
|
682
694
|
logger.debug(`Failed to open browser: ${error}`);
|
|
683
|
-
throw new Error(
|
|
684
|
-
|
|
685
|
-
${url}`
|
|
686
|
-
);
|
|
695
|
+
throw new Error(`Failed to open browser automatically. Please open this URL manually:
|
|
696
|
+
${url}`);
|
|
687
697
|
}
|
|
688
698
|
}
|
|
689
699
|
var execAsync;
|
|
@@ -699,7 +709,7 @@ var init_browser = __esm({
|
|
|
699
709
|
// src/services/auth.service.ts
|
|
700
710
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
701
711
|
import { readFileSync as readFileSync2 } from "fs";
|
|
702
|
-
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
712
|
+
import { fileURLToPath as fileURLToPath3, URLSearchParams } from "url";
|
|
703
713
|
import { dirname as dirname2, join as join3 } from "path";
|
|
704
714
|
import { ofetch } from "ofetch";
|
|
705
715
|
function getUserAgent() {
|
|
@@ -710,7 +720,7 @@ function getUserAgent() {
|
|
|
710
720
|
const platform = process.platform;
|
|
711
721
|
const arch = process.arch;
|
|
712
722
|
return `BragDuck-CLI/${version2} (${platform}-${arch})`;
|
|
713
|
-
} catch
|
|
723
|
+
} catch {
|
|
714
724
|
logger.debug("Failed to read package.json version");
|
|
715
725
|
return "BragDuck-CLI/2.0.0";
|
|
716
726
|
}
|
|
@@ -808,7 +818,7 @@ var init_auth_service = __esm({
|
|
|
808
818
|
const serverPromise = startOAuthCallbackServer(state);
|
|
809
819
|
try {
|
|
810
820
|
await openBrowser(authUrl);
|
|
811
|
-
} catch
|
|
821
|
+
} catch {
|
|
812
822
|
logger.warning("Could not open browser automatically");
|
|
813
823
|
logger.info(`Please open this URL in your browser:`);
|
|
814
824
|
logger.log(authUrl);
|
|
@@ -927,7 +937,7 @@ function getCurrentVersion() {
|
|
|
927
937
|
const packageJsonPath2 = join5(__dirname4, "../../package.json");
|
|
928
938
|
const packageJson2 = JSON.parse(readFileSync3(packageJsonPath2, "utf-8"));
|
|
929
939
|
return packageJson2.version;
|
|
930
|
-
} catch
|
|
940
|
+
} catch {
|
|
931
941
|
logger.debug("Failed to read package.json version");
|
|
932
942
|
return "1.0.0";
|
|
933
943
|
}
|
|
@@ -1025,13 +1035,14 @@ var init_version = __esm({
|
|
|
1025
1035
|
import { ofetch as ofetch2 } from "ofetch";
|
|
1026
1036
|
import { readFileSync as readFileSync4 } from "fs";
|
|
1027
1037
|
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
1038
|
+
import { URLSearchParams as URLSearchParams2 } from "url";
|
|
1028
1039
|
import { dirname as dirname4, join as join6 } from "path";
|
|
1029
1040
|
function getCliVersion() {
|
|
1030
1041
|
try {
|
|
1031
1042
|
const packageJsonPath2 = join6(__dirname5, "../../package.json");
|
|
1032
1043
|
const packageJson2 = JSON.parse(readFileSync4(packageJsonPath2, "utf-8"));
|
|
1033
1044
|
return packageJson2.version;
|
|
1034
|
-
} catch
|
|
1045
|
+
} catch {
|
|
1035
1046
|
logger.debug("Failed to read package.json version");
|
|
1036
1047
|
return "2.0.0";
|
|
1037
1048
|
}
|
|
@@ -1061,29 +1072,30 @@ var init_api_service = __esm({
|
|
|
1061
1072
|
baseURL: this.baseURL,
|
|
1062
1073
|
// Request interceptor
|
|
1063
1074
|
onRequest: async ({ options }) => {
|
|
1064
|
-
|
|
1075
|
+
const extendedOptions = options;
|
|
1076
|
+
logger.debug(
|
|
1077
|
+
`API Request: ${options.method} ${extendedOptions.baseURL}${extendedOptions.url}`
|
|
1078
|
+
);
|
|
1065
1079
|
const cliVersion = getCliVersion();
|
|
1066
1080
|
const platform = getPlatformInfo();
|
|
1067
1081
|
const userAgent = `BragDuck-CLI/${cliVersion} (${platform})`;
|
|
1068
1082
|
const token = await authService.getAccessToken();
|
|
1083
|
+
const newHeaders = {
|
|
1084
|
+
"User-Agent": userAgent
|
|
1085
|
+
};
|
|
1086
|
+
if (options.headers) {
|
|
1087
|
+
const existingHeaders = new Headers(options.headers);
|
|
1088
|
+
existingHeaders.forEach((value, key) => {
|
|
1089
|
+
newHeaders[key] = value;
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1069
1092
|
if (token) {
|
|
1070
|
-
|
|
1071
|
-
...options.headers,
|
|
1072
|
-
"User-Agent": userAgent,
|
|
1073
|
-
Authorization: `Bearer ${token}`
|
|
1074
|
-
};
|
|
1075
|
-
} else {
|
|
1076
|
-
options.headers = {
|
|
1077
|
-
...options.headers,
|
|
1078
|
-
"User-Agent": userAgent
|
|
1079
|
-
};
|
|
1093
|
+
newHeaders.Authorization = `Bearer ${token}`;
|
|
1080
1094
|
}
|
|
1081
1095
|
if (options.method && ["POST", "PUT", "PATCH"].includes(options.method)) {
|
|
1082
|
-
|
|
1083
|
-
...options.headers,
|
|
1084
|
-
"Content-Type": "application/json"
|
|
1085
|
-
};
|
|
1096
|
+
newHeaders["Content-Type"] = "application/json";
|
|
1086
1097
|
}
|
|
1098
|
+
options.headers = newHeaders;
|
|
1087
1099
|
},
|
|
1088
1100
|
// Response interceptor for success
|
|
1089
1101
|
onResponse: ({ response }) => {
|
|
@@ -1092,7 +1104,8 @@ var init_api_service = __esm({
|
|
|
1092
1104
|
// Response interceptor for errors
|
|
1093
1105
|
onResponseError: async ({ response, options }) => {
|
|
1094
1106
|
const status = response.status;
|
|
1095
|
-
const
|
|
1107
|
+
const extendedOptions = options;
|
|
1108
|
+
const url = `${extendedOptions.baseURL}${extendedOptions.url}`;
|
|
1096
1109
|
logger.debug(`API Error: ${status} ${response.statusText} - ${url}`);
|
|
1097
1110
|
if (status === HTTP_STATUS.UNAUTHORIZED) {
|
|
1098
1111
|
logger.debug("Token expired, attempting refresh");
|
|
@@ -1104,7 +1117,9 @@ var init_api_service = __esm({
|
|
|
1104
1117
|
if (error.message === "RETRY_WITH_NEW_TOKEN") {
|
|
1105
1118
|
throw error;
|
|
1106
1119
|
}
|
|
1107
|
-
throw new TokenExpiredError(
|
|
1120
|
+
throw new TokenExpiredError(
|
|
1121
|
+
'Your session has expired. Please run "bragduck init" to login again.'
|
|
1122
|
+
);
|
|
1108
1123
|
}
|
|
1109
1124
|
}
|
|
1110
1125
|
let errorMessage = "An unexpected error occurred";
|
|
@@ -1150,23 +1165,39 @@ var init_api_service = __esm({
|
|
|
1150
1165
|
}
|
|
1151
1166
|
}
|
|
1152
1167
|
/**
|
|
1153
|
-
* Refine
|
|
1168
|
+
* Refine brags using AI
|
|
1169
|
+
*/
|
|
1170
|
+
async refineBrags(request) {
|
|
1171
|
+
logger.debug(`Refining ${request.brags.length} brags`);
|
|
1172
|
+
try {
|
|
1173
|
+
const response = await this.makeRequest(API_ENDPOINTS.BRAGS.REFINE, {
|
|
1174
|
+
method: "POST",
|
|
1175
|
+
body: request
|
|
1176
|
+
});
|
|
1177
|
+
logger.debug(`Successfully refined ${response.refined_brags.length} brags`);
|
|
1178
|
+
return response;
|
|
1179
|
+
} catch (_error) {
|
|
1180
|
+
logger.debug("Failed to refine brags");
|
|
1181
|
+
throw _error;
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
/**
|
|
1185
|
+
* @deprecated Use refineBrags() instead. Will be removed in v3.0.0
|
|
1186
|
+
* Refine commits using AI (legacy endpoint)
|
|
1154
1187
|
*/
|
|
1155
1188
|
async refineCommits(request) {
|
|
1189
|
+
logger.debug(`[DEPRECATED] Using legacy refineCommits - migrate to refineBrags`);
|
|
1156
1190
|
logger.debug(`Refining ${request.commits.length} commits`);
|
|
1157
1191
|
try {
|
|
1158
|
-
const response = await this.makeRequest(
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
body: request
|
|
1163
|
-
}
|
|
1164
|
-
);
|
|
1192
|
+
const response = await this.makeRequest(API_ENDPOINTS.COMMITS.REFINE, {
|
|
1193
|
+
method: "POST",
|
|
1194
|
+
body: request
|
|
1195
|
+
});
|
|
1165
1196
|
logger.debug(`Successfully refined ${response.refined_commits.length} commits`);
|
|
1166
1197
|
return response;
|
|
1167
|
-
} catch (
|
|
1198
|
+
} catch (_error) {
|
|
1168
1199
|
logger.debug("Failed to refine commits");
|
|
1169
|
-
throw
|
|
1200
|
+
throw _error;
|
|
1170
1201
|
}
|
|
1171
1202
|
}
|
|
1172
1203
|
/**
|
|
@@ -1175,18 +1206,15 @@ var init_api_service = __esm({
|
|
|
1175
1206
|
async createBrags(request) {
|
|
1176
1207
|
logger.debug(`Creating ${request.brags.length} brags`);
|
|
1177
1208
|
try {
|
|
1178
|
-
const response = await this.makeRequest(
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
body: request
|
|
1183
|
-
}
|
|
1184
|
-
);
|
|
1209
|
+
const response = await this.makeRequest(API_ENDPOINTS.BRAGS.CREATE, {
|
|
1210
|
+
method: "POST",
|
|
1211
|
+
body: request
|
|
1212
|
+
});
|
|
1185
1213
|
logger.debug(`Successfully created ${response.created} brags`);
|
|
1186
1214
|
return response;
|
|
1187
|
-
} catch (
|
|
1215
|
+
} catch (_error) {
|
|
1188
1216
|
logger.debug("Failed to create brags");
|
|
1189
|
-
throw
|
|
1217
|
+
throw _error;
|
|
1190
1218
|
}
|
|
1191
1219
|
}
|
|
1192
1220
|
/**
|
|
@@ -1196,7 +1224,7 @@ var init_api_service = __esm({
|
|
|
1196
1224
|
const { limit = 50, offset = 0, tags, search } = params;
|
|
1197
1225
|
logger.debug(`Listing brags: limit=${limit}, offset=${offset}`);
|
|
1198
1226
|
try {
|
|
1199
|
-
const queryParams = new
|
|
1227
|
+
const queryParams = new URLSearchParams2({
|
|
1200
1228
|
limit: limit.toString(),
|
|
1201
1229
|
offset: offset.toString()
|
|
1202
1230
|
});
|
|
@@ -1210,10 +1238,33 @@ var init_api_service = __esm({
|
|
|
1210
1238
|
const response = await this.makeRequest(url, {
|
|
1211
1239
|
method: "GET"
|
|
1212
1240
|
});
|
|
1213
|
-
logger.debug(
|
|
1241
|
+
logger.debug(
|
|
1242
|
+
`Successfully fetched ${response.brags.length} brags (total: ${response.total})`
|
|
1243
|
+
);
|
|
1214
1244
|
return response;
|
|
1215
|
-
} catch (
|
|
1245
|
+
} catch (_error) {
|
|
1216
1246
|
logger.debug("Failed to list brags");
|
|
1247
|
+
throw _error;
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Get user's subscription status
|
|
1252
|
+
*/
|
|
1253
|
+
async getSubscriptionStatus() {
|
|
1254
|
+
logger.debug(`Fetching subscription status from ${API_ENDPOINTS.SUBSCRIPTION.STATUS}`);
|
|
1255
|
+
try {
|
|
1256
|
+
const response = await this.makeRequest(API_ENDPOINTS.SUBSCRIPTION.STATUS, {
|
|
1257
|
+
method: "GET"
|
|
1258
|
+
});
|
|
1259
|
+
logger.debug(`Subscription API response: ${JSON.stringify(response)}`);
|
|
1260
|
+
const subscriptionData = response.data;
|
|
1261
|
+
logger.debug(
|
|
1262
|
+
`Subscription tier: ${subscriptionData.tier}, status: ${subscriptionData.status}`
|
|
1263
|
+
);
|
|
1264
|
+
return subscriptionData;
|
|
1265
|
+
} catch (error) {
|
|
1266
|
+
logger.debug(`Failed to fetch subscription status: ${error}`);
|
|
1267
|
+
logger.debug(`Error details: ${JSON.stringify(error, null, 2)}`);
|
|
1217
1268
|
throw error;
|
|
1218
1269
|
}
|
|
1219
1270
|
}
|
|
@@ -1223,15 +1274,12 @@ var init_api_service = __esm({
|
|
|
1223
1274
|
async checkVersion() {
|
|
1224
1275
|
logger.debug("Checking for CLI updates");
|
|
1225
1276
|
try {
|
|
1226
|
-
const response = await this.makeRequest(
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
method: "GET"
|
|
1230
|
-
}
|
|
1231
|
-
);
|
|
1277
|
+
const response = await this.makeRequest(API_ENDPOINTS.VERSION, {
|
|
1278
|
+
method: "GET"
|
|
1279
|
+
});
|
|
1232
1280
|
logger.debug(`Latest version: ${response.latest_version}`);
|
|
1233
1281
|
return response;
|
|
1234
|
-
} catch
|
|
1282
|
+
} catch {
|
|
1235
1283
|
logger.debug("Failed to check version");
|
|
1236
1284
|
const { version: version2 } = await Promise.resolve().then(() => (init_version(), version_exports));
|
|
1237
1285
|
return {
|
|
@@ -1247,7 +1295,7 @@ var init_api_service = __esm({
|
|
|
1247
1295
|
try {
|
|
1248
1296
|
await this.checkVersion();
|
|
1249
1297
|
return true;
|
|
1250
|
-
} catch
|
|
1298
|
+
} catch {
|
|
1251
1299
|
return false;
|
|
1252
1300
|
}
|
|
1253
1301
|
}
|
|
@@ -1310,7 +1358,7 @@ ${chalk2.dim("Run")} ${chalk2.cyan("bragduck logout")} ${chalk2.dim("to sign out
|
|
|
1310
1358
|
)
|
|
1311
1359
|
);
|
|
1312
1360
|
logger.log("");
|
|
1313
|
-
setTimeout(() => {
|
|
1361
|
+
globalThis.setTimeout(() => {
|
|
1314
1362
|
process.exit(0);
|
|
1315
1363
|
}, 100);
|
|
1316
1364
|
return;
|
|
@@ -1339,7 +1387,7 @@ ${chalk2.dim("You can now use")} ${chalk2.cyan("bragduck scan")} ${chalk2.dim("t
|
|
|
1339
1387
|
)
|
|
1340
1388
|
);
|
|
1341
1389
|
logger.log("");
|
|
1342
|
-
setTimeout(() => {
|
|
1390
|
+
globalThis.setTimeout(() => {
|
|
1343
1391
|
process.exit(0);
|
|
1344
1392
|
}, 100);
|
|
1345
1393
|
return;
|
|
@@ -1396,14 +1444,17 @@ async function logoutCommand() {
|
|
|
1396
1444
|
const isAuthenticated = await authService.isAuthenticated();
|
|
1397
1445
|
if (!isAuthenticated) {
|
|
1398
1446
|
logger.log(
|
|
1399
|
-
boxen2(
|
|
1447
|
+
boxen2(
|
|
1448
|
+
`${chalk3.yellow("Not currently authenticated")}
|
|
1400
1449
|
|
|
1401
|
-
${chalk3.dim("Nothing to logout from")}`,
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1450
|
+
${chalk3.dim("Nothing to logout from")}`,
|
|
1451
|
+
{
|
|
1452
|
+
padding: 1,
|
|
1453
|
+
margin: 1,
|
|
1454
|
+
borderStyle: "round",
|
|
1455
|
+
borderColor: "yellow"
|
|
1456
|
+
}
|
|
1457
|
+
)
|
|
1407
1458
|
);
|
|
1408
1459
|
return;
|
|
1409
1460
|
}
|
|
@@ -1438,7 +1489,7 @@ ${chalk3.dim("Run")} ${chalk3.cyan("bragduck init")} ${chalk3.dim("to login agai
|
|
|
1438
1489
|
}
|
|
1439
1490
|
)
|
|
1440
1491
|
);
|
|
1441
|
-
} catch
|
|
1492
|
+
} catch {
|
|
1442
1493
|
spinner.fail("Logout failed");
|
|
1443
1494
|
logger.error("Failed to logout. Please try again.");
|
|
1444
1495
|
process.exit(1);
|
|
@@ -1447,8 +1498,14 @@ ${chalk3.dim("Run")} ${chalk3.cyan("bragduck init")} ${chalk3.dim("to login agai
|
|
|
1447
1498
|
|
|
1448
1499
|
// src/commands/scan.ts
|
|
1449
1500
|
init_esm_shims();
|
|
1450
|
-
import
|
|
1451
|
-
|
|
1501
|
+
import boxen6 from "boxen";
|
|
1502
|
+
|
|
1503
|
+
// node_modules/@inquirer/core/dist/esm/lib/errors.mjs
|
|
1504
|
+
init_esm_shims();
|
|
1505
|
+
var CancelPromptError = class extends Error {
|
|
1506
|
+
name = "CancelPromptError";
|
|
1507
|
+
message = "Prompt was canceled";
|
|
1508
|
+
};
|
|
1452
1509
|
|
|
1453
1510
|
// src/services/github.service.ts
|
|
1454
1511
|
init_esm_shims();
|
|
@@ -1587,7 +1644,9 @@ var GitService = class {
|
|
|
1587
1644
|
insertions: diffSummary.insertions,
|
|
1588
1645
|
deletions: diffSummary.deletions
|
|
1589
1646
|
};
|
|
1590
|
-
logger.debug(
|
|
1647
|
+
logger.debug(
|
|
1648
|
+
`Commit ${sha}: ${stats.filesChanged} files, +${stats.insertions} -${stats.deletions}`
|
|
1649
|
+
);
|
|
1591
1650
|
return stats;
|
|
1592
1651
|
} catch (error) {
|
|
1593
1652
|
if (error.message && error.message.includes("unknown revision")) {
|
|
@@ -1627,7 +1686,7 @@ var GitService = class {
|
|
|
1627
1686
|
...commit,
|
|
1628
1687
|
diffStats: stats
|
|
1629
1688
|
};
|
|
1630
|
-
} catch
|
|
1689
|
+
} catch {
|
|
1631
1690
|
logger.debug(`Failed to get stats for commit ${commit.sha}, continuing without stats`);
|
|
1632
1691
|
return commit;
|
|
1633
1692
|
}
|
|
@@ -1642,7 +1701,7 @@ var GitService = class {
|
|
|
1642
1701
|
try {
|
|
1643
1702
|
const email = await this.git.raw(["config", "user.email"]);
|
|
1644
1703
|
return email.trim() || null;
|
|
1645
|
-
} catch
|
|
1704
|
+
} catch {
|
|
1646
1705
|
logger.debug("Failed to get git user email");
|
|
1647
1706
|
return null;
|
|
1648
1707
|
}
|
|
@@ -1654,7 +1713,7 @@ var GitService = class {
|
|
|
1654
1713
|
try {
|
|
1655
1714
|
const name = await this.git.raw(["config", "user.name"]);
|
|
1656
1715
|
return name.trim() || null;
|
|
1657
|
-
} catch
|
|
1716
|
+
} catch {
|
|
1658
1717
|
logger.debug("Failed to get git user name");
|
|
1659
1718
|
return null;
|
|
1660
1719
|
}
|
|
@@ -1689,7 +1748,7 @@ var GitHubService = class {
|
|
|
1689
1748
|
try {
|
|
1690
1749
|
await execAsync2("command gh --version");
|
|
1691
1750
|
return true;
|
|
1692
|
-
} catch
|
|
1751
|
+
} catch {
|
|
1693
1752
|
return false;
|
|
1694
1753
|
}
|
|
1695
1754
|
}
|
|
@@ -1711,7 +1770,7 @@ var GitHubService = class {
|
|
|
1711
1770
|
try {
|
|
1712
1771
|
await execAsync2("command gh auth status");
|
|
1713
1772
|
return true;
|
|
1714
|
-
} catch
|
|
1773
|
+
} catch {
|
|
1715
1774
|
return false;
|
|
1716
1775
|
}
|
|
1717
1776
|
}
|
|
@@ -1793,7 +1852,7 @@ var GitHubService = class {
|
|
|
1793
1852
|
try {
|
|
1794
1853
|
const { stdout } = await execAsync2("command gh api user --jq .login");
|
|
1795
1854
|
return stdout.trim() || null;
|
|
1796
|
-
} catch
|
|
1855
|
+
} catch {
|
|
1797
1856
|
logger.debug("Failed to get GitHub user");
|
|
1798
1857
|
return null;
|
|
1799
1858
|
}
|
|
@@ -1876,68 +1935,260 @@ var githubService = new GitHubService();
|
|
|
1876
1935
|
|
|
1877
1936
|
// src/commands/scan.ts
|
|
1878
1937
|
init_api_service();
|
|
1879
|
-
init_auth_service();
|
|
1880
1938
|
init_storage_service();
|
|
1881
1939
|
init_logger();
|
|
1940
|
+
init_browser();
|
|
1941
|
+
|
|
1942
|
+
// src/utils/auth-helper.ts
|
|
1943
|
+
init_esm_shims();
|
|
1944
|
+
init_auth_service();
|
|
1945
|
+
import boxen5 from "boxen";
|
|
1946
|
+
init_logger();
|
|
1882
1947
|
|
|
1883
1948
|
// src/ui/prompts.ts
|
|
1884
1949
|
init_esm_shims();
|
|
1885
|
-
import { checkbox, confirm as confirm2, input, select } from "@inquirer/prompts";
|
|
1950
|
+
import { checkbox, confirm as confirm2, input, select, editor } from "@inquirer/prompts";
|
|
1951
|
+
import boxen4 from "boxen";
|
|
1886
1952
|
|
|
1887
1953
|
// src/ui/formatters.ts
|
|
1888
1954
|
init_esm_shims();
|
|
1889
|
-
import chalk5 from "chalk";
|
|
1890
1955
|
import Table from "cli-table3";
|
|
1891
1956
|
import terminalLink from "terminal-link";
|
|
1957
|
+
|
|
1958
|
+
// src/ui/theme.ts
|
|
1959
|
+
init_esm_shims();
|
|
1960
|
+
import chalk5 from "chalk";
|
|
1961
|
+
var colors = {
|
|
1962
|
+
// Primary colors for main actions and interactive elements
|
|
1963
|
+
primary: chalk5.cyan,
|
|
1964
|
+
// Success states
|
|
1965
|
+
success: chalk5.green,
|
|
1966
|
+
successBold: chalk5.green.bold,
|
|
1967
|
+
// Warning states
|
|
1968
|
+
warning: chalk5.yellow,
|
|
1969
|
+
warningBold: chalk5.yellow.bold,
|
|
1970
|
+
// Error states
|
|
1971
|
+
error: chalk5.red,
|
|
1972
|
+
errorBold: chalk5.red.bold,
|
|
1973
|
+
// Info and metadata
|
|
1974
|
+
info: chalk5.gray,
|
|
1975
|
+
infoDim: chalk5.dim,
|
|
1976
|
+
// Highlighted/important data
|
|
1977
|
+
highlight: chalk5.yellow.bold,
|
|
1978
|
+
highlightCyan: chalk5.cyan.bold,
|
|
1979
|
+
// Text emphasis
|
|
1980
|
+
bold: chalk5.bold,
|
|
1981
|
+
dim: chalk5.dim,
|
|
1982
|
+
// Special purpose
|
|
1983
|
+
white: chalk5.white,
|
|
1984
|
+
gray: chalk5.gray
|
|
1985
|
+
};
|
|
1986
|
+
var theme = {
|
|
1987
|
+
/**
|
|
1988
|
+
* Format command names and CLI actions
|
|
1989
|
+
*/
|
|
1990
|
+
command: (text) => colors.primary(text),
|
|
1991
|
+
/**
|
|
1992
|
+
* Format success messages
|
|
1993
|
+
*/
|
|
1994
|
+
success: (text) => colors.success(`\u2713 ${text}`),
|
|
1995
|
+
successBold: (text) => colors.successBold(`\u2713 ${text}`),
|
|
1996
|
+
/**
|
|
1997
|
+
* Format error messages
|
|
1998
|
+
*/
|
|
1999
|
+
error: (text) => colors.error(`\u2717 ${text}`),
|
|
2000
|
+
errorBold: (text) => colors.errorBold(`\u2717 ${text}`),
|
|
2001
|
+
/**
|
|
2002
|
+
* Format warning messages
|
|
2003
|
+
*/
|
|
2004
|
+
warning: (text) => colors.warning(`\u26A0 ${text}`),
|
|
2005
|
+
/**
|
|
2006
|
+
* Format info messages
|
|
2007
|
+
*/
|
|
2008
|
+
info: (text) => colors.info(text),
|
|
2009
|
+
/**
|
|
2010
|
+
* Format labels (e.g., "User:", "Email:")
|
|
2011
|
+
*/
|
|
2012
|
+
label: (text) => colors.gray(`${text}:`),
|
|
2013
|
+
/**
|
|
2014
|
+
* Format values
|
|
2015
|
+
*/
|
|
2016
|
+
value: (text) => colors.highlight(text),
|
|
2017
|
+
/**
|
|
2018
|
+
* Format counts and numbers
|
|
2019
|
+
*/
|
|
2020
|
+
count: (num) => colors.highlightCyan(num.toString()),
|
|
2021
|
+
/**
|
|
2022
|
+
* Format file paths
|
|
2023
|
+
*/
|
|
2024
|
+
path: (text) => colors.info(text),
|
|
2025
|
+
/**
|
|
2026
|
+
* Format step indicators (e.g., "Step 1/5:")
|
|
2027
|
+
*/
|
|
2028
|
+
step: (current, total) => colors.primary(`[${current}/${total}]`),
|
|
2029
|
+
/**
|
|
2030
|
+
* Format progress text
|
|
2031
|
+
*/
|
|
2032
|
+
progress: (text) => colors.infoDim(text),
|
|
2033
|
+
/**
|
|
2034
|
+
* Format emphasized text
|
|
2035
|
+
*/
|
|
2036
|
+
emphasis: (text) => colors.bold(text),
|
|
2037
|
+
/**
|
|
2038
|
+
* Format de-emphasized/secondary text
|
|
2039
|
+
*/
|
|
2040
|
+
secondary: (text) => colors.dim(text),
|
|
2041
|
+
/**
|
|
2042
|
+
* Format interactive elements (prompts, selections)
|
|
2043
|
+
*/
|
|
2044
|
+
interactive: (text) => colors.primary(text),
|
|
2045
|
+
/**
|
|
2046
|
+
* Format keys in key-value pairs
|
|
2047
|
+
*/
|
|
2048
|
+
key: (text) => colors.white(text)
|
|
2049
|
+
};
|
|
2050
|
+
var boxStyles = {
|
|
2051
|
+
success: {
|
|
2052
|
+
borderColor: "green",
|
|
2053
|
+
borderStyle: "round",
|
|
2054
|
+
padding: 1,
|
|
2055
|
+
margin: 1
|
|
2056
|
+
},
|
|
2057
|
+
error: {
|
|
2058
|
+
borderColor: "red",
|
|
2059
|
+
borderStyle: "round",
|
|
2060
|
+
padding: 1,
|
|
2061
|
+
margin: 1
|
|
2062
|
+
},
|
|
2063
|
+
warning: {
|
|
2064
|
+
borderColor: "yellow",
|
|
2065
|
+
borderStyle: "round",
|
|
2066
|
+
padding: 1,
|
|
2067
|
+
margin: 1
|
|
2068
|
+
},
|
|
2069
|
+
info: {
|
|
2070
|
+
borderColor: "cyan",
|
|
2071
|
+
borderStyle: "round",
|
|
2072
|
+
padding: 1,
|
|
2073
|
+
margin: 1
|
|
2074
|
+
},
|
|
2075
|
+
plain: {
|
|
2076
|
+
borderColor: "gray",
|
|
2077
|
+
borderStyle: "round",
|
|
2078
|
+
padding: 1,
|
|
2079
|
+
margin: 1
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
var tableStyles = {
|
|
2083
|
+
default: {
|
|
2084
|
+
style: {
|
|
2085
|
+
head: [],
|
|
2086
|
+
border: ["gray"]
|
|
2087
|
+
}
|
|
2088
|
+
},
|
|
2089
|
+
compact: {
|
|
2090
|
+
style: {
|
|
2091
|
+
head: [],
|
|
2092
|
+
border: ["dim"],
|
|
2093
|
+
compact: true
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
};
|
|
2097
|
+
var sizeIndicators = {
|
|
2098
|
+
small: colors.success("\u25CF"),
|
|
2099
|
+
medium: colors.warning("\u25CF"),
|
|
2100
|
+
large: colors.error("\u25CF")
|
|
2101
|
+
};
|
|
2102
|
+
function getSizeIndicator(insertions, deletions) {
|
|
2103
|
+
const total = insertions + deletions;
|
|
2104
|
+
if (total < 50) {
|
|
2105
|
+
return `${sizeIndicators.small} Small`;
|
|
2106
|
+
} else if (total < 200) {
|
|
2107
|
+
return `${sizeIndicators.medium} Medium`;
|
|
2108
|
+
} else {
|
|
2109
|
+
return `${sizeIndicators.large} Large`;
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
function formatDiffStats(insertions, deletions) {
|
|
2113
|
+
return `${colors.success(`+${insertions}`)} ${colors.error(`-${deletions}`)}`;
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
// src/ui/formatters.ts
|
|
1892
2117
|
function formatCommitChoice(commit) {
|
|
1893
2118
|
let displaySha;
|
|
1894
2119
|
if (commit.sha.startsWith("pr-")) {
|
|
1895
2120
|
const prNumber = commit.sha.replace("pr-", "#");
|
|
1896
|
-
displaySha =
|
|
2121
|
+
displaySha = colors.highlight(prNumber);
|
|
1897
2122
|
} else {
|
|
1898
|
-
displaySha =
|
|
2123
|
+
displaySha = colors.highlight(commit.sha.substring(0, 7));
|
|
2124
|
+
}
|
|
2125
|
+
const lines = commit.message.split("\n");
|
|
2126
|
+
const title = lines[0];
|
|
2127
|
+
let bodyPreview = "";
|
|
2128
|
+
if (lines.length > 1) {
|
|
2129
|
+
const body = lines.slice(1).join(" ").trim();
|
|
2130
|
+
if (body.length > 0) {
|
|
2131
|
+
const preview = body.length > 80 ? body.substring(0, 80) + "..." : body;
|
|
2132
|
+
bodyPreview = `
|
|
2133
|
+
${colors.infoDim(preview)}`;
|
|
2134
|
+
}
|
|
1899
2135
|
}
|
|
1900
|
-
const
|
|
1901
|
-
const
|
|
1902
|
-
const date = chalk5.gray(new Date(commit.date).toLocaleDateString());
|
|
2136
|
+
const author = colors.info(`by ${commit.author}`);
|
|
2137
|
+
const date = colors.info(new Date(commit.date).toLocaleDateString());
|
|
1903
2138
|
let stats = "";
|
|
2139
|
+
let sizeIndicator = "";
|
|
1904
2140
|
if (commit.diffStats) {
|
|
1905
2141
|
const { filesChanged, insertions, deletions } = commit.diffStats;
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
);
|
|
2142
|
+
sizeIndicator = ` ${getSizeIndicator(insertions, deletions)}`;
|
|
2143
|
+
stats = colors.info(` [${filesChanged} files, ${formatDiffStats(insertions, deletions)}]`);
|
|
1909
2144
|
}
|
|
1910
|
-
return `${displaySha} ${
|
|
1911
|
-
${author} \u2022 ${date}`;
|
|
2145
|
+
return `${displaySha} ${title}${sizeIndicator}${stats}
|
|
2146
|
+
${author} \u2022 ${date}${bodyPreview}`;
|
|
1912
2147
|
}
|
|
1913
|
-
function formatRefinedCommitsTable(
|
|
2148
|
+
function formatRefinedCommitsTable(brags, selectedCommits) {
|
|
1914
2149
|
const table = new Table({
|
|
1915
2150
|
head: [
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
2151
|
+
colors.primary("SHA"),
|
|
2152
|
+
colors.primary("Original"),
|
|
2153
|
+
colors.primary("Refined Title"),
|
|
2154
|
+
colors.primary("Description"),
|
|
2155
|
+
colors.primary("Tags")
|
|
1921
2156
|
],
|
|
1922
|
-
colWidths: [
|
|
2157
|
+
colWidths: [12, 28, 30, 40, 20],
|
|
1923
2158
|
wordWrap: true,
|
|
1924
|
-
style:
|
|
1925
|
-
head: [],
|
|
1926
|
-
border: ["gray"]
|
|
1927
|
-
}
|
|
2159
|
+
style: tableStyles.default.style
|
|
1928
2160
|
});
|
|
1929
|
-
|
|
1930
|
-
const
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
2161
|
+
brags.forEach((brag, index) => {
|
|
2162
|
+
const isNewBragType = !("sha" in brag);
|
|
2163
|
+
let displaySha;
|
|
2164
|
+
if (isNewBragType && selectedCommits) {
|
|
2165
|
+
const commit = selectedCommits[index];
|
|
2166
|
+
if (commit.sha.startsWith("pr-")) {
|
|
2167
|
+
displaySha = commit.sha.replace("pr-", "#");
|
|
2168
|
+
} else {
|
|
2169
|
+
displaySha = commit.sha.substring(0, 7);
|
|
2170
|
+
}
|
|
2171
|
+
} else if (!isNewBragType) {
|
|
2172
|
+
const commit = brag;
|
|
2173
|
+
if (commit.sha.startsWith("pr-")) {
|
|
2174
|
+
displaySha = commit.sha.replace("pr-", "#");
|
|
2175
|
+
} else {
|
|
2176
|
+
displaySha = commit.sha.substring(0, 7);
|
|
2177
|
+
}
|
|
2178
|
+
} else {
|
|
2179
|
+
displaySha = `#${index + 1}`;
|
|
2180
|
+
}
|
|
2181
|
+
const original = isNewBragType ? typeof brag.original_input === "string" ? brag.original_input.split("\n")[0] || "" : "Raw input" : brag.original_message.split("\n")[0] || "";
|
|
2182
|
+
const title = brag.refined_title;
|
|
2183
|
+
const description = brag.refined_description.length > 100 ? brag.refined_description.substring(0, 97) + "..." : brag.refined_description;
|
|
2184
|
+
const tags = (brag.suggested_tags || []).join(", ") || "none";
|
|
2185
|
+
const rowNum = colors.infoDim(`${index + 1}.`);
|
|
1935
2186
|
table.push([
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
2187
|
+
`${rowNum} ${colors.highlight(displaySha)}`,
|
|
2188
|
+
colors.info(original),
|
|
2189
|
+
colors.white(title),
|
|
2190
|
+
colors.dim(description),
|
|
2191
|
+
colors.primary(tags)
|
|
1941
2192
|
]);
|
|
1942
2193
|
});
|
|
1943
2194
|
return table.toString();
|
|
@@ -1946,26 +2197,35 @@ function formatCommitStats(commits) {
|
|
|
1946
2197
|
const totalFiles = commits.reduce((sum, c) => sum + (c.diffStats?.filesChanged || 0), 0);
|
|
1947
2198
|
const totalInsertions = commits.reduce((sum, c) => sum + (c.diffStats?.insertions || 0), 0);
|
|
1948
2199
|
const totalDeletions = commits.reduce((sum, c) => sum + (c.diffStats?.deletions || 0), 0);
|
|
1949
|
-
return
|
|
2200
|
+
return colors.info("Total changes: ") + colors.white(`${totalFiles} files`) + colors.info(", ") + formatDiffStats(totalInsertions, totalDeletions);
|
|
2201
|
+
}
|
|
2202
|
+
function formatSelectionSummary(count, commits) {
|
|
2203
|
+
const totalFiles = commits.reduce((sum, c) => sum + (c.diffStats?.filesChanged || 0), 0);
|
|
2204
|
+
const totalInsertions = commits.reduce((sum, c) => sum + (c.diffStats?.insertions || 0), 0);
|
|
2205
|
+
const totalDeletions = commits.reduce((sum, c) => sum + (c.diffStats?.deletions || 0), 0);
|
|
2206
|
+
const selectedText = theme.success(`Selected ${theme.count(count)} PR${count > 1 ? "s" : ""}`);
|
|
2207
|
+
const stats = `${theme.count(totalFiles)} files changed, ${formatDiffStats(totalInsertions, totalDeletions)}`;
|
|
2208
|
+
return `
|
|
2209
|
+
${selectedText}: ${stats}`;
|
|
1950
2210
|
}
|
|
1951
2211
|
function formatSuccessMessage(count) {
|
|
1952
2212
|
const emoji = "\u{1F389}";
|
|
1953
|
-
const title =
|
|
2213
|
+
const title = colors.successBold(
|
|
1954
2214
|
`${emoji} Successfully created ${count} brag${count > 1 ? "s" : ""}!`
|
|
1955
2215
|
);
|
|
1956
|
-
const message =
|
|
1957
|
-
const hint =
|
|
2216
|
+
const message = colors.white("\nYour achievements are now saved and ready to showcase.");
|
|
2217
|
+
const hint = theme.secondary("\nRun ") + theme.command("bragduck list") + theme.secondary(" to see all your brags");
|
|
1958
2218
|
const url = "https://bragduck.com/app/brags";
|
|
1959
2219
|
const clickableUrl = terminalLink(url, url, {
|
|
1960
|
-
fallback: () =>
|
|
2220
|
+
fallback: () => colors.primary(url)
|
|
1961
2221
|
});
|
|
1962
|
-
const webUrl =
|
|
2222
|
+
const webUrl = theme.secondary("\n\nOr, check ") + clickableUrl + theme.secondary(" to see all your brags");
|
|
1963
2223
|
return `${title}${message}${hint}${webUrl}`;
|
|
1964
2224
|
}
|
|
1965
2225
|
function formatErrorMessage(message, hint) {
|
|
1966
|
-
const title =
|
|
1967
|
-
const error =
|
|
1968
|
-
const hintText = hint ?
|
|
2226
|
+
const title = colors.errorBold("\u2717 Error");
|
|
2227
|
+
const error = colors.white(message);
|
|
2228
|
+
const hintText = hint ? theme.secondary("\n\nHint: ") + theme.command(hint) : "";
|
|
1969
2229
|
return `${title}
|
|
1970
2230
|
|
|
1971
2231
|
${error}${hintText}`;
|
|
@@ -2024,11 +2284,128 @@ async function promptDaysToScan(defaultDays = 30) {
|
|
|
2024
2284
|
}
|
|
2025
2285
|
return parseInt(selected, 10);
|
|
2026
2286
|
}
|
|
2287
|
+
async function promptSortOption() {
|
|
2288
|
+
const choices = [
|
|
2289
|
+
{
|
|
2290
|
+
name: "By date (newest first)",
|
|
2291
|
+
value: "date",
|
|
2292
|
+
description: "Most recent PRs first"
|
|
2293
|
+
},
|
|
2294
|
+
{ name: "By size (largest first)", value: "size", description: "Most lines changed" },
|
|
2295
|
+
{ name: "By files (most files)", value: "files", description: "Most files changed" },
|
|
2296
|
+
{ name: "No sorting", value: "none", description: "Keep original order" }
|
|
2297
|
+
];
|
|
2298
|
+
return await select({
|
|
2299
|
+
message: "How would you like to sort the PRs?",
|
|
2300
|
+
choices,
|
|
2301
|
+
default: "date"
|
|
2302
|
+
});
|
|
2303
|
+
}
|
|
2304
|
+
async function promptReviewBrags(refinedCommits) {
|
|
2305
|
+
const acceptedBrags = [];
|
|
2306
|
+
console.log("\n" + theme.info("Review each brag before creation:") + "\n");
|
|
2307
|
+
for (let i = 0; i < refinedCommits.length; i++) {
|
|
2308
|
+
const commit = refinedCommits[i];
|
|
2309
|
+
const current = i + 1;
|
|
2310
|
+
const total = refinedCommits.length;
|
|
2311
|
+
const displaySha = commit.sha.startsWith("pr-") ? commit.sha.replace("pr-", "#") : commit.sha.substring(0, 7);
|
|
2312
|
+
const bragDetails = `${theme.step(current, total)} ${colors.highlight(displaySha)}
|
|
2313
|
+
|
|
2314
|
+
${theme.label("Title")} ${colors.white(commit.refined_title)}
|
|
2315
|
+
|
|
2316
|
+
${theme.label("Description")}
|
|
2317
|
+
${colors.white(commit.refined_description)}
|
|
2318
|
+
|
|
2319
|
+
${theme.label("Tags")} ${colors.primary((commit.suggested_tags || []).join(", ") || "none")}
|
|
2320
|
+
|
|
2321
|
+
${theme.label("Impact Score")} ${colors.highlight(commit.impact_score?.toString() || "N/A")}`;
|
|
2322
|
+
console.log(boxen4(bragDetails, boxStyles.info));
|
|
2323
|
+
console.log("");
|
|
2324
|
+
const action = await select({
|
|
2325
|
+
message: `What would you like to do with this brag?`,
|
|
2326
|
+
choices: [
|
|
2327
|
+
{ name: "\u2713 Accept", value: "accept", description: "Add this brag as-is" },
|
|
2328
|
+
{ name: "\u270E Edit title", value: "edit-title", description: "Modify the title" },
|
|
2329
|
+
{ name: "\u270E Edit description", value: "edit-desc", description: "Modify the description" },
|
|
2330
|
+
{ name: "\u270E Edit both", value: "edit-both", description: "Modify title and description" },
|
|
2331
|
+
{ name: "\u2717 Skip", value: "skip", description: "Skip this brag" },
|
|
2332
|
+
...current < total ? [
|
|
2333
|
+
{
|
|
2334
|
+
name: "\u2713 Accept all remaining",
|
|
2335
|
+
value: "accept-all",
|
|
2336
|
+
description: "Accept this and all remaining brags"
|
|
2337
|
+
}
|
|
2338
|
+
] : [],
|
|
2339
|
+
{ name: "\u2717 Cancel", value: "cancel", description: "Cancel and discard all brags" }
|
|
2340
|
+
]
|
|
2341
|
+
});
|
|
2342
|
+
if (action === "cancel") {
|
|
2343
|
+
return [];
|
|
2344
|
+
}
|
|
2345
|
+
if (action === "accept-all") {
|
|
2346
|
+
acceptedBrags.push(commit);
|
|
2347
|
+
for (let j = i + 1; j < refinedCommits.length; j++) {
|
|
2348
|
+
acceptedBrags.push(refinedCommits[j]);
|
|
2349
|
+
}
|
|
2350
|
+
break;
|
|
2351
|
+
}
|
|
2352
|
+
if (action === "skip") {
|
|
2353
|
+
continue;
|
|
2354
|
+
}
|
|
2355
|
+
let editedCommit = { ...commit };
|
|
2356
|
+
if (action === "edit-title" || action === "edit-both") {
|
|
2357
|
+
const newTitle = await input({
|
|
2358
|
+
message: "Enter new title:",
|
|
2359
|
+
default: commit.refined_title
|
|
2360
|
+
});
|
|
2361
|
+
editedCommit.refined_title = newTitle;
|
|
2362
|
+
}
|
|
2363
|
+
if (action === "edit-desc" || action === "edit-both") {
|
|
2364
|
+
const newDesc = await editor({
|
|
2365
|
+
message: "Edit description (will open your default editor):",
|
|
2366
|
+
default: commit.refined_description
|
|
2367
|
+
});
|
|
2368
|
+
editedCommit.refined_description = newDesc;
|
|
2369
|
+
}
|
|
2370
|
+
acceptedBrags.push(editedCommit);
|
|
2371
|
+
}
|
|
2372
|
+
return acceptedBrags;
|
|
2373
|
+
}
|
|
2374
|
+
|
|
2375
|
+
// src/utils/auth-helper.ts
|
|
2376
|
+
async function ensureAuthenticated() {
|
|
2377
|
+
const isAuthenticated = await authService.isAuthenticated();
|
|
2378
|
+
if (isAuthenticated) {
|
|
2379
|
+
return true;
|
|
2380
|
+
}
|
|
2381
|
+
logger.log("");
|
|
2382
|
+
logger.log(
|
|
2383
|
+
boxen5(
|
|
2384
|
+
theme.warning("Not authenticated") + "\n\nYou need to be logged in to use this command.\n\nWould you like to authenticate now?",
|
|
2385
|
+
boxStyles.warning
|
|
2386
|
+
)
|
|
2387
|
+
);
|
|
2388
|
+
logger.log("");
|
|
2389
|
+
const shouldAuth = await promptConfirm("Authenticate now?", true);
|
|
2390
|
+
if (!shouldAuth) {
|
|
2391
|
+
logger.log("");
|
|
2392
|
+
logger.info(
|
|
2393
|
+
theme.secondary("Authentication skipped. Run ") + theme.command("bragduck init") + theme.secondary(" when you're ready to authenticate.")
|
|
2394
|
+
);
|
|
2395
|
+
logger.log("");
|
|
2396
|
+
return false;
|
|
2397
|
+
}
|
|
2398
|
+
try {
|
|
2399
|
+
await initCommand();
|
|
2400
|
+
return true;
|
|
2401
|
+
} catch {
|
|
2402
|
+
return false;
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2027
2405
|
|
|
2028
2406
|
// src/ui/spinners.ts
|
|
2029
2407
|
init_esm_shims();
|
|
2030
2408
|
import ora3 from "ora";
|
|
2031
|
-
import chalk6 from "chalk";
|
|
2032
2409
|
function createSpinner(text) {
|
|
2033
2410
|
return ora3({
|
|
2034
2411
|
text,
|
|
@@ -2036,57 +2413,99 @@ function createSpinner(text) {
|
|
|
2036
2413
|
spinner: "dots"
|
|
2037
2414
|
});
|
|
2038
2415
|
}
|
|
2039
|
-
function
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
return createSpinner(`Creating ${count} brag${count > 1 ? "s" : ""}...`);
|
|
2416
|
+
function createStepSpinner(currentStep, totalSteps, text) {
|
|
2417
|
+
const stepIndicator = theme.step(currentStep, totalSteps);
|
|
2418
|
+
return ora3({
|
|
2419
|
+
text: `${stepIndicator} ${text}`,
|
|
2420
|
+
color: "cyan",
|
|
2421
|
+
spinner: "dots"
|
|
2422
|
+
});
|
|
2047
2423
|
}
|
|
2048
2424
|
function fetchingBragsSpinner() {
|
|
2049
2425
|
return createSpinner("Fetching your brags...");
|
|
2050
2426
|
}
|
|
2051
2427
|
function succeedSpinner(spinner, text) {
|
|
2052
2428
|
if (text) {
|
|
2053
|
-
spinner.succeed(
|
|
2429
|
+
spinner.succeed(colors.success(text));
|
|
2054
2430
|
} else {
|
|
2055
2431
|
spinner.succeed();
|
|
2056
2432
|
}
|
|
2057
2433
|
}
|
|
2058
2434
|
function failSpinner(spinner, text) {
|
|
2059
2435
|
if (text) {
|
|
2060
|
-
spinner.fail(
|
|
2436
|
+
spinner.fail(colors.error(text));
|
|
2061
2437
|
} else {
|
|
2062
2438
|
spinner.fail();
|
|
2063
2439
|
}
|
|
2064
2440
|
}
|
|
2441
|
+
function succeedStepSpinner(spinner, currentStep, totalSteps, text) {
|
|
2442
|
+
const stepIndicator = theme.step(currentStep, totalSteps);
|
|
2443
|
+
spinner.succeed(`${stepIndicator} ${colors.success(text)}`);
|
|
2444
|
+
}
|
|
2445
|
+
function failStepSpinner(spinner, currentStep, totalSteps, text) {
|
|
2446
|
+
const stepIndicator = theme.step(currentStep, totalSteps);
|
|
2447
|
+
spinner.fail(`${stepIndicator} ${colors.error(text)}`);
|
|
2448
|
+
}
|
|
2065
2449
|
|
|
2066
2450
|
// src/commands/scan.ts
|
|
2067
2451
|
async function scanCommand(options = {}) {
|
|
2068
2452
|
logger.log("");
|
|
2453
|
+
const TOTAL_STEPS = 5;
|
|
2069
2454
|
try {
|
|
2070
|
-
const isAuthenticated = await
|
|
2455
|
+
const isAuthenticated = await ensureAuthenticated();
|
|
2071
2456
|
if (!isAuthenticated) {
|
|
2457
|
+
process.exit(1);
|
|
2458
|
+
}
|
|
2459
|
+
logger.debug("Fetching subscription status...");
|
|
2460
|
+
const subscriptionStatus = await apiService.getSubscriptionStatus();
|
|
2461
|
+
logger.debug("Subscription status response:", JSON.stringify(subscriptionStatus, null, 2));
|
|
2462
|
+
logger.debug(
|
|
2463
|
+
`Checking tier: "${subscriptionStatus.tier}" (type: ${typeof subscriptionStatus.tier})`
|
|
2464
|
+
);
|
|
2465
|
+
logger.debug(`Tier === 'FREE': ${subscriptionStatus.tier === "FREE"}`);
|
|
2466
|
+
if (subscriptionStatus.tier === "FREE") {
|
|
2467
|
+
logger.debug("FREE tier detected - blocking scan command");
|
|
2468
|
+
logger.log("");
|
|
2072
2469
|
logger.log(
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
Please run ${chalk7.cyan("bragduck init")} to login first.`,
|
|
2470
|
+
boxen6(
|
|
2471
|
+
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!"),
|
|
2077
2472
|
{
|
|
2473
|
+
...boxStyles.warning,
|
|
2078
2474
|
padding: 1,
|
|
2079
|
-
margin: 1
|
|
2080
|
-
borderStyle: "round",
|
|
2081
|
-
borderColor: "yellow"
|
|
2475
|
+
margin: 1
|
|
2082
2476
|
}
|
|
2083
2477
|
)
|
|
2084
2478
|
);
|
|
2085
|
-
|
|
2479
|
+
logger.log("");
|
|
2480
|
+
const shouldOpenBrowser = await promptConfirm(
|
|
2481
|
+
"Open subscription plans in your browser?",
|
|
2482
|
+
true
|
|
2483
|
+
);
|
|
2484
|
+
if (shouldOpenBrowser) {
|
|
2485
|
+
logger.log("");
|
|
2486
|
+
const plansUrl = "https://bragduck.com/app/settings/plans";
|
|
2487
|
+
try {
|
|
2488
|
+
await openBrowser(plansUrl);
|
|
2489
|
+
logger.info(theme.secondary("Opening browser..."));
|
|
2490
|
+
} catch {
|
|
2491
|
+
logger.warning("Could not open browser automatically");
|
|
2492
|
+
logger.info(`Please visit: ${theme.value(plansUrl)}`);
|
|
2493
|
+
}
|
|
2494
|
+
}
|
|
2495
|
+
logger.log("");
|
|
2496
|
+
return;
|
|
2086
2497
|
}
|
|
2498
|
+
logger.debug(`Subscription tier "${subscriptionStatus.tier}" - proceeding with scan`);
|
|
2499
|
+
const repoSpinner = createStepSpinner(1, TOTAL_STEPS, "Validating GitHub repository");
|
|
2500
|
+
repoSpinner.start();
|
|
2087
2501
|
await githubService.validateGitHubRepository();
|
|
2088
2502
|
const repoInfo = await githubService.getRepositoryInfo();
|
|
2089
|
-
|
|
2503
|
+
succeedStepSpinner(
|
|
2504
|
+
repoSpinner,
|
|
2505
|
+
1,
|
|
2506
|
+
TOTAL_STEPS,
|
|
2507
|
+
`Repository: ${theme.value(repoInfo.fullName)}`
|
|
2508
|
+
);
|
|
2090
2509
|
logger.log("");
|
|
2091
2510
|
let days = options.days;
|
|
2092
2511
|
if (!days) {
|
|
@@ -2094,8 +2513,12 @@ Please run ${chalk7.cyan("bragduck init")} to login first.`,
|
|
|
2094
2513
|
days = await promptDaysToScan(defaultDays);
|
|
2095
2514
|
logger.log("");
|
|
2096
2515
|
}
|
|
2097
|
-
const
|
|
2098
|
-
|
|
2516
|
+
const prSpinner = createStepSpinner(
|
|
2517
|
+
2,
|
|
2518
|
+
TOTAL_STEPS,
|
|
2519
|
+
`Fetching merged PRs from the last ${days} days`
|
|
2520
|
+
);
|
|
2521
|
+
prSpinner.start();
|
|
2099
2522
|
let prs;
|
|
2100
2523
|
if (options.all) {
|
|
2101
2524
|
prs = await githubService.getMergedPRs({ days });
|
|
@@ -2104,93 +2527,119 @@ Please run ${chalk7.cyan("bragduck init")} to login first.`,
|
|
|
2104
2527
|
}
|
|
2105
2528
|
const commits = prs.map((pr) => githubService.transformPRToCommit(pr));
|
|
2106
2529
|
if (commits.length === 0) {
|
|
2107
|
-
|
|
2530
|
+
failStepSpinner(prSpinner, 2, TOTAL_STEPS, `No merged PRs found in the last ${days} days`);
|
|
2108
2531
|
logger.log("");
|
|
2109
2532
|
logger.info("Try increasing the number of days or check your GitHub activity");
|
|
2110
2533
|
return;
|
|
2111
2534
|
}
|
|
2112
|
-
|
|
2535
|
+
succeedStepSpinner(
|
|
2536
|
+
prSpinner,
|
|
2537
|
+
2,
|
|
2538
|
+
TOTAL_STEPS,
|
|
2539
|
+
`Found ${theme.count(commits.length)} PR${commits.length > 1 ? "s" : ""}`
|
|
2540
|
+
);
|
|
2113
2541
|
logger.log("");
|
|
2114
2542
|
logger.log(formatCommitStats(commits));
|
|
2115
2543
|
logger.log("");
|
|
2116
|
-
const
|
|
2544
|
+
const sortOption = await promptSortOption();
|
|
2545
|
+
logger.log("");
|
|
2546
|
+
let sortedCommits = [...commits];
|
|
2547
|
+
if (sortOption === "date") {
|
|
2548
|
+
sortedCommits.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
2549
|
+
} else if (sortOption === "size") {
|
|
2550
|
+
sortedCommits.sort((a, b) => {
|
|
2551
|
+
const sizeA = (a.diffStats?.insertions || 0) + (a.diffStats?.deletions || 0);
|
|
2552
|
+
const sizeB = (b.diffStats?.insertions || 0) + (b.diffStats?.deletions || 0);
|
|
2553
|
+
return sizeB - sizeA;
|
|
2554
|
+
});
|
|
2555
|
+
} else if (sortOption === "files") {
|
|
2556
|
+
sortedCommits.sort((a, b) => {
|
|
2557
|
+
const filesA = a.diffStats?.filesChanged || 0;
|
|
2558
|
+
const filesB = b.diffStats?.filesChanged || 0;
|
|
2559
|
+
return filesB - filesA;
|
|
2560
|
+
});
|
|
2561
|
+
}
|
|
2562
|
+
const selectedShas = await promptSelectCommits(sortedCommits);
|
|
2117
2563
|
if (selectedShas.length === 0) {
|
|
2118
|
-
logger.
|
|
2564
|
+
logger.log("");
|
|
2565
|
+
logger.info(theme.secondary("No PRs selected. Scan cancelled."));
|
|
2566
|
+
logger.log("");
|
|
2119
2567
|
return;
|
|
2120
2568
|
}
|
|
2121
|
-
const selectedCommits =
|
|
2122
|
-
logger.log(
|
|
2123
|
-
logger.success(`Selected ${selectedCommits.length} PR${selectedCommits.length > 1 ? "s" : ""}`);
|
|
2569
|
+
const selectedCommits = sortedCommits.filter((c) => selectedShas.includes(c.sha));
|
|
2570
|
+
logger.log(formatSelectionSummary(selectedCommits.length, selectedCommits));
|
|
2124
2571
|
logger.log("");
|
|
2125
|
-
const refineSpinner =
|
|
2572
|
+
const refineSpinner = createStepSpinner(
|
|
2573
|
+
3,
|
|
2574
|
+
TOTAL_STEPS,
|
|
2575
|
+
`Refining ${theme.count(selectedCommits.length)} PR${selectedCommits.length > 1 ? "s" : ""} with AI`
|
|
2576
|
+
);
|
|
2126
2577
|
refineSpinner.start();
|
|
2127
2578
|
const refineRequest = {
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
message: c.message,
|
|
2131
|
-
author: c.author,
|
|
2579
|
+
brags: selectedCommits.map((c) => ({
|
|
2580
|
+
text: c.message,
|
|
2132
2581
|
date: c.date,
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
insertions: c.diffStats.insertions,
|
|
2136
|
-
deletions: c.diffStats.deletions
|
|
2137
|
-
} : void 0
|
|
2582
|
+
title: c.message.split("\n")[0]
|
|
2583
|
+
// First line as initial title
|
|
2138
2584
|
}))
|
|
2139
2585
|
};
|
|
2140
|
-
const refineResponse = await apiService.
|
|
2141
|
-
|
|
2142
|
-
|
|
2586
|
+
const refineResponse = await apiService.refineBrags(refineRequest);
|
|
2587
|
+
let refinedBrags = refineResponse.refined_brags;
|
|
2588
|
+
succeedStepSpinner(refineSpinner, 3, TOTAL_STEPS, "PRs refined successfully");
|
|
2143
2589
|
logger.log("");
|
|
2144
2590
|
logger.info("Preview of refined brags:");
|
|
2145
2591
|
logger.log("");
|
|
2146
|
-
logger.log(formatRefinedCommitsTable(
|
|
2592
|
+
logger.log(formatRefinedCommitsTable(refinedBrags, selectedCommits));
|
|
2147
2593
|
logger.log("");
|
|
2148
|
-
const
|
|
2149
|
-
if (
|
|
2150
|
-
logger.
|
|
2594
|
+
const acceptedBrags = await promptReviewBrags(refinedBrags, selectedCommits);
|
|
2595
|
+
if (acceptedBrags.length === 0) {
|
|
2596
|
+
logger.log("");
|
|
2597
|
+
logger.info(theme.secondary("No brags selected for creation. Scan cancelled."));
|
|
2598
|
+
logger.log("");
|
|
2151
2599
|
return;
|
|
2152
2600
|
}
|
|
2153
2601
|
logger.log("");
|
|
2154
|
-
const createSpinner2 =
|
|
2602
|
+
const createSpinner2 = createStepSpinner(
|
|
2603
|
+
4,
|
|
2604
|
+
TOTAL_STEPS,
|
|
2605
|
+
`Creating ${theme.count(acceptedBrags.length)} brag${acceptedBrags.length > 1 ? "s" : ""}`
|
|
2606
|
+
);
|
|
2155
2607
|
createSpinner2.start();
|
|
2156
2608
|
const createRequest = {
|
|
2157
|
-
brags:
|
|
2158
|
-
const originalCommit = selectedCommits
|
|
2609
|
+
brags: acceptedBrags.map((refined, index) => {
|
|
2610
|
+
const originalCommit = selectedCommits[index];
|
|
2159
2611
|
return {
|
|
2160
|
-
commit_sha:
|
|
2612
|
+
commit_sha: originalCommit?.sha || `brag-${index}`,
|
|
2161
2613
|
title: refined.refined_title,
|
|
2162
2614
|
description: refined.refined_description,
|
|
2163
2615
|
tags: refined.suggested_tags,
|
|
2164
2616
|
repository: repoInfo.url,
|
|
2165
|
-
date:
|
|
2166
|
-
commit_url:
|
|
2167
|
-
impact_score: refined.
|
|
2617
|
+
date: refined.date,
|
|
2618
|
+
commit_url: originalCommit?.url || "",
|
|
2619
|
+
impact_score: refined.suggested_impactLevel,
|
|
2168
2620
|
impact_description: refined.impact_description
|
|
2169
2621
|
};
|
|
2170
2622
|
})
|
|
2171
2623
|
};
|
|
2172
2624
|
const createResponse = await apiService.createBrags(createRequest);
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
margin: 1,
|
|
2179
|
-
borderStyle: "round",
|
|
2180
|
-
borderColor: "green"
|
|
2181
|
-
})
|
|
2625
|
+
succeedStepSpinner(
|
|
2626
|
+
createSpinner2,
|
|
2627
|
+
4,
|
|
2628
|
+
TOTAL_STEPS,
|
|
2629
|
+
`Created ${theme.count(createResponse.created)} brag${createResponse.created > 1 ? "s" : ""}`
|
|
2182
2630
|
);
|
|
2631
|
+
logger.log("");
|
|
2632
|
+
logger.log(boxen6(formatSuccessMessage(createResponse.created), boxStyles.success));
|
|
2183
2633
|
} catch (error) {
|
|
2634
|
+
if (error instanceof CancelPromptError) {
|
|
2635
|
+
logger.log("");
|
|
2636
|
+
logger.info(theme.secondary("Scan cancelled."));
|
|
2637
|
+
logger.log("");
|
|
2638
|
+
return;
|
|
2639
|
+
}
|
|
2184
2640
|
const err = error;
|
|
2185
2641
|
logger.log("");
|
|
2186
|
-
logger.log(
|
|
2187
|
-
boxen4(formatErrorMessage(err.message, getErrorHint2(err)), {
|
|
2188
|
-
padding: 1,
|
|
2189
|
-
margin: 1,
|
|
2190
|
-
borderStyle: "round",
|
|
2191
|
-
borderColor: "red"
|
|
2192
|
-
})
|
|
2193
|
-
);
|
|
2642
|
+
logger.log(boxen6(formatErrorMessage(err.message, getErrorHint2(err)), boxStyles.error));
|
|
2194
2643
|
process.exit(1);
|
|
2195
2644
|
}
|
|
2196
2645
|
}
|
|
@@ -2216,29 +2665,14 @@ function getErrorHint2(error) {
|
|
|
2216
2665
|
// src/commands/list.ts
|
|
2217
2666
|
init_esm_shims();
|
|
2218
2667
|
init_api_service();
|
|
2219
|
-
|
|
2220
|
-
init_logger();
|
|
2221
|
-
import boxen5 from "boxen";
|
|
2222
|
-
import chalk8 from "chalk";
|
|
2668
|
+
import boxen7 from "boxen";
|
|
2223
2669
|
import Table2 from "cli-table3";
|
|
2670
|
+
init_logger();
|
|
2224
2671
|
async function listCommand(options = {}) {
|
|
2225
2672
|
logger.log("");
|
|
2226
2673
|
try {
|
|
2227
|
-
const isAuthenticated = await
|
|
2674
|
+
const isAuthenticated = await ensureAuthenticated();
|
|
2228
2675
|
if (!isAuthenticated) {
|
|
2229
|
-
logger.log(
|
|
2230
|
-
boxen5(
|
|
2231
|
-
`${chalk8.yellow.bold("\u26A0 Not authenticated")}
|
|
2232
|
-
|
|
2233
|
-
Please run ${chalk8.cyan("bragduck init")} to login first.`,
|
|
2234
|
-
{
|
|
2235
|
-
padding: 1,
|
|
2236
|
-
margin: 1,
|
|
2237
|
-
borderStyle: "round",
|
|
2238
|
-
borderColor: "yellow"
|
|
2239
|
-
}
|
|
2240
|
-
)
|
|
2241
|
-
);
|
|
2242
2676
|
process.exit(1);
|
|
2243
2677
|
}
|
|
2244
2678
|
const limit = options.limit || 50;
|
|
@@ -2259,7 +2693,9 @@ Please run ${chalk8.cyan("bragduck init")} to login first.`,
|
|
|
2259
2693
|
if (search || tags) {
|
|
2260
2694
|
logger.info("Try adjusting your filters or run without filters to see all brags");
|
|
2261
2695
|
} else {
|
|
2262
|
-
logger.info(
|
|
2696
|
+
logger.info(
|
|
2697
|
+
theme.secondary("Run ") + theme.command("bragduck scan") + theme.secondary(" to create your first brag!")
|
|
2698
|
+
);
|
|
2263
2699
|
}
|
|
2264
2700
|
return;
|
|
2265
2701
|
}
|
|
@@ -2273,7 +2709,7 @@ Please run ${chalk8.cyan("bragduck init")} to login first.`,
|
|
|
2273
2709
|
`Showing ${offset + 1}-${offset + response.brags.length} of ${response.total} total brags`
|
|
2274
2710
|
);
|
|
2275
2711
|
logger.info(
|
|
2276
|
-
|
|
2712
|
+
theme.secondary("Run ") + theme.command(`bragduck list --offset ${nextOffset}`) + theme.secondary(" to see more")
|
|
2277
2713
|
);
|
|
2278
2714
|
logger.log("");
|
|
2279
2715
|
} else if (offset > 0) {
|
|
@@ -2286,51 +2722,41 @@ Please run ${chalk8.cyan("bragduck init")} to login first.`,
|
|
|
2286
2722
|
const filterInfo = [];
|
|
2287
2723
|
if (search) filterInfo.push(`search: "${search}"`);
|
|
2288
2724
|
if (tags) filterInfo.push(`tags: ${tags.join(", ")}`);
|
|
2289
|
-
logger.info(
|
|
2725
|
+
logger.info(theme.info(`Filters applied: ${filterInfo.join(", ")}`));
|
|
2290
2726
|
logger.log("");
|
|
2291
2727
|
}
|
|
2292
2728
|
} catch (error) {
|
|
2293
2729
|
const err = error;
|
|
2294
2730
|
logger.log("");
|
|
2295
|
-
logger.log(
|
|
2296
|
-
boxen5(formatErrorMessage(err.message, getErrorHint3(err)), {
|
|
2297
|
-
padding: 1,
|
|
2298
|
-
margin: 1,
|
|
2299
|
-
borderStyle: "round",
|
|
2300
|
-
borderColor: "red"
|
|
2301
|
-
})
|
|
2302
|
-
);
|
|
2731
|
+
logger.log(boxen7(formatErrorMessage(err.message, getErrorHint3(err)), boxStyles.error));
|
|
2303
2732
|
process.exit(1);
|
|
2304
2733
|
}
|
|
2305
2734
|
}
|
|
2306
2735
|
function formatBragsTable(brags) {
|
|
2307
2736
|
const table = new Table2({
|
|
2308
2737
|
head: [
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2738
|
+
colors.primary("Date"),
|
|
2739
|
+
colors.primary("Title"),
|
|
2740
|
+
colors.primary("Description"),
|
|
2741
|
+
colors.primary("Tags"),
|
|
2742
|
+
colors.primary("Repository")
|
|
2314
2743
|
],
|
|
2315
2744
|
colWidths: [12, 30, 40, 20, 30],
|
|
2316
2745
|
wordWrap: true,
|
|
2317
|
-
style:
|
|
2318
|
-
head: [],
|
|
2319
|
-
border: ["gray"]
|
|
2320
|
-
}
|
|
2746
|
+
style: tableStyles.default.style
|
|
2321
2747
|
});
|
|
2322
2748
|
brags.forEach((brag) => {
|
|
2323
2749
|
const date = new Date(brag.date).toLocaleDateString();
|
|
2324
2750
|
const title = brag.title;
|
|
2325
2751
|
const description = truncateText(brag.description, 100);
|
|
2326
|
-
const tags = brag.tags.length > 0 ? brag.tags.join(", ") :
|
|
2327
|
-
const repository = brag.repository ? truncateText(extractRepoName(brag.repository), 25) :
|
|
2752
|
+
const tags = brag.tags.length > 0 ? brag.tags.join(", ") : colors.dim("none");
|
|
2753
|
+
const repository = brag.repository ? truncateText(extractRepoName(brag.repository), 25) : colors.dim("none");
|
|
2328
2754
|
table.push([
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2755
|
+
colors.highlight(date),
|
|
2756
|
+
colors.white(title),
|
|
2757
|
+
colors.dim(description),
|
|
2758
|
+
colors.primary(tags),
|
|
2759
|
+
colors.info(repository)
|
|
2334
2760
|
]);
|
|
2335
2761
|
});
|
|
2336
2762
|
return table.toString();
|
|
@@ -2367,8 +2793,8 @@ init_esm_shims();
|
|
|
2367
2793
|
init_storage_service();
|
|
2368
2794
|
init_logger();
|
|
2369
2795
|
init_constants();
|
|
2370
|
-
import
|
|
2371
|
-
import
|
|
2796
|
+
import boxen8 from "boxen";
|
|
2797
|
+
import chalk6 from "chalk";
|
|
2372
2798
|
import Table3 from "cli-table3";
|
|
2373
2799
|
init_errors();
|
|
2374
2800
|
var VALID_CONFIG_KEYS = Object.values(CONFIG_KEYS);
|
|
@@ -2400,9 +2826,10 @@ async function configCommand(subcommand, key, value) {
|
|
|
2400
2826
|
);
|
|
2401
2827
|
}
|
|
2402
2828
|
} catch (error) {
|
|
2829
|
+
const err = error;
|
|
2403
2830
|
logger.log("");
|
|
2404
2831
|
logger.log(
|
|
2405
|
-
|
|
2832
|
+
boxen8(formatErrorMessage(err.message, getConfigHint(err)), {
|
|
2406
2833
|
padding: 1,
|
|
2407
2834
|
margin: 1,
|
|
2408
2835
|
borderStyle: "round",
|
|
@@ -2418,7 +2845,7 @@ async function handleListConfig() {
|
|
|
2418
2845
|
autoVersionCheck: storageService.getConfig("autoVersionCheck")
|
|
2419
2846
|
};
|
|
2420
2847
|
const table = new Table3({
|
|
2421
|
-
head: [
|
|
2848
|
+
head: [chalk6.cyan("Key"), chalk6.cyan("Value"), chalk6.cyan("Default")],
|
|
2422
2849
|
colWidths: [25, 40, 40],
|
|
2423
2850
|
wordWrap: true,
|
|
2424
2851
|
style: {
|
|
@@ -2427,36 +2854,36 @@ async function handleListConfig() {
|
|
|
2427
2854
|
}
|
|
2428
2855
|
});
|
|
2429
2856
|
table.push([
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2857
|
+
chalk6.white("defaultCommitDays"),
|
|
2858
|
+
chalk6.yellow(String(config2.defaultCommitDays)),
|
|
2859
|
+
chalk6.dim(String(DEFAULT_CONFIG.defaultCommitDays))
|
|
2433
2860
|
]);
|
|
2434
2861
|
table.push([
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2862
|
+
chalk6.white("autoVersionCheck"),
|
|
2863
|
+
chalk6.yellow(String(config2.autoVersionCheck)),
|
|
2864
|
+
chalk6.dim(String(DEFAULT_CONFIG.autoVersionCheck))
|
|
2438
2865
|
]);
|
|
2439
2866
|
logger.info("Current configuration:");
|
|
2440
2867
|
logger.log("");
|
|
2441
2868
|
logger.log(table.toString());
|
|
2442
2869
|
logger.log("");
|
|
2443
|
-
logger.info(
|
|
2870
|
+
logger.info(chalk6.dim("To change a value: ") + chalk6.cyan("bragduck config set <key> <value>"));
|
|
2444
2871
|
logger.log("");
|
|
2445
2872
|
}
|
|
2446
2873
|
async function handleGetConfig(key) {
|
|
2447
2874
|
validateConfigKey(key);
|
|
2448
2875
|
const value = storageService.getConfig(key);
|
|
2449
2876
|
const defaultValue = DEFAULT_CONFIG[key];
|
|
2450
|
-
logger.info(`Configuration for ${
|
|
2877
|
+
logger.info(`Configuration for ${chalk6.cyan(key)}:`);
|
|
2451
2878
|
logger.log("");
|
|
2452
|
-
logger.log(` ${
|
|
2453
|
-
logger.log(` ${
|
|
2879
|
+
logger.log(` ${chalk6.white("Current:")} ${chalk6.yellow(String(value))}`);
|
|
2880
|
+
logger.log(` ${chalk6.white("Default:")} ${chalk6.dim(String(defaultValue))}`);
|
|
2454
2881
|
logger.log("");
|
|
2455
2882
|
if (value === defaultValue) {
|
|
2456
|
-
logger.info(
|
|
2883
|
+
logger.info(chalk6.dim("Using default value"));
|
|
2457
2884
|
} else {
|
|
2458
2885
|
logger.info(
|
|
2459
|
-
|
|
2886
|
+
chalk6.dim("Custom value set. Reset with: ") + chalk6.cyan(`bragduck config set ${key} ${defaultValue}`)
|
|
2460
2887
|
);
|
|
2461
2888
|
}
|
|
2462
2889
|
logger.log("");
|
|
@@ -2466,10 +2893,10 @@ async function handleSetConfig(key, value) {
|
|
|
2466
2893
|
const typedValue = validateAndConvertValue(key, value);
|
|
2467
2894
|
storageService.setConfig(key, typedValue);
|
|
2468
2895
|
logger.log(
|
|
2469
|
-
|
|
2470
|
-
`${
|
|
2896
|
+
boxen8(
|
|
2897
|
+
`${chalk6.green.bold("\u2713 Configuration updated")}
|
|
2471
2898
|
|
|
2472
|
-
${
|
|
2899
|
+
${chalk6.white(key)}: ${chalk6.yellow(String(typedValue))}`,
|
|
2473
2900
|
{
|
|
2474
2901
|
padding: 1,
|
|
2475
2902
|
margin: 1,
|
|
@@ -2491,7 +2918,7 @@ ${VALID_CONFIG_KEYS.map((k) => ` - ${k}`).join("\n")}`
|
|
|
2491
2918
|
}
|
|
2492
2919
|
function validateAndConvertValue(key, value) {
|
|
2493
2920
|
switch (key) {
|
|
2494
|
-
case CONFIG_KEYS.DEFAULT_COMMIT_DAYS:
|
|
2921
|
+
case CONFIG_KEYS.DEFAULT_COMMIT_DAYS: {
|
|
2495
2922
|
const days = parseInt(value, 10);
|
|
2496
2923
|
if (isNaN(days) || days < 1 || days > 365) {
|
|
2497
2924
|
throw new ValidationError(
|
|
@@ -2501,7 +2928,8 @@ Must be a number between 1 and 365`
|
|
|
2501
2928
|
);
|
|
2502
2929
|
}
|
|
2503
2930
|
return days;
|
|
2504
|
-
|
|
2931
|
+
}
|
|
2932
|
+
case CONFIG_KEYS.AUTO_VERSION_CHECK: {
|
|
2505
2933
|
const lowerValue = value.toLowerCase();
|
|
2506
2934
|
if (lowerValue === "true" || lowerValue === "1" || lowerValue === "yes") {
|
|
2507
2935
|
return true;
|
|
@@ -2513,6 +2941,7 @@ Must be a number between 1 and 365`
|
|
|
2513
2941
|
|
|
2514
2942
|
Must be one of: true, false, yes, no, 1, 0`
|
|
2515
2943
|
);
|
|
2944
|
+
}
|
|
2516
2945
|
default:
|
|
2517
2946
|
throw new ValidationError(`Unknown config key: "${key}"`);
|
|
2518
2947
|
}
|
|
@@ -2573,7 +3002,7 @@ program.command("config [subcommand] [key] [value]").description("Manage CLI con
|
|
|
2573
3002
|
process.exit(1);
|
|
2574
3003
|
}
|
|
2575
3004
|
});
|
|
2576
|
-
program.hook("preAction", async (
|
|
3005
|
+
program.hook("preAction", async () => {
|
|
2577
3006
|
const options = program.opts();
|
|
2578
3007
|
if (options.debug) {
|
|
2579
3008
|
process.env.DEBUG = "true";
|
|
@@ -2583,7 +3012,7 @@ program.hook("preAction", async (_thisCommand) => {
|
|
|
2583
3012
|
if (!options.skipVersionCheck && !isVersionOrHelp) {
|
|
2584
3013
|
try {
|
|
2585
3014
|
await checkForUpdates({ silent: false });
|
|
2586
|
-
} catch
|
|
3015
|
+
} catch {
|
|
2587
3016
|
logger.debug("Version check failed, continuing...");
|
|
2588
3017
|
}
|
|
2589
3018
|
}
|