@bragduck/cli 2.37.1 → 2.38.2

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.
@@ -63,7 +63,7 @@ var init_constants = __esm({
63
63
  CLIENT_ID: "kJlsd66DLTnENE8p7Ru2JwqZg1Sie4yZ",
64
64
  AUTH_URL: "https://auth.atlassian.com/authorize",
65
65
  AUDIENCE: "api.atlassian.com",
66
- SCOPES: "read:jira-work read:jira-user read:page:confluence read:confluence-user offline_access read:me",
66
+ SCOPES: "read:jira-work read:jira-user read:confluence-content.all read:confluence-user offline_access",
67
67
  ACCESSIBLE_RESOURCES_URL: "https://api.atlassian.com/oauth/token/accessible-resources",
68
68
  API_GATEWAY_URL: "https://api.atlassian.com"
69
69
  };
@@ -1891,6 +1891,19 @@ var AtlassianAuthService = class {
1891
1891
  callbackResult = await resultPromise;
1892
1892
  } catch (error) {
1893
1893
  storageService.deleteOAuthState();
1894
+ const rawMessage = error?.message ?? String(error);
1895
+ if (/invalid_scope/i.test(rawMessage)) {
1896
+ throw new AtlassianError(
1897
+ "Atlassian rejected the requested scopes. The app must list all of these classic scopes: read:jira-work, read:jira-user, read:confluence-content.all, read:confluence-user, offline_access.",
1898
+ { originalError: rawMessage }
1899
+ );
1900
+ }
1901
+ if (/redirect_uri|invalid_request/i.test(rawMessage)) {
1902
+ throw new AtlassianError(
1903
+ "Atlassian rejected the redirect URI. All of http://127.0.0.1:8000/callback through http://127.0.0.1:8004/callback must be registered in the Atlassian app callback URL list.",
1904
+ { originalError: rawMessage }
1905
+ );
1906
+ }
1894
1907
  throw error;
1895
1908
  }
1896
1909
  storageService.deleteOAuthState();
@@ -4275,6 +4288,13 @@ init_errors();
4275
4288
  init_logger();
4276
4289
  init_storage_service();
4277
4290
  init_constants();
4291
+ function adfToText(node) {
4292
+ if (!node) return "";
4293
+ if (typeof node === "string") return node;
4294
+ if (node.text) return node.text;
4295
+ if (node.content) return node.content.map(adfToText).join("");
4296
+ return "";
4297
+ }
4278
4298
  var JiraService = class {
4279
4299
  MAX_DESCRIPTION_LENGTH = 5e3;
4280
4300
  /**
@@ -4469,9 +4489,10 @@ var JiraService = class {
4469
4489
  * Determine the type of contribution the current user made to an issue
4470
4490
  * Returns: 'created' | 'reported' | 'assigned-resolved' | 'edited'
4471
4491
  */
4472
- async determineJiraContributionType(issue, userEmail) {
4473
- const isCreator = issue.fields.creator.emailAddress === userEmail;
4474
- const isReporter = issue.fields.reporter?.emailAddress === userEmail;
4492
+ async determineJiraContributionType(issue, userIdentifier) {
4493
+ const matchesUser = (person) => !!person && (person.accountId === userIdentifier || person.emailAddress === userIdentifier);
4494
+ const isCreator = matchesUser(issue.fields.creator);
4495
+ const isReporter = matchesUser(issue.fields.reporter);
4475
4496
  if (isCreator) {
4476
4497
  return {
4477
4498
  type: "created",
@@ -4484,9 +4505,9 @@ var JiraService = class {
4484
4505
  details: `Reported ${issue.fields.issuetype.name}: ${issue.fields.status.name}`
4485
4506
  };
4486
4507
  }
4487
- const isAssigned = issue.fields.assignee?.emailAddress === userEmail;
4508
+ const isAssigned = matchesUser(issue.fields.assignee);
4488
4509
  const isResolved = issue.fields.resolutiondate !== null && issue.fields.resolutiondate !== void 0;
4489
- const userEdits = issue.changelog?.histories?.filter((history) => history.author.emailAddress === userEmail) || [];
4510
+ const userEdits = issue.changelog?.histories?.filter((history) => matchesUser(history.author)) || [];
4490
4511
  const hasEdits = userEdits.length > 0;
4491
4512
  if (isAssigned && isResolved) {
4492
4513
  return {
@@ -4558,7 +4579,7 @@ var JiraService = class {
4558
4579
  );
4559
4580
  break;
4560
4581
  }
4561
- const endpoint = `/rest/api/3/search/jql?jql=${encodeURIComponent(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=${fields.join(",")}`;
4582
+ const endpoint = `/rest/api/3/search?jql=${encodeURIComponent(jql)}&startAt=${startAt}&maxResults=${maxResults}&fields=${fields.join(",")}`;
4562
4583
  try {
4563
4584
  const response = await this.request(endpoint);
4564
4585
  if (response.issues.length === 0) {
@@ -4663,7 +4684,8 @@ var JiraService = class {
4663
4684
 
4664
4685
  ${contribution.details}`;
4665
4686
  if (contribution.type === "created" && issue.fields.description) {
4666
- const truncatedDesc = issue.fields.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
4687
+ const plainDesc = adfToText(issue.fields.description);
4688
+ const truncatedDesc = plainDesc.substring(0, this.MAX_DESCRIPTION_LENGTH);
4667
4689
  message = `${contributionPrefix}${issue.fields.summary}
4668
4690
 
4669
4691
  ${truncatedDesc}
@@ -4673,7 +4695,8 @@ ${contribution.details}`;
4673
4695
  } else {
4674
4696
  message = issue.fields.summary;
4675
4697
  if (issue.fields.description) {
4676
- const truncatedDesc = issue.fields.description.substring(0, this.MAX_DESCRIPTION_LENGTH);
4698
+ const plainDesc = adfToText(issue.fields.description);
4699
+ const truncatedDesc = plainDesc.substring(0, this.MAX_DESCRIPTION_LENGTH);
4677
4700
  message = `${issue.fields.summary}
4678
4701
 
4679
4702
  ${truncatedDesc}`;
@@ -4921,16 +4944,13 @@ var ConfluenceService = class {
4921
4944
  }
4922
4945
  /**
4923
4946
  * Build CQL query from options
4924
- * Returns empty string if no filters need CQL (will use simple endpoint instead)
4947
+ * Always returns a CQL string with at least a user filter so we never return all pages.
4925
4948
  */
4926
4949
  buildCQL(options) {
4927
- if (!options.days && !options.author && !options.cql) {
4928
- return "";
4929
- }
4930
4950
  const queries = [];
4931
4951
  queries.push("type = page");
4932
4952
  if (options.days) {
4933
- queries.push(`lastModified > startOfDay("-${options.days}d")`);
4953
+ queries.push(`lastmodified > startOfDay("-${options.days}d")`);
4934
4954
  }
4935
4955
  if (options.author) {
4936
4956
  const escapedAuthor = options.author.replace(/"/g, '\\"');
@@ -4954,17 +4974,16 @@ var ConfluenceService = class {
4954
4974
  * Determine the type of contribution the current user made to a page
4955
4975
  * Returns: 'created' | 'edited' | 'commented'
4956
4976
  */
4957
- async determineContributionType(page, userEmail) {
4958
- if (page.history?.createdBy?.email === userEmail) {
4977
+ async determineContributionType(page, userIdentifier) {
4978
+ const matchesUser = (by) => !!by && (by.accountId === userIdentifier || by.email === userIdentifier);
4979
+ if (matchesUser(page.history?.createdBy)) {
4959
4980
  return {
4960
4981
  type: "created",
4961
4982
  details: `Created page with ${page.version?.number || 1} version${(page.version?.number || 1) > 1 ? "s" : ""}`
4962
4983
  };
4963
4984
  }
4964
- const hasEdits = page.version?.by?.email === userEmail && (page.version?.number || 0) > 1;
4965
- const userComments = page.children?.comment?.results?.filter(
4966
- (comment) => comment.version?.by?.email === userEmail
4967
- ) || [];
4985
+ const hasEdits = matchesUser(page.version?.by) && (page.version?.number || 0) > 1;
4986
+ const userComments = page.children?.comment?.results?.filter((comment) => matchesUser(comment.version?.by)) || [];
4968
4987
  const hasComments = userComments.length > 0;
4969
4988
  if (hasEdits && hasComments) {
4970
4989
  return {
@@ -5008,9 +5027,7 @@ var ConfluenceService = class {
5008
5027
  */
5009
5028
  async getPages(options = {}) {
5010
5029
  const cql = this.buildCQL(options);
5011
- if (cql) {
5012
- logger.debug(`Using CQL query: ${cql}`);
5013
- }
5030
+ logger.debug(`Using CQL query: ${cql}`);
5014
5031
  const allPages = [];
5015
5032
  const seenPageIds = /* @__PURE__ */ new Set();
5016
5033
  let start = 0;
@@ -5025,29 +5042,14 @@ var ConfluenceService = class {
5025
5042
  );
5026
5043
  break;
5027
5044
  }
5028
- let endpoint;
5029
- let params;
5030
- if (cql) {
5031
- params = {
5032
- cql,
5033
- start: start.toString(),
5034
- limit: limit.toString(),
5035
- expand: "version,history,children.comment,body.storage"
5036
- };
5037
- const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
5038
- endpoint = `/wiki/rest/api/content/search?${queryString}`;
5039
- } else {
5040
- logger.debug("Using simple content list (no CQL filters)");
5041
- params = {
5042
- type: "page",
5043
- status: "current",
5044
- start: start.toString(),
5045
- limit: limit.toString(),
5046
- expand: "version,history,children.comment,body.storage"
5047
- };
5048
- const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
5049
- endpoint = `/wiki/rest/api/content?${queryString}`;
5050
- }
5045
+ const params = {
5046
+ cql,
5047
+ start: start.toString(),
5048
+ limit: limit.toString(),
5049
+ expand: "version,history,children.comment,body.storage"
5050
+ };
5051
+ const queryString = Object.entries(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
5052
+ const endpoint = `/wiki/rest/api/content/search?${queryString}`;
5051
5053
  try {
5052
5054
  const response = await this.request(endpoint);
5053
5055
  if (response.results.length === 0) {
@@ -6981,7 +6983,7 @@ async function syncSingleService(sourceType, options, TOTAL_STEPS, sharedDays, s
6981
6983
  typeKey: refined.suggested_type_key,
6982
6984
  impactDescription: refined.impact_description,
6983
6985
  impact_description: refined.impact_description,
6984
- attachments: originalCommit?.url ? [originalCommit.url] : [],
6986
+ attachments: [],
6985
6987
  orgId: selectedOrgId || void 0,
6986
6988
  // External fields for non-git sources (Jira, Confluence, etc.)
6987
6989
  externalId: originalCommit?.externalId,