paperclip-github-plugin 0.3.5 → 0.4.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.
package/dist/worker.js CHANGED
@@ -1600,13 +1600,16 @@ function buildGitHubRepositoryTokenCapabilityAudit(params) {
1600
1600
  function normalizeSecretRef(value) {
1601
1601
  return typeof value === "string" && value.trim() ? value.trim() : void 0;
1602
1602
  }
1603
- function normalizeGitHubUserLogin(value) {
1603
+ function normalizeGitHubLowercaseString(value) {
1604
1604
  if (typeof value !== "string") {
1605
1605
  return void 0;
1606
1606
  }
1607
1607
  const trimmed = stripNullBytes(value).trim();
1608
1608
  return trimmed ? trimmed.toLowerCase() : void 0;
1609
1609
  }
1610
+ function normalizeGitHubUserLogin(value) {
1611
+ return normalizeGitHubLowercaseString(value);
1612
+ }
1610
1613
  function normalizeGitHubTokenRef(value) {
1611
1614
  return normalizeSecretRef(value);
1612
1615
  }
@@ -2624,17 +2627,27 @@ function getPublicSettings(settings) {
2624
2627
  const {
2625
2628
  githubTokenRef: _githubTokenRef,
2626
2629
  paperclipBoardApiTokenRefs: _paperclipBoardApiTokenRefs,
2630
+ paperclipBoardAccessIdentityByCompanyId: _paperclipBoardAccessIdentityByCompanyId,
2627
2631
  companyAdvancedSettingsByCompanyId: _companyAdvancedSettingsByCompanyId,
2628
2632
  ...publicSettings
2629
2633
  } = settings;
2630
2634
  return publicSettings;
2631
2635
  }
2636
+ function getPaperclipBoardAccessIdentity(settings, companyId) {
2637
+ const normalizedCompanyId = normalizeCompanyId(companyId);
2638
+ if (!normalizedCompanyId) {
2639
+ return void 0;
2640
+ }
2641
+ return normalizeOptionalString2(settings.paperclipBoardAccessIdentityByCompanyId?.[normalizedCompanyId]);
2642
+ }
2632
2643
  function getPublicSettingsForScope(settings, companyId) {
2633
2644
  const publicSettings = getPublicSettings(settings);
2645
+ const paperclipBoardAccessIdentity = getPaperclipBoardAccessIdentity(settings, companyId);
2634
2646
  return {
2635
2647
  ...publicSettings,
2636
2648
  mappings: filterMappingsByCompany(publicSettings.mappings, companyId),
2637
- advancedSettings: getCompanyAdvancedSettings(settings, companyId)
2649
+ advancedSettings: getCompanyAdvancedSettings(settings, companyId),
2650
+ ...paperclipBoardAccessIdentity ? { paperclipBoardAccessIdentity } : {}
2638
2651
  };
2639
2652
  }
2640
2653
  async function listAvailableAssignees(ctx, companyId) {
@@ -3036,6 +3049,20 @@ function normalizePaperclipBoardApiTokenRefs(value) {
3036
3049
  }
3037
3050
  return Object.fromEntries(entries);
3038
3051
  }
3052
+ function normalizePaperclipBoardAccessIdentityByCompanyId(value) {
3053
+ if (!value || typeof value !== "object") {
3054
+ return void 0;
3055
+ }
3056
+ const entries = Object.entries(value).map(([companyId, identityLabel]) => {
3057
+ const normalizedCompanyId = normalizeCompanyId(companyId);
3058
+ const normalizedIdentityLabel = normalizeOptionalString2(identityLabel);
3059
+ return normalizedCompanyId && normalizedIdentityLabel ? [normalizedCompanyId, normalizedIdentityLabel] : null;
3060
+ }).filter((entry) => entry !== null);
3061
+ if (entries.length === 0) {
3062
+ return void 0;
3063
+ }
3064
+ return Object.fromEntries(entries);
3065
+ }
3039
3066
  function normalizeSyncCancellationRequest(value) {
3040
3067
  if (!value || typeof value !== "object") {
3041
3068
  return null;
@@ -3122,6 +3149,10 @@ function normalizeIgnoredIssueAuthorUsernames(value) {
3122
3149
  const entries = Array.isArray(value) ? value.map((entry) => normalizeGitHubUsername(entry)).filter((entry) => Boolean(entry)) : typeof value === "string" ? parseIgnoredIssueAuthorUsernames(value) : [];
3123
3150
  return [...new Set(entries)];
3124
3151
  }
3152
+ function normalizeAgentIds(value) {
3153
+ const entries = Array.isArray(value) ? value.map((entry) => normalizeOptionalString2(entry)).filter((entry) => Boolean(entry)) : [];
3154
+ return [...new Set(entries)].sort((left, right) => left.localeCompare(right));
3155
+ }
3125
3156
  function normalizeAdvancedSettings(value) {
3126
3157
  if (!value || typeof value !== "object") {
3127
3158
  return DEFAULT_ADVANCED_SETTINGS;
@@ -3130,10 +3161,12 @@ function normalizeAdvancedSettings(value) {
3130
3161
  const defaultAssigneeAgentId = normalizeOptionalString2(record.defaultAssigneeAgentId);
3131
3162
  const defaultStatus = "defaultStatus" in record ? coercePaperclipIssueStatus(record.defaultStatus) : DEFAULT_ADVANCED_SETTINGS.defaultStatus;
3132
3163
  const ignoredIssueAuthorUsernames = "ignoredIssueAuthorUsernames" in record ? normalizeIgnoredIssueAuthorUsernames(record.ignoredIssueAuthorUsernames) : DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames;
3164
+ const githubTokenPropagationAgentIds = "githubTokenPropagationAgentIds" in record ? normalizeAgentIds(record.githubTokenPropagationAgentIds) : [];
3133
3165
  return {
3134
3166
  ...defaultAssigneeAgentId ? { defaultAssigneeAgentId } : {},
3135
3167
  defaultStatus,
3136
- ignoredIssueAuthorUsernames
3168
+ ignoredIssueAuthorUsernames,
3169
+ ...githubTokenPropagationAgentIds.length > 0 ? { githubTokenPropagationAgentIds } : {}
3137
3170
  };
3138
3171
  }
3139
3172
  function normalizeCompanyAdvancedSettingsByCompanyId(value) {
@@ -3235,7 +3268,11 @@ function normalizeSettings(value) {
3235
3268
  const record = value;
3236
3269
  const paperclipApiBaseUrl = resolvePaperclipApiBaseUrl(record.paperclipApiBaseUrl);
3237
3270
  const githubTokenRef = normalizeGitHubTokenRef(record.githubTokenRef);
3271
+ const githubTokenLogin = normalizeOptionalString2(record.githubTokenLogin);
3238
3272
  const paperclipBoardApiTokenRefs = normalizePaperclipBoardApiTokenRefs(record.paperclipBoardApiTokenRefs);
3273
+ const paperclipBoardAccessIdentityByCompanyId = normalizePaperclipBoardAccessIdentityByCompanyId(
3274
+ record.paperclipBoardAccessIdentityByCompanyId
3275
+ );
3239
3276
  const companyAdvancedSettingsByCompanyId = normalizeCompanyAdvancedSettingsByCompanyId(record.companyAdvancedSettingsByCompanyId);
3240
3277
  return {
3241
3278
  mappings: normalizeMappings(record.mappings),
@@ -3243,7 +3280,9 @@ function normalizeSettings(value) {
3243
3280
  scheduleFrequencyMinutes: normalizeScheduleFrequencyMinutes(record.scheduleFrequencyMinutes),
3244
3281
  ...paperclipApiBaseUrl ? { paperclipApiBaseUrl } : {},
3245
3282
  ...githubTokenRef ? { githubTokenRef } : {},
3283
+ ...githubTokenLogin ? { githubTokenLogin } : {},
3246
3284
  ...paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs } : {},
3285
+ ...paperclipBoardAccessIdentityByCompanyId ? { paperclipBoardAccessIdentityByCompanyId } : {},
3247
3286
  ...companyAdvancedSettingsByCompanyId ? { companyAdvancedSettingsByCompanyId } : {},
3248
3287
  updatedAt: typeof record.updatedAt === "string" ? record.updatedAt : void 0
3249
3288
  };
@@ -4207,8 +4246,9 @@ async function isGitHubUserRepositoryMaintainer(octokit, repository, login, cach
4207
4246
  "X-GitHub-Api-Version": GITHUB_API_VERSION
4208
4247
  }
4209
4248
  });
4210
- const roleName = response.data && typeof response.data === "object" && "role_name" in response.data ? normalizeGitHubUserLogin(response.data.role_name) : void 0;
4211
- const isMaintainer = roleName ? GITHUB_REPOSITORY_MAINTAINER_ROLE_NAMES.has(roleName) : false;
4249
+ const permission = response.data && typeof response.data === "object" && "permission" in response.data ? normalizeGitHubLowercaseString(response.data.permission) : void 0;
4250
+ const roleName = response.data && typeof response.data === "object" && "role_name" in response.data ? normalizeGitHubLowercaseString(response.data.role_name) : void 0;
4251
+ const isMaintainer = (permission ? GITHUB_REPOSITORY_MAINTAINER_ROLE_NAMES.has(permission) : false) || (roleName ? GITHUB_REPOSITORY_MAINTAINER_ROLE_NAMES.has(roleName) : false);
4212
4252
  cache.set(cacheKey, isMaintainer);
4213
4253
  return isMaintainer;
4214
4254
  } catch (error) {
@@ -4933,9 +4973,6 @@ function selectPaperclipLabelForGitHubLabel(githubLabel, directory) {
4933
4973
  function getPaperclipLabelsEndpoint(baseUrl, companyId) {
4934
4974
  return new URL(`/api/companies/${companyId}/labels`, baseUrl).toString();
4935
4975
  }
4936
- function getPaperclipIssuesEndpoint(baseUrl, companyId) {
4937
- return new URL(`/api/companies/${companyId}/issues`, baseUrl).toString();
4938
- }
4939
4976
  function getPaperclipIssueEndpoint(baseUrl, issueId) {
4940
4977
  return new URL(`/api/issues/${issueId}`, baseUrl).toString();
4941
4978
  }
@@ -4986,17 +5023,6 @@ async function detectPaperclipBoardAccessRequirement(paperclipApiBaseUrl) {
4986
5023
  return false;
4987
5024
  }
4988
5025
  }
4989
- function parsePaperclipIssueId(value) {
4990
- if (!value || typeof value !== "object") {
4991
- return null;
4992
- }
4993
- const id = value.id;
4994
- if (typeof id !== "string") {
4995
- return null;
4996
- }
4997
- const trimmedId = id.trim();
4998
- return trimmedId || null;
4999
- }
5000
5026
  function parsePaperclipIssueDescription(value) {
5001
5027
  if (!value || typeof value !== "object") {
5002
5028
  return void 0;
@@ -5801,87 +5827,22 @@ function shouldIgnoreGitHubIssue(issue, advancedSettings) {
5801
5827
  (ignoredUsername) => buildGitHubUsernameAliases(ignoredUsername).some((alias) => issueAuthorAliases.has(alias))
5802
5828
  );
5803
5829
  }
5804
- async function applyDefaultAssigneeToPaperclipIssue(ctx, params) {
5805
- const { companyId, issueId, defaultAssigneeAgentId } = params;
5806
- if (!defaultAssigneeAgentId) {
5807
- return;
5808
- }
5809
- try {
5810
- await ctx.issues.update(issueId, { assigneeAgentId: defaultAssigneeAgentId }, companyId);
5811
- } catch (error) {
5812
- ctx.logger.warn("Unable to apply the default assignee to an imported GitHub issue.", {
5813
- companyId,
5814
- issueId,
5815
- assigneeAgentId: defaultAssigneeAgentId,
5816
- error: getErrorMessage(error)
5817
- });
5818
- }
5819
- }
5820
5830
  async function createPaperclipIssue(ctx, mapping, advancedSettings, issue, availableLabels, paperclipApiBaseUrl, syncFailureContext) {
5821
5831
  if (!mapping.companyId || !mapping.paperclipProjectId) {
5822
5832
  throw new Error(`Mapping ${mapping.id} is missing resolved Paperclip project identifiers.`);
5823
5833
  }
5824
5834
  const title = issue.title;
5825
5835
  const description = buildPaperclipIssueDescription(issue);
5826
- let createdIssueId = null;
5827
- let createdIssueDescription;
5828
- let createPath = "sdk";
5829
- if (paperclipApiBaseUrl) {
5830
- try {
5831
- const response = await fetchPaperclipApi(
5832
- getPaperclipIssuesEndpoint(paperclipApiBaseUrl, mapping.companyId),
5833
- {
5834
- method: "POST",
5835
- headers: {
5836
- accept: "application/json",
5837
- "content-type": "application/json"
5838
- },
5839
- body: JSON.stringify({
5840
- projectId: mapping.paperclipProjectId,
5841
- title,
5842
- ...description ? { description } : {}
5843
- })
5844
- },
5845
- {
5846
- companyId: mapping.companyId
5847
- }
5848
- );
5849
- const payloadResult = await readPaperclipApiJsonResponse(response, {
5850
- operationLabel: "issue create"
5851
- });
5852
- if (!payloadResult.failure) {
5853
- const createdIssue = payloadResult.data;
5854
- createdIssueId = parsePaperclipIssueId(createdIssue);
5855
- createdIssueDescription = parsePaperclipIssueDescription(createdIssue);
5856
- createPath = "local_api";
5857
- }
5858
- } catch {
5859
- }
5860
- }
5861
- if (!createdIssueId) {
5862
- const createdIssue = await ctx.issues.create({
5863
- companyId: mapping.companyId,
5864
- projectId: mapping.paperclipProjectId,
5865
- title,
5866
- ...description ? { description } : {},
5867
- ...advancedSettings.defaultAssigneeAgentId ? { assigneeAgentId: advancedSettings.defaultAssigneeAgentId } : {}
5868
- });
5869
- createdIssueId = createdIssue.id;
5870
- createdIssueDescription = createdIssue.description;
5871
- createPath = "sdk";
5872
- }
5873
- const ensuredCreatedIssueId = createdIssueId;
5874
- if (!ensuredCreatedIssueId) {
5875
- throw new Error("GitHub sync could not resolve the created Paperclip issue id.");
5876
- }
5877
- const normalizedCreatedIssueDescription = createdIssueDescription ?? void 0;
5878
- if (createPath !== "sdk") {
5879
- await applyDefaultAssigneeToPaperclipIssue(ctx, {
5880
- companyId: mapping.companyId,
5881
- issueId: ensuredCreatedIssueId,
5882
- defaultAssigneeAgentId: advancedSettings.defaultAssigneeAgentId
5883
- });
5884
- }
5836
+ const createdIssue = await ctx.issues.create({
5837
+ companyId: mapping.companyId,
5838
+ projectId: mapping.paperclipProjectId,
5839
+ title,
5840
+ ...description ? { description } : {},
5841
+ ...advancedSettings.defaultAssigneeAgentId ? { assigneeAgentId: advancedSettings.defaultAssigneeAgentId } : {}
5842
+ });
5843
+ const ensuredCreatedIssueId = createdIssue.id;
5844
+ const normalizedCreatedIssueDescription = createdIssue.description ?? void 0;
5845
+ const createPath = "sdk";
5885
5846
  if (normalizeIssueDescriptionValue(normalizedCreatedIssueDescription) !== description) {
5886
5847
  logIssueDescriptionDiagnostic(
5887
5848
  ctx,
@@ -10640,6 +10601,7 @@ var plugin = definePlugin({
10640
10601
  const hasMappingsPatch = "mappings" in record;
10641
10602
  const hasAdvancedSettingsPatch = "advancedSettings" in record;
10642
10603
  const githubTokenRef = "githubTokenRef" in record ? normalizeGitHubTokenRef(record.githubTokenRef) : normalizeGitHubTokenRef(previous.githubTokenRef) ?? normalizeGitHubTokenRef(config.githubTokenRef);
10604
+ const githubTokenLogin = "githubTokenLogin" in record ? normalizeOptionalString2(record.githubTokenLogin) : previous.githubTokenLogin;
10643
10605
  const inputMappings = hasMappingsPatch ? normalizeMappings(record.mappings) : previous.mappings;
10644
10606
  const nextCompanyAdvancedSettingsByCompanyId = {
10645
10607
  ...previous.companyAdvancedSettingsByCompanyId ?? {}
@@ -10659,7 +10621,9 @@ var plugin = definePlugin({
10659
10621
  syncState: previous.syncState,
10660
10622
  scheduleFrequencyMinutes: "scheduleFrequencyMinutes" in record ? record.scheduleFrequencyMinutes : previous.scheduleFrequencyMinutes,
10661
10623
  paperclipApiBaseUrl: "paperclipApiBaseUrl" in record ? resolveTrustedPaperclipApiBaseUrlInput(record.paperclipApiBaseUrl, previous, config) : getConfiguredPaperclipApiBaseUrl(previous, config),
10624
+ ...githubTokenLogin ? { githubTokenLogin } : {},
10662
10625
  paperclipBoardApiTokenRefs: previous.paperclipBoardApiTokenRefs,
10626
+ paperclipBoardAccessIdentityByCompanyId: previous.paperclipBoardAccessIdentityByCompanyId,
10663
10627
  ...Object.keys(nextCompanyAdvancedSettingsByCompanyId).length > 0 ? { companyAdvancedSettingsByCompanyId: nextCompanyAdvancedSettingsByCompanyId } : {},
10664
10628
  ...githubTokenRef ? { githubTokenRef } : {}
10665
10629
  });
@@ -10675,7 +10639,9 @@ var plugin = definePlugin({
10675
10639
  syncState: previous.syncState,
10676
10640
  scheduleFrequencyMinutes: current.scheduleFrequencyMinutes,
10677
10641
  ...current.paperclipApiBaseUrl ? { paperclipApiBaseUrl: current.paperclipApiBaseUrl } : {},
10642
+ ...current.githubTokenLogin ? { githubTokenLogin: current.githubTokenLogin } : {},
10678
10643
  ...current.paperclipBoardApiTokenRefs ? { paperclipBoardApiTokenRefs: current.paperclipBoardApiTokenRefs } : {},
10644
+ ...current.paperclipBoardAccessIdentityByCompanyId ? { paperclipBoardAccessIdentityByCompanyId: current.paperclipBoardAccessIdentityByCompanyId } : {},
10679
10645
  ...current.companyAdvancedSettingsByCompanyId ? { companyAdvancedSettingsByCompanyId: current.companyAdvancedSettingsByCompanyId } : {},
10680
10646
  ...githubTokenRef ? { githubTokenRef } : {},
10681
10647
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
@@ -10703,18 +10669,32 @@ var plugin = definePlugin({
10703
10669
  const nextPaperclipBoardApiTokenRefs = {
10704
10670
  ...previous.paperclipBoardApiTokenRefs ?? {}
10705
10671
  };
10672
+ const nextPaperclipBoardAccessIdentityByCompanyId = {
10673
+ ...previous.paperclipBoardAccessIdentityByCompanyId ?? {}
10674
+ };
10706
10675
  if (nextSecretRef) {
10707
10676
  nextPaperclipBoardApiTokenRefs[companyId] = nextSecretRef;
10708
10677
  } else {
10709
10678
  delete nextPaperclipBoardApiTokenRefs[companyId];
10679
+ delete nextPaperclipBoardAccessIdentityByCompanyId[companyId];
10680
+ }
10681
+ if ("paperclipBoardAccessIdentity" in record) {
10682
+ const nextIdentityLabel = normalizeOptionalString2(record.paperclipBoardAccessIdentity);
10683
+ if (nextIdentityLabel) {
10684
+ nextPaperclipBoardAccessIdentityByCompanyId[companyId] = nextIdentityLabel;
10685
+ } else {
10686
+ delete nextPaperclipBoardAccessIdentityByCompanyId[companyId];
10687
+ }
10710
10688
  }
10711
10689
  const {
10712
10690
  paperclipBoardApiTokenRefs: _previousPaperclipBoardApiTokenRefs,
10691
+ paperclipBoardAccessIdentityByCompanyId: _previousPaperclipBoardAccessIdentityByCompanyId,
10713
10692
  ...previousWithoutBoardAccess
10714
10693
  } = previous;
10715
10694
  const next = sanitizeSettingsForCurrentSetup({
10716
10695
  ...previousWithoutBoardAccess,
10717
10696
  ...Object.keys(nextPaperclipBoardApiTokenRefs).length > 0 ? { paperclipBoardApiTokenRefs: nextPaperclipBoardApiTokenRefs } : {},
10697
+ ...Object.keys(nextPaperclipBoardAccessIdentityByCompanyId).length > 0 ? { paperclipBoardAccessIdentityByCompanyId: nextPaperclipBoardAccessIdentityByCompanyId } : {},
10718
10698
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
10719
10699
  }, {
10720
10700
  hasToken: hasConfiguredGithubToken(previous, config),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-github-plugin",
3
- "version": "0.3.5",
3
+ "version": "0.4.0",
4
4
  "description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",