@bragduck/cli 2.7.0 → 2.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ var init_esm_shims = __esm({
22
22
  import { config } from "dotenv";
23
23
  import { fileURLToPath as fileURLToPath2 } from "url";
24
24
  import { dirname, join } from "path";
25
- var __filename, __dirname, APP_NAME, DEFAULT_CONFIG, OAUTH_CONFIG, API_ENDPOINTS, ENCRYPTION_CONFIG, STORAGE_PATHS, HTTP_STATUS;
25
+ var __filename, __dirname, APP_NAME, DEFAULT_CONFIG, OAUTH_CONFIG, API_ENDPOINTS, ENCRYPTION_CONFIG, STORAGE_PATHS, HTTP_STATUS, CONFIG_FILES;
26
26
  var init_constants = __esm({
27
27
  "src/constants.ts"() {
28
28
  "use strict";
@@ -33,7 +33,12 @@ var init_constants = __esm({
33
33
  APP_NAME = "bragduck";
34
34
  DEFAULT_CONFIG = {
35
35
  defaultCommitDays: 30,
36
- autoVersionCheck: true
36
+ autoVersionCheck: true,
37
+ defaultSource: void 0,
38
+ sourcePriority: void 0,
39
+ jiraInstance: void 0,
40
+ confluenceInstance: void 0,
41
+ gitlabInstance: void 0
37
42
  };
38
43
  OAUTH_CONFIG = {
39
44
  CLIENT_ID: "bragduck-cli",
@@ -88,6 +93,222 @@ var init_constants = __esm({
88
93
  NOT_FOUND: 404,
89
94
  INTERNAL_SERVER_ERROR: 500
90
95
  };
96
+ CONFIG_FILES = [".bragduckrc", ".bragduck/config.json", ".bragduckrc.json"];
97
+ }
98
+ });
99
+
100
+ // src/utils/env-loader.ts
101
+ function parseEnvNumber(key) {
102
+ const value = process.env[key];
103
+ if (!value) return void 0;
104
+ const parsed = parseInt(value, 10);
105
+ return isNaN(parsed) ? void 0 : parsed;
106
+ }
107
+ function parseEnvBoolean(key) {
108
+ const value = process.env[key]?.toLowerCase();
109
+ if (!value) return void 0;
110
+ if (["true", "yes", "1"].includes(value)) return true;
111
+ if (["false", "no", "0"].includes(value)) return false;
112
+ return void 0;
113
+ }
114
+ function parseEnvArray(key) {
115
+ const value = process.env[key];
116
+ if (!value) return void 0;
117
+ const items = value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
118
+ return items.length > 0 ? items : void 0;
119
+ }
120
+ function parseEnvSource(key) {
121
+ const value = process.env[key];
122
+ if (!value) return void 0;
123
+ const validSources = ["github", "gitlab", "bitbucket", "jira", "confluence"];
124
+ return validSources.includes(value) ? value : void 0;
125
+ }
126
+ function loadEnvConfig() {
127
+ return {
128
+ // Source configuration
129
+ source: parseEnvSource("BRAGDUCK_SOURCE"),
130
+ jiraInstance: process.env.BRAGDUCK_JIRA_INSTANCE,
131
+ confluenceInstance: process.env.BRAGDUCK_CONFLUENCE_INSTANCE,
132
+ gitlabInstance: process.env.BRAGDUCK_GITLAB_INSTANCE,
133
+ // Behavior configuration
134
+ defaultCommitDays: parseEnvNumber("BRAGDUCK_DEFAULT_COMMIT_DAYS"),
135
+ autoVersionCheck: parseEnvBoolean("BRAGDUCK_AUTO_VERSION_CHECK"),
136
+ sourcePriority: parseEnvArray("BRAGDUCK_SOURCE_PRIORITY"),
137
+ // Credential overrides (for CI/CD)
138
+ jiraToken: process.env.BRAGDUCK_JIRA_TOKEN,
139
+ confluenceToken: process.env.BRAGDUCK_CONFLUENCE_TOKEN,
140
+ gitlabToken: process.env.BRAGDUCK_GITLAB_TOKEN
141
+ };
142
+ }
143
+ var init_env_loader = __esm({
144
+ "src/utils/env-loader.ts"() {
145
+ "use strict";
146
+ init_esm_shims();
147
+ }
148
+ });
149
+
150
+ // src/utils/errors.ts
151
+ var BragduckError, AuthenticationError, ApiError, NetworkError, ValidationError, OAuthError, TokenExpiredError;
152
+ var init_errors = __esm({
153
+ "src/utils/errors.ts"() {
154
+ "use strict";
155
+ init_esm_shims();
156
+ BragduckError = class extends Error {
157
+ code;
158
+ details;
159
+ constructor(message, code, details) {
160
+ super(message);
161
+ this.name = "BragduckError";
162
+ this.code = code;
163
+ this.details = details;
164
+ Error.captureStackTrace(this, this.constructor);
165
+ }
166
+ };
167
+ AuthenticationError = class extends BragduckError {
168
+ constructor(message, details) {
169
+ super(message, "AUTH_ERROR", details);
170
+ this.name = "AuthenticationError";
171
+ }
172
+ };
173
+ ApiError = class extends BragduckError {
174
+ statusCode;
175
+ constructor(message, statusCode, details) {
176
+ super(message, "API_ERROR", details);
177
+ this.name = "ApiError";
178
+ this.statusCode = statusCode;
179
+ }
180
+ };
181
+ NetworkError = class extends BragduckError {
182
+ constructor(message, details) {
183
+ super(message, "NETWORK_ERROR", details);
184
+ this.name = "NetworkError";
185
+ }
186
+ };
187
+ ValidationError = class extends BragduckError {
188
+ constructor(message, details) {
189
+ super(message, "VALIDATION_ERROR", details);
190
+ this.name = "ValidationError";
191
+ }
192
+ };
193
+ OAuthError = class extends AuthenticationError {
194
+ constructor(message, details) {
195
+ super(message, details);
196
+ this.name = "OAuthError";
197
+ }
198
+ };
199
+ TokenExpiredError = class extends AuthenticationError {
200
+ constructor(message = "Authentication token has expired") {
201
+ super(message);
202
+ this.name = "TokenExpiredError";
203
+ this.code = "TOKEN_EXPIRED";
204
+ }
205
+ };
206
+ }
207
+ });
208
+
209
+ // src/utils/config-loader.ts
210
+ import { promises as fs } from "fs";
211
+ import path2 from "path";
212
+ async function findProjectConfig() {
213
+ const cwd = process.cwd();
214
+ if (configCache.has(cwd)) {
215
+ return configCache.get(cwd) || null;
216
+ }
217
+ for (const filename of CONFIG_FILES) {
218
+ const configPath = path2.join(cwd, filename);
219
+ try {
220
+ await fs.access(configPath);
221
+ const config2 = await loadAndValidateConfig(configPath);
222
+ configCache.set(cwd, config2);
223
+ return config2;
224
+ } catch {
225
+ continue;
226
+ }
227
+ }
228
+ configCache.set(cwd, null);
229
+ return null;
230
+ }
231
+ async function loadAndValidateConfig(configPath) {
232
+ try {
233
+ const content = await fs.readFile(configPath, "utf-8");
234
+ const config2 = JSON.parse(content);
235
+ validateProjectConfig(config2);
236
+ return config2;
237
+ } catch (error) {
238
+ if (error instanceof SyntaxError) {
239
+ throw new ValidationError(`Invalid JSON in config file: ${configPath}`, {
240
+ originalError: error.message
241
+ });
242
+ }
243
+ throw error;
244
+ }
245
+ }
246
+ function validateProjectConfig(config2) {
247
+ if (typeof config2 !== "object" || config2 === null) {
248
+ throw new ValidationError("Config must be a JSON object");
249
+ }
250
+ const cfg = config2;
251
+ if (cfg.defaultCommitDays !== void 0) {
252
+ if (typeof cfg.defaultCommitDays !== "number") {
253
+ throw new ValidationError("defaultCommitDays must be a number");
254
+ }
255
+ if (cfg.defaultCommitDays < 1 || cfg.defaultCommitDays > 365) {
256
+ throw new ValidationError("defaultCommitDays must be between 1 and 365");
257
+ }
258
+ }
259
+ if (cfg.autoVersionCheck !== void 0) {
260
+ if (typeof cfg.autoVersionCheck !== "boolean") {
261
+ throw new ValidationError("autoVersionCheck must be a boolean");
262
+ }
263
+ }
264
+ if (cfg.defaultSource !== void 0) {
265
+ const validSources = ["github", "gitlab", "bitbucket", "jira", "confluence"];
266
+ if (!validSources.includes(cfg.defaultSource)) {
267
+ throw new ValidationError(
268
+ `Invalid defaultSource: ${cfg.defaultSource}. Must be one of: ${validSources.join(", ")}`
269
+ );
270
+ }
271
+ }
272
+ if (cfg.sourcePriority !== void 0) {
273
+ if (!Array.isArray(cfg.sourcePriority)) {
274
+ throw new ValidationError("sourcePriority must be an array");
275
+ }
276
+ const validSources = ["github", "gitlab", "bitbucket", "jira", "confluence"];
277
+ for (const source of cfg.sourcePriority) {
278
+ if (!validSources.includes(source)) {
279
+ throw new ValidationError(
280
+ `Invalid source in sourcePriority: ${source}. Must be one of: ${validSources.join(", ")}`
281
+ );
282
+ }
283
+ }
284
+ }
285
+ const instanceFields = ["jiraInstance", "confluenceInstance", "gitlabInstance"];
286
+ for (const field of instanceFields) {
287
+ if (cfg[field] !== void 0) {
288
+ if (typeof cfg[field] !== "string") {
289
+ throw new ValidationError(`${field} must be a string`);
290
+ }
291
+ const value = cfg[field];
292
+ if (!value.match(/^[a-zA-Z0-9.-]+(:[0-9]+)?(\/.*)?$/)) {
293
+ throw new ValidationError(`Invalid ${field}: ${value}`);
294
+ }
295
+ }
296
+ }
297
+ const booleanFields = ["requireAuthentication", "skipSourceDetection"];
298
+ for (const field of booleanFields) {
299
+ if (cfg[field] !== void 0 && typeof cfg[field] !== "boolean") {
300
+ throw new ValidationError(`${field} must be a boolean`);
301
+ }
302
+ }
303
+ }
304
+ var configCache;
305
+ var init_config_loader = __esm({
306
+ "src/utils/config-loader.ts"() {
307
+ "use strict";
308
+ init_esm_shims();
309
+ init_constants();
310
+ init_errors();
311
+ configCache = /* @__PURE__ */ new Map();
91
312
  }
92
313
  });
93
314
 
@@ -103,6 +324,8 @@ var init_storage_service = __esm({
103
324
  "use strict";
104
325
  init_esm_shims();
105
326
  init_constants();
327
+ init_env_loader();
328
+ init_config_loader();
106
329
  StorageService = class {
107
330
  config;
108
331
  storageBackend;
@@ -216,17 +439,10 @@ var init_storage_service = __esm({
216
439
  }
217
440
  }
218
441
  /**
219
- * Check if user is authenticated
442
+ * Check if user is authenticated (checks bragduck service)
220
443
  */
221
444
  async isAuthenticated() {
222
- const credentials = await this.getCredentials();
223
- if (!credentials || !credentials.accessToken) {
224
- return false;
225
- }
226
- if (credentials.expiresAt && credentials.expiresAt < Date.now()) {
227
- return false;
228
- }
229
- return true;
445
+ return this.isServiceAuthenticated("bragduck");
230
446
  }
231
447
  /**
232
448
  * Get credentials for a specific service
@@ -341,7 +557,27 @@ var init_storage_service = __esm({
341
557
  this.config.delete("oauthState");
342
558
  }
343
559
  /**
344
- * Get configuration value
560
+ * Get configuration value with hierarchy resolution
561
+ * Priority: env vars > project config > user config > defaults
562
+ */
563
+ async getConfigWithHierarchy(key) {
564
+ const envConfig = loadEnvConfig();
565
+ const envKey = key === "defaultSource" ? "source" : key;
566
+ if (envConfig[envKey] !== void 0) {
567
+ return envConfig[envKey];
568
+ }
569
+ const projectConfig = await findProjectConfig();
570
+ if (projectConfig && projectConfig[key] !== void 0) {
571
+ return projectConfig[key];
572
+ }
573
+ const userValue = this.config.get(key);
574
+ if (userValue !== void 0) {
575
+ return userValue;
576
+ }
577
+ return DEFAULT_CONFIG[key];
578
+ }
579
+ /**
580
+ * Get configuration value (uses hierarchy resolution)
345
581
  */
346
582
  getConfig(key) {
347
583
  return this.config.get(key);
@@ -353,7 +589,32 @@ var init_storage_service = __esm({
353
589
  this.config.set(key, value);
354
590
  }
355
591
  /**
356
- * Get all configuration
592
+ * Get all configuration (merges all layers)
593
+ * Priority: env vars > project config > user config > defaults
594
+ */
595
+ async getAllConfigWithHierarchy() {
596
+ const envConfig = loadEnvConfig();
597
+ const projectConfig = await findProjectConfig();
598
+ const userConfig = this.config.store;
599
+ return {
600
+ ...DEFAULT_CONFIG,
601
+ ...userConfig,
602
+ ...projectConfig,
603
+ ...envConfig.source && { defaultSource: envConfig.source },
604
+ ...envConfig.jiraInstance && { jiraInstance: envConfig.jiraInstance },
605
+ ...envConfig.confluenceInstance && { confluenceInstance: envConfig.confluenceInstance },
606
+ ...envConfig.gitlabInstance && { gitlabInstance: envConfig.gitlabInstance },
607
+ ...envConfig.defaultCommitDays !== void 0 && {
608
+ defaultCommitDays: envConfig.defaultCommitDays
609
+ },
610
+ ...envConfig.autoVersionCheck !== void 0 && {
611
+ autoVersionCheck: envConfig.autoVersionCheck
612
+ },
613
+ ...envConfig.sourcePriority && { sourcePriority: envConfig.sourcePriority }
614
+ };
615
+ }
616
+ /**
617
+ * Get all configuration (user config only)
357
618
  */
358
619
  getAllConfig() {
359
620
  return this.config.store;
@@ -364,7 +625,9 @@ var init_storage_service = __esm({
364
625
  resetConfig() {
365
626
  this.config.clear();
366
627
  Object.entries(DEFAULT_CONFIG).forEach(([key, value]) => {
367
- this.config.set(key, value);
628
+ if (value !== void 0) {
629
+ this.config.set(key, value);
630
+ }
368
631
  });
369
632
  }
370
633
  /**
@@ -387,59 +650,6 @@ var init_storage_service = __esm({
387
650
  }
388
651
  });
389
652
 
390
- // src/utils/errors.ts
391
- var BragduckError, AuthenticationError, ApiError, NetworkError, OAuthError, TokenExpiredError;
392
- var init_errors = __esm({
393
- "src/utils/errors.ts"() {
394
- "use strict";
395
- init_esm_shims();
396
- BragduckError = class extends Error {
397
- code;
398
- details;
399
- constructor(message, code, details) {
400
- super(message);
401
- this.name = "BragduckError";
402
- this.code = code;
403
- this.details = details;
404
- Error.captureStackTrace(this, this.constructor);
405
- }
406
- };
407
- AuthenticationError = class extends BragduckError {
408
- constructor(message, details) {
409
- super(message, "AUTH_ERROR", details);
410
- this.name = "AuthenticationError";
411
- }
412
- };
413
- ApiError = class extends BragduckError {
414
- statusCode;
415
- constructor(message, statusCode, details) {
416
- super(message, "API_ERROR", details);
417
- this.name = "ApiError";
418
- this.statusCode = statusCode;
419
- }
420
- };
421
- NetworkError = class extends BragduckError {
422
- constructor(message, details) {
423
- super(message, "NETWORK_ERROR", details);
424
- this.name = "NetworkError";
425
- }
426
- };
427
- OAuthError = class extends AuthenticationError {
428
- constructor(message, details) {
429
- super(message, details);
430
- this.name = "OAuthError";
431
- }
432
- };
433
- TokenExpiredError = class extends AuthenticationError {
434
- constructor(message = "Authentication token has expired") {
435
- super(message);
436
- this.name = "TokenExpiredError";
437
- this.code = "TOKEN_EXPIRED";
438
- }
439
- };
440
- }
441
- });
442
-
443
653
  // src/utils/logger.ts
444
654
  import chalk from "chalk";
445
655
  var logger;