paperclip-github-plugin 0.8.4 → 0.8.5

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/README.md CHANGED
@@ -170,7 +170,7 @@ Additional behavior:
170
170
  - If the Paperclip host initially creates that imported maintainer issue in `backlog`, GitHub Sync promotes it to `todo` without replacing the configured default assignee with the executor handoff assignee, so triage ownership stays intact.
171
171
  - When Paperclip board access is connected for a company, the advanced assignee dropdowns list both company agents and `Me` for the connected board user.
172
172
  - Newly imported issues that finish sync in `todo` and are assigned to an agent enqueue an assignee wakeup so the agent can pick them up promptly.
173
- - For linked pull requests, GitHub Sync treats merge-conflict, behind-branch, blocked, draft, unstable merge states, and unresolved review threads as executor work, while merge-ready states such as `CLEAN` and `HAS_HOOKS` can move work into `in_review` when CI is green and review threads are resolved. A stale aggregate `CHANGES_REQUESTED` review decision alone does not move that maintainer wait back to active execution.
173
+ - For linked pull requests, GitHub Sync treats merge-conflict, behind-branch, blocked, draft, unstable merge states, and unresolved review threads as executor work, while merge-ready states such as `CLEAN` and `HAS_HOOKS` can move work into `in_review` when CI is green and review threads are resolved. A stale aggregate `CHANGES_REQUESTED` review decision alone does not move that maintainer wait back to active execution. Transient `UNKNOWN` mergeability also does not move an already `in_review` maintainer wait back to active execution when CI is green and review threads are resolved.
174
174
  - Imported issues that are already `blocked` stay `blocked` while any first-class `blockedBy` issue is still non-terminal, even if the linked GitHub pull request is otherwise green and review-ready.
175
175
  - When sync moves work into `in_review`, GitHub Sync first follows the Paperclip issue execution policy's current reviewer or approver when that stage is visible on the issue. If Paperclip exposes an internal review or approval stage but not yet the participant, the plugin falls back to the configured reviewer or approver handoff assignee. If the transition is only a healthy linked-PR wait with no visible internal review or approval stage, GitHub Sync leaves the issue unassigned so it can wait on normal maintainer review without waking an internal owner.
176
176
  - When sync moves work back into active execution, GitHub Sync first follows the Paperclip issue execution policy `returnAssignee` when it is available. Otherwise it falls back to the configured executor handoff assignee and then to the default imported assignee.
package/dist/manifest.js CHANGED
@@ -535,7 +535,7 @@ var COMPANY_METRIC_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/a
535
535
  var require2 = createRequire(import.meta.url);
536
536
  var packageJson = require2("../package.json");
537
537
  var SCHEDULE_TICK_CRON = "* * * * *";
538
- var MANIFEST_VERSION = "0.8.4"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
538
+ var MANIFEST_VERSION = "0.8.5"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
539
539
  var manifest = {
540
540
  id: GITHUB_SYNC_PLUGIN_ID,
541
541
  apiVersion: 1,
package/dist/worker.js CHANGED
@@ -1447,7 +1447,16 @@ function formatGitHubIssueCountLabel(count) {
1447
1447
  return `${normalizedCount} GitHub ${normalizedCount === 1 ? "issue" : "issues"}`;
1448
1448
  }
1449
1449
  function getErrorMessage(error) {
1450
- return error instanceof Error ? error.message : String(error);
1450
+ if (error instanceof Error) {
1451
+ return error.message;
1452
+ }
1453
+ if (error && typeof error === "object" && "message" in error) {
1454
+ const message = error.message;
1455
+ if (typeof message === "string") {
1456
+ return message;
1457
+ }
1458
+ }
1459
+ return String(error);
1451
1460
  }
1452
1461
  function isPaperclipLabelSyncError(error) {
1453
1462
  return error instanceof PaperclipLabelSyncError;
@@ -4889,7 +4898,9 @@ function resolvePaperclipStatusFromLinkedPullRequests(linkedPullRequests, option
4889
4898
  )) {
4890
4899
  return options?.preferInProgress ? "in_progress" : "todo";
4891
4900
  }
4892
- if (linkedPullRequests.length > 0 && linkedPullRequests.every((pullRequest) => isGitHubPullRequestReviewReadyForSync(pullRequest))) {
4901
+ if (linkedPullRequests.length > 0 && linkedPullRequests.every(
4902
+ (pullRequest) => isGitHubPullRequestReviewReadyForSync(pullRequest) || options?.preserveTransientUnknownMergeabilityWait === true && isGitHubPullRequestTransientUnknownMergeabilityWait(pullRequest)
4903
+ )) {
4893
4904
  return "in_review";
4894
4905
  }
4895
4906
  return "in_progress";
@@ -5033,6 +5044,10 @@ function hasUnresolvedPaperclipIssueBlockerSummary(blockers) {
5033
5044
  return status !== "done" && status !== "cancelled";
5034
5045
  });
5035
5046
  }
5047
+ function isMissingIssueRelationsReadCapabilityError(error) {
5048
+ const message = getErrorMessage(error);
5049
+ return /missing required capability/i.test(message) && /issue\.relations\.read/i.test(message) && /issues\.relations\.get/i.test(message);
5050
+ }
5036
5051
  async function hasUnresolvedPaperclipIssueBlocker(ctx, issue, companyId) {
5037
5052
  const record = issue;
5038
5053
  if (hasUnresolvedPaperclipIssueBlockerSummary(record.blockedBy)) {
@@ -5041,8 +5056,15 @@ async function hasUnresolvedPaperclipIssueBlocker(ctx, issue, companyId) {
5041
5056
  if (typeof ctx.issues.relations?.get !== "function") {
5042
5057
  return false;
5043
5058
  }
5044
- const relations = await ctx.issues.relations.get(issue.id, companyId);
5045
- return hasUnresolvedPaperclipIssueBlockerSummary(relations.blockedBy);
5059
+ try {
5060
+ const relations = await ctx.issues.relations.get(issue.id, companyId);
5061
+ return hasUnresolvedPaperclipIssueBlockerSummary(relations.blockedBy);
5062
+ } catch (error) {
5063
+ if (isMissingIssueRelationsReadCapabilityError(error)) {
5064
+ return false;
5065
+ }
5066
+ throw error;
5067
+ }
5046
5068
  }
5047
5069
  function isSamePaperclipIssueAssigneePrincipal(left, right) {
5048
5070
  if (!left || !right) {
@@ -5415,7 +5437,8 @@ function resolvePaperclipIssueStatus(params) {
5415
5437
  }
5416
5438
  if (snapshot.linkedPullRequests.length > 0) {
5417
5439
  return resolvePaperclipStatusFromLinkedPullRequests(snapshot.linkedPullRequests, {
5418
- preferInProgress: hasExecutorHandoffTarget
5440
+ preferInProgress: hasExecutorHandoffTarget,
5441
+ preserveTransientUnknownMergeabilityWait: currentStatus === "done" || currentStatus === "in_review"
5419
5442
  });
5420
5443
  }
5421
5444
  if (wasImportedThisRun) {
@@ -5432,7 +5455,8 @@ function resolvePaperclipPullRequestIssueStatus(params) {
5432
5455
  return currentStatus;
5433
5456
  }
5434
5457
  return resolvePaperclipStatusFromLinkedPullRequests([pullRequest], {
5435
- preferInProgress: hasExecutorHandoffTarget
5458
+ preferInProgress: hasExecutorHandoffTarget,
5459
+ preserveTransientUnknownMergeabilityWait: currentStatus === "in_review"
5436
5460
  });
5437
5461
  }
5438
5462
  async function listLinkedPullRequestsForIssue(octokit, repository, issueNumber) {
@@ -5581,6 +5605,9 @@ function normalizeGitHubPullRequestReviewDecision(value) {
5581
5605
  function isGitHubPullRequestActionRequiredForSync(pullRequest) {
5582
5606
  return pullRequest.mergeability === "conflicting" || ACTION_REQUIRED_GITHUB_PULL_REQUEST_MERGE_STATE_STATUSES.has(pullRequest.mergeStateStatus);
5583
5607
  }
5608
+ function isGitHubPullRequestTransientUnknownMergeabilityWait(pullRequest) {
5609
+ return pullRequest.ciState === "green" && !pullRequest.hasUnresolvedReviewThreads && pullRequest.mergeability !== "conflicting" && pullRequest.mergeStateStatus === "unknown";
5610
+ }
5584
5611
  function isGitHubPullRequestReviewReadyForSync(pullRequest) {
5585
5612
  if (pullRequest.ciState !== "green" || pullRequest.hasUnresolvedReviewThreads) {
5586
5613
  return false;
@@ -14353,6 +14380,7 @@ function shouldStartWorkerHost(moduleUrl, entry = process.argv[1]) {
14353
14380
  }
14354
14381
  var __testing = {
14355
14382
  buildSyncFallbackExecutionStatePatch,
14383
+ hasUnresolvedPaperclipIssueBlocker,
14356
14384
  isHealthyMaintainerWaitTransition,
14357
14385
  resolveSyncTransitionAssignee
14358
14386
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-github-plugin",
3
- "version": "0.8.4",
3
+ "version": "0.8.5",
4
4
  "description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",