paperclip-github-plugin 0.4.5 → 0.4.6
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 +3 -2
- package/dist/manifest.js +1 -1
- package/dist/ui/index.js +60 -11
- package/dist/ui/index.js.map +2 -2
- package/dist/worker.js +112 -8
- package/package.json +1 -1
package/dist/worker.js
CHANGED
|
@@ -623,6 +623,8 @@ var GITHUB_TOKEN_PERMISSION_AUDIT_CACHE_TTL_MS = 5 * 6e4;
|
|
|
623
623
|
var MANUAL_SYNC_RESPONSE_GRACE_PERIOD_MS = 500;
|
|
624
624
|
var RUNNING_SYNC_MESSAGE = "GitHub sync is running in the background. This page will update when it finishes.";
|
|
625
625
|
var CANCELLING_SYNC_MESSAGE = "Cancellation requested. GitHub sync will stop after the current step finishes.";
|
|
626
|
+
var INTERRUPTED_SYNC_MESSAGE = "GitHub sync stopped unexpectedly before it finished. The worker restarted while the sync was running.";
|
|
627
|
+
var INTERRUPTED_SYNC_ACTION = "Run GitHub sync again. If it stops on the same repository or issue, retry that narrower scope to isolate the failing step.";
|
|
626
628
|
var SYNC_PROGRESS_PERSIST_INTERVAL_MS = 250;
|
|
627
629
|
var MAX_SYNC_FAILURE_LOG_ENTRIES = 25;
|
|
628
630
|
var GITHUB_SECONDARY_RATE_LIMIT_FALLBACK_MS = 6e4;
|
|
@@ -2895,6 +2897,97 @@ async function getSyncCancellationRequest(ctx) {
|
|
|
2895
2897
|
}
|
|
2896
2898
|
return normalizeSyncCancellationRequest(await ctx.state.get(SYNC_CANCELLATION_SCOPE));
|
|
2897
2899
|
}
|
|
2900
|
+
function buildInterruptedSyncMessage(progress) {
|
|
2901
|
+
const completedIssueCount = typeof progress?.completedIssueCount === "number" ? Math.max(0, progress.completedIssueCount) : void 0;
|
|
2902
|
+
const totalIssueCount = typeof progress?.totalIssueCount === "number" ? Math.max(0, progress.totalIssueCount) : void 0;
|
|
2903
|
+
const completionSummary = completedIssueCount !== void 0 && totalIssueCount !== void 0 ? ` Completed ${Math.min(completedIssueCount, totalIssueCount)} of ${totalIssueCount} issues before the worker restarted.` : "";
|
|
2904
|
+
return `${INTERRUPTED_SYNC_MESSAGE}${completionSummary}`;
|
|
2905
|
+
}
|
|
2906
|
+
function getInterruptedSyncFailurePhase(progress) {
|
|
2907
|
+
switch (progress?.phase) {
|
|
2908
|
+
case "preparing":
|
|
2909
|
+
return "building_import_plan";
|
|
2910
|
+
case "importing":
|
|
2911
|
+
return "importing_issue";
|
|
2912
|
+
case "syncing":
|
|
2913
|
+
return "evaluating_github_status";
|
|
2914
|
+
default:
|
|
2915
|
+
return void 0;
|
|
2916
|
+
}
|
|
2917
|
+
}
|
|
2918
|
+
function getActiveRunningSyncForScope(companyId) {
|
|
2919
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2920
|
+
if (activeRunningSyncState?.syncState.status !== "running") {
|
|
2921
|
+
return null;
|
|
2922
|
+
}
|
|
2923
|
+
const activeSyncMatchesScope = normalizedCompanyId === void 0 || activeRunningSyncCompanyId === void 0 || activeRunningSyncCompanyId === normalizedCompanyId;
|
|
2924
|
+
if (!activeSyncMatchesScope) {
|
|
2925
|
+
return null;
|
|
2926
|
+
}
|
|
2927
|
+
return materializeScopedSettings(activeRunningSyncState, null, normalizedCompanyId);
|
|
2928
|
+
}
|
|
2929
|
+
async function reconcileOrphanedRunningSyncState(ctx, companyId, resolution = "error") {
|
|
2930
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2931
|
+
const activeRunningSync = getActiveRunningSyncForScope(normalizedCompanyId);
|
|
2932
|
+
if (activeRunningSync) {
|
|
2933
|
+
return activeRunningSync;
|
|
2934
|
+
}
|
|
2935
|
+
const current = normalizeSettings(await ctx.state.get(SETTINGS_SCOPE));
|
|
2936
|
+
const scopedSyncState = getScopedSyncState(current, normalizedCompanyId);
|
|
2937
|
+
if (scopedSyncState.status !== "running") {
|
|
2938
|
+
return materializeScopedSettings(current, null, normalizedCompanyId);
|
|
2939
|
+
}
|
|
2940
|
+
const trigger = scopedSyncState.lastRunTrigger ?? "manual";
|
|
2941
|
+
const progress = normalizeSyncProgress(scopedSyncState.progress);
|
|
2942
|
+
const syncCounts = {
|
|
2943
|
+
syncedIssuesCount: scopedSyncState.syncedIssuesCount ?? 0,
|
|
2944
|
+
createdIssuesCount: scopedSyncState.createdIssuesCount ?? 0,
|
|
2945
|
+
skippedIssuesCount: scopedSyncState.skippedIssuesCount ?? 0,
|
|
2946
|
+
erroredIssuesCount: scopedSyncState.erroredIssuesCount ?? 0
|
|
2947
|
+
};
|
|
2948
|
+
const nextSyncState = resolution === "cancelled" || Boolean(scopedSyncState.cancelRequestedAt?.trim()) ? createCancelledSyncState({
|
|
2949
|
+
message: buildCancelledSyncMessage(void 0, progress),
|
|
2950
|
+
trigger,
|
|
2951
|
+
...syncCounts,
|
|
2952
|
+
...progress ? { progress } : {}
|
|
2953
|
+
}) : (() => {
|
|
2954
|
+
const errorDetails = normalizeSyncErrorDetails({
|
|
2955
|
+
...getInterruptedSyncFailurePhase(progress) ? { phase: getInterruptedSyncFailurePhase(progress) } : {},
|
|
2956
|
+
...progress?.currentRepositoryUrl ? { repositoryUrl: progress.currentRepositoryUrl } : {},
|
|
2957
|
+
...typeof progress?.currentIssueNumber === "number" ? { githubIssueNumber: progress.currentIssueNumber } : {},
|
|
2958
|
+
rawMessage: INTERRUPTED_SYNC_MESSAGE,
|
|
2959
|
+
suggestedAction: INTERRUPTED_SYNC_ACTION
|
|
2960
|
+
});
|
|
2961
|
+
const message = buildInterruptedSyncMessage(progress);
|
|
2962
|
+
return createErrorSyncState({
|
|
2963
|
+
message,
|
|
2964
|
+
trigger,
|
|
2965
|
+
...syncCounts,
|
|
2966
|
+
...progress ? { progress } : {},
|
|
2967
|
+
...errorDetails ? { errorDetails } : {},
|
|
2968
|
+
recentFailures: appendRecentSyncFailureLogEntry(
|
|
2969
|
+
scopedSyncState.recentFailures,
|
|
2970
|
+
createSyncFailureLogEntry({
|
|
2971
|
+
message,
|
|
2972
|
+
...errorDetails ? { errorDetails } : {}
|
|
2973
|
+
})
|
|
2974
|
+
)
|
|
2975
|
+
});
|
|
2976
|
+
})();
|
|
2977
|
+
const next = await saveSettingsSyncState(ctx, current, nextSyncState, normalizedCompanyId);
|
|
2978
|
+
await setSyncCancellationRequest(ctx, null);
|
|
2979
|
+
return next;
|
|
2980
|
+
}
|
|
2981
|
+
function resolvePersistedRunningSyncCompanyId(settings) {
|
|
2982
|
+
if (normalizeSyncState(settings.syncState).status === "running") {
|
|
2983
|
+
return void 0;
|
|
2984
|
+
}
|
|
2985
|
+
const runningCompanyIds = Object.entries(settings.syncStateByCompanyId ?? {}).flatMap(([companyId, syncState]) => {
|
|
2986
|
+
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2987
|
+
return normalizedCompanyId && normalizeSyncState(syncState).status === "running" ? [normalizedCompanyId] : [];
|
|
2988
|
+
});
|
|
2989
|
+
return runningCompanyIds.length === 1 ? runningCompanyIds[0] : null;
|
|
2990
|
+
}
|
|
2898
2991
|
function buildCancelledSyncMessage(target, progress) {
|
|
2899
2992
|
const completedIssueCount = typeof progress?.completedIssueCount === "number" ? Math.max(0, progress.completedIssueCount) : void 0;
|
|
2900
2993
|
const totalIssueCount = typeof progress?.totalIssueCount === "number" ? Math.max(0, progress.totalIssueCount) : void 0;
|
|
@@ -2949,11 +3042,11 @@ async function waitForSyncResultWithinGracePeriod(promise, timeoutMs) {
|
|
|
2949
3042
|
}
|
|
2950
3043
|
async function getActiveOrCurrentSyncState(ctx, companyId) {
|
|
2951
3044
|
const normalizedCompanyId = normalizeCompanyId(companyId);
|
|
2952
|
-
|
|
2953
|
-
|
|
3045
|
+
const activeRunningSync = getActiveRunningSyncForScope(normalizedCompanyId);
|
|
3046
|
+
if (activeRunningSync) {
|
|
3047
|
+
return activeRunningSync;
|
|
2954
3048
|
}
|
|
2955
|
-
|
|
2956
|
-
return materializeScopedSettings(current, null, normalizedCompanyId);
|
|
3049
|
+
return reconcileOrphanedRunningSyncState(ctx, normalizedCompanyId);
|
|
2957
3050
|
}
|
|
2958
3051
|
function updateSyncFailureContext(current, next) {
|
|
2959
3052
|
if ("phase" in next) {
|
|
@@ -9467,6 +9560,9 @@ function shouldRunScheduledSync(settings, scheduledAt) {
|
|
|
9467
9560
|
if (getActiveGitHubRateLimitPause(settings.syncState, now)) {
|
|
9468
9561
|
return false;
|
|
9469
9562
|
}
|
|
9563
|
+
if (settings.syncState.status === "running") {
|
|
9564
|
+
return false;
|
|
9565
|
+
}
|
|
9470
9566
|
if (!settings.syncState.checkedAt) {
|
|
9471
9567
|
return true;
|
|
9472
9568
|
}
|
|
@@ -10026,6 +10122,7 @@ async function startSync(ctx, trigger, options = {}) {
|
|
|
10026
10122
|
);
|
|
10027
10123
|
return quickResult2 ?? await getActiveOrCurrentSyncState(ctx);
|
|
10028
10124
|
}
|
|
10125
|
+
await reconcileOrphanedRunningSyncState(ctx, options.target?.companyId);
|
|
10029
10126
|
const [config, persistedSettings] = await Promise.all([
|
|
10030
10127
|
getResolvedConfig(ctx),
|
|
10031
10128
|
ctx.state.get(SETTINGS_SCOPE).then((value) => normalizeSettings(value))
|
|
@@ -10893,6 +10990,7 @@ var plugin = definePlugin({
|
|
|
10893
10990
|
const record = input && typeof input === "object" ? input : {};
|
|
10894
10991
|
const requestedCompanyId = normalizeCompanyId(record.companyId);
|
|
10895
10992
|
const includeAssignees = Boolean(requestedCompanyId && record.includeAssignees === true);
|
|
10993
|
+
await reconcileOrphanedRunningSyncState(ctx, requestedCompanyId);
|
|
10896
10994
|
const saved = await ctx.state.get(SETTINGS_SCOPE);
|
|
10897
10995
|
const importRegistry = normalizeImportRegistry(await ctx.state.get(IMPORT_REGISTRY_SCOPE));
|
|
10898
10996
|
const normalizedSettings = normalizeSettings(saved);
|
|
@@ -11179,7 +11277,12 @@ var plugin = definePlugin({
|
|
|
11179
11277
|
});
|
|
11180
11278
|
});
|
|
11181
11279
|
ctx.actions.register("sync.cancel", async () => {
|
|
11182
|
-
const
|
|
11280
|
+
const persistedRunningSyncCompanyId = activeRunningSyncState?.syncState.status === "running" ? activeRunningSyncCompanyId : resolvePersistedRunningSyncCompanyId(normalizeSettings(await ctx.state.get(SETTINGS_SCOPE)));
|
|
11281
|
+
const currentSettings = await reconcileOrphanedRunningSyncState(
|
|
11282
|
+
ctx,
|
|
11283
|
+
persistedRunningSyncCompanyId === null ? void 0 : persistedRunningSyncCompanyId,
|
|
11284
|
+
"cancelled"
|
|
11285
|
+
);
|
|
11183
11286
|
if (currentSettings.syncState.status !== "running") {
|
|
11184
11287
|
return currentSettings;
|
|
11185
11288
|
}
|
|
@@ -11200,7 +11303,7 @@ var plugin = definePlugin({
|
|
|
11200
11303
|
message: CANCELLING_SYNC_MESSAGE,
|
|
11201
11304
|
cancelRequestedAt: cancellationRequest.requestedAt
|
|
11202
11305
|
}),
|
|
11203
|
-
|
|
11306
|
+
persistedRunningSyncCompanyId === null ? void 0 : persistedRunningSyncCompanyId
|
|
11204
11307
|
);
|
|
11205
11308
|
activeRunningSyncState = next;
|
|
11206
11309
|
return next;
|
|
@@ -11211,14 +11314,15 @@ var plugin = definePlugin({
|
|
|
11211
11314
|
const trigger = job.trigger === "retry" ? "retry" : "schedule";
|
|
11212
11315
|
const scheduledTargets = listScheduledSyncTargets(settings);
|
|
11213
11316
|
if (scheduledTargets.length === 0) {
|
|
11214
|
-
|
|
11317
|
+
const reconciledSettings = await reconcileOrphanedRunningSyncState(ctx);
|
|
11318
|
+
if (job.trigger === "schedule" && !shouldRunScheduledSync(reconciledSettings, job.scheduledAt)) {
|
|
11215
11319
|
return;
|
|
11216
11320
|
}
|
|
11217
11321
|
await startSync(ctx, trigger);
|
|
11218
11322
|
return;
|
|
11219
11323
|
}
|
|
11220
11324
|
for (const target of scheduledTargets) {
|
|
11221
|
-
const scopedSettings =
|
|
11325
|
+
const scopedSettings = await reconcileOrphanedRunningSyncState(ctx, target?.companyId);
|
|
11222
11326
|
if (job.trigger === "schedule" && !shouldRunScheduledSync(scopedSettings, job.scheduledAt)) {
|
|
11223
11327
|
continue;
|
|
11224
11328
|
}
|