paperclip-github-plugin 0.8.2 → 0.8.4

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
@@ -35,7 +35,7 @@ The plugin adds a full in-host workflow instead of a one-off import script:
35
35
  - saved sync diagnostics that let operators inspect the latest per-issue failures, raw errors, and suggested next steps
36
36
  - a project sidebar item that opens a live project-scoped Pull Requests page for the mapped repository and can show the open PR count through a lightweight badge read
37
37
  - manual sync actions from global, project, and issue surfaces
38
- - a GitHub detail tab on synced Paperclip issues that includes GitHub-marked action buttons plus the GitHub issue creator with avatar, and lets operators manually link an unlinked Paperclip issue to a GitHub issue or pull request
38
+ - a GitHub detail tab on synced Paperclip issues that includes GitHub-marked action buttons plus the GitHub issue creator with avatar, and lets operators manually link or unlink a Paperclip issue from a GitHub issue or pull request
39
39
  - GitHub link annotations on sync-generated status transition comments when the host supports comment annotations
40
40
 
41
41
  ## How it works
@@ -88,6 +88,8 @@ If a Paperclip issue was created locally or by an agent workflow before GitHub S
88
88
 
89
89
  Manual GitHub issue links are added to the same import registry and issue-link entity used by normal sync, so future syncs update the Paperclip issue from the GitHub issue. Manual pull request links are added to the PR-link entity used by the project Pull Requests page, so future syncs monitor PR status even when there is no closing GitHub issue.
90
90
 
91
+ Linked Paperclip issues can also be unlinked from the GitHub detail surface. Unlinking removes the active GitHub Sync link metadata and import-registry tracking for that Paperclip issue without deleting either side, so the issue stays local until it is linked again.
92
+
91
93
  ### Agent workflows built in
92
94
 
93
95
  Paperclip agents can search GitHub for duplicates, read and update issues, assign issues to the saved token owner, post comments, create pull requests, inspect changed files and CI, reply to review threads, resolve or unresolve threads, request reviewers, search org-level GitHub Projects, and associate pull requests with those projects without leaving the Paperclip plugin surface.
@@ -146,6 +148,8 @@ To keep imported issues recognizable without cluttering the visible description,
146
148
 
147
149
  Repeated syncs keep existing imports current instead of creating duplicates again. If the plugin's import registry is stale, the worker can repair deduplication by reusing existing Paperclip issues when durable GitHub link metadata is already present.
148
150
 
151
+ If a linked GitHub issue is transferred to another repository, GitHub Sync follows the canonical GitHub URL. When the destination repository is mapped to another Paperclip project in the same company, the existing Paperclip issue moves to that project and keeps its GitHub link. When the destination repository is not mapped, GitHub Sync unlinks the Paperclip issue and marks it `cancelled` with a Paperclip comment explaining the transfer.
152
+
149
153
  When the local Paperclip API is available, the plugin also syncs labels by name, prefers exact color matches when multiple Paperclip labels share the same name, and creates missing Paperclip labels when needed.
150
154
 
151
155
  ### Status mapping
@@ -155,17 +159,19 @@ When the local Paperclip API is available, the plugin also syncs labels by name,
155
159
  | Open issue with no linked pull request, created by a repository maintainer | `todo` on first import |
156
160
  | Open issue with no linked pull request | Configured default status, which defaults to `backlog` |
157
161
  | Open issue with a linked pull request and unfinished CI | `in_progress` |
158
- | Open issue with failing CI, a non-mergeable linked pull request, requested changes, or unresolved review threads | `todo`, or `in_progress` when GitHub Sync can hand the work back to an executor |
159
- | Open issue with green CI, a merge-ready linked pull request, no requested changes, and all review threads resolved | `in_review` |
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
+ | Open issue with green CI, a merge-ready linked pull request, and all review threads resolved | `in_review` |
160
164
  | Closed issue completed as finished work | `done` |
161
165
  | Closed issue closed as `not_planned` or `duplicate` | `cancelled` |
162
166
 
163
167
  Additional behavior:
164
168
 
165
169
  - Open issues with no linked pull request that are created by a verified repository maintainer/admin bypass the default imported status and start in `todo`.
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.
166
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.
167
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.
168
- - For linked pull requests, GitHub Sync treats merge-conflict, behind-branch, blocked, draft, unstable merge states, and requested-changes review decisions as executor work, while merge-ready states such as `CLEAN` and `HAS_HOOKS` can move work into `in_review` when CI is green and there are no requested changes or unresolved review threads.
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.
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.
169
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.
170
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.
171
177
  - Sync-driven handoffs to agent assignees best-effort enqueue an explicit wakeup so the next reviewer, approver, or executor can pick the issue up even when their agent is not running heartbeats.
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.2"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
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";
539
539
  var manifest = {
540
540
  id: GITHUB_SYNC_PLUGIN_ID,
541
541
  apiVersion: 1,
@@ -559,6 +559,7 @@ var manifest = {
559
559
  "issues.create",
560
560
  "issues.update",
561
561
  "issues.wakeup",
562
+ "issue.relations.read",
562
563
  "issue.comments.read",
563
564
  "issue.comments.create",
564
565
  "agents.read",
package/dist/ui/index.js CHANGED
@@ -34641,11 +34641,13 @@ function GitHubSyncIssueDetailTabContent(props) {
34641
34641
  forceVisible: true
34642
34642
  });
34643
34643
  const linkGitHubItem = usePluginAction("issue.linkGitHubItem");
34644
+ const unlinkGitHubItem = usePluginAction("issue.unlinkGitHubItem");
34644
34645
  const toast = usePluginToast();
34645
34646
  const [manualLinkOpen, setManualLinkOpen] = useState2(false);
34646
34647
  const [manualLinkKind, setManualLinkKind] = useState2("issue");
34647
34648
  const [manualLinkReference, setManualLinkReference] = useState2("");
34648
34649
  const [manualLinkPending, setManualLinkPending] = useState2(false);
34650
+ const [unlinkPending, setUnlinkPending] = useState2(false);
34649
34651
  useEffect2(() => {
34650
34652
  if (!props.companyId || !props.issueId) {
34651
34653
  return;
@@ -34703,6 +34705,36 @@ function GitHubSyncIssueDetailTabContent(props) {
34703
34705
  setManualLinkPending(false);
34704
34706
  }
34705
34707
  }
34708
+ async function handleUnlinkGitHubItem() {
34709
+ if (!props.companyId || !props.issueId || unlinkPending) {
34710
+ return;
34711
+ }
34712
+ if (typeof window !== "undefined" && !window.confirm("Unlink this Paperclip issue from GitHub? GitHub Sync will stop updating it until it is linked again.")) {
34713
+ return;
34714
+ }
34715
+ setUnlinkPending(true);
34716
+ try {
34717
+ await unlinkGitHubItem({
34718
+ companyId: props.companyId,
34719
+ issueId: props.issueId
34720
+ });
34721
+ await details.refresh();
34722
+ notifyGitHubSyncPullRequestsChanged();
34723
+ toast({
34724
+ title: "GitHub link removed",
34725
+ body: "This Paperclip issue is no longer linked to GitHub.",
34726
+ tone: "success"
34727
+ });
34728
+ } catch (error) {
34729
+ toast({
34730
+ title: "Unable to unlink GitHub item",
34731
+ body: getActionErrorMessage(error, "GitHub Sync could not remove this link."),
34732
+ tone: "error"
34733
+ });
34734
+ } finally {
34735
+ setUnlinkPending(false);
34736
+ }
34737
+ }
34706
34738
  return /* @__PURE__ */ jsxs2("section", { className: "ghsync-issue-detail", style: props.themeVars, children: [
34707
34739
  /* @__PURE__ */ jsx2("style", { children: EXTENSION_SURFACE_STYLES }),
34708
34740
  detailTabState === "loading" ? /* @__PURE__ */ jsx2("p", { className: "ghsync-extension-empty", children: "Loading GitHub sync details\u2026" }) : null,
@@ -34786,7 +34818,24 @@ function GitHubSyncIssueDetailTabContent(props) {
34786
34818
  }),
34787
34819
  children: /* @__PURE__ */ jsx2(GitHubButtonLabel, { label: "Open on GitHub" })
34788
34820
  }
34789
- ) : null
34821
+ ) : null,
34822
+ /* @__PURE__ */ jsx2(
34823
+ "button",
34824
+ {
34825
+ type: "button",
34826
+ className: getPluginActionClassName({
34827
+ variant: "danger",
34828
+ size: "sm",
34829
+ extraClassName: "ghsync-extension-link"
34830
+ }),
34831
+ disabled: unlinkPending,
34832
+ onClick: () => {
34833
+ void handleUnlinkGitHubItem();
34834
+ },
34835
+ title: "Unlink from GitHub",
34836
+ children: /* @__PURE__ */ jsx2(LoadingButtonContent, { busy: unlinkPending, label: "Unlink", busyLabel: "Unlinking" })
34837
+ }
34838
+ )
34790
34839
  ] })
34791
34840
  ] }),
34792
34841
  /* @__PURE__ */ jsxs2("div", { className: "ghsync-extension-grid", children: [