paperclip-github-plugin 0.9.9 → 0.9.10
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 +7 -7
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +41 -17
- package/dist/ui/index.js.map +3 -3
- package/dist/worker.js +3 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -19,7 +19,7 @@ With this plugin, you can:
|
|
|
19
19
|
- import open GitHub issues into Paperclip without adding title prefixes or duplicate issues
|
|
20
20
|
- keep descriptions, labels, and status aligned with GitHub over time
|
|
21
21
|
- configure mappings and import defaults per Paperclip company
|
|
22
|
-
-
|
|
22
|
+
- choose exactly which company agents should receive the saved GitHub token as `GITHUB_TOKEN`
|
|
23
23
|
- run sync manually or on a schedule
|
|
24
24
|
- triage open pull requests from mapped Paperclip projects in a hosted queue
|
|
25
25
|
- give Paperclip agents native GitHub tools for issues, pull requests, CI, review threads, and org-level projects
|
|
@@ -29,7 +29,7 @@ With this plugin, you can:
|
|
|
29
29
|
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
|
+
- setup controls for Paperclip board access and company-scoped agent token propagation
|
|
33
33
|
- a dashboard widget that shows sync readiness, current sync status, and run/cancel controls
|
|
34
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
|
|
35
35
|
- saved sync diagnostics that let operators inspect the latest per-issue failures, raw errors, and suggested next steps
|
|
@@ -137,8 +137,8 @@ npx paperclipai plugin install --local "$PWD"
|
|
|
137
137
|
|
|
138
138
|
1. Open the plugin settings for **GitHub Sync** from inside the Paperclip company you want to configure.
|
|
139
139
|
2. Paste a GitHub token, validate it, and save it.
|
|
140
|
-
3. If the deployment is authenticated, connect Paperclip board access from the same settings page and complete the approval flow.
|
|
141
|
-
4.
|
|
140
|
+
3. If the deployment is authenticated or local trusted, connect Paperclip board access from the same settings page and complete the approval flow when host API calls need board credentials.
|
|
141
|
+
4. Choose which agents in the current company should receive the saved GitHub token as `GITHUB_TOKEN`.
|
|
142
142
|
5. Add one or more repository mappings for the current company.
|
|
143
143
|
6. For each mapping, either choose an existing GitHub-linked Paperclip project or enter the project name that should receive synced issues.
|
|
144
144
|
7. Optionally configure company-wide defaults for imported issues, including the default assignee, the default Paperclip status, executor/reviewer/approver handoff assignees for sync-driven transitions, and ignored GitHub usernames. When Paperclip board access is connected, each assignee dropdown also offers `Me` for the connected board user. `Automatic routing` means GitHub Sync follows the issue's Paperclip execution policy first and only uses the saved fallback when Paperclip does not expose the next reviewer, approver, or return assignee yet. Bot aliases such as `renovate[bot]` are matched when you save `renovate`.
|
|
@@ -197,10 +197,10 @@ The plugin is designed to avoid persisting raw credentials in plugin state.
|
|
|
197
197
|
- GitHub tokens saved through the UI are stored as per-company Paperclip secret references.
|
|
198
198
|
- Paperclip board access tokens are also stored as per-company secret references.
|
|
199
199
|
- The settings UI also keeps lightweight non-secret identity labels for those saved connections, so later visits can still show who each company GitHub token and board access are connected as.
|
|
200
|
-
-
|
|
200
|
+
- 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.
|
|
201
201
|
- The worker resolves those secret references at runtime instead of storing raw tokens in plugin state.
|
|
202
202
|
- When the current Paperclip host rejects plugin secret refs, GitHub Sync keeps company-scoped worker-local compatibility copies for GitHub tokens and Paperclip board-access tokens in `${PAPERCLIP_HOME:-~/.paperclip}/plugins/github-sync/config.json`. Reconnect board access once after upgrading if sync still cannot authenticate Paperclip label or issue REST calls.
|
|
203
|
-
- On authenticated Paperclip deployments, sync is blocked until the relevant company has connected Paperclip board access.
|
|
203
|
+
- On authenticated Paperclip deployments, sync is blocked until the relevant company has connected Paperclip board access. On local trusted deployments, board access setup remains visible so operators can configure it for host API paths that still require board credentials, but missing board access does not by itself block sync preflight.
|
|
204
204
|
- KPI API route requests must include `Authorization: Bearer <PAPERCLIP_API_KEY>` from an agent run; the Paperclip host authenticates the token and supplies the agent company before the worker records any metric event.
|
|
205
205
|
|
|
206
206
|
### Optional worker-local token file
|
|
@@ -225,7 +225,7 @@ Notes:
|
|
|
225
225
|
- The raw token is never persisted back into plugin state or plugin config.
|
|
226
226
|
- A GitHub token secret saved through the settings UI is the primary source. If the current Paperclip host rejects plugin secret-ref resolution while company-scoped plugin config is unavailable, GitHub Sync stores the validated token in `githubTokensByCompanyId` as a worker-local compatibility fallback.
|
|
227
227
|
- A Paperclip board access secret saved through the settings UI is also the primary source. If the host cannot resolve it for plugin workers, reconnecting board access stores the approved board token in `paperclipBoardApiTokensByCompanyId` as a worker-local compatibility fallback for direct Paperclip REST calls.
|
|
228
|
-
-
|
|
228
|
+
- Selected agents receive `GITHUB_TOKEN` as a latest-version secret-ref env binding, and the settings UI patches agent adapter config with `replaceAdapterConfig: true` so newer Paperclip hosts persist the merged env map.
|
|
229
229
|
|
|
230
230
|
### Worker-facing Paperclip API URL
|
|
231
231
|
|
package/dist/manifest.js
CHANGED
|
@@ -642,7 +642,7 @@ var PULL_REQUEST_ASSET_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_I
|
|
|
642
642
|
var require2 = createRequire(import.meta.url);
|
|
643
643
|
var packageJson = require2("../package.json");
|
|
644
644
|
var SCHEDULE_TICK_CRON = "* * * * *";
|
|
645
|
-
var MANIFEST_VERSION = "0.9.
|
|
645
|
+
var MANIFEST_VERSION = "0.9.10"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
|
|
646
646
|
var manifest = {
|
|
647
647
|
id: GITHUB_SYNC_PLUGIN_ID,
|
|
648
648
|
apiVersion: 1,
|
package/dist/ui/index.js
CHANGED
|
@@ -22408,10 +22408,21 @@ function normalizePaperclipHealthResponse(value) {
|
|
|
22408
22408
|
...authReady !== void 0 ? { authReady } : {}
|
|
22409
22409
|
};
|
|
22410
22410
|
}
|
|
22411
|
-
function
|
|
22412
|
-
const health = normalizePaperclipHealthResponse(value);
|
|
22411
|
+
function requiresPaperclipBoardAccessForHealth(health) {
|
|
22413
22412
|
return health?.deploymentMode?.toLowerCase() === "authenticated";
|
|
22414
22413
|
}
|
|
22414
|
+
function shouldShowPaperclipBoardAccessSettingsForHealth(health) {
|
|
22415
|
+
const deploymentMode = health?.deploymentMode?.toLowerCase();
|
|
22416
|
+
return deploymentMode === "authenticated" || deploymentMode === "local_trusted";
|
|
22417
|
+
}
|
|
22418
|
+
function resolvePaperclipAuthControlsPolicy(value) {
|
|
22419
|
+
const health = normalizePaperclipHealthResponse(value);
|
|
22420
|
+
return {
|
|
22421
|
+
boardAccessRequired: requiresPaperclipBoardAccessForHealth(health),
|
|
22422
|
+
boardAccessSettingsVisible: shouldShowPaperclipBoardAccessSettingsForHealth(health),
|
|
22423
|
+
githubTokenPropagationSettingsVisible: true
|
|
22424
|
+
};
|
|
22425
|
+
}
|
|
22415
22426
|
|
|
22416
22427
|
// src/ui/assignees.ts
|
|
22417
22428
|
function normalizeCompanyAssigneeOptionsResponse(response) {
|
|
@@ -23098,7 +23109,12 @@ function getSyncSetupMessage(issue, hasCompanyContext) {
|
|
|
23098
23109
|
}
|
|
23099
23110
|
}
|
|
23100
23111
|
function usePaperclipBoardAccessRequirement() {
|
|
23101
|
-
const [
|
|
23112
|
+
const [state, setState] = useState2({
|
|
23113
|
+
status: "loading",
|
|
23114
|
+
required: false,
|
|
23115
|
+
settingsVisible: false,
|
|
23116
|
+
githubTokenPropagationSettingsVisible: true
|
|
23117
|
+
});
|
|
23102
23118
|
useEffect2(() => {
|
|
23103
23119
|
let cancelled = false;
|
|
23104
23120
|
void (async () => {
|
|
@@ -23107,19 +23123,28 @@ function usePaperclipBoardAccessRequirement() {
|
|
|
23107
23123
|
return;
|
|
23108
23124
|
}
|
|
23109
23125
|
if (!health) {
|
|
23110
|
-
|
|
23126
|
+
const policy2 = resolvePaperclipAuthControlsPolicy(null);
|
|
23127
|
+
setState({
|
|
23128
|
+
status: "unknown",
|
|
23129
|
+
required: policy2.boardAccessRequired,
|
|
23130
|
+
settingsVisible: policy2.boardAccessSettingsVisible,
|
|
23131
|
+
githubTokenPropagationSettingsVisible: policy2.githubTokenPropagationSettingsVisible
|
|
23132
|
+
});
|
|
23111
23133
|
return;
|
|
23112
23134
|
}
|
|
23113
|
-
|
|
23135
|
+
const policy = resolvePaperclipAuthControlsPolicy(health);
|
|
23136
|
+
setState({
|
|
23137
|
+
status: policy.boardAccessRequired ? "required" : "not_required",
|
|
23138
|
+
required: policy.boardAccessRequired,
|
|
23139
|
+
settingsVisible: policy.boardAccessSettingsVisible,
|
|
23140
|
+
githubTokenPropagationSettingsVisible: policy.githubTokenPropagationSettingsVisible
|
|
23141
|
+
});
|
|
23114
23142
|
})();
|
|
23115
23143
|
return () => {
|
|
23116
23144
|
cancelled = true;
|
|
23117
23145
|
};
|
|
23118
23146
|
}, []);
|
|
23119
|
-
return
|
|
23120
|
-
status,
|
|
23121
|
-
required: status === "required"
|
|
23122
|
-
};
|
|
23147
|
+
return state;
|
|
23123
23148
|
}
|
|
23124
23149
|
function getGitHubRateLimitResourceLabel(resource) {
|
|
23125
23150
|
switch (resource?.trim().toLowerCase()) {
|
|
@@ -32384,6 +32409,8 @@ function GitHubSyncSettingsPage() {
|
|
|
32384
32409
|
const hasSavedToken = Boolean(form.githubTokenConfigured || showSavedTokenHint);
|
|
32385
32410
|
const boardAccessConfigured = Boolean(form.paperclipBoardAccessConfigured);
|
|
32386
32411
|
const boardAccessRequired = boardAccessRequirement.required;
|
|
32412
|
+
const boardAccessSettingsVisible = boardAccessRequirement.settingsVisible;
|
|
32413
|
+
const githubTokenPropagationSettingsVisible = boardAccessRequirement.githubTokenPropagationSettingsVisible;
|
|
32387
32414
|
const boardAccessReady = !boardAccessRequired || hasCompanyContext && boardAccessConfigured;
|
|
32388
32415
|
const tokenStatus = tokenStatusOverride ?? (hasSavedToken ? "valid" : "required");
|
|
32389
32416
|
const tokenTone = tokenStatus === "valid" ? "success" : tokenStatus === "invalid" ? "danger" : "warning";
|
|
@@ -32492,7 +32519,7 @@ function GitHubSyncSettingsPage() {
|
|
|
32492
32519
|
const manualSyncScopePillLabel = hasCompanyContext ? "This company" : "All companies";
|
|
32493
32520
|
const manualSyncButtonLabel = hasCompanyContext ? "Run sync for this company" : "Run sync across all companies";
|
|
32494
32521
|
const advancedSettingsSummary = formatAdvancedSettingsSummary(form.advancedSettings, availableAssignees, {
|
|
32495
|
-
includePropagation:
|
|
32522
|
+
includePropagation: githubTokenPropagationSettingsVisible
|
|
32496
32523
|
});
|
|
32497
32524
|
const assigneeSelectOptions = [
|
|
32498
32525
|
{ value: "", label: "Unassigned" },
|
|
@@ -32646,9 +32673,6 @@ function GitHubSyncSettingsPage() {
|
|
|
32646
32673
|
});
|
|
32647
32674
|
}
|
|
32648
32675
|
async function propagateGitHubTokenToSelectedAgents(options) {
|
|
32649
|
-
if (!boardAccessRequired) {
|
|
32650
|
-
return;
|
|
32651
|
-
}
|
|
32652
32676
|
const selectedAgentIds = normalizeAgentIds(options.selectedAgentIds);
|
|
32653
32677
|
const previousAgentIds = normalizeAgentIds(options.previousAgentIds);
|
|
32654
32678
|
if (selectedAgentIds.length === 0 && previousAgentIds.length === 0) {
|
|
@@ -32855,7 +32879,7 @@ function GitHubSyncSettingsPage() {
|
|
|
32855
32879
|
}));
|
|
32856
32880
|
toast({
|
|
32857
32881
|
title: boardIdentity.label ? `Paperclip board access connected as ${boardIdentity.label}` : "Paperclip board access connected",
|
|
32858
|
-
body: "Direct Paperclip REST calls can now authenticate
|
|
32882
|
+
body: "Direct Paperclip REST calls can now authenticate when the host requires board access.",
|
|
32859
32883
|
tone: "success"
|
|
32860
32884
|
});
|
|
32861
32885
|
notifyGitHubSyncSettingsChanged();
|
|
@@ -33224,7 +33248,7 @@ function GitHubSyncSettingsPage() {
|
|
|
33224
33248
|
/* @__PURE__ */ jsx2("div", { className: "ghsync__permission-audit-list", children: /* @__PURE__ */ jsx2("div", { className: "ghsync__permission-audit-item", children: /* @__PURE__ */ jsx2("span", { children: tokenPermissionAuditData?.warnings[0] ?? "Add a mapped repository in this company so GitHub Sync can verify the token permissions it needs." }) }) })
|
|
33225
33249
|
] }) : null
|
|
33226
33250
|
] }),
|
|
33227
|
-
|
|
33251
|
+
boardAccessSettingsVisible ? /* @__PURE__ */ jsxs2("section", { className: "ghsync__section", children: [
|
|
33228
33252
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-head", children: [
|
|
33229
33253
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-copy", children: [
|
|
33230
33254
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__section-title-row", children: [
|
|
@@ -33565,7 +33589,7 @@ function GitHubSyncSettingsPage() {
|
|
|
33565
33589
|
),
|
|
33566
33590
|
/* @__PURE__ */ jsx2("p", { className: "ghsync__hint", children: "Comma or newline separated." })
|
|
33567
33591
|
] }),
|
|
33568
|
-
|
|
33592
|
+
githubTokenPropagationSettingsVisible ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__field", children: [
|
|
33569
33593
|
/* @__PURE__ */ jsx2("label", { htmlFor: "advanced-token-propagation", children: "Propagate GitHub token to agents" }),
|
|
33570
33594
|
/* @__PURE__ */ jsx2(
|
|
33571
33595
|
SettingsAgentMultiPicker,
|
|
@@ -33769,7 +33793,7 @@ function GitHubSyncSettingsPage() {
|
|
|
33769
33793
|
] }),
|
|
33770
33794
|
/* @__PURE__ */ jsx2("span", { children: !repositoriesUnlocked ? "Requires a token." : savedMappingCount > 0 ? hasCompanyContext ? `${savedMappingCount} saved.` : `${savedMappingCount} saved.` : hasCompanyContext ? "Add a repository." : "Select a company." })
|
|
33771
33795
|
] }),
|
|
33772
|
-
|
|
33796
|
+
boardAccessSettingsVisible ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__check", children: [
|
|
33773
33797
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__check-top", children: [
|
|
33774
33798
|
/* @__PURE__ */ jsx2("strong", { children: "Paperclip board access" }),
|
|
33775
33799
|
/* @__PURE__ */ jsx2("span", { className: `ghsync__badge ${getToneClass(boardAccessStatusTone)}`, children: boardAccessStatusLabel })
|