@sentry/junior-github 0.126.1 → 0.128.0

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.js CHANGED
@@ -1,8 +1,16 @@
1
1
  import {
2
+ GITHUB_DEPLOYMENT_EVENTS,
3
+ GITHUB_DEPLOYMENT_SUGGESTED_EVENTS,
4
+ GITHUB_ISSUE_EVENTS,
5
+ GITHUB_ISSUE_SUGGESTED_EVENTS,
6
+ GITHUB_PULL_REQUEST_EVENTS,
7
+ GITHUB_PULL_REQUEST_SUGGESTED_EVENTS,
2
8
  gitHubDeploymentSourceSubscribable,
9
+ gitHubIssueSubscribable,
3
10
  gitHubPullRequestSubscribable,
11
+ gitHubRepositorySubscribable,
4
12
  normalizeGitHubResourceEvents
5
- } from "./chunk-NNSOXVGR.js";
13
+ } from "./chunk-25NTEYYB.js";
6
14
 
7
15
  // src/plugin.ts
8
16
  import {
@@ -71,7 +79,8 @@ import {
71
79
  definePluginTool,
72
80
  EgressAuthRequired,
73
81
  PluginToolInputError as PluginToolInputError2,
74
- pluginToolResultSchema
82
+ subscribableResourceSchema,
83
+ pluginToolOutputSchema
75
84
  } from "@sentry/junior-plugin-api";
76
85
  import { Type } from "@sinclair/typebox";
77
86
  import { Value } from "@sinclair/typebox/value";
@@ -120,7 +129,7 @@ function githubConversationFooter(conversationId, dashboardUrl) {
120
129
  const id = nonEmptyString(conversationId, "conversationId");
121
130
  const normalizedDashboardUrl = dashboardUrl?.trim();
122
131
  const sentryUrl = sentryConversationUrl(id);
123
- const sessionLinks = normalizedDashboardUrl ? `[View Junior Session](${normalizedDashboardUrl})${sentryUrl ? ` [Sentry](${sentryUrl})` : ""}` : sentryUrl ? `[View Junior Session in Sentry](${sentryUrl})` : void 0;
132
+ const sessionLinks = normalizedDashboardUrl ? `[View Junior Session](${normalizedDashboardUrl})${sentryUrl ? ` [[Sentry]](${sentryUrl})` : ""}` : sentryUrl ? `[View Junior Session in Sentry](${sentryUrl})` : void 0;
124
133
  if (!sessionLinks) {
125
134
  return void 0;
126
135
  }
@@ -293,23 +302,23 @@ var createIssueStateSchema = Type.Union([
293
302
  ]);
294
303
  var gitHubIssueDataSchema = z.object({
295
304
  number: z.number(),
305
+ subscribable: subscribableResourceSchema.optional(),
296
306
  url: z.string()
297
307
  });
298
- var gitHubIssueOutputSchema = pluginToolResultSchema.extend({
299
- ok: z.literal(true),
300
- status: z.literal("success"),
308
+ var gitHubIssueOutputSchema = pluginToolOutputSchema.extend({
301
309
  target: z.literal("createIssue"),
302
- data: gitHubIssueDataSchema,
303
- number: z.number(),
304
- url: z.string()
310
+ ...gitHubIssueDataSchema.shape
305
311
  });
306
- function gitHubIssueToolResult(result) {
312
+ function gitHubIssueToolResult(input, result, canSubscribe) {
313
+ const repo = parseRepo(input.repo);
314
+ const subscribable = canSubscribe ? gitHubIssueSubscribable({
315
+ number: result.number,
316
+ repo: `${repo.owner}/${repo.name}`
317
+ }) : void 0;
318
+ const data = { ...result, ...subscribable ? { subscribable } : {} };
307
319
  return {
308
- ok: true,
309
- status: "success",
310
320
  target: "createIssue",
311
- data: result,
312
- ...result
321
+ ...data
313
322
  };
314
323
  }
315
324
  function parseCreateIssueInput(input) {
@@ -479,7 +488,11 @@ function createGitHubIssueTool(ctx) {
479
488
  url: state.url
480
489
  };
481
490
  await annotateIssue(ctx, completedInput, completedResult);
482
- return gitHubIssueToolResult(completedResult);
491
+ return gitHubIssueToolResult(
492
+ completedInput,
493
+ completedResult,
494
+ ctx.resourceEvents.canSubscribe
495
+ );
483
496
  }
484
497
  if (state?.status === "pending") {
485
498
  throw new Error(
@@ -518,7 +531,11 @@ function createGitHubIssueTool(ctx) {
518
531
  );
519
532
  }
520
533
  await annotateIssue(ctx, parsedInput, result);
521
- return gitHubIssueToolResult(result);
534
+ return gitHubIssueToolResult(
535
+ parsedInput,
536
+ result,
537
+ ctx.resourceEvents.canSubscribe
538
+ );
522
539
  } catch (error) {
523
540
  if (isEgressAuthRequired(error) || isDefinitiveGitHubIssueCreateRejection(error)) {
524
541
  await ctx.state.delete(key);
@@ -535,8 +552,8 @@ function createGitHubIssueTool(ctx) {
535
552
  import {
536
553
  definePluginTool as definePluginTool2,
537
554
  PluginToolInputError as PluginToolInputError3,
538
- pluginToolResultSchema as pluginToolResultSchema2,
539
- subscribableResourceSchema
555
+ pluginToolOutputSchema as pluginToolOutputSchema2,
556
+ subscribableResourceSchema as subscribableResourceSchema2
540
557
  } from "@sentry/junior-plugin-api";
541
558
  import { z as z2 } from "zod";
542
559
  var commitShaSchema = z2.string().regex(/^[0-9a-f]{40}$/i);
@@ -575,12 +592,9 @@ var deploymentSourceSchema = z2.object({
575
592
  deployment: deploymentSchema.nullable(),
576
593
  environment: z2.string().nullable(),
577
594
  repo: z2.string(),
578
- subscribable: subscribableResourceSchema.optional()
595
+ subscribable: subscribableResourceSchema2.optional()
579
596
  }).strict();
580
- var outputSchema = pluginToolResultSchema2.extend({
581
- data: deploymentSourceSchema,
582
- ok: z2.literal(true),
583
- status: z2.literal("success"),
597
+ var outputSchema = pluginToolOutputSchema2.extend({
584
598
  target: z2.literal("getDeployment"),
585
599
  ...deploymentSourceSchema.shape
586
600
  }).strict();
@@ -715,11 +729,11 @@ function createGitHubGetDeploymentTool(ctx) {
715
729
  url: `https://github.com/${repo.ref}/deployments`
716
730
  };
717
731
  }
718
- const subscribable = gitHubDeploymentSourceSubscribable({
732
+ const subscribable = ctx.resourceEvents.canSubscribe ? gitHubDeploymentSourceSubscribable({
719
733
  commitSha,
720
734
  environment: input.environment,
721
735
  repo: repo.ref
722
- });
736
+ }) : void 0;
723
737
  const data = {
724
738
  commitSha,
725
739
  deployment,
@@ -728,9 +742,6 @@ function createGitHubGetDeploymentTool(ctx) {
728
742
  ...subscribable ? { subscribable } : {}
729
743
  };
730
744
  return {
731
- data,
732
- ok: true,
733
- status: "success",
734
745
  target: "getDeployment",
735
746
  ...data
736
747
  };
@@ -743,12 +754,12 @@ import {
743
754
  definePluginTool as definePluginTool3,
744
755
  EgressAuthRequired as EgressAuthRequired2,
745
756
  PluginToolInputError as PluginToolInputError4,
746
- pluginToolResultSchema as pluginToolResultSchema3
757
+ pluginToolOutputSchema as pluginToolOutputSchema3
747
758
  } from "@sentry/junior-plugin-api";
748
759
  import { Type as Type2 } from "@sinclair/typebox";
749
760
  import { Value as Value2 } from "@sinclair/typebox/value";
750
761
  import { z as z3 } from "zod";
751
- import { subscribableResourceSchema as subscribableResourceSchema2 } from "@sentry/junior-plugin-api";
762
+ import { subscribableResourceSchema as subscribableResourceSchema3 } from "@sentry/junior-plugin-api";
752
763
  var GITHUB_PULL_REQUEST_CREATE_IDEMPOTENCY_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
753
764
  var GITHUB_PULL_REQUEST_CREATE_LOCK_TTL_MS = 6e4;
754
765
  var GitHubPullRequestCreateRejectedError = class extends Error {
@@ -817,16 +828,11 @@ var createPullRequestStateSchema = Type2.Union([
817
828
  var gitHubPullRequestDataSchema = z3.object({
818
829
  number: z3.number(),
819
830
  url: z3.string(),
820
- subscribable: subscribableResourceSchema2.optional()
831
+ subscribable: subscribableResourceSchema3.optional()
821
832
  });
822
- var gitHubPullRequestOutputSchema = pluginToolResultSchema3.extend({
823
- ok: z3.literal(true),
824
- status: z3.literal("success"),
833
+ var gitHubPullRequestOutputSchema = pluginToolOutputSchema3.extend({
825
834
  target: z3.literal("createPullRequest"),
826
- data: gitHubPullRequestDataSchema,
827
- number: z3.number(),
828
- url: z3.string(),
829
- subscribable: subscribableResourceSchema2.optional()
835
+ ...gitHubPullRequestDataSchema.shape
830
836
  });
831
837
  function parseCreatePullRequestInput(input) {
832
838
  try {
@@ -975,12 +981,12 @@ async function createGitHubPullRequest(ctx, request) {
975
981
  url: pullRequest.html_url
976
982
  };
977
983
  }
978
- function gitHubPullRequestToolResult(input, result) {
984
+ function gitHubPullRequestToolResult(input, result, canSubscribe) {
979
985
  const repo = parseRepo3(input.repo);
980
- const subscribable = gitHubPullRequestSubscribable({
986
+ const subscribable = canSubscribe ? gitHubPullRequestSubscribable({
981
987
  number: result.number,
982
988
  repo: `${repo.owner}/${repo.name}`
983
- });
989
+ }) : void 0;
984
990
  return { ...result, ...subscribable ? { subscribable } : {} };
985
991
  }
986
992
  async function annotatePullRequest(ctx, input, result) {
@@ -993,13 +999,10 @@ async function annotatePullRequest(ctx, input, result) {
993
999
  status: input.draft ? "draft" : "open"
994
1000
  });
995
1001
  }
996
- function gitHubPullRequestStructuredResult(input, result) {
997
- const data = gitHubPullRequestToolResult(input, result);
1002
+ function gitHubPullRequestStructuredResult(input, result, canSubscribe) {
1003
+ const data = gitHubPullRequestToolResult(input, result, canSubscribe);
998
1004
  return {
999
- ok: true,
1000
- status: "success",
1001
1005
  target: "createPullRequest",
1002
- data,
1003
1006
  ...data
1004
1007
  };
1005
1008
  }
@@ -1036,7 +1039,8 @@ function createGitHubPullRequestTool(ctx) {
1036
1039
  await annotatePullRequest(ctx, completedInput, completedResult);
1037
1040
  return gitHubPullRequestStructuredResult(
1038
1041
  completedInput,
1039
- completedResult
1042
+ completedResult,
1043
+ ctx.resourceEvents.canSubscribe
1040
1044
  );
1041
1045
  }
1042
1046
  if (state?.status === "pending") {
@@ -1076,7 +1080,11 @@ function createGitHubPullRequestTool(ctx) {
1076
1080
  );
1077
1081
  }
1078
1082
  await annotatePullRequest(ctx, parsedInput, result);
1079
- return gitHubPullRequestStructuredResult(parsedInput, result);
1083
+ return gitHubPullRequestStructuredResult(
1084
+ parsedInput,
1085
+ result,
1086
+ ctx.resourceEvents.canSubscribe
1087
+ );
1080
1088
  } catch (error) {
1081
1089
  if (isEgressAuthRequired2(error) || isDefinitiveGitHubPullRequestCreateRejection(error)) {
1082
1090
  await ctx.state.delete(key);
@@ -1093,10 +1101,10 @@ function createGitHubPullRequestTool(ctx) {
1093
1101
  import {
1094
1102
  definePluginTool as definePluginTool4,
1095
1103
  PluginToolInputError as PluginToolInputError5,
1096
- pluginToolResultSchema as pluginToolResultSchema4
1104
+ pluginToolOutputSchema as pluginToolOutputSchema4
1097
1105
  } from "@sentry/junior-plugin-api";
1098
1106
  import { z as z4 } from "zod";
1099
- import { subscribableResourceSchema as subscribableResourceSchema3 } from "@sentry/junior-plugin-api";
1107
+ import { subscribableResourceSchema as subscribableResourceSchema4 } from "@sentry/junior-plugin-api";
1100
1108
  var commitShaSchema2 = z4.string().regex(/^[0-9a-f]{40}$/i);
1101
1109
  var inputSchema2 = z4.object({
1102
1110
  repo: z4.string().describe('Repository in "owner/name" format.'),
@@ -1110,15 +1118,12 @@ var pullRequestSchema = z4.object({
1110
1118
  merged: z4.boolean(),
1111
1119
  number: z4.number(),
1112
1120
  state: z4.string(),
1113
- subscribable: subscribableResourceSchema3.optional(),
1121
+ subscribable: subscribableResourceSchema4.optional(),
1114
1122
  title: z4.string(),
1115
1123
  url: z4.string()
1116
1124
  });
1117
- var outputSchema2 = pluginToolResultSchema4.extend({
1118
- ok: z4.literal(true),
1119
- status: z4.literal("success"),
1125
+ var outputSchema2 = pluginToolOutputSchema4.extend({
1120
1126
  target: z4.literal("getPullRequest"),
1121
- data: pullRequestSchema,
1122
1127
  ...pullRequestSchema.shape
1123
1128
  });
1124
1129
  function parseRepo4(value) {
@@ -1178,10 +1183,10 @@ function createGitHubGetPullRequestTool(ctx) {
1178
1183
  state: z4.string(),
1179
1184
  title: z4.string()
1180
1185
  }).parse(parsed);
1181
- const subscribable = gitHubPullRequestSubscribable({
1186
+ const subscribable = ctx.resourceEvents.canSubscribe ? gitHubPullRequestSubscribable({
1182
1187
  number: providerResult.number,
1183
1188
  repo: repo.ref
1184
- });
1189
+ }) : void 0;
1185
1190
  const data = {
1186
1191
  base: providerResult.base.ref,
1187
1192
  draft: providerResult.draft,
@@ -1195,68 +1200,159 @@ function createGitHubGetPullRequestTool(ctx) {
1195
1200
  url: providerResult.html_url
1196
1201
  };
1197
1202
  return {
1198
- ok: true,
1199
- status: "success",
1200
1203
  target: "getPullRequest",
1201
- data,
1202
1204
  ...data
1203
1205
  };
1204
1206
  }
1205
1207
  });
1206
1208
  }
1207
1209
 
1208
- // src/tools/update-pull-request.ts
1210
+ // src/tools/get-repository.ts
1209
1211
  import {
1210
1212
  definePluginTool as definePluginTool5,
1211
1213
  PluginToolInputError as PluginToolInputError6,
1212
- pluginToolResultSchema as pluginToolResultSchema5
1214
+ pluginToolOutputSchema as pluginToolOutputSchema5,
1215
+ subscribableResourceSchema as subscribableResourceSchema5
1213
1216
  } from "@sentry/junior-plugin-api";
1214
1217
  import { z as z5 } from "zod";
1215
- import { subscribableResourceSchema as subscribableResourceSchema4 } from "@sentry/junior-plugin-api";
1216
1218
  var inputSchema3 = z5.object({
1217
- repo: z5.string().describe('Repository in "owner/name" format.'),
1218
- number: z5.number().int().positive().describe("Pull request number."),
1219
- title: z5.string().trim().min(1).optional().describe("Replacement pull request title."),
1220
- body: z5.string().optional().describe(
1219
+ repo: z5.string().describe('Repository in "owner/name" format.')
1220
+ }).strict();
1221
+ var repositorySchema = z5.object({
1222
+ defaultBranch: z5.string(),
1223
+ description: z5.string().nullable(),
1224
+ fullName: z5.string(),
1225
+ private: z5.boolean(),
1226
+ subscribable: subscribableResourceSchema5.optional(),
1227
+ url: z5.string()
1228
+ });
1229
+ var outputSchema3 = pluginToolOutputSchema5.extend({
1230
+ target: z5.literal("getRepository"),
1231
+ ...repositorySchema.shape
1232
+ });
1233
+ function parseRepo5(value) {
1234
+ const parts = value.split("/").map((part) => part.trim());
1235
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
1236
+ throw new PluginToolInputError6('repo must use "owner/name" format');
1237
+ }
1238
+ return { owner: parts[0], name: parts[1] };
1239
+ }
1240
+ async function readJson3(response) {
1241
+ const text2 = await response.text();
1242
+ if (!text2) return void 0;
1243
+ try {
1244
+ return JSON.parse(text2);
1245
+ } catch {
1246
+ return text2;
1247
+ }
1248
+ }
1249
+ function createGitHubGetRepositoryTool(ctx) {
1250
+ return definePluginTool5({
1251
+ annotations: {
1252
+ destructiveHint: false,
1253
+ idempotentHint: true,
1254
+ openWorldHint: true,
1255
+ readOnlyHint: true
1256
+ },
1257
+ description: "Get a GitHub repository. Use this when repository-wide issue activity may need resource-event monitoring; the result includes a subscribable hint when GitHub webhooks are configured.",
1258
+ inputSchema: inputSchema3,
1259
+ outputSchema: outputSchema3,
1260
+ async execute(input) {
1261
+ const repo = parseRepo5(input.repo);
1262
+ const response = await ctx.egress.fetch({
1263
+ provider: "github",
1264
+ operation: "github.repository.get",
1265
+ request: new Request(
1266
+ `https://api.github.com/repos/${encodeURIComponent(repo.owner)}/${encodeURIComponent(repo.name)}`,
1267
+ {
1268
+ headers: {
1269
+ Accept: "application/vnd.github+json",
1270
+ "X-GitHub-Api-Version": "2022-11-28"
1271
+ }
1272
+ }
1273
+ )
1274
+ });
1275
+ const parsed = await readJson3(response);
1276
+ if (!response.ok) {
1277
+ throw new PluginToolInputError6(
1278
+ `GitHub repository lookup failed with HTTP ${response.status}`
1279
+ );
1280
+ }
1281
+ const providerResult = z5.object({
1282
+ default_branch: z5.string(),
1283
+ description: z5.string().nullable(),
1284
+ full_name: z5.string(),
1285
+ html_url: z5.string(),
1286
+ private: z5.boolean()
1287
+ }).parse(parsed);
1288
+ const subscribable = ctx.resourceEvents.canSubscribe ? gitHubRepositorySubscribable({
1289
+ repo: providerResult.full_name
1290
+ }) : void 0;
1291
+ const data = {
1292
+ defaultBranch: providerResult.default_branch,
1293
+ description: providerResult.description,
1294
+ fullName: providerResult.full_name,
1295
+ private: providerResult.private,
1296
+ ...subscribable ? { subscribable } : {},
1297
+ url: providerResult.html_url
1298
+ };
1299
+ return {
1300
+ target: "getRepository",
1301
+ ...data
1302
+ };
1303
+ }
1304
+ });
1305
+ }
1306
+
1307
+ // src/tools/update-pull-request.ts
1308
+ import {
1309
+ definePluginTool as definePluginTool6,
1310
+ PluginToolInputError as PluginToolInputError7,
1311
+ pluginToolOutputSchema as pluginToolOutputSchema6
1312
+ } from "@sentry/junior-plugin-api";
1313
+ import { z as z6 } from "zod";
1314
+ import { subscribableResourceSchema as subscribableResourceSchema6 } from "@sentry/junior-plugin-api";
1315
+ var inputSchema4 = z6.object({
1316
+ repo: z6.string().describe('Repository in "owner/name" format.'),
1317
+ number: z6.number().int().positive().describe("Pull request number."),
1318
+ title: z6.string().trim().min(1).optional().describe("Replacement pull request title."),
1319
+ body: z6.string().optional().describe(
1221
1320
  "Replacement pull request body. Junior appends requester attribution and the conversation footer."
1222
1321
  ),
1223
- base: z5.string().trim().min(1).optional().describe("Replacement base branch."),
1224
- state: z5.enum(["open", "closed"]).optional().describe("Replacement pull request state.")
1322
+ base: z6.string().trim().min(1).optional().describe("Replacement base branch."),
1323
+ state: z6.enum(["open", "closed"]).optional().describe("Replacement pull request state.")
1225
1324
  }).strict().refine(
1226
1325
  ({ title, body, base, state }) => title !== void 0 || body !== void 0 || base !== void 0 || state !== void 0,
1227
1326
  { message: "At least one pull request field must be provided." }
1228
1327
  );
1229
- var pullRequestSchema2 = z5.object({
1230
- base: z5.string(),
1231
- body: z5.string().nullable(),
1232
- draft: z5.boolean(),
1233
- number: z5.number(),
1234
- state: z5.string(),
1235
- subscribable: subscribableResourceSchema4.optional(),
1236
- title: z5.string(),
1237
- url: z5.string()
1328
+ var pullRequestSchema2 = z6.object({
1329
+ base: z6.string(),
1330
+ body: z6.string().nullable(),
1331
+ draft: z6.boolean(),
1332
+ number: z6.number(),
1333
+ state: z6.string(),
1334
+ subscribable: subscribableResourceSchema6.optional(),
1335
+ title: z6.string(),
1336
+ url: z6.string()
1238
1337
  });
1239
- var outputSchema3 = pluginToolResultSchema5.extend({
1240
- ok: z5.literal(true),
1241
- status: z5.literal("success"),
1242
- target: z5.literal("updatePullRequest"),
1243
- data: pullRequestSchema2,
1338
+ var outputSchema4 = pluginToolOutputSchema6.extend({
1339
+ target: z6.literal("updatePullRequest"),
1244
1340
  ...pullRequestSchema2.shape
1245
1341
  });
1246
1342
  function nonEmptyString4(value, name) {
1247
1343
  if (!value?.trim()) {
1248
- throw new PluginToolInputError6(`${name} is required`);
1344
+ throw new PluginToolInputError7(`${name} is required`);
1249
1345
  }
1250
1346
  return value.trim();
1251
1347
  }
1252
- function parseRepo5(value) {
1348
+ function parseRepo6(value) {
1253
1349
  const parts = value.split("/").map((part) => part.trim());
1254
1350
  if (parts.length !== 2 || !parts[0] || !parts[1]) {
1255
- throw new PluginToolInputError6('repo must use "owner/name" format');
1351
+ throw new PluginToolInputError7('repo must use "owner/name" format');
1256
1352
  }
1257
1353
  return { owner: parts[0], name: parts[1], ref: `${parts[0]}/${parts[1]}` };
1258
1354
  }
1259
- async function readJson3(response) {
1355
+ async function readJson4(response) {
1260
1356
  const text2 = await response.text();
1261
1357
  if (!text2) return void 0;
1262
1358
  try {
@@ -1274,7 +1370,7 @@ function githubApiErrorMessage3(payload) {
1274
1370
  return "GitHub request failed";
1275
1371
  }
1276
1372
  function createGitHubUpdatePullRequestTool(ctx) {
1277
- return definePluginTool5({
1373
+ return definePluginTool6({
1278
1374
  annotations: {
1279
1375
  destructiveHint: true,
1280
1376
  idempotentHint: true,
@@ -1282,18 +1378,18 @@ function createGitHubUpdatePullRequestTool(ctx) {
1282
1378
  readOnlyHint: false
1283
1379
  },
1284
1380
  description: "Update an existing GitHub pull request's title, body, base branch, or open/closed state. Use this instead of raw GitHub API calls when changing PR metadata.",
1285
- inputSchema: inputSchema3,
1286
- outputSchema: outputSchema3,
1381
+ inputSchema: inputSchema4,
1382
+ outputSchema: outputSchema4,
1287
1383
  async execute(input) {
1288
- const parsedInput = inputSchema3.safeParse(input);
1384
+ const parsedInput = inputSchema4.safeParse(input);
1289
1385
  if (!parsedInput.success) {
1290
- throw new PluginToolInputError6(
1386
+ throw new PluginToolInputError7(
1291
1387
  "Invalid GitHub updatePullRequest input.",
1292
1388
  { cause: parsedInput.error }
1293
1389
  );
1294
1390
  }
1295
1391
  const update = parsedInput.data;
1296
- const repo = parseRepo5(update.repo);
1392
+ const repo = parseRepo6(update.repo);
1297
1393
  const payload = {
1298
1394
  ...update.title !== void 0 ? { title: update.title } : {},
1299
1395
  ...update.body !== void 0 ? {
@@ -1322,25 +1418,25 @@ function createGitHubUpdatePullRequestTool(ctx) {
1322
1418
  }
1323
1419
  )
1324
1420
  });
1325
- const parsed = await readJson3(response);
1421
+ const parsed = await readJson4(response);
1326
1422
  if (!response.ok) {
1327
1423
  throw new Error(
1328
1424
  `GitHub pull request update failed with HTTP ${response.status}: ${githubApiErrorMessage3(parsed)}`
1329
1425
  );
1330
1426
  }
1331
- const providerResult = z5.object({
1332
- base: z5.object({ ref: z5.string() }),
1333
- body: z5.string().nullable().optional().default(null),
1334
- draft: z5.boolean(),
1335
- html_url: z5.string(),
1336
- number: z5.number(),
1337
- state: z5.string(),
1338
- title: z5.string()
1427
+ const providerResult = z6.object({
1428
+ base: z6.object({ ref: z6.string() }),
1429
+ body: z6.string().nullable().optional().default(null),
1430
+ draft: z6.boolean(),
1431
+ html_url: z6.string(),
1432
+ number: z6.number(),
1433
+ state: z6.string(),
1434
+ title: z6.string()
1339
1435
  }).parse(parsed);
1340
- const subscribable = gitHubPullRequestSubscribable({
1436
+ const subscribable = ctx.resourceEvents.canSubscribe ? gitHubPullRequestSubscribable({
1341
1437
  number: providerResult.number,
1342
1438
  repo: repo.ref
1343
- });
1439
+ }) : void 0;
1344
1440
  const data = {
1345
1441
  base: providerResult.base.ref,
1346
1442
  body: providerResult.body,
@@ -1352,10 +1448,7 @@ function createGitHubUpdatePullRequestTool(ctx) {
1352
1448
  url: providerResult.html_url
1353
1449
  };
1354
1450
  return {
1355
- ok: true,
1356
- status: "success",
1357
1451
  target: "updatePullRequest",
1358
- data,
1359
1452
  ...data
1360
1453
  };
1361
1454
  }
@@ -1369,6 +1462,7 @@ function createGitHubTools(ctx) {
1369
1462
  createPullRequest: createGitHubPullRequestTool(ctx),
1370
1463
  getDeployment: createGitHubGetDeploymentTool(ctx),
1371
1464
  getPullRequest: createGitHubGetPullRequestTool(ctx),
1465
+ getRepository: createGitHubGetRepositoryTool(ctx),
1372
1466
  updatePullRequest: createGitHubUpdatePullRequestTool(ctx)
1373
1467
  };
1374
1468
  }
@@ -1378,7 +1472,7 @@ import { createHmac, timingSafeEqual } from "crypto";
1378
1472
 
1379
1473
  // src/issue-outcomes/store.ts
1380
1474
  import { and, eq, lte, sql as sql2 } from "drizzle-orm";
1381
- import { z as z7 } from "zod";
1475
+ import { z as z8 } from "zod";
1382
1476
 
1383
1477
  // src/db/schema.ts
1384
1478
  import { sql } from "drizzle-orm";
@@ -1390,18 +1484,18 @@ import {
1390
1484
  text,
1391
1485
  timestamp
1392
1486
  } from "drizzle-orm/pg-core";
1393
- import { z as z6 } from "zod";
1394
- var githubPullRequestStateSchema = z6.enum([
1487
+ import { z as z7 } from "zod";
1488
+ var githubPullRequestStateSchema = z7.enum([
1395
1489
  "closed_unmerged",
1396
1490
  "merged",
1397
1491
  "open"
1398
1492
  ]);
1399
- var githubPullRequestCommitCompositionSchema = z6.enum([
1493
+ var githubPullRequestCommitCompositionSchema = z7.enum([
1400
1494
  "junior_only",
1401
1495
  "mixed"
1402
1496
  ]);
1403
- var githubIssueStateSchema = z6.enum(["closed", "open"]);
1404
- var githubIssueStateReasonSchema = z6.enum([
1497
+ var githubIssueStateSchema = z7.enum(["closed", "open"]);
1498
+ var githubIssueStateReasonSchema = z7.enum([
1405
1499
  "completed",
1406
1500
  "duplicate",
1407
1501
  "not_planned",
@@ -1470,21 +1564,21 @@ var juniorGitHubPullRequestIssues = pgTable(
1470
1564
  );
1471
1565
 
1472
1566
  // src/issue-outcomes/store.ts
1473
- var githubIssueOutcomeInputSchema = z7.object({
1474
- candidateOwned: z7.boolean(),
1475
- closedAt: z7.date().optional(),
1476
- issueId: z7.string().min(1),
1477
- number: z7.number().int().positive(),
1478
- openedAt: z7.date(),
1479
- repositoryFullName: z7.string().min(1),
1480
- repositoryId: z7.string().min(1),
1567
+ var githubIssueOutcomeInputSchema = z8.object({
1568
+ candidateOwned: z8.boolean(),
1569
+ closedAt: z8.date().optional(),
1570
+ issueId: z8.string().min(1),
1571
+ number: z8.number().int().positive(),
1572
+ openedAt: z8.date(),
1573
+ repositoryFullName: z8.string().min(1),
1574
+ repositoryId: z8.string().min(1),
1481
1575
  state: githubIssueStateSchema,
1482
1576
  stateReason: githubIssueStateReasonSchema.optional(),
1483
- updatedAt: z7.date()
1577
+ updatedAt: z8.date()
1484
1578
  }).strict();
1485
- var githubIssueConversationsInputSchema = z7.object({
1486
- conversationIds: z7.array(z7.string().min(1)).min(1),
1487
- issueId: z7.string().min(1)
1579
+ var githubIssueConversationsInputSchema = z8.object({
1580
+ conversationIds: z8.array(z8.string().min(1)).min(1),
1581
+ issueId: z8.string().min(1)
1488
1582
  }).strict();
1489
1583
  function projectionValues(input) {
1490
1584
  return {
@@ -1537,32 +1631,32 @@ async function recordGitHubIssueConversations(db, input) {
1537
1631
 
1538
1632
  // src/pull-request-outcomes/store.ts
1539
1633
  import { and as and2, eq as eq2, lte as lte2, sql as sql3 } from "drizzle-orm";
1540
- import { z as z8 } from "zod";
1541
- var githubPullRequestOutcomeInputSchema = z8.object({
1542
- candidateOwned: z8.boolean(),
1543
- closedAt: z8.date().optional(),
1634
+ import { z as z9 } from "zod";
1635
+ var githubPullRequestOutcomeInputSchema = z9.object({
1636
+ candidateOwned: z9.boolean(),
1637
+ closedAt: z9.date().optional(),
1544
1638
  commitComposition: githubPullRequestCommitCompositionSchema.optional(),
1545
- mergedAt: z8.date().optional(),
1546
- number: z8.number().int().positive(),
1547
- openedAt: z8.date(),
1548
- pullRequestId: z8.string().min(1),
1549
- repositoryFullName: z8.string().min(1),
1550
- repositoryId: z8.string().min(1),
1639
+ mergedAt: z9.date().optional(),
1640
+ number: z9.number().int().positive(),
1641
+ openedAt: z9.date(),
1642
+ pullRequestId: z9.string().min(1),
1643
+ repositoryFullName: z9.string().min(1),
1644
+ repositoryId: z9.string().min(1),
1551
1645
  state: githubPullRequestStateSchema,
1552
- updatedAt: z8.date()
1646
+ updatedAt: z9.date()
1553
1647
  }).strict();
1554
- var githubPullRequestConversationsInputSchema = z8.object({
1555
- conversationIds: z8.array(z8.string().min(1)).min(1),
1556
- pullRequestId: z8.string().min(1)
1648
+ var githubPullRequestConversationsInputSchema = z9.object({
1649
+ conversationIds: z9.array(z9.string().min(1)).min(1),
1650
+ pullRequestId: z9.string().min(1)
1557
1651
  }).strict();
1558
- var githubPullRequestLinkedIssuesInputSchema = z8.object({
1559
- linkedIssues: z8.array(
1560
- z8.object({
1561
- number: z8.number().int().positive(),
1562
- repositoryFullName: z8.string().min(1)
1652
+ var githubPullRequestLinkedIssuesInputSchema = z9.object({
1653
+ linkedIssues: z9.array(
1654
+ z9.object({
1655
+ number: z9.number().int().positive(),
1656
+ repositoryFullName: z9.string().min(1)
1563
1657
  }).strict()
1564
1658
  ).min(1),
1565
- pullRequestId: z8.string().min(1)
1659
+ pullRequestId: z9.string().min(1)
1566
1660
  }).strict();
1567
1661
  function projectionValues2(input) {
1568
1662
  return {
@@ -1652,7 +1746,7 @@ async function recordGitHubPullRequestLinkedIssues(db, input) {
1652
1746
  }
1653
1747
 
1654
1748
  // src/webhooks/issue-outcome.ts
1655
- import { z as z9 } from "zod";
1749
+ import { z as z10 } from "zod";
1656
1750
 
1657
1751
  // src/webhooks/ownership.ts
1658
1752
  var GITHUB_NOREPLY_DOMAIN = "users.noreply.github.com";
@@ -1669,38 +1763,38 @@ function botLoginFromEmail(value) {
1669
1763
  }
1670
1764
 
1671
1765
  // src/webhooks/issue-outcome.ts
1672
- var canonicalIssueOutcomeSchema = z9.object({
1673
- action: z9.enum(["opened", "closed", "reopened"]),
1674
- issue: z9.object({
1675
- body: z9.string().nullable().optional(),
1676
- closed_at: z9.string().nullable().optional(),
1677
- created_at: z9.string(),
1678
- id: z9.number().int().positive(),
1679
- number: z9.number().int().positive(),
1766
+ var canonicalIssueOutcomeSchema = z10.object({
1767
+ action: z10.enum(["opened", "closed", "reopened"]),
1768
+ issue: z10.object({
1769
+ body: z10.string().nullable().optional(),
1770
+ closed_at: z10.string().nullable().optional(),
1771
+ created_at: z10.string(),
1772
+ id: z10.number().int().positive(),
1773
+ number: z10.number().int().positive(),
1680
1774
  state_reason: githubIssueStateReasonSchema.nullable().optional(),
1681
- updated_at: z9.string(),
1682
- user: z9.object({ login: z9.string().min(1) }).strict()
1775
+ updated_at: z10.string(),
1776
+ user: z10.object({ login: z10.string().min(1) }).strict()
1683
1777
  }).strict(),
1684
- repository: z9.object({
1685
- full_name: z9.string().min(1),
1686
- id: z9.number().int().positive()
1778
+ repository: z10.object({
1779
+ full_name: z10.string().min(1),
1780
+ id: z10.number().int().positive()
1687
1781
  }).strict()
1688
1782
  }).strict();
1689
- var issueOutcomeSchema = z9.object({
1690
- action: z9.enum(["opened", "closed", "reopened"]),
1691
- issue: z9.object({
1692
- body: z9.string().nullable().optional(),
1693
- closed_at: z9.string().nullable().optional(),
1694
- created_at: z9.string(),
1695
- id: z9.number().int().positive(),
1696
- number: z9.number().int().positive(),
1783
+ var issueOutcomeSchema = z10.object({
1784
+ action: z10.enum(["opened", "closed", "reopened"]),
1785
+ issue: z10.object({
1786
+ body: z10.string().nullable().optional(),
1787
+ closed_at: z10.string().nullable().optional(),
1788
+ created_at: z10.string(),
1789
+ id: z10.number().int().positive(),
1790
+ number: z10.number().int().positive(),
1697
1791
  state_reason: githubIssueStateReasonSchema.nullable().optional(),
1698
- updated_at: z9.string(),
1699
- user: z9.object({ login: z9.string().min(1) }).passthrough()
1792
+ updated_at: z10.string(),
1793
+ user: z10.object({ login: z10.string().min(1) }).passthrough()
1700
1794
  }).passthrough(),
1701
- repository: z9.object({
1702
- full_name: z9.string().min(1),
1703
- id: z9.number().int().positive()
1795
+ repository: z10.object({
1796
+ full_name: z10.string().min(1),
1797
+ id: z10.number().int().positive()
1704
1798
  }).passthrough()
1705
1799
  }).passthrough().transform(
1706
1800
  (provider) => canonicalIssueOutcomeSchema.parse({
@@ -1721,7 +1815,7 @@ var issueOutcomeSchema = z9.object({
1721
1815
  }
1722
1816
  })
1723
1817
  );
1724
- var issueLifecycleActionSchema = z9.object({ action: z9.string() }).passthrough();
1818
+ var issueLifecycleActionSchema = z10.object({ action: z10.string() }).passthrough();
1725
1819
  function timestamp2(value) {
1726
1820
  if (!value) return void 0;
1727
1821
  const parsed = new Date(value);
@@ -1767,21 +1861,21 @@ function normalizeGitHubIssueOutcome(args) {
1767
1861
  updatedAt
1768
1862
  };
1769
1863
  }
1770
- var canonicalIssueConversationSchema = z9.object({
1771
- issue: z9.object({
1772
- body: z9.string().nullable().optional(),
1773
- id: z9.number().int().positive(),
1774
- user: z9.object({ login: z9.string().min(1) }).strict()
1864
+ var canonicalIssueConversationSchema = z10.object({
1865
+ issue: z10.object({
1866
+ body: z10.string().nullable().optional(),
1867
+ id: z10.number().int().positive(),
1868
+ user: z10.object({ login: z10.string().min(1) }).strict()
1775
1869
  }).strict(),
1776
- sender: z9.object({ login: z9.string().min(1) }).strict().optional()
1870
+ sender: z10.object({ login: z10.string().min(1) }).strict().optional()
1777
1871
  }).strict();
1778
- var issueConversationSchema = z9.object({
1779
- issue: z9.object({
1780
- body: z9.string().nullable().optional(),
1781
- id: z9.number().int().positive(),
1782
- user: z9.object({ login: z9.string().min(1) }).passthrough()
1872
+ var issueConversationSchema = z10.object({
1873
+ issue: z10.object({
1874
+ body: z10.string().nullable().optional(),
1875
+ id: z10.number().int().positive(),
1876
+ user: z10.object({ login: z10.string().min(1) }).passthrough()
1783
1877
  }).passthrough(),
1784
- sender: z9.object({ login: z9.string().min(1) }).passthrough().optional()
1878
+ sender: z10.object({ login: z10.string().min(1) }).passthrough().optional()
1785
1879
  }).passthrough().transform(
1786
1880
  (provider) => canonicalIssueConversationSchema.parse({
1787
1881
  issue: {
@@ -1808,41 +1902,41 @@ function normalizeGitHubIssueConversations(args) {
1808
1902
  }
1809
1903
 
1810
1904
  // src/webhooks/pull-request-outcome.ts
1811
- import { z as z10 } from "zod";
1812
- var canonicalPullRequestOutcomeSchema = z10.object({
1813
- action: z10.enum(["opened", "closed", "reopened"]),
1814
- pull_request: z10.object({
1815
- body: z10.string().nullable().optional(),
1816
- closed_at: z10.string().nullable().optional(),
1817
- created_at: z10.string(),
1818
- id: z10.number().int().positive(),
1819
- merged: z10.boolean(),
1820
- merged_at: z10.string().nullable().optional(),
1821
- number: z10.number().int().positive(),
1822
- updated_at: z10.string(),
1823
- user: z10.object({ login: z10.string().min(1) }).strict()
1905
+ import { z as z11 } from "zod";
1906
+ var canonicalPullRequestOutcomeSchema = z11.object({
1907
+ action: z11.enum(["opened", "closed", "reopened"]),
1908
+ pull_request: z11.object({
1909
+ body: z11.string().nullable().optional(),
1910
+ closed_at: z11.string().nullable().optional(),
1911
+ created_at: z11.string(),
1912
+ id: z11.number().int().positive(),
1913
+ merged: z11.boolean(),
1914
+ merged_at: z11.string().nullable().optional(),
1915
+ number: z11.number().int().positive(),
1916
+ updated_at: z11.string(),
1917
+ user: z11.object({ login: z11.string().min(1) }).strict()
1824
1918
  }).strict(),
1825
- repository: z10.object({
1826
- full_name: z10.string().min(1),
1827
- id: z10.number().int().positive()
1919
+ repository: z11.object({
1920
+ full_name: z11.string().min(1),
1921
+ id: z11.number().int().positive()
1828
1922
  }).strict()
1829
1923
  }).strict();
1830
- var pullRequestOutcomeSchema = z10.object({
1831
- action: z10.enum(["opened", "closed", "reopened"]),
1832
- pull_request: z10.object({
1833
- body: z10.string().nullable().optional(),
1834
- closed_at: z10.string().nullable().optional(),
1835
- created_at: z10.string(),
1836
- id: z10.number().int().positive(),
1837
- merged: z10.boolean(),
1838
- merged_at: z10.string().nullable().optional(),
1839
- number: z10.number().int().positive(),
1840
- updated_at: z10.string(),
1841
- user: z10.object({ login: z10.string().min(1) }).passthrough()
1924
+ var pullRequestOutcomeSchema = z11.object({
1925
+ action: z11.enum(["opened", "closed", "reopened"]),
1926
+ pull_request: z11.object({
1927
+ body: z11.string().nullable().optional(),
1928
+ closed_at: z11.string().nullable().optional(),
1929
+ created_at: z11.string(),
1930
+ id: z11.number().int().positive(),
1931
+ merged: z11.boolean(),
1932
+ merged_at: z11.string().nullable().optional(),
1933
+ number: z11.number().int().positive(),
1934
+ updated_at: z11.string(),
1935
+ user: z11.object({ login: z11.string().min(1) }).passthrough()
1842
1936
  }).passthrough(),
1843
- repository: z10.object({
1844
- full_name: z10.string().min(1),
1845
- id: z10.number().int().positive()
1937
+ repository: z11.object({
1938
+ full_name: z11.string().min(1),
1939
+ id: z11.number().int().positive()
1846
1940
  }).passthrough()
1847
1941
  }).passthrough().transform(
1848
1942
  (provider) => canonicalPullRequestOutcomeSchema.parse({
@@ -1864,24 +1958,24 @@ var pullRequestOutcomeSchema = z10.object({
1864
1958
  }
1865
1959
  })
1866
1960
  );
1867
- var pullRequestLifecycleActionSchema = z10.object({ action: z10.string() }).passthrough();
1868
- var canonicalPullRequestConversationSchema = z10.object({
1869
- pull_request: z10.object({
1870
- body: z10.string().nullable().optional(),
1871
- id: z10.number().int().positive(),
1872
- user: z10.object({ login: z10.string().min(1) }).strict()
1961
+ var pullRequestLifecycleActionSchema = z11.object({ action: z11.string() }).passthrough();
1962
+ var canonicalPullRequestConversationSchema = z11.object({
1963
+ pull_request: z11.object({
1964
+ body: z11.string().nullable().optional(),
1965
+ id: z11.number().int().positive(),
1966
+ user: z11.object({ login: z11.string().min(1) }).strict()
1873
1967
  }).strict(),
1874
- repository: z10.object({ full_name: z10.string().min(1) }).strict(),
1875
- sender: z10.object({ login: z10.string().min(1) }).strict()
1968
+ repository: z11.object({ full_name: z11.string().min(1) }).strict(),
1969
+ sender: z11.object({ login: z11.string().min(1) }).strict()
1876
1970
  }).strict();
1877
- var pullRequestConversationSchema = z10.object({
1878
- pull_request: z10.object({
1879
- body: z10.string().nullable().optional(),
1880
- id: z10.number().int().positive(),
1881
- user: z10.object({ login: z10.string().min(1) }).passthrough()
1971
+ var pullRequestConversationSchema = z11.object({
1972
+ pull_request: z11.object({
1973
+ body: z11.string().nullable().optional(),
1974
+ id: z11.number().int().positive(),
1975
+ user: z11.object({ login: z11.string().min(1) }).passthrough()
1882
1976
  }).passthrough(),
1883
- repository: z10.object({ full_name: z10.string().min(1) }).passthrough(),
1884
- sender: z10.object({ login: z10.string().min(1) }).passthrough()
1977
+ repository: z11.object({ full_name: z11.string().min(1) }).passthrough(),
1978
+ sender: z11.object({ login: z11.string().min(1) }).passthrough()
1885
1979
  }).passthrough().transform(
1886
1980
  (provider) => canonicalPullRequestConversationSchema.parse({
1887
1981
  pull_request: {
@@ -1986,6 +2080,20 @@ function parseJson(body) {
1986
2080
  return void 0;
1987
2081
  }
1988
2082
  }
2083
+ function parseInstallationId(value) {
2084
+ const parsed = typeof value === "string" && /^\d+$/.test(value) ? Number(value) : value;
2085
+ return typeof parsed === "number" && Number.isSafeInteger(parsed) && parsed > 0 ? parsed : void 0;
2086
+ }
2087
+ function webhookInstallationId(body) {
2088
+ if (!body || typeof body !== "object" || Array.isArray(body)) {
2089
+ return void 0;
2090
+ }
2091
+ const installation = body.installation;
2092
+ if (!installation || typeof installation !== "object" || Array.isArray(installation)) {
2093
+ return void 0;
2094
+ }
2095
+ return parseInstallationId(installation.id);
2096
+ }
1989
2097
  function createGitHubWebhookRoute(args) {
1990
2098
  return {
1991
2099
  method: "POST",
@@ -2002,6 +2110,15 @@ function createGitHubWebhookRoute(args) {
2002
2110
  return new Response("Malformed GitHub webhook", { status: 400 });
2003
2111
  }
2004
2112
  const body = parseJson(rawBody);
2113
+ const installationId = parseInstallationId(args.installationId());
2114
+ if (!installationId) {
2115
+ return new Response("GitHub webhook installation is not configured", {
2116
+ status: 503
2117
+ });
2118
+ }
2119
+ if (webhookInstallationId(body) !== installationId) {
2120
+ return new Response("Ignored", { status: 202 });
2121
+ }
2005
2122
  const botEmail = args.botEmail();
2006
2123
  const pullRequestOutcome = eventName === "pull_request" ? normalizeGitHubPullRequestOutcome({ body, botEmail }) : void 0;
2007
2124
  const issueOutcome = eventName === "issues" ? normalizeGitHubIssueOutcome({ body, botEmail }) : void 0;
@@ -2066,18 +2183,18 @@ function createGitHubWebhookRoute(args) {
2066
2183
 
2067
2184
  // src/outcomes/report.ts
2068
2185
  import { sql as sql5 } from "drizzle-orm";
2069
- import { z as z12 } from "zod";
2186
+ import { z as z13 } from "zod";
2070
2187
 
2071
2188
  // src/outcomes/cost.ts
2072
2189
  import { sql as sql4 } from "drizzle-orm";
2073
- import { z as z11 } from "zod";
2190
+ import { z as z12 } from "zod";
2074
2191
  var DAY_MS = 24 * 60 * 60 * 1e3;
2075
- var costWindowSchema = z11.object({
2076
- days: z11.number().int().positive(),
2077
- issueCostUsd: z11.number().nonnegative().nullable(),
2078
- medianIssueCostUsd: z11.number().nonnegative().nullable(),
2079
- medianPullRequestCostUsd: z11.number().nonnegative().nullable(),
2080
- pullRequestCostUsd: z11.number().nonnegative().nullable()
2192
+ var costWindowSchema = z12.object({
2193
+ days: z12.number().int().positive(),
2194
+ issueCostUsd: z12.number().nonnegative().nullable(),
2195
+ medianIssueCostUsd: z12.number().nonnegative().nullable(),
2196
+ medianPullRequestCostUsd: z12.number().nonnegative().nullable(),
2197
+ pullRequestCostUsd: z12.number().nonnegative().nullable()
2081
2198
  }).strict().transform((row) => ({
2082
2199
  days: row.days,
2083
2200
  issueCostUsd: row.issueCostUsd ?? void 0,
@@ -2085,12 +2202,12 @@ var costWindowSchema = z11.object({
2085
2202
  medianPullRequestCostUsd: row.medianPullRequestCostUsd ?? void 0,
2086
2203
  pullRequestCostUsd: row.pullRequestCostUsd ?? void 0
2087
2204
  }));
2088
- var repositoryCostSchema = z11.object({
2089
- issueCostUsd: z11.number().nonnegative().nullable(),
2090
- medianIssueCostUsd: z11.number().nonnegative().nullable(),
2091
- medianPullRequestCostUsd: z11.number().nonnegative().nullable(),
2092
- pullRequestCostUsd: z11.number().nonnegative().nullable(),
2093
- repository: z11.string().min(1)
2205
+ var repositoryCostSchema = z12.object({
2206
+ issueCostUsd: z12.number().nonnegative().nullable(),
2207
+ medianIssueCostUsd: z12.number().nonnegative().nullable(),
2208
+ medianPullRequestCostUsd: z12.number().nonnegative().nullable(),
2209
+ pullRequestCostUsd: z12.number().nonnegative().nullable(),
2210
+ repository: z12.string().min(1)
2094
2211
  }).strict().transform((row) => ({
2095
2212
  issueCostUsd: row.issueCostUsd ?? void 0,
2096
2213
  medianIssueCostUsd: row.medianIssueCostUsd ?? void 0,
@@ -2295,7 +2412,7 @@ async function aggregateGitHubCostWindows(args) {
2295
2412
  INNER JOIN issue_window ON issue_window.days = pull_request_window.days
2296
2413
  ORDER BY pull_request_window.days
2297
2414
  `);
2298
- return z11.array(costWindowSchema).parse(queryRows(result));
2415
+ return z12.array(costWindowSchema).parse(queryRows(result));
2299
2416
  }
2300
2417
  async function aggregateGitHubRepositoryCosts(args) {
2301
2418
  if (!await hasConversationUsageTable(args.db)) {
@@ -2393,7 +2510,7 @@ async function aggregateGitHubRepositoryCosts(args) {
2393
2510
  ON issue_totals.repository = repositories.repository
2394
2511
  ORDER BY "repository" ASC
2395
2512
  `);
2396
- return z11.array(repositoryCostSchema).parse(queryRows(result));
2513
+ return z12.array(repositoryCostSchema).parse(queryRows(result));
2397
2514
  }
2398
2515
  function formatCostUsd(value) {
2399
2516
  if (value === void 0) return "\u2014";
@@ -2408,12 +2525,12 @@ function formatCostUsd(value) {
2408
2525
  // src/outcomes/report.ts
2409
2526
  var DAY_MS2 = 24 * 60 * 60 * 1e3;
2410
2527
  var WINDOWS = [7, 30, 90];
2411
- var pullRequestStatsSchema = z12.object({
2412
- closed: z12.number().int().nonnegative(),
2413
- created: z12.number().int().nonnegative(),
2414
- days: z12.number().int().positive(),
2415
- medianMergeTimeMs: z12.number().nonnegative().nullable(),
2416
- merged: z12.number().int().nonnegative()
2528
+ var pullRequestStatsSchema = z13.object({
2529
+ closed: z13.number().int().nonnegative(),
2530
+ created: z13.number().int().nonnegative(),
2531
+ days: z13.number().int().positive(),
2532
+ medianMergeTimeMs: z13.number().nonnegative().nullable(),
2533
+ merged: z13.number().int().nonnegative()
2417
2534
  }).strict().transform((row) => {
2418
2535
  const terminal = row.merged + row.closed;
2419
2536
  return {
@@ -2422,12 +2539,12 @@ var pullRequestStatsSchema = z12.object({
2422
2539
  mergeRate: terminal > 0 ? row.merged / terminal : void 0
2423
2540
  };
2424
2541
  });
2425
- var pullRequestRepositoryStatsSchema = z12.object({
2426
- closed: z12.number().int().nonnegative(),
2427
- created: z12.number().int().nonnegative(),
2428
- juniorOnly: z12.number().int().nonnegative(),
2429
- merged: z12.number().int().nonnegative(),
2430
- repository: z12.string().min(1)
2542
+ var pullRequestRepositoryStatsSchema = z13.object({
2543
+ closed: z13.number().int().nonnegative(),
2544
+ created: z13.number().int().nonnegative(),
2545
+ juniorOnly: z13.number().int().nonnegative(),
2546
+ merged: z13.number().int().nonnegative(),
2547
+ repository: z13.string().min(1)
2431
2548
  }).strict().transform((row) => {
2432
2549
  const terminal = row.merged + row.closed;
2433
2550
  return {
@@ -2435,33 +2552,33 @@ var pullRequestRepositoryStatsSchema = z12.object({
2435
2552
  mergeRate: terminal > 0 ? row.merged / terminal : void 0
2436
2553
  };
2437
2554
  });
2438
- var issueStatsSchema = z12.object({
2439
- closedCompleted: z12.number().int().nonnegative(),
2440
- closedDuplicate: z12.number().int().nonnegative(),
2441
- closedNotPlanned: z12.number().int().nonnegative(),
2442
- closedUnknown: z12.number().int().nonnegative(),
2443
- created: z12.number().int().nonnegative(),
2444
- days: z12.number().int().positive(),
2445
- medianCloseTimeMs: z12.number().nonnegative().nullable()
2555
+ var issueStatsSchema = z13.object({
2556
+ closedCompleted: z13.number().int().nonnegative(),
2557
+ closedDuplicate: z13.number().int().nonnegative(),
2558
+ closedNotPlanned: z13.number().int().nonnegative(),
2559
+ closedUnknown: z13.number().int().nonnegative(),
2560
+ created: z13.number().int().nonnegative(),
2561
+ days: z13.number().int().positive(),
2562
+ medianCloseTimeMs: z13.number().nonnegative().nullable()
2446
2563
  }).strict().transform((row) => ({
2447
2564
  ...row,
2448
2565
  medianCloseTimeMs: row.medianCloseTimeMs ?? void 0
2449
2566
  }));
2450
- var pullRequestDaySchema = z12.object({
2451
- created: z12.number().int().nonnegative(),
2452
- date: z12.string().date()
2567
+ var pullRequestDaySchema = z13.object({
2568
+ created: z13.number().int().nonnegative(),
2569
+ date: z13.string().date()
2453
2570
  }).strict();
2454
- var issueDaySchema = z12.object({
2455
- created: z12.number().int().nonnegative(),
2456
- date: z12.string().date()
2571
+ var issueDaySchema = z13.object({
2572
+ created: z13.number().int().nonnegative(),
2573
+ date: z13.string().date()
2457
2574
  }).strict();
2458
- var issueRepositoryStatsSchema = z12.object({
2459
- closedCompleted: z12.number().int().nonnegative(),
2460
- closedDuplicate: z12.number().int().nonnegative(),
2461
- closedNotPlanned: z12.number().int().nonnegative(),
2462
- closedUnknown: z12.number().int().nonnegative(),
2463
- created: z12.number().int().nonnegative(),
2464
- repository: z12.string().min(1)
2575
+ var issueRepositoryStatsSchema = z13.object({
2576
+ closedCompleted: z13.number().int().nonnegative(),
2577
+ closedDuplicate: z13.number().int().nonnegative(),
2578
+ closedNotPlanned: z13.number().int().nonnegative(),
2579
+ closedUnknown: z13.number().int().nonnegative(),
2580
+ created: z13.number().int().nonnegative(),
2581
+ repository: z13.string().min(1)
2465
2582
  }).strict();
2466
2583
  function queryRows2(result) {
2467
2584
  if (typeof result !== "object" || result === null || !("rows" in result) || !Array.isArray(result.rows)) {
@@ -2525,7 +2642,7 @@ async function aggregatePullRequestWindows(args) {
2525
2642
  GROUP BY windows.days
2526
2643
  ORDER BY windows.days
2527
2644
  `);
2528
- return z12.array(pullRequestStatsSchema).parse(queryRows2(result));
2645
+ return z13.array(pullRequestStatsSchema).parse(queryRows2(result));
2529
2646
  }
2530
2647
  async function aggregatePullRequestDays(args) {
2531
2648
  const end = new Date(args.nowMs);
@@ -2553,7 +2670,7 @@ async function aggregatePullRequestDays(args) {
2553
2670
  LEFT JOIN daily ON daily.day = days.day
2554
2671
  ORDER BY days.day
2555
2672
  `);
2556
- return z12.array(pullRequestDaySchema).parse(queryRows2(result));
2673
+ return z13.array(pullRequestDaySchema).parse(queryRows2(result));
2557
2674
  }
2558
2675
  async function aggregatePullRequestRepositories(args) {
2559
2676
  const start = new Date(args.nowMs - 30 * DAY_MS2);
@@ -2583,7 +2700,7 @@ async function aggregatePullRequestRepositories(args) {
2583
2700
  ORDER BY "merged" DESC, "created" DESC, "repository" ASC
2584
2701
  LIMIT 25
2585
2702
  `);
2586
- return z12.array(pullRequestRepositoryStatsSchema).parse(queryRows2(result));
2703
+ return z13.array(pullRequestRepositoryStatsSchema).parse(queryRows2(result));
2587
2704
  }
2588
2705
  async function aggregateIssueWindows(args) {
2589
2706
  const starts = WINDOWS.map(
@@ -2652,7 +2769,7 @@ async function aggregateIssueWindows(args) {
2652
2769
  GROUP BY windows.days
2653
2770
  ORDER BY windows.days
2654
2771
  `);
2655
- return z12.array(issueStatsSchema).parse(queryRows2(result));
2772
+ return z13.array(issueStatsSchema).parse(queryRows2(result));
2656
2773
  }
2657
2774
  async function aggregateIssueDays(args) {
2658
2775
  const end = new Date(args.nowMs);
@@ -2680,7 +2797,7 @@ async function aggregateIssueDays(args) {
2680
2797
  LEFT JOIN daily ON daily.day = days.day
2681
2798
  ORDER BY days.day
2682
2799
  `);
2683
- return z12.array(issueDaySchema).parse(queryRows2(result));
2800
+ return z13.array(issueDaySchema).parse(queryRows2(result));
2684
2801
  }
2685
2802
  async function aggregateIssueRepositories(args) {
2686
2803
  const start = new Date(args.nowMs - 30 * DAY_MS2);
@@ -2717,7 +2834,7 @@ async function aggregateIssueRepositories(args) {
2717
2834
  ORDER BY "created" DESC, "closedCompleted" DESC, "repository" ASC
2718
2835
  LIMIT 25
2719
2836
  `);
2720
- return z12.array(issueRepositoryStatsSchema).parse(queryRows2(result));
2837
+ return z13.array(issueRepositoryStatsSchema).parse(queryRows2(result));
2721
2838
  }
2722
2839
  function formatPercent(value) {
2723
2840
  return value === void 0 ? "\u2014" : `${Math.round(value * 100)}%`;
@@ -2881,18 +2998,18 @@ async function buildGitHubOutcomeReport(args) {
2881
2998
  }
2882
2999
 
2883
3000
  // src/pull-request-outcomes/commit-composition.ts
2884
- import { z as z13 } from "zod";
2885
- var canonicalCommitSchema = z13.object({
2886
- authorEmail: z13.string().nullable(),
2887
- authorLogin: z13.string().nullable()
3001
+ import { z as z14 } from "zod";
3002
+ var canonicalCommitSchema = z14.object({
3003
+ authorEmail: z14.string().nullable(),
3004
+ authorLogin: z14.string().nullable()
2888
3005
  }).strict();
2889
- var providerCommitSchema = z13.object({
2890
- author: z13.object({ login: z13.string() }).passthrough().nullable(),
2891
- commit: z13.object({
2892
- author: z13.object({ email: z13.string() }).passthrough().nullable()
3006
+ var providerCommitSchema = z14.object({
3007
+ author: z14.object({ login: z14.string() }).passthrough().nullable(),
3008
+ commit: z14.object({
3009
+ author: z14.object({ email: z14.string() }).passthrough().nullable()
2893
3010
  }).passthrough()
2894
3011
  }).passthrough();
2895
- var commitPageSchema = z13.array(providerCommitSchema).transform(
3012
+ var commitPageSchema = z14.array(providerCommitSchema).transform(
2896
3013
  (commits) => commits.map(
2897
3014
  (commit) => canonicalCommitSchema.parse({
2898
3015
  authorEmail: commit.commit.author?.email ?? null,
@@ -4090,6 +4207,32 @@ function githubPlugin(options = {}) {
4090
4207
  const userScope = userScopes.length ? userScopes.join(" ") : void 0;
4091
4208
  return defineJuniorPlugin({
4092
4209
  packageName: "@sentry/junior-github",
4210
+ resourceEvents: {
4211
+ resourceTypes: [
4212
+ {
4213
+ type: "deployment_source",
4214
+ supportedEvents: [...GITHUB_DEPLOYMENT_EVENTS],
4215
+ suggestedEvents: [...GITHUB_DEPLOYMENT_SUGGESTED_EVENTS]
4216
+ },
4217
+ {
4218
+ type: "issue",
4219
+ supportedEvents: [...GITHUB_ISSUE_EVENTS],
4220
+ suggestedEvents: [...GITHUB_ISSUE_SUGGESTED_EVENTS]
4221
+ },
4222
+ {
4223
+ type: "pull_request",
4224
+ supportedEvents: [...GITHUB_PULL_REQUEST_EVENTS],
4225
+ suggestedEvents: [...GITHUB_PULL_REQUEST_SUGGESTED_EVENTS]
4226
+ },
4227
+ {
4228
+ type: "repository",
4229
+ supportedEvents: [...GITHUB_ISSUE_EVENTS],
4230
+ suggestedEvents: ["issue.opened", ...GITHUB_ISSUE_SUGGESTED_EVENTS]
4231
+ }
4232
+ ],
4233
+ isEnabled: () => Boolean(readEnv("GITHUB_WEBHOOK_SECRET")),
4234
+ normalizeIdentifier: (identifier) => identifier.toLowerCase()
4235
+ },
4093
4236
  manifest: {
4094
4237
  name: "github",
4095
4238
  displayName: "GitHub",
@@ -4168,6 +4311,7 @@ function githubPlugin(options = {}) {
4168
4311
  });
4169
4312
  },
4170
4313
  db: ctx.db,
4314
+ installationId: () => readEnv(installationIdEnv),
4171
4315
  log: ctx.log,
4172
4316
  resourceEvents: ctx.resourceEvents,
4173
4317
  webhookSecret: () => readEnv("GITHUB_WEBHOOK_SECRET")