paperclip-github-plugin 0.4.2 → 0.4.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 +1 -0
- package/dist/manifest.js +1 -1
- package/dist/worker.js +70 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -144,6 +144,7 @@ When the local Paperclip API is available, the plugin also syncs labels by name,
|
|
|
144
144
|
Additional behavior:
|
|
145
145
|
|
|
146
146
|
- 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`.
|
|
147
|
+
- 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.
|
|
147
148
|
- Open imported issues that are already in `backlog` stay in `backlog` until someone changes them in Paperclip.
|
|
148
149
|
- If an imported issue is `done` or `cancelled` and GitHub shows it open again with no linked pull request, sync moves it to `todo` so agents can pick it up again.
|
|
149
150
|
- Trusted new GitHub comments from the original issue author or a verified maintainer/admin can move an open imported issue back to `todo`.
|
package/dist/manifest.js
CHANGED
|
@@ -503,7 +503,7 @@ var require2 = createRequire(import.meta.url);
|
|
|
503
503
|
var packageJson = require2("../package.json");
|
|
504
504
|
var DASHBOARD_WIDGET_CAPABILITY = "ui.dashboardWidget.register";
|
|
505
505
|
var SCHEDULE_TICK_CRON = "* * * * *";
|
|
506
|
-
var MANIFEST_VERSION = "0.4.
|
|
506
|
+
var MANIFEST_VERSION = "0.4.4"?.trim() || typeof packageJson.version === "string" && packageJson.version.trim() || process.env.npm_package_version?.trim() || "0.0.0-dev";
|
|
507
507
|
var manifest = {
|
|
508
508
|
id: "paperclip-github-plugin",
|
|
509
509
|
apiVersion: 1,
|
package/dist/worker.js
CHANGED
|
@@ -618,12 +618,14 @@ var CANCELLING_SYNC_MESSAGE = "Cancellation requested. GitHub sync will stop aft
|
|
|
618
618
|
var SYNC_PROGRESS_PERSIST_INTERVAL_MS = 250;
|
|
619
619
|
var MAX_SYNC_FAILURE_LOG_ENTRIES = 25;
|
|
620
620
|
var GITHUB_SECONDARY_RATE_LIMIT_FALLBACK_MS = 6e4;
|
|
621
|
+
var IMPORTED_ISSUE_WAKEUP_CONCURRENCY = 4;
|
|
621
622
|
var MISSING_GITHUB_TOKEN_SYNC_MESSAGE = "Configure a GitHub token before running sync.";
|
|
622
623
|
var MISSING_GITHUB_TOKEN_SYNC_ACTION = 'Open settings and save a GitHub token secret, or create $PAPERCLIP_HOME/plugins/github-sync/config.json (or ~/.paperclip/plugins/github-sync/config.json when PAPERCLIP_HOME is unset) with a "githubToken" value, and then run sync again.';
|
|
623
624
|
var MISSING_MAPPING_SYNC_MESSAGE = "Save at least one mapping with a created Paperclip project before running sync.";
|
|
624
625
|
var MISSING_MAPPING_SYNC_ACTION = "Open settings, add a repository mapping, let Paperclip create the target project, and then retry sync.";
|
|
625
626
|
var MISSING_BOARD_ACCESS_SYNC_MESSAGE = "Connect Paperclip board access before running sync on this authenticated deployment.";
|
|
626
627
|
var MISSING_BOARD_ACCESS_SYNC_ACTION = "Open plugin settings for each mapped company that sync will touch, connect Paperclip board access, approve the flow, and then run sync again.";
|
|
628
|
+
var IMPORTED_ISSUE_WAKE_REASON = "GitHub Sync imported an assigned issue that is ready for work.";
|
|
627
629
|
var ISSUE_LINK_ENTITY_TYPE = "paperclip-github-plugin.issue-link";
|
|
628
630
|
var PULL_REQUEST_LINK_ENTITY_TYPE = "paperclip-github-plugin.pull-request-link";
|
|
629
631
|
var COMMENT_ANNOTATION_ENTITY_TYPE = "paperclip-github-plugin.comment-annotation";
|
|
@@ -4121,7 +4123,7 @@ function resolvePaperclipIssueStatus(params) {
|
|
|
4121
4123
|
if (snapshot.state === "closed") {
|
|
4122
4124
|
return snapshot.stateReason === "duplicate" || snapshot.stateReason === "not_planned" ? "cancelled" : "done";
|
|
4123
4125
|
}
|
|
4124
|
-
if (currentStatus === "backlog") {
|
|
4126
|
+
if (currentStatus === "backlog" && !wasImportedThisRun) {
|
|
4125
4127
|
return "backlog";
|
|
4126
4128
|
}
|
|
4127
4129
|
const baselineCommentCount = previousCommentCount ?? snapshot.commentCount;
|
|
@@ -5225,6 +5227,9 @@ function getPaperclipIssueEndpoint(baseUrl, issueId) {
|
|
|
5225
5227
|
function getPaperclipHealthEndpoint(baseUrl) {
|
|
5226
5228
|
return new URL("/api/health", baseUrl).toString();
|
|
5227
5229
|
}
|
|
5230
|
+
function getPaperclipAgentWakeupEndpoint(baseUrl, agentId) {
|
|
5231
|
+
return new URL(`/api/agents/${agentId}/wakeup`, baseUrl).toString();
|
|
5232
|
+
}
|
|
5228
5233
|
function getActivePaperclipApiAuthToken(companyId) {
|
|
5229
5234
|
if (!companyId) {
|
|
5230
5235
|
return void 0;
|
|
@@ -5269,6 +5274,46 @@ async function detectPaperclipBoardAccessRequirement(paperclipApiBaseUrl) {
|
|
|
5269
5274
|
return false;
|
|
5270
5275
|
}
|
|
5271
5276
|
}
|
|
5277
|
+
async function wakePaperclipAssigneeForImportedIssue(ctx, params) {
|
|
5278
|
+
if (!params.assigneeAgentId || !params.paperclipApiBaseUrl) {
|
|
5279
|
+
return;
|
|
5280
|
+
}
|
|
5281
|
+
try {
|
|
5282
|
+
const response = await fetchPaperclipApi(
|
|
5283
|
+
getPaperclipAgentWakeupEndpoint(params.paperclipApiBaseUrl, params.assigneeAgentId),
|
|
5284
|
+
{
|
|
5285
|
+
method: "POST",
|
|
5286
|
+
headers: {
|
|
5287
|
+
accept: "application/json",
|
|
5288
|
+
"content-type": "application/json"
|
|
5289
|
+
},
|
|
5290
|
+
body: JSON.stringify({
|
|
5291
|
+
source: "assignment",
|
|
5292
|
+
triggerDetail: "system",
|
|
5293
|
+
reason: IMPORTED_ISSUE_WAKE_REASON,
|
|
5294
|
+
payload: {
|
|
5295
|
+
issueId: params.paperclipIssueId,
|
|
5296
|
+
mutation: "import"
|
|
5297
|
+
}
|
|
5298
|
+
})
|
|
5299
|
+
},
|
|
5300
|
+
{
|
|
5301
|
+
companyId: params.companyId
|
|
5302
|
+
}
|
|
5303
|
+
);
|
|
5304
|
+
if (!response.ok) {
|
|
5305
|
+
throw new Error(`Wakeup request failed with status ${response.status}.`);
|
|
5306
|
+
}
|
|
5307
|
+
} catch (error) {
|
|
5308
|
+
ctx.logger.warn("GitHub sync could not wake the assignee for an imported Paperclip issue.", {
|
|
5309
|
+
issueId: params.paperclipIssueId,
|
|
5310
|
+
agentId: params.assigneeAgentId,
|
|
5311
|
+
companyId: params.companyId,
|
|
5312
|
+
paperclipApiBaseUrl: params.paperclipApiBaseUrl,
|
|
5313
|
+
error: error instanceof Error ? error.message : String(error)
|
|
5314
|
+
});
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5272
5317
|
function parsePaperclipIssueDescription(value) {
|
|
5273
5318
|
if (!value || typeof value !== "object") {
|
|
5274
5319
|
return void 0;
|
|
@@ -6226,6 +6271,7 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
6226
6271
|
let updatedDescriptionsCount = 0;
|
|
6227
6272
|
let completedIssueCount = 0;
|
|
6228
6273
|
const totalIssueCount = importedIssues.length;
|
|
6274
|
+
const queuedImportedIssueWakeups = [];
|
|
6229
6275
|
for (const importedIssue of importedIssues) {
|
|
6230
6276
|
if (assertNotCancelled) {
|
|
6231
6277
|
await assertNotCancelled();
|
|
@@ -6357,9 +6403,16 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
6357
6403
|
defaultImportedStatus: advancedSettings.defaultStatus,
|
|
6358
6404
|
maintainerAuthoredImportedIssue
|
|
6359
6405
|
});
|
|
6406
|
+
const shouldWakeImportedAssignee = wasImportedThisRun && nextStatus === "todo" && Boolean(paperclipIssue.assigneeAgentId);
|
|
6360
6407
|
importedIssue.githubIssueNumber = githubIssue.number;
|
|
6361
6408
|
importedIssue.lastSeenCommentCount = snapshot.commentCount;
|
|
6362
6409
|
if (paperclipIssue.status === nextStatus) {
|
|
6410
|
+
if (shouldWakeImportedAssignee) {
|
|
6411
|
+
queuedImportedIssueWakeups.push({
|
|
6412
|
+
assigneeAgentId: paperclipIssue.assigneeAgentId,
|
|
6413
|
+
paperclipIssueId: importedIssue.paperclipIssueId
|
|
6414
|
+
});
|
|
6415
|
+
}
|
|
6363
6416
|
continue;
|
|
6364
6417
|
}
|
|
6365
6418
|
const transitionComment = buildPaperclipIssueStatusTransitionComment({
|
|
@@ -6385,6 +6438,12 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
6385
6438
|
paperclipApiBaseUrl
|
|
6386
6439
|
});
|
|
6387
6440
|
updatedStatusesCount += 1;
|
|
6441
|
+
if (shouldWakeImportedAssignee) {
|
|
6442
|
+
queuedImportedIssueWakeups.push({
|
|
6443
|
+
assigneeAgentId: paperclipIssue.assigneeAgentId,
|
|
6444
|
+
paperclipIssueId: importedIssue.paperclipIssueId
|
|
6445
|
+
});
|
|
6446
|
+
}
|
|
6388
6447
|
} catch (error) {
|
|
6389
6448
|
if (isGitHubRateLimitError(error)) {
|
|
6390
6449
|
throw error;
|
|
@@ -6403,6 +6462,16 @@ async function synchronizePaperclipIssueStatuses(ctx, octokit, repository, mappi
|
|
|
6403
6462
|
}
|
|
6404
6463
|
}
|
|
6405
6464
|
}
|
|
6465
|
+
await mapWithConcurrency(
|
|
6466
|
+
queuedImportedIssueWakeups,
|
|
6467
|
+
IMPORTED_ISSUE_WAKEUP_CONCURRENCY,
|
|
6468
|
+
async (queuedWakeup) => wakePaperclipAssigneeForImportedIssue(ctx, {
|
|
6469
|
+
assigneeAgentId: queuedWakeup.assigneeAgentId,
|
|
6470
|
+
paperclipIssueId: queuedWakeup.paperclipIssueId,
|
|
6471
|
+
companyId: mapping.companyId,
|
|
6472
|
+
paperclipApiBaseUrl
|
|
6473
|
+
})
|
|
6474
|
+
);
|
|
6406
6475
|
return {
|
|
6407
6476
|
updatedStatusesCount,
|
|
6408
6477
|
updatedLabelsCount,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paperclip-github-plugin",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.4",
|
|
4
4
|
"description": "Paperclip plugin for synchronizing GitHub issues into Paperclip projects.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -54,6 +54,6 @@
|
|
|
54
54
|
"esbuild": "0.28.0",
|
|
55
55
|
"playwright": "1.59.1",
|
|
56
56
|
"tsx": "4.21.0",
|
|
57
|
-
"typescript": "6.0.
|
|
57
|
+
"typescript": "6.0.3"
|
|
58
58
|
}
|
|
59
59
|
}
|