paperclip-github-plugin 0.8.8 → 0.8.9
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 +9 -2
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +71 -10
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +49 -24
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -215,6 +215,12 @@ Notes:
|
|
|
215
215
|
- The raw token is never persisted back into plugin state or plugin config.
|
|
216
216
|
- A GitHub token secret saved through the settings UI takes precedence over the local file.
|
|
217
217
|
|
|
218
|
+
### Worker-facing Paperclip API URL
|
|
219
|
+
|
|
220
|
+
GitHub Sync uses direct worker-side Paperclip REST calls for host paths that are not fully covered by the plugin SDK, such as label reconciliation and some issue repair paths. By default, manual setup and sync actions use the current browser origin. If that origin is not reachable from the plugin worker, set **Worker Paperclip API URL** in GitHub Sync settings; the value is saved internally as plugin config `paperclipApiBaseUrl`.
|
|
221
|
+
|
|
222
|
+
For private LAN, Docker, Kubernetes, custom DNS, or self-signed-certificate deployments, set that field to a local route the plugin worker can reach, such as `http://localhost:3100`, and port-forward or route that address to the Paperclip API when needed. Do not rely on exporting a process environment variable named `PAPERCLIP_API_URL` to Paperclip; Paperclip `2026.428.0` does not pass that value through to plugin worker runtime.
|
|
223
|
+
|
|
218
224
|
## GitHub agent tools
|
|
219
225
|
|
|
220
226
|
The plugin exposes GitHub workflow tools to Paperclip agents, including:
|
|
@@ -296,9 +302,10 @@ curl -X POST "${PAPERCLIP_API_URL%/}/api/plugins/paperclip-github-plugin/api/iss
|
|
|
296
302
|
- If Paperclip says board access is required, open plugin settings inside the affected company and complete the Paperclip board access flow before retrying sync.
|
|
297
303
|
- 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.
|
|
298
304
|
- If a KPI API route 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 any `companyId` in the payload matches the calling agent's company.
|
|
299
|
-
- 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
|
|
305
|
+
- 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 **Worker Paperclip API URL** in GitHub Sync settings to a worker-accessible Paperclip API origin.
|
|
306
|
+
- If a Paperclip API fetch fails before any HTTP response is returned, the saved diagnostics include the method, URL, primary error, nested cause, and cause code when Node exposes them.
|
|
300
307
|
- 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.
|
|
301
|
-
- If sync says the Paperclip API URL is not trusted,
|
|
308
|
+
- If sync says the Paperclip API URL is not trusted, set **Worker Paperclip API URL** in GitHub Sync settings to the worker-accessible Paperclip API origin and retry.
|
|
302
309
|
- If a pull request comment or review action is rejected, read the full toast message. Fine-grained GitHub tokens need write access to that repository, and GitHub requires a review summary when requesting changes.
|
|
303
310
|
- If a GitHub-linked project does not show the **Pull requests** sidebar entry, reopen the plugin settings and re-save the mapping. The project pull request surfaces also recover older mappings when saved ids are missing, and they can fall back to the active project's bound GitHub repository when the project already has a GitHub workspace configured.
|
|
304
311
|
- If GitHub rate limiting is hit, the plugin pauses sync until the reported reset time instead of retrying pointlessly.
|
package/dist/manifest.js
CHANGED
|
@@ -587,7 +587,7 @@ var ISSUE_LINK_API_ROUTE_URL_PATH = `/api/plugins/${GITHUB_SYNC_PLUGIN_ID}/api${
|
|
|
587
587
|
var require2 = createRequire(import.meta.url);
|
|
588
588
|
var packageJson = require2("../package.json");
|
|
589
589
|
var SCHEDULE_TICK_CRON = "* * * * *";
|
|
590
|
-
var MANIFEST_VERSION = "0.8.
|
|
590
|
+
var MANIFEST_VERSION = "0.8.9"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
|
|
591
591
|
var manifest = {
|
|
592
592
|
id: GITHUB_SYNC_PLUGIN_ID,
|
|
593
593
|
apiVersion: 1,
|
package/dist/ui/index.js
CHANGED
|
@@ -22694,6 +22694,9 @@ function normalizePluginConfig(value) {
|
|
|
22694
22694
|
}
|
|
22695
22695
|
return record;
|
|
22696
22696
|
}
|
|
22697
|
+
function resolvePaperclipApiBaseUrlForPluginAction(value, fallbackOrigin) {
|
|
22698
|
+
return normalizePluginConfig(value).paperclipApiBaseUrl ?? normalizePaperclipApiBaseUrl(fallbackOrigin);
|
|
22699
|
+
}
|
|
22697
22700
|
function mergePluginConfig(currentValue, patch5) {
|
|
22698
22701
|
const current = normalizePluginConfig(currentValue);
|
|
22699
22702
|
const currentGitHubTokenRefs = normalizePluginConfigGitHubTokenRefs(current.githubTokenRefs);
|
|
@@ -27577,7 +27580,7 @@ function shouldAutofillProjectName(mapping) {
|
|
|
27577
27580
|
const previousSuggestedProjectName = formatProjectNameFromRepository(mapping.repositoryUrl);
|
|
27578
27581
|
return previousSuggestedProjectName !== "" && currentProjectName === previousSuggestedProjectName;
|
|
27579
27582
|
}
|
|
27580
|
-
function
|
|
27583
|
+
function getPaperclipApiBrowserOrigin() {
|
|
27581
27584
|
if (typeof window === "undefined" || !window.location?.origin) {
|
|
27582
27585
|
return void 0;
|
|
27583
27586
|
}
|
|
@@ -27616,23 +27619,22 @@ async function fetchPluginDataResult(params) {
|
|
|
27616
27619
|
return response.data;
|
|
27617
27620
|
}
|
|
27618
27621
|
async function syncTrustedPaperclipApiBaseUrl(pluginId) {
|
|
27619
|
-
const paperclipApiBaseUrl = getPaperclipApiBaseUrl();
|
|
27620
|
-
if (!paperclipApiBaseUrl) {
|
|
27621
|
-
return void 0;
|
|
27622
|
-
}
|
|
27623
27622
|
const resolvedPluginId = await resolveCurrentPluginId(pluginId);
|
|
27624
27623
|
if (!resolvedPluginId) {
|
|
27625
27624
|
throw new Error(
|
|
27626
27625
|
"Unable to sync the trusted Paperclip API origin because the plugin ID is missing. Reload the plugin and try again before saving or syncing."
|
|
27627
27626
|
);
|
|
27628
27627
|
}
|
|
27628
|
+
const currentConfigResponse = await fetchJson(`/api/plugins/${resolvedPluginId}/config`);
|
|
27629
|
+
const currentConfig = normalizePluginConfig(currentConfigResponse?.configJson);
|
|
27630
|
+
const paperclipApiBaseUrl = resolvePaperclipApiBaseUrlForPluginAction(currentConfig, getPaperclipApiBrowserOrigin());
|
|
27631
|
+
if (!paperclipApiBaseUrl) {
|
|
27632
|
+
return void 0;
|
|
27633
|
+
}
|
|
27629
27634
|
const lastSyncedPaperclipApiBaseUrl = syncedPaperclipApiBaseUrlsByPluginId.get(resolvedPluginId);
|
|
27630
27635
|
if (lastSyncedPaperclipApiBaseUrl === paperclipApiBaseUrl) {
|
|
27631
27636
|
return paperclipApiBaseUrl;
|
|
27632
27637
|
}
|
|
27633
|
-
await patchPluginConfig(resolvedPluginId, {
|
|
27634
|
-
paperclipApiBaseUrl
|
|
27635
|
-
});
|
|
27636
27638
|
syncedPaperclipApiBaseUrlsByPluginId.set(resolvedPluginId, paperclipApiBaseUrl);
|
|
27637
27639
|
return paperclipApiBaseUrl;
|
|
27638
27640
|
}
|
|
@@ -31964,6 +31966,7 @@ function GitHubSyncSettingsPage() {
|
|
|
31964
31966
|
const [cancellingSync, setCancellingSync] = useState2(false);
|
|
31965
31967
|
const [manualSyncRequestError, setManualSyncRequestError] = useState2(null);
|
|
31966
31968
|
const [scheduleFrequencyDraft, setScheduleFrequencyDraft] = useState2(String(DEFAULT_SCHEDULE_FREQUENCY_MINUTES));
|
|
31969
|
+
const [paperclipApiBaseUrlDraft, setPaperclipApiBaseUrlDraft] = useState2("");
|
|
31967
31970
|
const [ignoredAuthorsDraft, setIgnoredAuthorsDraft] = useState2(DEFAULT_ADVANCED_SETTINGS.ignoredIssueAuthorUsernames.join(", "));
|
|
31968
31971
|
const [tokenStatusOverride, setTokenStatusOverride] = useState2(null);
|
|
31969
31972
|
const [validatedLogin, setValidatedLogin] = useState2(null);
|
|
@@ -32012,6 +32015,9 @@ function GitHubSyncSettingsPage() {
|
|
|
32012
32015
|
updatedAt: settings.data.updatedAt
|
|
32013
32016
|
});
|
|
32014
32017
|
setScheduleFrequencyDraft(String(nextScheduleFrequencyMinutes));
|
|
32018
|
+
setPaperclipApiBaseUrlDraft(
|
|
32019
|
+
settings.data.paperclipApiBaseUrlConfigured ? settings.data.paperclipApiBaseUrl ?? "" : getPaperclipApiBrowserOrigin() ?? ""
|
|
32020
|
+
);
|
|
32015
32021
|
setIgnoredAuthorsDraft(normalizeAdvancedSettings(settings.data.advancedSettings).ignoredIssueAuthorUsernames.join(", "));
|
|
32016
32022
|
setTokenDraft("");
|
|
32017
32023
|
setValidatedLogin(tokenUiState.validatedLogin);
|
|
@@ -32283,12 +32289,21 @@ function GitHubSyncSettingsPage() {
|
|
|
32283
32289
|
const scheduleFrequencyMinutes = parseScheduleFrequencyDraft(scheduleFrequencyDraft) ?? form.scheduleFrequencyMinutes;
|
|
32284
32290
|
const savedScheduleFrequencyMinutes = normalizeScheduleFrequencyMinutes(currentSettings?.scheduleFrequencyMinutes);
|
|
32285
32291
|
const scheduleDirty = scheduleFrequencyError === null && scheduleFrequencyMinutes !== savedScheduleFrequencyMinutes;
|
|
32292
|
+
const browserPaperclipApiBaseUrl = getPaperclipApiBrowserOrigin();
|
|
32293
|
+
const normalizedPaperclipApiBaseUrlDraft = normalizePaperclipApiBaseUrl(paperclipApiBaseUrlDraft);
|
|
32294
|
+
const paperclipApiBaseUrlError = paperclipApiBaseUrlDraft.trim() && !normalizedPaperclipApiBaseUrlDraft ? "Enter a valid URL." : null;
|
|
32295
|
+
const effectivePaperclipApiBaseUrl = normalizedPaperclipApiBaseUrlDraft ?? browserPaperclipApiBaseUrl;
|
|
32296
|
+
const paperclipApiBaseUrlIsOverride = Boolean(
|
|
32297
|
+
normalizedPaperclipApiBaseUrlDraft && browserPaperclipApiBaseUrl && normalizedPaperclipApiBaseUrlDraft !== browserPaperclipApiBaseUrl
|
|
32298
|
+
);
|
|
32299
|
+
const savedPaperclipApiBaseUrl = currentSettings?.paperclipApiBaseUrlConfigured ? currentSettings.paperclipApiBaseUrl ?? "" : browserPaperclipApiBaseUrl ?? "";
|
|
32300
|
+
const paperclipApiBaseUrlDirty = paperclipApiBaseUrlError === null && (normalizedPaperclipApiBaseUrlDraft ?? "") !== savedPaperclipApiBaseUrl;
|
|
32286
32301
|
const mappings = form.mappings.length > 0 ? form.mappings : [createEmptyMapping(0)];
|
|
32287
32302
|
const settingsMutationsLocked = syncInFlight;
|
|
32288
32303
|
const settingsMutationsLockReason = settingsMutationsLocked ? "Settings are temporarily locked while a sync is running to avoid overwriting local edits." : null;
|
|
32289
32304
|
const syncStatus = getSyncStatus(displaySyncState, runningSync, syncUnlocked);
|
|
32290
32305
|
const canSaveToken = hasCompanyContext && !settingsMutationsLocked && !submittingToken && !showInitialLoadingState && tokenDraft.trim().length > 0;
|
|
32291
|
-
const canSaveSetup = hasCompanyContext && repositoriesUnlocked && !settingsMutationsLocked && !submittingSetup && !showInitialLoadingState && scheduleFrequencyError === null && (mappingsDirty || advancedSettingsDirty || scheduleDirty);
|
|
32306
|
+
const canSaveSetup = hasCompanyContext && repositoriesUnlocked && !settingsMutationsLocked && !submittingSetup && !showInitialLoadingState && scheduleFrequencyError === null && paperclipApiBaseUrlError === null && (mappingsDirty || advancedSettingsDirty || scheduleDirty || paperclipApiBaseUrlDirty);
|
|
32292
32307
|
const canConnectBoardAccess = hasCompanyContext && !settingsMutationsLocked && !connectingBoardAccess && !showInitialLoadingState;
|
|
32293
32308
|
const boardAccessStatusLabel = !hasCompanyContext ? "Unavailable" : boardAccessBannerLabel;
|
|
32294
32309
|
const boardAccessStatusTone = !hasCompanyContext ? boardAccessRequired ? "warning" : "neutral" : boardAccessTone;
|
|
@@ -32693,6 +32708,9 @@ function GitHubSyncSettingsPage() {
|
|
|
32693
32708
|
if (scheduleFrequencyError) {
|
|
32694
32709
|
throw new Error(scheduleFrequencyError);
|
|
32695
32710
|
}
|
|
32711
|
+
if (paperclipApiBaseUrlError) {
|
|
32712
|
+
throw new Error(paperclipApiBaseUrlError);
|
|
32713
|
+
}
|
|
32696
32714
|
const resolvedMappings = [];
|
|
32697
32715
|
for (const mapping of form.mappings) {
|
|
32698
32716
|
const repositoryInput = mapping.repositoryUrl.trim();
|
|
@@ -32717,7 +32735,18 @@ function GitHubSyncSettingsPage() {
|
|
|
32717
32735
|
companyId
|
|
32718
32736
|
});
|
|
32719
32737
|
}
|
|
32720
|
-
const
|
|
32738
|
+
const pluginId = await resolveCurrentPluginId(pluginIdFromLocation);
|
|
32739
|
+
if (!pluginId) {
|
|
32740
|
+
throw new Error("Plugin id is required to save setup.");
|
|
32741
|
+
}
|
|
32742
|
+
const trustedPaperclipApiBaseUrl = effectivePaperclipApiBaseUrl;
|
|
32743
|
+
if (!trustedPaperclipApiBaseUrl) {
|
|
32744
|
+
throw new Error("Could not resolve the current browser origin for Paperclip API calls.");
|
|
32745
|
+
}
|
|
32746
|
+
const nextConfiguredPaperclipApiBaseUrl = paperclipApiBaseUrlIsOverride ? normalizedPaperclipApiBaseUrlDraft ?? "" : "";
|
|
32747
|
+
await patchPluginConfig(pluginId, {
|
|
32748
|
+
paperclipApiBaseUrl: nextConfiguredPaperclipApiBaseUrl
|
|
32749
|
+
});
|
|
32721
32750
|
const result = await saveRegistration({
|
|
32722
32751
|
companyId,
|
|
32723
32752
|
mappings: resolvedMappings,
|
|
@@ -32743,9 +32772,11 @@ function GitHubSyncSettingsPage() {
|
|
|
32743
32772
|
advancedSettings: normalizeAdvancedSettings(result.advancedSettings),
|
|
32744
32773
|
availableAssignees: result.availableAssignees ?? current.availableAssignees,
|
|
32745
32774
|
paperclipApiBaseUrl: result.paperclipApiBaseUrl,
|
|
32775
|
+
paperclipApiBaseUrlConfigured: paperclipApiBaseUrlIsOverride,
|
|
32746
32776
|
updatedAt: result.updatedAt
|
|
32747
32777
|
}));
|
|
32748
32778
|
setScheduleFrequencyDraft(String(normalizeScheduleFrequencyMinutes(result.scheduleFrequencyMinutes)));
|
|
32779
|
+
setPaperclipApiBaseUrlDraft(paperclipApiBaseUrlIsOverride ? nextConfiguredPaperclipApiBaseUrl : trustedPaperclipApiBaseUrl);
|
|
32749
32780
|
toast({
|
|
32750
32781
|
title: "GitHub sync setup saved",
|
|
32751
32782
|
body: `Advanced defaults, mappings, and automatic sync are saved for ${currentCompanyName}.`,
|
|
@@ -33423,6 +33454,32 @@ function GitHubSyncSettingsPage() {
|
|
|
33423
33454
|
] })
|
|
33424
33455
|
] })
|
|
33425
33456
|
] }),
|
|
33457
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__schedule-card", children: [
|
|
33458
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__field", children: [
|
|
33459
|
+
/* @__PURE__ */ jsx2("label", { htmlFor: "paperclip-api-base-url", children: "Worker Paperclip API URL" }),
|
|
33460
|
+
/* @__PURE__ */ jsx2(
|
|
33461
|
+
"input",
|
|
33462
|
+
{
|
|
33463
|
+
id: "paperclip-api-base-url",
|
|
33464
|
+
className: "ghsync__input",
|
|
33465
|
+
type: "url",
|
|
33466
|
+
value: paperclipApiBaseUrlDraft,
|
|
33467
|
+
disabled: settingsMutationsLocked || !hasCompanyContext,
|
|
33468
|
+
onChange: (event) => {
|
|
33469
|
+
setPaperclipApiBaseUrlDraft(event.currentTarget.value);
|
|
33470
|
+
},
|
|
33471
|
+
placeholder: browserPaperclipApiBaseUrl ?? "https://paperclip.example.com",
|
|
33472
|
+
autoComplete: "off"
|
|
33473
|
+
}
|
|
33474
|
+
),
|
|
33475
|
+
/* @__PURE__ */ jsx2("p", { className: `ghsync__hint${paperclipApiBaseUrlError ? " ghsync__hint--error" : ""}`, children: paperclipApiBaseUrlError ?? "Edit this only when the plugin worker needs a different Paperclip API origin." })
|
|
33476
|
+
] }),
|
|
33477
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__schedule-meta", children: [
|
|
33478
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__scope-pill ghsync__scope-pill--global", children: "Worker" }),
|
|
33479
|
+
/* @__PURE__ */ jsx2("strong", { children: effectivePaperclipApiBaseUrl ?? "Browser origin unavailable" }),
|
|
33480
|
+
/* @__PURE__ */ jsx2("span", { children: paperclipApiBaseUrlIsOverride ? "Configured override." : "Using browser origin." })
|
|
33481
|
+
] })
|
|
33482
|
+
] }),
|
|
33426
33483
|
!syncUnlocked ? /* @__PURE__ */ jsxs2("div", { className: "ghsync__locked", children: [
|
|
33427
33484
|
/* @__PURE__ */ jsxs2("div", { children: [
|
|
33428
33485
|
/* @__PURE__ */ jsx2("strong", { children: syncSetupIssue === "missing_board_access" ? "Paperclip board access is required" : "Manual sync is locked" }),
|
|
@@ -33544,6 +33601,10 @@ function GitHubSyncSettingsPage() {
|
|
|
33544
33601
|
/* @__PURE__ */ jsx2("span", { className: "ghsync__detail-label", children: "Auto-sync" }),
|
|
33545
33602
|
/* @__PURE__ */ jsx2("strong", { className: "ghsync__detail-value", children: scheduleDescription })
|
|
33546
33603
|
] }),
|
|
33604
|
+
/* @__PURE__ */ jsxs2("div", { className: "ghsync__detail", children: [
|
|
33605
|
+
/* @__PURE__ */ jsx2("span", { className: "ghsync__detail-label", children: "Worker API" }),
|
|
33606
|
+
/* @__PURE__ */ jsx2("strong", { className: "ghsync__detail-value", children: effectivePaperclipApiBaseUrl })
|
|
33607
|
+
] }),
|
|
33547
33608
|
/* @__PURE__ */ jsxs2("div", { className: "ghsync__detail", children: [
|
|
33548
33609
|
/* @__PURE__ */ jsx2("span", { className: "ghsync__detail-label", children: "Last sync" }),
|
|
33549
33610
|
/* @__PURE__ */ jsx2("strong", { className: "ghsync__detail-value", children: lastSync })
|