@atolis-hq/wake 0.1.15 → 0.1.16

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.
@@ -62,8 +62,10 @@ export function createGitHubPullRequestActivitySource(deps) {
62
62
  return { owner, repo, repoRef: `${owner}/${repo}`, number: Number(numberStr) };
63
63
  }
64
64
  async function discoverPullRequests(ingestedAt) {
65
+ const seenPrData = new Map();
66
+ const confirmedOpenRepos = new Set();
65
67
  if (!deps.config.sources.github.pullRequests.enabled) {
66
- return [];
68
+ return { events: [], seenPrData, confirmedOpenRepos };
67
69
  }
68
70
  const events = [];
69
71
  for (const repoRef of deps.config.sources.github.repos) {
@@ -72,9 +74,22 @@ export function createGitHubPullRequestActivitySource(deps) {
72
74
  continue;
73
75
  }
74
76
  try {
75
- const prs = await deps.client.listPullRequests(owner, repo, deps.config.sources.github.pullRequests.maxPullRequestsPerRepo);
77
+ const maxResults = deps.config.sources.github.pullRequests.maxPullRequestsPerRepo;
78
+ const prs = await deps.client.listPullRequests(owner, repo, maxResults);
79
+ // listPullRequests only ever returns open PRs (state: 'open'), so an
80
+ // uncapped result set here is a complete picture of what's currently
81
+ // open — used below to confirm a watched PR has actually closed
82
+ // rather than merely being truncated by maxResults.
83
+ if (prs.length < maxResults) {
84
+ confirmedOpenRepos.add(repoRef);
85
+ }
76
86
  for (const pr of prs) {
77
87
  const resourceUri = prResourceUri(repoRef, pr.number);
88
+ seenPrData.set(resourceUri, {
89
+ headSha: pr.head.sha,
90
+ baseRef: pr.base?.ref,
91
+ htmlUrl: pr.html_url,
92
+ });
78
93
  const known = await deps.resourceIndex.resolve(resourceUri);
79
94
  if (known !== undefined) {
80
95
  continue;
@@ -110,7 +125,7 @@ export function createGitHubPullRequestActivitySource(deps) {
110
125
  console.error(`[github-pr-activity-source] discovery failed for ${repoRef}, skipping this tick: ${error instanceof Error ? error.message : String(error)}`);
111
126
  }
112
127
  }
113
- return events;
128
+ return { events, seenPrData, confirmedOpenRepos };
114
129
  }
115
130
  async function pollWatchedPr(resourceUri, ingestedAt) {
116
131
  if (!deps.config.sources.github.pullRequests.enabled) {
@@ -236,7 +251,7 @@ export function createGitHubPullRequestActivitySource(deps) {
236
251
  }
237
252
  return events;
238
253
  }
239
- async function pollRequiredCheckFailures(ref, resourceUri, ingestedAt) {
254
+ async function pollRequiredCheckFailures(ref, resourceUri, ingestedAt, cachedPr) {
240
255
  if (!deps.config.sources.github.pullRequests.enabled ||
241
256
  !deps.config.sources.github.pullRequests.checks.enabled ||
242
257
  deps.client.getRequiredStatusChecks === undefined ||
@@ -244,9 +259,25 @@ export function createGitHubPullRequestActivitySource(deps) {
244
259
  deps.client.getCombinedStatusForRef === undefined) {
245
260
  return [];
246
261
  }
247
- const pr = await deps.client.getPullRequest(ref.owner, ref.repo, ref.number);
248
- const headSha = pr.head.sha;
249
- const baseRef = pr.base?.ref;
262
+ // headSha/baseRef/htmlUrl are already returned by this tick's PR
263
+ // discovery pass (listPullRequests) — reuse that instead of spending a
264
+ // dedicated getPullRequest call per watched PR. Falls back only when the
265
+ // watched PR wasn't present in discovery (e.g. truncated by
266
+ // maxPullRequestsPerRepo, or pullRequests polling failed this tick).
267
+ let headSha;
268
+ let baseRef;
269
+ let htmlUrl;
270
+ if (cachedPr?.headSha !== undefined && cachedPr.baseRef !== undefined) {
271
+ headSha = cachedPr.headSha;
272
+ baseRef = cachedPr.baseRef;
273
+ htmlUrl = cachedPr.htmlUrl;
274
+ }
275
+ else {
276
+ const pr = await deps.client.getPullRequest(ref.owner, ref.repo, ref.number);
277
+ headSha = pr.head.sha;
278
+ baseRef = pr.base?.ref;
279
+ htmlUrl = pr.html_url;
280
+ }
250
281
  if (headSha === undefined || baseRef === undefined) {
251
282
  return [];
252
283
  }
@@ -265,7 +296,7 @@ export function createGitHubPullRequestActivitySource(deps) {
265
296
  continue;
266
297
  }
267
298
  const occurredAt = run.completed_at ?? run.started_at ?? ingestedAt;
268
- const sourceUrl = run.html_url ?? run.details_url ?? pr.html_url;
299
+ const sourceUrl = run.html_url ?? run.details_url ?? htmlUrl;
269
300
  events.push(createUnkeyedEventEnvelope({
270
301
  eventId: `pr-check-failed-${safeEventToken(ref.repoRef)}-${ref.number}-${safeEventToken(run.name)}-${headSha}-${safeEventToken(occurredAt)}-${run.conclusion}`,
271
302
  streamScope: 'work-item',
@@ -306,7 +337,7 @@ export function createGitHubPullRequestActivitySource(deps) {
306
337
  sourceEventType: 'pr.checks.failed',
307
338
  sourceRefs: {
308
339
  repo: ref.repoRef,
309
- sourceUrl: status.target_url ?? pr.html_url,
340
+ sourceUrl: status.target_url ?? htmlUrl,
310
341
  resourceUri,
311
342
  },
312
343
  occurredAt: status.updated_at,
@@ -336,15 +367,28 @@ export function createGitHubPullRequestActivitySource(deps) {
336
367
  async pollEvents(input) {
337
368
  const ingestedAt = deps.now().toISOString();
338
369
  const watched = (input?.watch ?? []).filter((ref) => ref.resourceUri.startsWith('github:pr:'));
339
- const discovered = await discoverPullRequests(ingestedAt);
340
- const activityBatches = await Promise.all(watched.map((ref) => pollWatchedPr(ref.resourceUri, ingestedAt)));
341
- const checkBatches = await Promise.all(watched.map(async (watchRef) => {
370
+ const { events: discovered, seenPrData, confirmedOpenRepos, } = await discoverPullRequests(ingestedAt);
371
+ // A watched PR absent from this tick's complete open-PR listing has
372
+ // closed or merged stop spending its 7 activity/checks calls every
373
+ // tick. `confirmedOpenRepos` only covers repos where discovery
374
+ // succeeded and wasn't truncated, so an untruncated miss or a failed
375
+ // repo poll leaves the PR in the active set rather than risking a
376
+ // false drop.
377
+ const activeWatched = watched.filter((ref) => {
378
+ const parsed = repoAndNumberFromPrUri(ref.resourceUri);
379
+ if (parsed === null) {
380
+ return true;
381
+ }
382
+ return !confirmedOpenRepos.has(parsed.repoRef) || seenPrData.has(ref.resourceUri);
383
+ });
384
+ const activityBatches = await Promise.all(activeWatched.map((ref) => pollWatchedPr(ref.resourceUri, ingestedAt)));
385
+ const checkBatches = await Promise.all(activeWatched.map(async (watchRef) => {
342
386
  const ref = repoAndNumberFromPrUri(watchRef.resourceUri);
343
387
  if (ref === null) {
344
388
  return [];
345
389
  }
346
390
  try {
347
- return await pollRequiredCheckFailures(ref, watchRef.resourceUri, ingestedAt);
391
+ return await pollRequiredCheckFailures(ref, watchRef.resourceUri, ingestedAt, seenPrData.get(watchRef.resourceUri));
348
392
  }
349
393
  catch (error) {
350
394
  console.error(`[github-pr-activity-source] check poll failed for ${watchRef.resourceUri}, skipping this tick: ${error instanceof Error ? error.message : String(error)}`);
@@ -1 +1 @@
1
- export const wakeVersion = "0.1.15+ge2584a1";
1
+ export const wakeVersion = "0.1.16+g97c5859";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atolis-hq/wake",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "Local autonomous agent control plane for software development",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {