@straiffi/archon 1.0.11 → 1.0.12

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.
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Archon</title>
8
- <script type="module" crossorigin src="/assets/index-Dgewr5ST.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-vramqRal.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-BhQzJS4j.css">
10
10
  </head>
11
11
  <body>
@@ -866,13 +866,17 @@ const getBundleReviewState = (projectId, tickets) => {
866
866
  can_re_review: reviewState.can_re_review,
867
867
  };
868
868
  };
869
- const BUNDLE_PULL_REQUEST_SYNC_TTL_MS = 15 * 1000;
869
+ const BUNDLE_PULL_REQUEST_SYNC_TTL_MS = 60 * 1000;
870
870
  const BUNDLE_PULL_REQUEST_DISCOVERY_MISS_COOLDOWN_MS = 10 * 60 * 1000;
871
871
  const BUNDLE_PULL_REQUEST_DISCOVERY_ERROR_COOLDOWN_MS = 2 * 60 * 1000;
872
+ const BUNDLE_PULL_REQUEST_SYNC_ERROR_COOLDOWN_MS = 2 * 60 * 1000;
873
+ const MAX_BACKGROUND_PULL_REQUEST_SYNCS_PER_PROJECT_REFRESH = 2;
872
874
  // Avoid repeated open-triggered discovery hits when a bundle has no PR yet or GitHub is temporarily unavailable.
873
875
  const bundlePullRequestDiscoveryInFlight = new Map();
874
876
  const bundlePullRequestDiscoveryMissTimestamps = new Map();
875
877
  const bundlePullRequestDiscoveryErrorTimestamps = new Map();
878
+ const bundlePullRequestSyncInFlight = new Map();
879
+ const bundlePullRequestSyncErrorTimestamps = new Map();
876
880
  const getBundlePullRequestDiscoveryKey = (projectId, bundleId) => `${projectId}:${bundleId}`;
877
881
  const isBundlePullRequestDiscoveryCoolingDown = (timestamps, key, cooldownMs) => {
878
882
  const lastAttemptAt = timestamps.get(key);
@@ -985,6 +989,7 @@ const discoverOpenBundlePullRequest = async (project, bundle) => {
985
989
  };
986
990
  const syncTrackedBundlePullRequestIfNeeded = async (project, bundle, options = {}) => {
987
991
  const force = options.force ?? false;
992
+ const rethrow = options.rethrow ?? false;
988
993
  const githubConfig = getGitHubConnectionConfig(project.id);
989
994
  const existingRecord = getBundlePullRequestRecord(bundle.id, project.id);
990
995
  if (!githubConfig || !existingRecord) {
@@ -1000,9 +1005,49 @@ const syncTrackedBundlePullRequestIfNeeded = async (project, bundle, options = {
1000
1005
  }
1001
1006
  catch (error) {
1002
1007
  console.warn(`[integrations] github pr sync failed project=${project.id} bundle=${bundle.id} pr=${existingRecord.number}`, error);
1008
+ if (rethrow) {
1009
+ throw error;
1010
+ }
1003
1011
  return existingRecord;
1004
1012
  }
1005
1013
  };
1014
+ const shouldStartTrackedBundlePullRequestSync = (project, bundle, options = {}) => {
1015
+ const force = options.force ?? false;
1016
+ const existingRecord = getBundlePullRequestRecord(bundle.id, project.id);
1017
+ if (!getGitHubConnectionConfig(project.id) || !existingRecord) {
1018
+ return false;
1019
+ }
1020
+ if (!force && !shouldSyncBundlePullRequest(existingRecord, BUNDLE_PULL_REQUEST_SYNC_TTL_MS)) {
1021
+ return false;
1022
+ }
1023
+ const key = getBundlePullRequestDiscoveryKey(project.id, bundle.id);
1024
+ if (bundlePullRequestSyncInFlight.has(key)) {
1025
+ return false;
1026
+ }
1027
+ return force || !isBundlePullRequestDiscoveryCoolingDown(bundlePullRequestSyncErrorTimestamps, key, BUNDLE_PULL_REQUEST_SYNC_ERROR_COOLDOWN_MS);
1028
+ };
1029
+ const startTrackedBundlePullRequestSyncIfNeeded = (project, bundle, options = {}) => {
1030
+ if (!shouldStartTrackedBundlePullRequestSync(project, bundle, options)) {
1031
+ return false;
1032
+ }
1033
+ const key = getBundlePullRequestDiscoveryKey(project.id, bundle.id);
1034
+ const task = (async () => {
1035
+ try {
1036
+ await syncTrackedBundlePullRequestIfNeeded(project, bundle, { ...options, rethrow: true });
1037
+ bundlePullRequestSyncErrorTimestamps.delete(key);
1038
+ reconcileBundleTicketsAfterPullRequestSync(project.id, bundle.id);
1039
+ }
1040
+ catch (error) {
1041
+ bundlePullRequestSyncErrorTimestamps.set(key, Date.now());
1042
+ console.warn(`[integrations] github pr background sync failed project=${project.id} bundle=${bundle.id}`, error);
1043
+ }
1044
+ finally {
1045
+ bundlePullRequestSyncInFlight.delete(key);
1046
+ }
1047
+ })();
1048
+ bundlePullRequestSyncInFlight.set(key, task);
1049
+ return true;
1050
+ };
1006
1051
  const listBundleTicketIds = (projectId, bundleId) => {
1007
1052
  const rows = db.prepare('SELECT id FROM tickets WHERE project_id = ? AND worktree_bundle_id = ? ORDER BY updated_at DESC, id DESC').all(projectId, bundleId);
1008
1053
  return rows.map(row => row.id);
@@ -1060,11 +1105,15 @@ const reconcileBundleTicketsAfterPullRequestSync = (projectId, bundleId) => {
1060
1105
  }
1061
1106
  };
1062
1107
  const syncProjectBundlePullRequestsIfNeeded = async (project, bundles, options = {}) => {
1063
- const force = options.force ?? false;
1064
- await Promise.all(bundles.map(async (bundle) => {
1065
- await syncTrackedBundlePullRequestIfNeeded(project, bundle, { force });
1066
- reconcileBundleTicketsAfterPullRequestSync(project.id, bundle.id);
1067
- }));
1108
+ let startedCount = 0;
1109
+ for (const bundle of bundles) {
1110
+ if (startedCount >= MAX_BACKGROUND_PULL_REQUEST_SYNCS_PER_PROJECT_REFRESH) {
1111
+ return;
1112
+ }
1113
+ if (startTrackedBundlePullRequestSyncIfNeeded(project, bundle, options)) {
1114
+ startedCount += 1;
1115
+ }
1116
+ }
1068
1117
  };
1069
1118
  const startProjectBundlePullRequestSyncIfNeeded = (project, bundles, options = {}) => {
1070
1119
  void syncProjectBundlePullRequestsIfNeeded(project, bundles, options).catch(error => {
@@ -2057,10 +2106,8 @@ app.get('/tickets/:id', async (req, res) => {
2057
2106
  const project = getProjectById(ticket.project_id);
2058
2107
  const bundle = project ? getBundle(ticket.worktree_bundle_id, project.id) : null;
2059
2108
  if (project && bundle) {
2060
- await syncTrackedBundlePullRequestIfNeeded(project, bundle);
2061
- reconcileBundleTicketsAfterPullRequestSync(project.id, bundle.id);
2109
+ startTrackedBundlePullRequestSyncIfNeeded(project, bundle);
2062
2110
  startBundlePullRequestDiscoveryIfNeeded(project, bundle);
2063
- ticket = getTicket(req.params.id);
2064
2111
  }
2065
2112
  }
2066
2113
  return res.json(ticket);