@mastra/github-signals 0.1.0 → 0.1.1

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/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ export declare const GITHUB_SUBSCRIBE_PR_TAG = "github-subscribe-pr";
8
8
  export declare const GITHUB_UNSUBSCRIBE_PR_TAG = "github-unsubscribe-pr";
9
9
  export declare const GITHUB_SYNC_STATUS_TAG = "github-sync-status";
10
10
  export declare const GITHUB_SIGNALS_METADATA_KEY = "githubSignals";
11
+ export type GithubPermission = 'admin' | 'maintain' | 'write' | 'triage' | 'read' | 'none';
11
12
  export type GithubPRSubscription = {
12
13
  owner: string;
13
14
  repo: string;
@@ -64,6 +65,14 @@ export type GithubPullRequestCheckSnapshot = {
64
65
  detailsUrl?: string;
65
66
  updatedAt?: string;
66
67
  };
68
+ export type GithubPullRequestCommentSnapshot = {
69
+ author?: string;
70
+ authorType?: string;
71
+ isBot?: boolean;
72
+ body?: string;
73
+ url?: string;
74
+ updatedAt?: string;
75
+ };
67
76
  type GithubPullRequestCheckInput = GithubPullRequestCheckSnapshot & {
68
77
  source: 'check' | 'workflow';
69
78
  };
@@ -87,6 +96,11 @@ export type GithubPullRequestSnapshot = {
87
96
  latestCommentAuthor?: string;
88
97
  latestCommentAuthorType?: string;
89
98
  latestCommentIsBot?: boolean;
99
+ latestCommentBody?: string;
100
+ latestCommentUrl?: string;
101
+ latestCommentUpdatedAt?: string;
102
+ /** Recent comments newest-first, used to fall back when the latest comment is unauthorized noise. */
103
+ latestComments?: GithubPullRequestCommentSnapshot[];
90
104
  };
91
105
  export type GithubSignalsSyncClient = {
92
106
  syncPullRequest(input: GithubSignalsSyncInput): Promise<GithubSignalsSyncResult>;
@@ -111,6 +125,9 @@ export type GithubSignalsThreadStore = {
111
125
  thread: StorageThreadType;
112
126
  }): Promise<StorageThreadType>;
113
127
  };
128
+ export type GithubPermissionResolver = {
129
+ getPermission(owner: string, repo: string, user: string): Promise<GithubPermission | undefined>;
130
+ };
114
131
  export type GithubSignalsOptions = {
115
132
  owner?: string;
116
133
  repo?: string;
@@ -123,18 +140,32 @@ export type GithubSignalsOptions = {
123
140
  repositoryResolver?: GithubRepositoryResolver;
124
141
  threadStore?: GithubSignalsThreadStore;
125
142
  getNotificationStreamOptions?: GithubSignalAgentOptions['getNotificationStreamOptions'];
143
+ /** Permissions that authorize a human commenter to trigger notifications (default: admin, maintain, write). */
144
+ authorizedPermissions?: GithubPermission[];
145
+ /** Bot logins authorized to trigger notifications (default: coderabbitai[bot], devin-ai-integration[bot]). */
146
+ authorizedBots?: string[];
147
+ /** Bot logins whose comments should be ignored and NOT trigger notifications. */
148
+ ignoredBots?: string[];
149
+ /** Custom resolver for looking up collaborator permissions (default: gh api). */
150
+ permissionResolver?: GithubPermissionResolver;
126
151
  };
127
152
  export type GithubSubscriptionsChangedEvent = {
128
153
  threadId: string;
129
154
  resourceId: string;
130
155
  subscriptions: GithubPRSubscription[];
131
156
  };
157
+ export type GithubPollingChangedEvent = {
158
+ threadId: string;
159
+ resourceId: string;
160
+ running: boolean;
161
+ };
132
162
  type GithubSubscriptionsChangedHandler = (event: GithubSubscriptionsChangedEvent) => void;
163
+ type GithubPollingChangedHandler = (event: GithubPollingChangedEvent) => void;
133
164
  type GithubSignalAgent = {
134
165
  sendSignal(signal: AgentSignalInput, target: unknown): {
135
166
  accepted: unknown;
136
167
  };
137
- sendNotificationSignal?(notification: unknown, target: unknown): {
168
+ sendNotificationSignal?(notification: unknown | unknown[], target: unknown): {
138
169
  accepted?: unknown;
139
170
  } | Promise<unknown>;
140
171
  };
@@ -200,6 +231,7 @@ export declare class GithubSignals extends SignalProvider<'github-signals'> {
200
231
  getInputProcessors(): InputProcessorOrWorkflow[];
201
232
  getOutputProcessors(): OutputProcessorOrWorkflow[];
202
233
  onSubscriptionsChanged(handler: GithubSubscriptionsChangedHandler): void;
234
+ onPollingChanged(handler: GithubPollingChangedHandler): void;
203
235
  __registerMastra(mastra: Mastra<any, any, any, any, any, any, any, any, any, any>): void;
204
236
  syncThreadNow(input: GithubPollingThread): Promise<number>;
205
237
  subscribeThreadToPR(input: GithubPollingThread & {
@@ -213,6 +245,7 @@ export declare class GithubSignals extends SignalProvider<'github-signals'> {
213
245
  }): Promise<boolean>;
214
246
  stopPollingForThread(input: GithubPollingThread): void;
215
247
  isPollingThread(input: GithubPollingThread): boolean;
248
+ isPollingThreadRunning(input: GithubPollingThread): boolean;
216
249
  getPollIntervalMs(): number;
217
250
  stopAllPolling(): void;
218
251
  pollThreadNow(input: GithubPollingThread): Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -20,6 +20,10 @@ var GITHUB_SUBSCRIBE_PR_TAG = "github-subscribe-pr";
20
20
  var GITHUB_UNSUBSCRIBE_PR_TAG = "github-unsubscribe-pr";
21
21
  var GITHUB_SYNC_STATUS_TAG = "github-sync-status";
22
22
  var GITHUB_SIGNALS_METADATA_KEY = "githubSignals";
23
+ var DEFAULT_AUTHORIZED_PERMISSIONS = ["admin", "maintain", "write"];
24
+ var DEFAULT_AUTHORIZED_BOTS = ["coderabbitai[bot]", "devin-ai-integration[bot]"];
25
+ var PERMISSION_CACHE_TTL_MS = 5 * 60 * 1e3;
26
+ var AUTHOR_GATED_NOTIFICATION_KINDS = /* @__PURE__ */ new Set(["pull-request-activity", "pull-request-review-activity"]);
23
27
  var createGithubTool = createTool;
24
28
  function isPlainObject(value) {
25
29
  return typeof value === "object" && value !== null && !Array.isArray(value);
@@ -140,6 +144,36 @@ function getPrLabel(subscription, snapshot) {
140
144
  function getMergedNotificationSummary(label) {
141
145
  return `${label} was merged. This thread has been automatically unsubscribed from this PR. Resubscribe if you still need updates.`;
142
146
  }
147
+ function getCommentExcerpt(body) {
148
+ const excerpt = body.replace(/\s+/g, " ").trim();
149
+ return excerpt.length > 240 ? `${excerpt.slice(0, 237)}...` : excerpt;
150
+ }
151
+ function getCommentNotificationSummary(pr, snapshot) {
152
+ if (!snapshot.latestCommentAuthor || !snapshot.latestCommentBody) return void 0;
153
+ return `${snapshot.latestCommentAuthor} commented on ${pr}: ${getCommentExcerpt(snapshot.latestCommentBody)}`;
154
+ }
155
+ var githubActivityNotificationPriority = {
156
+ high: 0,
157
+ medium: 1
158
+ };
159
+ function getGithubActivityNotificationRank(notification) {
160
+ return notification.kind === "pull-request-activity" ? 0 : 1;
161
+ }
162
+ function compareGithubActivityNotifications(a, b) {
163
+ if (!a && !b) return 0;
164
+ if (!a) return 1;
165
+ if (!b) return -1;
166
+ const priorityComparison = githubActivityNotificationPriority[a.priority] - githubActivityNotificationPriority[b.priority];
167
+ if (priorityComparison !== 0) return priorityComparison;
168
+ return getGithubActivityNotificationRank(a) - getGithubActivityNotificationRank(b);
169
+ }
170
+ function classifyGithubCommentActivityNotification(input) {
171
+ if (isBotOnlyActivity(input.snapshot)) return void 0;
172
+ const pr = `${input.subscription.owner}/${input.subscription.repo}#${input.subscription.number}`;
173
+ const summary = getCommentNotificationSummary(pr, input.snapshot);
174
+ if (!summary) return void 0;
175
+ return { kind: "pull-request-activity", priority: "high", summary };
176
+ }
143
177
  function getCheckUpdatedTime(check) {
144
178
  const value = check.updatedAt ? Date.parse(check.updatedAt) : Number.NaN;
145
179
  return Number.isFinite(value) ? value : 0;
@@ -263,10 +297,11 @@ function classifyGithubActivityNotification(input) {
263
297
  }
264
298
  if (input.snapshot.ciState === "pending" && input.subscription.lastObservedCiState === "pending") return void 0;
265
299
  if (isBotOnlyActivity(input.snapshot)) return void 0;
300
+ const commentSummary = getCommentNotificationSummary(pr, input.snapshot);
266
301
  return {
267
302
  kind: "pull-request-activity",
268
- priority: "medium",
269
- summary: `${pr} has new activity${input.snapshot.title ? `: ${input.snapshot.title}` : ""}`
303
+ priority: commentSummary ? "high" : "medium",
304
+ summary: commentSummary ?? `${pr} has new activity${input.snapshot.title ? `: ${input.snapshot.title}` : ""}`
270
305
  };
271
306
  }
272
307
  function classifyGithubBaselineNotification(input) {
@@ -391,13 +426,15 @@ var GitcrawlSyncClient = class {
391
426
  join threads t on t.id=rt.thread_id
392
427
  join repositories r on r.id=t.repo_id
393
428
  where r.owner=${owner} and r.name=${repo} and t.number=${number} and rt.is_resolved=0`);
394
- const [latestComment] = await queryGitcrawlDb(`select c.author_login, c.author_type, c.is_bot
429
+ const latestComments = await queryGitcrawlDb(`select c.author_login, c.author_type, c.is_bot, c.body, json_extract(c.raw_json, '$.html_url') as html_url,
430
+ coalesce(c.updated_at_gh, c.created_at_gh) as updated_at
395
431
  from comments c
396
432
  join threads t on t.id=c.thread_id
397
433
  join repositories r on r.id=t.repo_id
398
434
  where r.owner=${owner} and r.name=${repo} and t.number=${number}
399
435
  order by coalesce(c.updated_at_gh, c.created_at_gh) desc
400
- limit 1`);
436
+ limit 20`);
437
+ const latestComment = latestComments[0];
401
438
  const checks = normalizeGithubChecksForSnapshot({
402
439
  checkRows: checkRows.map((row) => ({
403
440
  source: "check",
@@ -459,7 +496,18 @@ var GitcrawlSyncClient = class {
459
496
  latestReviewThreadAt: readString(reviewState?.latest_review_thread_at),
460
497
  latestCommentAuthor: readString(latestComment?.author_login),
461
498
  latestCommentAuthorType: readString(latestComment?.author_type),
462
- latestCommentIsBot: latestComment?.is_bot === 1
499
+ latestCommentIsBot: latestComment?.is_bot === 1,
500
+ latestCommentBody: readString(latestComment?.body),
501
+ latestCommentUrl: readString(latestComment?.html_url),
502
+ latestCommentUpdatedAt: readString(latestComment?.updated_at),
503
+ latestComments: latestComments.map((comment) => ({
504
+ author: readString(comment.author_login),
505
+ authorType: readString(comment.author_type),
506
+ isBot: comment.is_bot === 1,
507
+ body: readString(comment.body),
508
+ url: readString(comment.html_url),
509
+ updatedAt: readString(comment.updated_at)
510
+ }))
463
511
  };
464
512
  } catch {
465
513
  return void 0;
@@ -514,9 +562,11 @@ var GithubSignals = class extends SignalProvider {
514
562
  #syncClient;
515
563
  #repositoryResolver;
516
564
  #polling = /* @__PURE__ */ new Map();
565
+ #permissionCache = /* @__PURE__ */ new Map();
517
566
  #agent;
518
567
  #agentOptions = {};
519
568
  #subscriptionsChangedHandler;
569
+ #pollingChangedHandler;
520
570
  constructor(options = {}) {
521
571
  super();
522
572
  this.#options = options;
@@ -551,6 +601,9 @@ var GithubSignals = class extends SignalProvider {
551
601
  onSubscriptionsChanged(handler) {
552
602
  this.#subscriptionsChangedHandler = handler;
553
603
  }
604
+ onPollingChanged(handler) {
605
+ this.#pollingChangedHandler = handler;
606
+ }
554
607
  __registerMastra(mastra) {
555
608
  super.__registerMastra(mastra);
556
609
  this.#ghMastra = mastra;
@@ -589,15 +642,13 @@ var GithubSignals = class extends SignalProvider {
589
642
  this.#polling.delete(pollingKey);
590
643
  }
591
644
  if (this.#polling.has(key)) return true;
592
- let scheduledPollCount = options.pollImmediately ? 1 : 0;
593
645
  const runPoll = (pollOptions = {}) => {
594
646
  void this.#pollThread(input, pollOptions).catch((error) => {
595
647
  console.warn("GitHub PR polling failed:", error);
596
648
  });
597
649
  };
598
650
  const timer = setInterval(() => {
599
- scheduledPollCount += 1;
600
- runPoll({ includeComments: scheduledPollCount % 2 === 1 });
651
+ runPoll({ includeComments: true });
601
652
  }, this.#options.pollIntervalMs ?? 3e5);
602
653
  if (options.pollImmediately) runPoll({ includeComments: true });
603
654
  timer.unref?.();
@@ -614,6 +665,9 @@ var GithubSignals = class extends SignalProvider {
614
665
  isPollingThread(input) {
615
666
  return this.#polling.has(this.#pollingKey(input));
616
667
  }
668
+ isPollingThreadRunning(input) {
669
+ return this.#polling.get(this.#pollingKey(input))?.running ?? false;
670
+ }
617
671
  getPollIntervalMs() {
618
672
  return this.#options.pollIntervalMs ?? 3e5;
619
673
  }
@@ -705,6 +759,10 @@ var GithubSignals = class extends SignalProvider {
705
759
  }
706
760
  #createTools(args) {
707
761
  const threadContext = this.#getThreadContext(args);
762
+ const getExecutionThreadContext = (context) => ({
763
+ threadId: context?.agent?.threadId ?? threadContext.threadId,
764
+ resourceId: context?.agent?.resourceId ?? threadContext.resourceId
765
+ });
708
766
  return {
709
767
  ...args.tools,
710
768
  github_subscribe_pr: createGithubTool({
@@ -715,14 +773,15 @@ var GithubSignals = class extends SignalProvider {
715
773
  owner: z.string().optional(),
716
774
  repo: z.string().optional()
717
775
  }),
718
- execute: async (input) => {
776
+ execute: async (input, context) => {
777
+ const executionThreadContext = getExecutionThreadContext(context);
719
778
  const result = await this.#subscribe({
720
779
  id: `github-tool-subscribe-${randomUUID()}`,
721
780
  owner: input.owner,
722
781
  repo: input.repo,
723
782
  number: input.number,
724
- threadId: threadContext.threadId,
725
- resourceId: threadContext.resourceId
783
+ threadId: executionThreadContext.threadId,
784
+ resourceId: executionThreadContext.resourceId
726
785
  });
727
786
  return {
728
787
  subscribed: true,
@@ -742,14 +801,15 @@ var GithubSignals = class extends SignalProvider {
742
801
  owner: z.string().optional(),
743
802
  repo: z.string().optional()
744
803
  }),
745
- execute: async (input) => {
804
+ execute: async (input, context) => {
805
+ const executionThreadContext = getExecutionThreadContext(context);
746
806
  const result = await this.#unsubscribe({
747
807
  id: `github-tool-unsubscribe-${randomUUID()}`,
748
808
  owner: input.owner,
749
809
  repo: input.repo,
750
810
  number: input.number,
751
- threadId: threadContext.threadId,
752
- resourceId: threadContext.resourceId
811
+ threadId: executionThreadContext.threadId,
812
+ resourceId: executionThreadContext.resourceId
753
813
  });
754
814
  return {
755
815
  unsubscribed: result.removed ?? false,
@@ -799,6 +859,9 @@ var GithubSignals = class extends SignalProvider {
799
859
  #notifySubscriptionsChanged(input) {
800
860
  this.#subscriptionsChangedHandler?.(input);
801
861
  }
862
+ #notifyPollingChanged(input) {
863
+ this.#pollingChangedHandler?.(input);
864
+ }
802
865
  async #pollThread(input, options = {}) {
803
866
  const key = this.#pollingKey(input);
804
867
  const state = this.#polling.get(key);
@@ -806,6 +869,7 @@ var GithubSignals = class extends SignalProvider {
806
869
  return 0;
807
870
  }
808
871
  if (state) state.running = true;
872
+ this.#notifyPollingChanged({ threadId: input.threadId, resourceId: input.resourceId, running: true });
809
873
  try {
810
874
  const { threadStore, loadedThread } = await this.#loadThread(input);
811
875
  const githubMetadata = getGithubMetadata(loadedThread.metadata);
@@ -824,7 +888,9 @@ var GithubSignals = class extends SignalProvider {
824
888
  includeComments: options.includeComments
825
889
  };
826
890
  const syncResult = await this.#syncClient.syncPullRequest(syncInput);
827
- const snapshot = syncResult.ok ? await this.#syncClient.getPullRequestSnapshot?.(syncInput) : void 0;
891
+ let snapshot = syncResult.ok ? await this.#syncClient.getPullRequestSnapshot?.(syncInput) : void 0;
892
+ if (snapshot)
893
+ snapshot = await this.#filterUnauthorizedLatestComment(subscription.owner, subscription.repo, snapshot);
828
894
  const nextSubscription = {
829
895
  ...subscription,
830
896
  updatedAt: now,
@@ -837,25 +903,28 @@ var GithubSignals = class extends SignalProvider {
837
903
  const previousContentHash = subscription.lastObservedContentHash;
838
904
  const previousThreadContentHash = subscription.lastObservedThreadContentHash;
839
905
  const previousHeadSha = subscription.lastObservedHeadSha;
906
+ const latestCommentChanged = !!previousGithubUpdatedAt && !!snapshot?.latestCommentUpdatedAt && Date.parse(snapshot.latestCommentUpdatedAt) > Date.parse(previousGithubUpdatedAt);
840
907
  if (snapshot) applySnapshotCursor(nextSubscription, snapshot);
841
908
  const isFirstObservation = syncResult.ok && snapshot && !previousGithubUpdatedAt && !previousContentHash;
842
909
  const legacyAggregateChanged = previousContentHash && snapshot?.contentHash && previousContentHash !== snapshot.contentHash && !previousThreadContentHash && !previousHeadSha;
843
- const changed = isFirstObservation || syncResult.ok && snapshot && (legacyAggregateChanged || previousThreadContentHash && snapshot.threadContentHash && previousThreadContentHash !== snapshot.threadContentHash || previousHeadSha && snapshot.headSha && previousHeadSha !== snapshot.headSha || subscription.lastObservedState && snapshot.state && subscription.lastObservedState !== snapshot.state || subscription.lastObservedMergeableState && snapshot.mergeableState && subscription.lastObservedMergeableState !== snapshot.mergeableState || subscription.lastObservedCiState && snapshot.ciState && subscription.lastObservedCiState !== snapshot.ciState || subscription.lastObservedReviewStateHash && snapshot.reviewStateHash && subscription.lastObservedReviewStateHash !== snapshot.reviewStateHash);
910
+ const changed = isFirstObservation || syncResult.ok && snapshot && (legacyAggregateChanged || latestCommentChanged || previousThreadContentHash && snapshot.threadContentHash && previousThreadContentHash !== snapshot.threadContentHash || previousHeadSha && snapshot.headSha && previousHeadSha !== snapshot.headSha || subscription.lastObservedState && snapshot.state && subscription.lastObservedState !== snapshot.state || subscription.lastObservedMergeableState && snapshot.mergeableState && subscription.lastObservedMergeableState !== snapshot.mergeableState || subscription.lastObservedCiState && snapshot.ciState && subscription.lastObservedCiState !== snapshot.ciState || subscription.lastObservedReviewStateHash && snapshot.reviewStateHash && subscription.lastObservedReviewStateHash !== snapshot.reviewStateHash);
844
911
  let shouldKeepSubscription = true;
845
- if (changed) {
846
- const notification = await this.#sendActivityNotification({
912
+ if (changed && snapshot) {
913
+ const notifications = await this.#sendActivityNotifications({
847
914
  polling: input,
848
915
  subscription,
849
916
  snapshot,
850
917
  previousGithubUpdatedAt,
851
- previousContentHash
918
+ previousContentHash,
919
+ latestCommentChanged
852
920
  });
853
- if (notification) {
921
+ const primaryNotification = notifications[0];
922
+ if (primaryNotification) {
854
923
  nextSubscription.lastNotificationAt = now;
855
- nextSubscription.lastNotificationKind = notification.kind;
856
- nextSubscription.lastNotificationPriority = notification.priority;
857
- nextSubscription.lastNotificationSummary = notification.summary;
858
- shouldKeepSubscription = notification.kind !== "pull-request-merged";
924
+ nextSubscription.lastNotificationKind = primaryNotification.kind;
925
+ nextSubscription.lastNotificationPriority = primaryNotification.priority;
926
+ nextSubscription.lastNotificationSummary = primaryNotification.summary;
927
+ shouldKeepSubscription = notifications.every((notification) => notification.kind !== "pull-request-merged");
859
928
  }
860
929
  }
861
930
  if (shouldKeepSubscription) subscriptions.push(nextSubscription);
@@ -878,17 +947,20 @@ var GithubSignals = class extends SignalProvider {
878
947
  } finally {
879
948
  const latestState = this.#polling.get(key);
880
949
  if (latestState) latestState.running = false;
950
+ this.#notifyPollingChanged({ threadId: input.threadId, resourceId: input.resourceId, running: false });
881
951
  }
882
952
  }
883
- async #sendGithubNotification(input) {
953
+ #createGithubNotificationInput(input) {
884
954
  const failingChecks = getFailingChecks(input.snapshot);
885
955
  const pendingChecks = getPendingChecks(input.snapshot);
956
+ const latestCommentExcerpt = input.snapshot.latestCommentBody ? getCommentExcerpt(input.snapshot.latestCommentBody) : void 0;
957
+ const latestCommentDedupeSuffix = input.notification.kind === "pull-request-activity" && input.snapshot.latestCommentUrl ? `comment:${input.snapshot.latestCommentUrl}:${input.snapshot.latestCommentUpdatedAt ?? ""}` : input.dedupeSuffix;
886
958
  const notificationInput = {
887
959
  source: "github",
888
960
  kind: input.notification.kind,
889
961
  priority: input.notification.priority,
890
962
  summary: input.notification.summary,
891
- dedupeKey: `github:${input.subscription.owner}/${input.subscription.repo}#${input.subscription.number}:${input.dedupeSuffix}`,
963
+ dedupeKey: `github:${input.subscription.owner}/${input.subscription.repo}#${input.subscription.number}:${latestCommentDedupeSuffix}`,
892
964
  coalesceKey: `github:${input.subscription.owner}/${input.subscription.repo}#${input.subscription.number}:${input.notification.kind}`,
893
965
  attributes: {
894
966
  owner: input.subscription.owner,
@@ -902,6 +974,10 @@ var GithubSignals = class extends SignalProvider {
902
974
  ...input.snapshot.mergeableState ? { mergeableState: input.snapshot.mergeableState } : {},
903
975
  ...input.snapshot.ciState ? { ciState: input.snapshot.ciState } : {},
904
976
  ...input.snapshot.unresolvedReviewThreads !== void 0 ? { unresolvedReviewThreads: input.snapshot.unresolvedReviewThreads } : {},
977
+ ...input.snapshot.latestCommentAuthor ? { latestCommentAuthor: input.snapshot.latestCommentAuthor } : {},
978
+ ...latestCommentExcerpt ? { latestCommentExcerpt } : {},
979
+ ...input.snapshot.latestCommentUrl ? { latestCommentUrl: input.snapshot.latestCommentUrl } : {},
980
+ ...input.snapshot.latestCommentUpdatedAt ? { latestCommentUpdatedAt: input.snapshot.latestCommentUpdatedAt } : {},
905
981
  ...failingChecks.length > 0 ? { failingChecks: failingChecks.map((check) => check.name).join(", ") } : {},
906
982
  ...pendingChecks.length > 0 ? { pendingChecks: pendingChecks.map((check) => check.name).join(", ") } : {}
907
983
  },
@@ -930,11 +1006,19 @@ var GithubSignals = class extends SignalProvider {
930
1006
  latestCommentAuthor: input.snapshot.latestCommentAuthor,
931
1007
  latestCommentAuthorType: input.snapshot.latestCommentAuthorType,
932
1008
  latestCommentIsBot: input.snapshot.latestCommentIsBot,
1009
+ latestCommentBody: input.snapshot.latestCommentBody,
1010
+ latestCommentExcerpt,
1011
+ latestCommentUrl: input.snapshot.latestCommentUrl,
1012
+ latestCommentUpdatedAt: input.snapshot.latestCommentUpdatedAt,
933
1013
  failingChecks,
934
1014
  pendingChecks
935
1015
  }
936
1016
  }
937
1017
  };
1018
+ return notificationInput;
1019
+ }
1020
+ async #sendGithubNotification(input) {
1021
+ const notificationInput = this.#createGithubNotificationInput(input);
938
1022
  const streamOptions = await this.#agentOptions.getNotificationStreamOptions?.(input.target);
939
1023
  await input.agent?.sendNotificationSignal?.(
940
1024
  notificationInput,
@@ -953,25 +1037,144 @@ var GithubSignals = class extends SignalProvider {
953
1037
  dedupeSuffix: `baseline:${input.subscription.lastSubscribeSignalId}`
954
1038
  });
955
1039
  }
956
- async #sendActivityNotification(input) {
1040
+ async #isAuthorizedAuthor(owner, repo, user, metadata = {}) {
1041
+ if (!user) return false;
1042
+ const normalizedUser = user.toLowerCase();
1043
+ const isBot = metadata.isBot === true || metadata.authorType?.toLowerCase() === "bot" || normalizedUser.endsWith("[bot]");
1044
+ if (isBot) {
1045
+ const ignoredBots = this.#options.ignoredBots ?? [];
1046
+ if (ignoredBots.some((bot) => bot.toLowerCase() === normalizedUser)) return false;
1047
+ const authorizedBots = this.#options.authorizedBots ?? DEFAULT_AUTHORIZED_BOTS;
1048
+ return authorizedBots.some((bot) => bot.toLowerCase() === normalizedUser);
1049
+ }
1050
+ const permission = await this.#loadAuthorPermission(owner, repo, user);
1051
+ const authorizedPermissions = this.#options.authorizedPermissions ?? DEFAULT_AUTHORIZED_PERMISSIONS;
1052
+ return !!permission && authorizedPermissions.includes(permission);
1053
+ }
1054
+ async #filterUnauthorizedLatestComment(owner, repo, snapshot) {
1055
+ const comments = snapshot.latestComments?.length ? snapshot.latestComments : [
1056
+ {
1057
+ author: snapshot.latestCommentAuthor,
1058
+ authorType: snapshot.latestCommentAuthorType,
1059
+ isBot: snapshot.latestCommentIsBot,
1060
+ body: snapshot.latestCommentBody,
1061
+ url: snapshot.latestCommentUrl,
1062
+ updatedAt: snapshot.latestCommentUpdatedAt
1063
+ }
1064
+ ];
1065
+ if (!comments.some((comment) => comment.author)) return snapshot;
1066
+ if (!comments.some((comment) => comment.body || comment.url || comment.updatedAt)) return snapshot;
1067
+ for (const comment of comments) {
1068
+ if (!await this.#isAuthorizedAuthor(owner, repo, comment.author, {
1069
+ authorType: comment.authorType,
1070
+ isBot: comment.isBot
1071
+ })) {
1072
+ continue;
1073
+ }
1074
+ return {
1075
+ ...snapshot,
1076
+ latestCommentAuthor: comment.author,
1077
+ latestCommentAuthorType: comment.authorType,
1078
+ latestCommentIsBot: comment.isBot,
1079
+ latestCommentBody: comment.body,
1080
+ latestCommentUrl: comment.url,
1081
+ latestCommentUpdatedAt: comment.updatedAt
1082
+ };
1083
+ }
1084
+ return {
1085
+ ...snapshot,
1086
+ latestCommentAuthor: void 0,
1087
+ latestCommentAuthorType: void 0,
1088
+ latestCommentIsBot: void 0,
1089
+ latestCommentBody: void 0,
1090
+ latestCommentUrl: void 0,
1091
+ latestCommentUpdatedAt: void 0
1092
+ };
1093
+ }
1094
+ async #loadAuthorPermission(owner, repo, user) {
1095
+ const cacheKey = `${owner}/${repo}:${user.toLowerCase()}`;
1096
+ const cached = this.#permissionCache.get(cacheKey);
1097
+ if (cached && cached.expiresAt > Date.now()) return cached.permission;
1098
+ if (cached) this.#permissionCache.delete(cacheKey);
1099
+ try {
1100
+ let permission;
1101
+ if (this.#options.permissionResolver) {
1102
+ permission = await this.#options.permissionResolver.getPermission(owner, repo, user);
1103
+ } else {
1104
+ const { stdout } = await execFileAsync("gh", [
1105
+ "api",
1106
+ `repos/${owner}/${repo}/collaborators/${user}/permission`,
1107
+ "--jq",
1108
+ ".permission"
1109
+ ]);
1110
+ const raw = stdout.trim();
1111
+ permission = ["admin", "maintain", "write", "triage", "read", "none"].includes(
1112
+ raw
1113
+ ) ? raw : void 0;
1114
+ }
1115
+ if (permission) {
1116
+ this.#permissionCache.set(cacheKey, { permission, expiresAt: Date.now() + PERMISSION_CACHE_TTL_MS });
1117
+ }
1118
+ return permission;
1119
+ } catch {
1120
+ this.#permissionCache.delete(cacheKey);
1121
+ return void 0;
1122
+ }
1123
+ }
1124
+ async #sendActivityNotifications(input) {
957
1125
  const agent = this.#getNotificationAgent(input.polling);
958
- if (!agent?.sendNotificationSignal) return void 0;
959
- const notification = classifyGithubActivityNotification({
960
- subscription: input.subscription,
961
- snapshot: input.snapshot
962
- });
963
- if (!notification) return void 0;
964
- await this.#sendGithubNotification({
965
- agent,
966
- subscription: input.subscription,
967
- snapshot: input.snapshot,
968
- notification,
969
- target: { resourceId: input.polling.resourceId, threadId: input.polling.threadId },
970
- dedupeSuffix: input.snapshot.contentHash ?? input.snapshot.githubUpdatedAt ?? String(Date.now()),
971
- previousGithubUpdatedAt: input.previousGithubUpdatedAt,
972
- previousContentHash: input.previousContentHash
973
- });
974
- return notification;
1126
+ if (!agent?.sendNotificationSignal) return [];
1127
+ const notifications = [
1128
+ classifyGithubActivityNotification({
1129
+ subscription: input.subscription,
1130
+ snapshot: input.snapshot
1131
+ })
1132
+ ];
1133
+ if (input.latestCommentChanged && notifications[0]?.kind !== "pull-request-activity") {
1134
+ notifications.push(
1135
+ classifyGithubCommentActivityNotification({
1136
+ subscription: input.subscription,
1137
+ snapshot: input.snapshot
1138
+ })
1139
+ );
1140
+ }
1141
+ const sent = [];
1142
+ const notificationInputs = [];
1143
+ for (const notification of notifications.sort(compareGithubActivityNotifications)) {
1144
+ if (!notification) continue;
1145
+ if (AUTHOR_GATED_NOTIFICATION_KINDS.has(notification.kind)) {
1146
+ const authorized = await this.#isAuthorizedAuthor(
1147
+ input.subscription.owner,
1148
+ input.subscription.repo,
1149
+ input.snapshot.latestCommentAuthor,
1150
+ {
1151
+ authorType: input.snapshot.latestCommentAuthorType,
1152
+ isBot: input.snapshot.latestCommentIsBot
1153
+ }
1154
+ );
1155
+ if (!authorized) continue;
1156
+ }
1157
+ notificationInputs.push(
1158
+ this.#createGithubNotificationInput({
1159
+ subscription: input.subscription,
1160
+ snapshot: input.snapshot,
1161
+ notification,
1162
+ dedupeSuffix: input.snapshot.contentHash ?? input.snapshot.githubUpdatedAt ?? String(Date.now()),
1163
+ previousGithubUpdatedAt: input.previousGithubUpdatedAt,
1164
+ previousContentHash: input.previousContentHash
1165
+ })
1166
+ );
1167
+ sent.push(notification);
1168
+ }
1169
+ if (notificationInputs.length > 0) {
1170
+ const target = { resourceId: input.polling.resourceId, threadId: input.polling.threadId };
1171
+ const streamOptions = await this.#agentOptions.getNotificationStreamOptions?.(target);
1172
+ await agent.sendNotificationSignal(
1173
+ notificationInputs,
1174
+ streamOptions ? { ...target, ifIdle: { streamOptions } } : target
1175
+ );
1176
+ }
1177
+ return sent;
975
1178
  }
976
1179
  async #subscribe(input) {
977
1180
  const { owner, repo } = await this.#resolveRepository(input);