paperclip-github-plugin 0.8.6 → 0.8.7

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
@@ -62,7 +62,7 @@ If a company already has a Paperclip project bound to a GitHub repository worksp
62
62
 
63
63
  ### Status sync with delivery context
64
64
 
65
- The plugin does more than mirror issue text. It looks at linked pull requests, mergeability, CI, review decisions, review threads, and trusted new GitHub comments so imported Paperclip issues can reflect where the work actually is. When GitHub links an issue to a pull request in another repository, GitHub Sync now follows that pull request's actual repository for status checks, review state, and deep links instead of assuming the issue repository. When sync closes an imported issue as `done` or `cancelled`, it also clears any pending Paperclip review or approval execution state so the host accepts the terminal transition cleanly.
65
+ The plugin does more than mirror issue text. It looks at linked pull requests, mergeability, CI, review decisions, review threads, and trusted new GitHub comments so imported Paperclip issues can reflect where the work actually is. When GitHub links an issue to a pull request in another repository, GitHub Sync now follows that pull request's actual repository for status checks, review state, and deep links instead of assuming the issue repository. When sync closes an imported issue as `done` or `cancelled`, it also clears any pending Paperclip review or approval execution policy/state so the host accepts the terminal transition cleanly and does not keep waking stale review participants.
66
66
 
67
67
  ### Company KPI dashboard
68
68
 
@@ -158,7 +158,7 @@ When the local Paperclip API is available, the plugin also syncs labels by name,
158
158
  | --- | --- |
159
159
  | Open issue with no linked pull request, created by a repository maintainer | `todo` on first import |
160
160
  | Open issue with no linked pull request | Configured default status, which defaults to `backlog` |
161
- | Open issue with a linked pull request and unfinished CI | `in_progress` |
161
+ | Open issue with a linked pull request and unfinished CI | `in_progress`; already-blocked pending-only PR waits remain `blocked` |
162
162
  | Open issue with failing CI, a non-mergeable linked pull request, or unresolved review threads | `todo`, or `in_progress` when GitHub Sync can hand the work back to an executor |
163
163
  | Open issue with green CI, a merge-ready linked pull request, and all review threads resolved | `in_review` |
164
164
  | Closed issue completed as finished work | `done` |
@@ -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. 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.
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. If an issue is already `blocked` and GitHub reports only pending external merge requirements while CI is unfinished, sync preserves the external wait instead of waking an executor. 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.6"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
538
+ var MANIFEST_VERSION = "0.8.7"?.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
@@ -5329,6 +5329,9 @@ function isHealthyMaintainerWaitTransition(params) {
5329
5329
  const { currentStatus, nextStatus, syncContext } = params;
5330
5330
  return nextStatus === "in_review" && (currentStatus === "done" || currentStatus === "in_review") && syncContext.executionState === null && syncContext.executionPolicy !== null;
5331
5331
  }
5332
+ function shouldClearCompletedSyncExecutionPolicy(params) {
5333
+ return (params.nextStatus === "done" || params.nextStatus === "cancelled") && (params.syncContext.executionPolicy !== null || params.syncContext.executionState !== null);
5334
+ }
5332
5335
  function shouldPreserveImportedTriageAssignee(params) {
5333
5336
  return params.wasImportedThisRun && params.maintainerAuthoredImportedIssue === true && params.currentStatus === "backlog" && params.nextStatus === "todo";
5334
5337
  }
@@ -5518,6 +5521,12 @@ function resolvePaperclipIssueStatus(params) {
5518
5521
  return hasExecutorHandoffTarget ? "in_progress" : "todo";
5519
5522
  }
5520
5523
  if (snapshot.linkedPullRequests.length > 0) {
5524
+ if (shouldPreserveBlockedExternalPullRequestWait({
5525
+ currentStatus,
5526
+ linkedPullRequests: snapshot.linkedPullRequests
5527
+ })) {
5528
+ return "blocked";
5529
+ }
5521
5530
  return resolvePaperclipStatusFromLinkedPullRequests(snapshot.linkedPullRequests, {
5522
5531
  preferInProgress: hasExecutorHandoffTarget,
5523
5532
  preserveTransientUnknownMergeabilityWait: currentStatus === "done" || currentStatus === "in_review"
@@ -5536,6 +5545,12 @@ function resolvePaperclipPullRequestIssueStatus(params) {
5536
5545
  if (currentStatus === "done" || currentStatus === "cancelled") {
5537
5546
  return currentStatus;
5538
5547
  }
5548
+ if (shouldPreserveBlockedExternalPullRequestWait({
5549
+ currentStatus,
5550
+ linkedPullRequests: [pullRequest]
5551
+ })) {
5552
+ return "blocked";
5553
+ }
5539
5554
  return resolvePaperclipStatusFromLinkedPullRequests([pullRequest], {
5540
5555
  preferInProgress: hasExecutorHandoffTarget,
5541
5556
  preserveTransientUnknownMergeabilityWait: currentStatus === "in_review"
@@ -5687,6 +5702,12 @@ function normalizeGitHubPullRequestReviewDecision(value) {
5687
5702
  function isGitHubPullRequestActionRequiredForSync(pullRequest) {
5688
5703
  return pullRequest.mergeability === "conflicting" || ACTION_REQUIRED_GITHUB_PULL_REQUEST_MERGE_STATE_STATUSES.has(pullRequest.mergeStateStatus);
5689
5704
  }
5705
+ function isGitHubPullRequestPendingExternalWaitForSync(pullRequest) {
5706
+ return pullRequest.ciState === "unfinished" && !pullRequest.hasUnresolvedReviewThreads && pullRequest.mergeability !== "conflicting" && (pullRequest.mergeStateStatus === "blocked" || pullRequest.mergeStateStatus === "unstable");
5707
+ }
5708
+ function shouldPreserveBlockedExternalPullRequestWait(params) {
5709
+ return params.currentStatus === "blocked" && params.linkedPullRequests.length > 0 && params.linkedPullRequests.every((pullRequest) => isGitHubPullRequestPendingExternalWaitForSync(pullRequest));
5710
+ }
5690
5711
  function isGitHubPullRequestTransientUnknownMergeabilityWait(pullRequest) {
5691
5712
  return pullRequest.ciState === "green" && !pullRequest.hasUnresolvedReviewThreads && pullRequest.mergeability !== "conflicting" && pullRequest.mergeStateStatus === "unknown";
5692
5713
  }
@@ -9171,6 +9192,10 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
9171
9192
  nextStatus,
9172
9193
  syncContext: paperclipIssueSyncContext
9173
9194
  });
9195
+ const shouldClearCompletedExecutionPolicy = shouldClearCompletedSyncExecutionPolicy({
9196
+ nextStatus,
9197
+ syncContext: paperclipIssueSyncContext
9198
+ });
9174
9199
  const shouldPreserveImportedTriageRouting = shouldPreserveImportedTriageAssignee({
9175
9200
  currentStatus: paperclipIssue.status,
9176
9201
  nextStatus,
@@ -9192,7 +9217,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
9192
9217
  importedIssue.lastSeenGitHubState = snapshot.state;
9193
9218
  importedIssue.linkedPullRequestCommentCounts = currentLinkedPullRequestCommentCounts;
9194
9219
  if (paperclipIssue.status === nextStatus) {
9195
- if (shouldClearTransitionAssignee) {
9220
+ if (shouldClearTransitionAssignee || shouldClearCompletedExecutionPolicy) {
9196
9221
  updateSyncFailureContext(syncFailureContext, {
9197
9222
  phase: "updating_paperclip_status",
9198
9223
  repositoryUrl: repository.url,
@@ -9204,8 +9229,8 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
9204
9229
  currentStatus: paperclipIssue.status,
9205
9230
  syncContext: paperclipIssueSyncContext,
9206
9231
  nextStatus,
9207
- clearAssignee: true,
9208
- ...shouldPreserveMaintainerWaitRouting ? { clearExecutionPolicy: true } : {},
9232
+ ...shouldClearTransitionAssignee ? { clearAssignee: true } : {},
9233
+ ...shouldPreserveMaintainerWaitRouting || shouldClearCompletedExecutionPolicy ? { clearExecutionPolicy: true } : {},
9209
9234
  transitionComment: "",
9210
9235
  paperclipApiBaseUrl
9211
9236
  });
@@ -9241,7 +9266,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
9241
9266
  nextStatus,
9242
9267
  ...nextTransitionAssignee ? { nextAssignee: nextTransitionAssignee.principal } : {},
9243
9268
  ...shouldClearTransitionAssignee ? { clearAssignee: true } : {},
9244
- ...shouldPreserveMaintainerWaitRouting ? { clearExecutionPolicy: true } : {},
9269
+ ...shouldPreserveMaintainerWaitRouting || shouldClearCompletedExecutionPolicy ? { clearExecutionPolicy: true } : {},
9245
9270
  transitionComment: transitionComment.body,
9246
9271
  transitionCommentAnnotation: transitionComment.annotation,
9247
9272
  paperclipApiBaseUrl
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "paperclip-github-plugin",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",