@bragduck/cli 2.39.1 → 2.40.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.
@@ -6375,9 +6375,9 @@ async function promptSortOption() {
6375
6375
  default: "date"
6376
6376
  });
6377
6377
  }
6378
- async function promptSelectOrganisation(organisations) {
6378
+ async function promptSelectOrganisation(organisations, allowNone = true) {
6379
6379
  const choices = [
6380
- { name: "No company", value: "none" },
6380
+ ...allowNone ? [{ name: "No company", value: "none" }] : [],
6381
6381
  ...organisations.map((org) => ({
6382
6382
  name: org.name,
6383
6383
  value: org.id
@@ -6386,11 +6386,11 @@ async function promptSelectOrganisation(organisations) {
6386
6386
  const selected = await select3({
6387
6387
  message: "Attach brags to which company?",
6388
6388
  choices,
6389
- default: "none"
6389
+ default: allowNone ? "none" : void 0
6390
6390
  });
6391
6391
  return selected === "none" ? null : selected;
6392
6392
  }
6393
- async function promptSelectOrganisationWithDefault(organisations, defaultOrgId) {
6393
+ async function promptSelectOrganisationWithDefault(organisations, defaultOrgId, allowNone = true) {
6394
6394
  if (defaultOrgId) {
6395
6395
  const defaultOrg = organisations.find((org) => org.id === defaultOrgId);
6396
6396
  if (defaultOrg) {
@@ -6403,7 +6403,7 @@ async function promptSelectOrganisationWithDefault(organisations, defaultOrgId)
6403
6403
  }
6404
6404
  }
6405
6405
  }
6406
- return await promptSelectOrganisation(organisations);
6406
+ return await promptSelectOrganisation(organisations, allowNone);
6407
6407
  }
6408
6408
  async function promptReviewBrags(refinedBrags, selectedCommits) {
6409
6409
  const acceptedBrags = [];
@@ -6733,9 +6733,56 @@ async function discoverRepositories() {
6733
6733
  // src/sync/multi-repo-sync.ts
6734
6734
  init_esm_shims();
6735
6735
  init_api_service();
6736
+ init_storage_service();
6737
+
6738
+ // src/sync/organisation.ts
6739
+ init_esm_shims();
6740
+ init_api_service();
6736
6741
  init_auth_service();
6737
6742
  init_storage_service();
6738
6743
  init_logger();
6744
+ init_errors();
6745
+ var CREATE_COMPANY_URL = "https://bragduck.com/app";
6746
+ async function loadSyncOrganisations() {
6747
+ const userInfo = authService.getUserInfo();
6748
+ if (!userInfo?.id) {
6749
+ throw new AuthenticationError("Could not read your account to load your companies");
6750
+ }
6751
+ const orgsResponse = await apiService.listUserOrganisations(userInfo.id);
6752
+ const companies = orgsResponse.items.filter((org) => org.role !== "__virtual__");
6753
+ if (companies.length === 0) {
6754
+ throw new ValidationError(
6755
+ `Synced brags belong to a company, and you don't have one yet. Create a company at ${CREATE_COMPANY_URL}, then run sync again.`,
6756
+ { hint: `Create a company at ${CREATE_COMPANY_URL}` }
6757
+ );
6758
+ }
6759
+ return companies;
6760
+ }
6761
+ async function selectSyncOrganisation(organisations, turbo) {
6762
+ if (organisations.length === 1) {
6763
+ return organisations[0].id;
6764
+ }
6765
+ const defaultOrgId = storageService.getConfig("defaultCompany");
6766
+ if (turbo) {
6767
+ if (defaultOrgId && organisations.some((org) => org.id === defaultOrgId)) {
6768
+ logger.debug(`Turbo mode: using default company ${defaultOrgId}`);
6769
+ return defaultOrgId;
6770
+ }
6771
+ const companies = organisations.map((org) => `${org.name} (${org.id})`).join(", ");
6772
+ throw new ValidationError(
6773
+ `Turbo mode needs a default company when you belong to more than one: ${companies}`,
6774
+ {
6775
+ hint: 'Run "bragduck config set defaultCompany <company-id>", or sync without --turbo to pick one'
6776
+ }
6777
+ );
6778
+ }
6779
+ const orgId = await promptSelectOrganisationWithDefault(organisations, defaultOrgId, false);
6780
+ logger.log("");
6781
+ return orgId;
6782
+ }
6783
+
6784
+ // src/sync/multi-repo-sync.ts
6785
+ init_logger();
6739
6786
 
6740
6787
  // src/utils/source-tag.ts
6741
6788
  init_esm_shims();
@@ -6865,6 +6912,7 @@ async function syncSingleRepository(repo, days, sortOption, scanMode, orgId, opt
6865
6912
  );
6866
6913
  refineSpinner.start();
6867
6914
  const refineRequest = {
6915
+ orgId,
6868
6916
  brags: selectedCommits.map((c) => ({
6869
6917
  text: c.message,
6870
6918
  date: c.date,
@@ -6919,7 +6967,7 @@ async function syncSingleRepository(repo, days, sortOption, scanMode, orgId, opt
6919
6967
  impactDescription: refined.impact_description,
6920
6968
  impact_description: refined.impact_description,
6921
6969
  attachments: originalCommit?.url ? [originalCommit.url] : [],
6922
- orgId: orgId || void 0,
6970
+ orgId,
6923
6971
  // External fields for non-git sources
6924
6972
  externalId: originalCommit?.externalId,
6925
6973
  externalType: originalCommit?.externalType,
@@ -6969,6 +7017,8 @@ async function syncSingleRepository(repo, days, sortOption, scanMode, orgId, opt
6969
7017
  }
6970
7018
  async function syncMultipleRepositories(repos, options) {
6971
7019
  logger.debug(`Starting multi-repo sync for ${repos.length} repositories`);
7020
+ const organisations = await loadSyncOrganisations();
7021
+ const turboOrgId = options.turbo ? await selectSyncOrganisation(organisations, true) : void 0;
6972
7022
  let days = options.days;
6973
7023
  if (!days && options.today) {
6974
7024
  days = 1;
@@ -7010,25 +7060,7 @@ async function syncMultipleRepositories(repos, options) {
7010
7060
  logger.log(colors.highlight(`\u2501\u2501\u2501 Syncing ${current}/${total}: ${repo.name} \u2501\u2501\u2501`));
7011
7061
  logger.log("");
7012
7062
  try {
7013
- let selectedOrgId = null;
7014
- if (!options.turbo) {
7015
- const userInfo = authService.getUserInfo();
7016
- if (userInfo?.id) {
7017
- try {
7018
- const orgsResponse = await apiService.listUserOrganisations(userInfo.id);
7019
- if (orgsResponse.items.length > 0) {
7020
- const defaultOrgId = storageService.getConfig("defaultCompany");
7021
- selectedOrgId = await promptSelectOrganisationWithDefault(
7022
- orgsResponse.items,
7023
- defaultOrgId
7024
- );
7025
- logger.log("");
7026
- }
7027
- } catch {
7028
- logger.debug("Failed to fetch organisations, skipping org selection");
7029
- }
7030
- }
7031
- }
7063
+ const selectedOrgId = turboOrgId ?? await selectSyncOrganisation(organisations);
7032
7064
  const result = await syncSingleRepository(
7033
7065
  repo,
7034
7066
  days,
@@ -7129,6 +7161,7 @@ async function promptSelectService() {
7129
7161
  return selected;
7130
7162
  }
7131
7163
  async function syncSingleService(sourceType, options, TOTAL_STEPS, sharedDays, sharedOrgId) {
7164
+ const selectedOrgId = sharedOrgId ?? await pickSyncOrganisation(options);
7132
7165
  const adapter = AdapterFactory.getAdapter(sourceType);
7133
7166
  const validationText = sourceType === "jira" || sourceType === "confluence" ? "Connecting to Atlassian instance" : sourceType === "google-docs" ? "Connecting to Google Drive" : "Validating repository";
7134
7167
  const repoSpinner = createStepSpinner(2, TOTAL_STEPS, validationText);
@@ -7274,6 +7307,7 @@ async function syncSingleService(sourceType, options, TOTAL_STEPS, sharedDays, s
7274
7307
  );
7275
7308
  refineSpinner.start();
7276
7309
  const refineRequest = {
7310
+ orgId: selectedOrgId,
7277
7311
  brags: selectedCommits.map((c) => ({
7278
7312
  text: c.message,
7279
7313
  date: c.date,
@@ -7303,25 +7337,6 @@ async function syncSingleService(sourceType, options, TOTAL_STEPS, sharedDays, s
7303
7337
  return { created: 0, skipped: duplicates.length };
7304
7338
  }
7305
7339
  logger.log("");
7306
- let selectedOrgId = sharedOrgId !== void 0 ? sharedOrgId : null;
7307
- if (sharedOrgId === void 0) {
7308
- const userInfo = authService.getUserInfo();
7309
- if (userInfo?.id) {
7310
- const orgSpinner = createFetchSpinner("Loading organizations...");
7311
- orgSpinner.start();
7312
- try {
7313
- const orgsResponse = await apiService.listUserOrganisations(userInfo.id);
7314
- orgSpinner.stop();
7315
- if (orgsResponse.items.length > 0) {
7316
- selectedOrgId = await promptSelectOrganisation(orgsResponse.items);
7317
- logger.log("");
7318
- }
7319
- } catch {
7320
- orgSpinner.stop();
7321
- logger.debug("Failed to fetch organisations, skipping org selection");
7322
- }
7323
- }
7324
- }
7325
7340
  const createSpinner = createStepSpinner(
7326
7341
  5,
7327
7342
  TOTAL_STEPS,
@@ -7350,7 +7365,7 @@ async function syncSingleService(sourceType, options, TOTAL_STEPS, sharedDays, s
7350
7365
  impactDescription: refined.impact_description,
7351
7366
  impact_description: refined.impact_description,
7352
7367
  attachments: [],
7353
- orgId: selectedOrgId || void 0,
7368
+ orgId: selectedOrgId,
7354
7369
  // External fields for non-git sources (Jira, Confluence, etc.)
7355
7370
  externalId: originalCommit?.externalId,
7356
7371
  externalType: originalCommit?.externalType,
@@ -7466,26 +7481,7 @@ async function syncAllAuthenticatedServices(options) {
7466
7481
  sharedDays = storageService.getConfig("defaultCommitDays") || 30;
7467
7482
  logger.debug(`Turbo mode: using default ${sharedDays} days`);
7468
7483
  }
7469
- let sharedOrgId = null;
7470
- if (!options.turbo) {
7471
- const userInfo = authService.getUserInfo();
7472
- if (userInfo?.id) {
7473
- const orgSpinner = createFetchSpinner("Loading organizations...");
7474
- orgSpinner.start();
7475
- try {
7476
- const orgsResponse = await apiService.listUserOrganisations(userInfo.id);
7477
- orgSpinner.stop();
7478
- if (orgsResponse.items.length > 0) {
7479
- const defaultOrgId = storageService.getConfig("defaultCompany");
7480
- sharedOrgId = await promptSelectOrganisationWithDefault(orgsResponse.items, defaultOrgId);
7481
- logger.log("");
7482
- }
7483
- } catch {
7484
- orgSpinner.stop();
7485
- logger.debug("Failed to fetch organisations, skipping org selection");
7486
- }
7487
- }
7488
- }
7484
+ const sharedOrgId = await pickSyncOrganisation(options);
7489
7485
  const results = [];
7490
7486
  for (let i = 0; i < servicesToSync.length; i++) {
7491
7487
  const service = servicesToSync[i];
@@ -7808,6 +7804,17 @@ To authenticate:
7808
7804
  process.exit(1);
7809
7805
  }
7810
7806
  }
7807
+ async function pickSyncOrganisation(options) {
7808
+ const orgSpinner = createFetchSpinner("Loading organizations...");
7809
+ orgSpinner.start();
7810
+ let organisations;
7811
+ try {
7812
+ organisations = await loadSyncOrganisations();
7813
+ } finally {
7814
+ orgSpinner.stop();
7815
+ }
7816
+ return await selectSyncOrganisation(organisations, options.turbo);
7817
+ }
7811
7818
  function getServiceLabel(service) {
7812
7819
  if (service === "google-docs") return "Google Docs";
7813
7820
  if (service === "slack") return "Slack";
@@ -7838,7 +7845,7 @@ function getErrorHint(error, sourceType) {
7838
7845
  }
7839
7846
  return 'Run "bragduck auth login" to login again';
7840
7847
  }
7841
- if (error.name === "IntegrationError" && error.details?.hint) {
7848
+ if ((error.name === "IntegrationError" || error.name === "ValidationError") && error.details?.hint) {
7842
7849
  return error.details.hint;
7843
7850
  }
7844
7851
  if (error.name === "GoogleDocsError") {