paperclip-github-plugin 0.5.3 → 0.6.1

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
@@ -30,7 +30,8 @@ The plugin adds a full in-host workflow instead of a one-off import script:
30
30
 
31
31
  - a hosted settings page for GitHub auth, repository mappings, company defaults, execution-policy handoff fallbacks, and sync controls
32
32
  - authenticated-only setup controls for Paperclip board access and company-scoped agent token propagation
33
- - a dashboard widget that shows readiness, sync status, and last-run results
33
+ - a dashboard widget that shows sync readiness, current sync status, and run/cancel controls
34
+ - a separate KPI dashboard widget that tracks GitHub backlog size, GitHub issues closed, and Paperclip pull requests created with recent history and historical comparisons
34
35
  - saved sync diagnostics that let operators inspect the latest per-issue failures, raw errors, and suggested next steps
35
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
36
37
  - manual sync actions from global, project, and issue surfaces
@@ -63,12 +64,22 @@ If a company already has a Paperclip project bound to a GitHub repository worksp
63
64
 
64
65
  The plugin does more than mirror issue text. It looks at linked pull requests, mergeability, CI, 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-thread 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
66
 
67
+ ### Company KPI dashboard
68
+
69
+ GitHub Sync exposes a dedicated KPI dashboard widget alongside the operational sync widget. During full company syncs, the worker snapshots the current open GitHub backlog and records when already-imported GitHub issues move from open to closed. The KPI widget turns that worker-owned state into backlog, issue-closure, and Paperclip PR-creation cards with recent history and comparisons against older periods.
70
+
71
+ Because GitHub alone cannot tell which pull requests came from a Paperclip company, the plugin uses explicit Paperclip attribution for delivery activity. `create_pull_request` automatically records a Paperclip-created PR event, and agents that use `gh` or another non-plugin GitHub client can post pull-request-created events to the plugin webhook so the KPI history stays specific to Paperclip work.
72
+
73
+ That webhook path matters on authenticated Paperclip deployments today because a current host bug blocks agents from calling plugin tools unless the instance runs in `local_trusted` mode. Those agents can still use `gh` with the propagated `GITHUB_TOKEN`, then call the plugin-owned webhook from the shell after they create a PR. KPI webhook requests instead authenticate with `Authorization: Bearer <PAPERCLIP_API_KEY>`, which the deployment validates through `GET /api/agents/me`, so anonymous POSTs are rejected.
74
+
66
75
  ### Project pull request command center
67
76
 
68
77
  Each mapped project can expose a **Pull Requests** entry in the sidebar that opens a live GitHub queue page for that repository. The sidebar badge uses a lightweight total-count read, while the queue keeps the default view fast by loading only the current 10-row page, uses a repo-wide metrics read for the summary cards, reuses that cached metrics scan to keep filtered views fast by fetching only the visible filtered rows, keeps repo-scoped count, metrics, and per-PR review/check insight caches warm for repeat visits, lets operators explicitly bust those caches with Refresh when they want a live reread, shows total, mergeable, reviewable, and failing cards that filter the table, only treats a pull request as mergeable when it targets the current default branch with green checks, at least one approval, no outstanding change requests, and no unresolved review threads, includes an **Up to date** column that distinguishes current branches, clean update candidates, conflict cases, and unknown freshness when GitHub cannot confirm the comparison, shows the PR target branch with a highlighted default-branch badge, keeps the list sorted by most recently updated first, paginates larger repositories, keeps a compact bottom detail pane with markdown-and-HTML-rendered conversation plus an inline comment composer, supports deterministic **Update branch** actions for clean behind-base pull requests, adds Copilot quick actions that post `@copilot` requests for **Fix CI**, **Rebase**, and **Address review feedback**, requests Copilot through GitHub’s native reviewer flow for **Review**, keeps comment, review, quick approve/request-changes, re-run CI, merge, and close actions available, lets the review modal submit comment-only, approve, or request-changes reviews, hides any pull request action whose required GitHub permission is not verified for the saved token, and opens linked Paperclip issues in a plugin-provided right drawer so operators can stay on the queue page.
69
78
 
70
79
  Paperclip issue linkage on the queue prefers the GitHub issue that the pull request closes, so imported GitHub issues and delivery work stay connected in the same project view. If a pull request has no closing-issue-backed link yet, the queue falls back to the Paperclip issue created directly from that pull request and updates the table immediately when that create action returns.
71
80
 
81
+ Those pull-request-created Paperclip issues also stay in the scheduled/manual sync loop even when the pull request does not close a GitHub issue. GitHub Sync checks their CI, merge state, and review threads so new failures or unresolved feedback move the Paperclip issue back into active work.
82
+
72
83
  The issue detail panel and sync-created comment annotations also preserve cross-repository linked pull requests, showing those PRs with their real repository path so operators land in the right place on GitHub.
73
84
 
74
85
  ### Agent workflows built in
@@ -167,6 +178,7 @@ The plugin is designed to avoid persisting raw credentials in plugin state.
167
178
  - On authenticated deployments, any selected propagation agents receive `GITHUB_TOKEN` as an agent env secret-ref binding that points at the same saved GitHub token secret instead of a copied raw token.
168
179
  - The worker resolves those secret references at runtime instead of storing raw tokens in plugin state.
169
180
  - On authenticated Paperclip deployments, sync is blocked until the relevant company has connected Paperclip board access.
181
+ - KPI webhook requests must include `Authorization: Bearer <PAPERCLIP_API_KEY>`, and the worker validates that agent-scoped Paperclip token against `GET /api/agents/me` before it records any metric event.
170
182
 
171
183
  ### Optional worker-local token file
172
184
 
@@ -196,13 +208,50 @@ The plugin exposes GitHub workflow tools to Paperclip agents, including:
196
208
 
197
209
  When an agent sends GitHub body content through the plugin, including issue bodies, pull request descriptions, comments, and review-thread replies, the plugin adds a GitHub-flavored Markdown footer with a horizontal rule and compact heading that discloses AI authorship. If the tool caller supplies `llmModel`, the footer also includes the model name, for example `###### ✨ This comment was AI-generated using gpt-5.4`.
198
210
 
211
+ ### KPI attribution webhook
212
+
213
+ The `create_pull_request` tool automatically records a company-level Paperclip PR creation metric. For delivery flows that use `gh` or another non-plugin GitHub client, post a JSON payload to `/api/plugins/paperclip-github-plugin/webhooks/record-company-metric-event` after the PR is created.
214
+
215
+ Supported payload fields:
216
+
217
+ - `metric` required: `pull_request_created`
218
+ - `companyId` optional when `repository` maps to exactly one company
219
+ - `repository` optional: `owner/repo` or `https://github.com/owner/repo`
220
+ - `pullRequestNumber` optional
221
+ - `pullRequestUrl` optional
222
+ - `occurredAt` optional ISO timestamp
223
+ - `eventKey` optional custom dedupe key
224
+ - `count` optional positive integer
225
+
226
+ Each request must include:
227
+
228
+ - `Authorization: Bearer <PAPERCLIP_API_KEY>`
229
+
230
+ The worker validates that bearer token against Paperclip's built-in `GET /api/agents/me` endpoint on the trusted Paperclip API origin (`PAPERCLIP_API_URL` when available, otherwise the saved plugin origin). Requests are rejected when the token is missing, invalid, expired, or belongs to a different company than the metric target.
231
+
232
+ Example:
233
+
234
+ ```bash
235
+ payload='{"metric":"pull_request_created","repository":"paperclipai/example-repo","pullRequestNumber":21}'
236
+
237
+ curl -X POST "${PAPERCLIP_API_URL%/}/api/plugins/paperclip-github-plugin/webhooks/record-company-metric-event" \
238
+ -H "content-type: application/json" \
239
+ -H "authorization: Bearer ${PAPERCLIP_API_KEY}" \
240
+ -d "${payload}"
241
+ ```
242
+
243
+ The worker deduplicates repeated PR events by preferring the pull request URL, then `repository + pullRequestNumber`, before falling back to the explicit `eventKey`.
244
+
199
245
  Current host caveat: on authenticated Paperclip deployments, the Paperclip host currently guards `GET /api/plugins/tools` and `POST /api/plugins/tools/execute` with board authentication before dispatching to any plugin worker. If an agent run does not have board access for the target company, GitHub Sync tool discovery and execution fail with `403 {"error":"Board access required"}` before this plugin's worker code runs.
200
246
 
247
+ Because the KPI attribution endpoint is a normal plugin webhook rather than a plugin tool, authenticated agent runs can still call it directly with `PAPERCLIP_API_KEY` even while that host bug blocks the GitHub Sync tool surface.
248
+
201
249
  ## Troubleshooting
202
250
 
203
251
  - If setup is reported as incomplete, confirm that a GitHub token has been saved or that `${PAPERCLIP_HOME:-~/.paperclip}/plugins/github-sync/config.json` contains `githubToken`, and make sure at least one mapping has a created Paperclip project.
204
252
  - If Paperclip says board access is required, open plugin settings inside the affected company and complete the Paperclip board access flow before retrying sync.
205
253
  - If GitHub Sync agent tools fail with `403 {"error":"Board access required"}` on `/api/plugins/tools` or `/api/plugins/tools/execute`, the current Paperclip host rejected the request before the plugin worker ran. Re-run from a board-authenticated session or agent run that has board access to the target company.
254
+ - If a KPI webhook call is rejected, make sure the request includes `Authorization: Bearer ${PAPERCLIP_API_KEY}`, that the token is still valid for the current run, and that it belongs to the same company the metric event targets.
206
255
  - If the worker reaches an authenticated HTML page instead of the Paperclip API JSON responses it expects, connect Paperclip board access for that company or set `PAPERCLIP_API_URL` to a worker-accessible Paperclip API origin.
207
256
  - If a sync run finishes with partial failures, open the saved troubleshooting panel in GitHub Sync to inspect the repository, issue number, raw error, and suggested fix for each recorded failure.
208
257
  - If sync says the Paperclip API URL is not trusted, reopen the plugin from the current Paperclip host so the settings UI can refresh the saved origin, or set `PAPERCLIP_API_URL` for the worker.
@@ -227,7 +276,7 @@ Useful scripts:
227
276
  - `pnpm dev` watches the manifest, worker, and UI bundles and rebuilds them into `dist/`
228
277
  - `pnpm dev:ui` starts a local Paperclip plugin UI dev server from `dist/ui` on port `4177`
229
278
  - `pnpm test:e2e` builds the plugin, boots an isolated Paperclip instance, installs the plugin, and verifies the hosted settings page renders
230
- - `pnpm verify:manual` builds the plugin, boots a Paperclip instance for manual inspection, seeds a project already mapped to `https://github.com/alvarosanchez/paperclip-github-plugin`, seeds a `CEO` agent on the Codex local adapter with model `gpt-5.4`, and opens the plugin settings page
279
+ - `pnpm verify:manual` builds the plugin, boots a local-trusted Paperclip instance for manual inspection, seeds a `Dummy Company` with a mapped review project and a `CEO` agent on the Codex local adapter using model `gpt-5.4`, installs the plugin, and opens the company dashboard without seeding KPI history.
231
280
 
232
281
  For fast hosted UI iteration, run `pnpm dev` in one terminal and `pnpm dev:ui` in another.
233
282
 
package/dist/manifest.js CHANGED
@@ -506,14 +506,19 @@ var GITHUB_AGENT_TOOLS = [
506
506
  }
507
507
  ];
508
508
 
509
+ // src/kpi-contract.ts
510
+ var GITHUB_SYNC_PLUGIN_ID = "paperclip-github-plugin";
511
+ var COMPANY_METRIC_WEBHOOK_ENDPOINT_KEY = "record-company-metric-event";
512
+ var COMPANY_METRIC_WEBHOOK_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/webhooks/${COMPANY_METRIC_WEBHOOK_ENDPOINT_KEY}`;
513
+
509
514
  // src/manifest.ts
510
515
  var require2 = createRequire(import.meta.url);
511
516
  var packageJson = require2("../package.json");
512
517
  var DASHBOARD_WIDGET_CAPABILITY = "ui.dashboardWidget.register";
513
518
  var SCHEDULE_TICK_CRON = "* * * * *";
514
- var MANIFEST_VERSION = "0.5.3"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
519
+ var MANIFEST_VERSION = "0.6.1"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
515
520
  var manifest = {
516
- id: "paperclip-github-plugin",
521
+ id: GITHUB_SYNC_PLUGIN_ID,
517
522
  apiVersion: 1,
518
523
  version: MANIFEST_VERSION,
519
524
  displayName: "GitHub Sync",
@@ -538,6 +543,7 @@ var manifest = {
538
543
  "issue.comments.create",
539
544
  "agents.read",
540
545
  "jobs.schedule",
546
+ "webhooks.receive",
541
547
  "http.outbound",
542
548
  "secrets.read-ref",
543
549
  "agent.tools.register"
@@ -573,6 +579,13 @@ var manifest = {
573
579
  schedule: SCHEDULE_TICK_CRON
574
580
  }
575
581
  ],
582
+ webhooks: [
583
+ {
584
+ endpointKey: COMPANY_METRIC_WEBHOOK_ENDPOINT_KEY,
585
+ displayName: "Record Company KPI Event",
586
+ description: "Record Paperclip-attributed pull request activity from agent flows that use gh or other non-plugin GitHub clients."
587
+ }
588
+ ],
576
589
  tools: GITHUB_AGENT_TOOLS,
577
590
  entrypoints: {
578
591
  worker: "./dist/worker.js",
@@ -601,6 +614,12 @@ var manifest = {
601
614
  displayName: "GitHub Sync",
602
615
  exportName: "GitHubSyncDashboardWidget"
603
616
  },
617
+ {
618
+ type: "dashboardWidget",
619
+ id: "paperclip-github-plugin-kpi-dashboard-widget",
620
+ displayName: "GitHub KPIs",
621
+ exportName: "GitHubSyncKpiDashboardWidget"
622
+ },
604
623
  {
605
624
  type: "taskDetailView",
606
625
  id: "paperclip-github-plugin-issue-detail-tab",