@debugbundle/mcp 0.1.2 → 0.1.5

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.
Files changed (2) hide show
  1. package/dist/main.cjs +596 -117
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -15198,7 +15198,7 @@ function createProjectManagementApi(client) {
15198
15198
 
15199
15199
  // ../../packages/retrieval-client/src/index.ts
15200
15200
  var IncidentReasonSchema = external_exports.object({
15201
- kind: external_exports.enum(["backend_exception", "frontend_exception", "request_failure_5xx", "error_log"]),
15201
+ kind: external_exports.enum(["backend_exception", "frontend_exception", "request_failure", "error_log"]),
15202
15202
  description: external_exports.string(),
15203
15203
  event_type: external_exports.enum(["backend_exception", "frontend_exception", "request_event", "log_event"]),
15204
15204
  event_class: external_exports.literal("incident_signal"),
@@ -15520,6 +15520,121 @@ function createRetrievalApi(client) {
15520
15520
  };
15521
15521
  }
15522
15522
 
15523
+ // ../../packages/slack-client/src/index.ts
15524
+ var SlackDestinationRecordSchema = external_exports.object({
15525
+ slack_destination_id: external_exports.string(),
15526
+ organization_id: external_exports.string(),
15527
+ slack_team_id: external_exports.string(),
15528
+ slack_team_name: external_exports.string().nullable(),
15529
+ slack_channel_id: external_exports.string(),
15530
+ slack_channel_name: external_exports.string().nullable(),
15531
+ installed_by_member_id: external_exports.string().nullable(),
15532
+ is_active: external_exports.boolean(),
15533
+ created_at: external_exports.string(),
15534
+ updated_at: external_exports.string()
15535
+ }).strict();
15536
+ var SlackDestinationListResponseSchema = external_exports.object({
15537
+ destinations: external_exports.array(SlackDestinationRecordSchema)
15538
+ }).strict();
15539
+ var SlackInstallUrlResponseSchema = external_exports.object({
15540
+ install_url: external_exports.string().url()
15541
+ }).strict();
15542
+ var SlackDestinationTestResponseSchema = external_exports.object({
15543
+ delivered: external_exports.boolean()
15544
+ }).strict();
15545
+ var ApiErrorResponseSchema6 = external_exports.object({
15546
+ error: external_exports.string()
15547
+ }).strict();
15548
+ var SlackApiError = class extends Error {
15549
+ status;
15550
+ code;
15551
+ constructor(status, code) {
15552
+ super(`slack_api_error: ${status}:${code}`);
15553
+ this.status = status;
15554
+ this.code = code;
15555
+ }
15556
+ };
15557
+ function parseApiError6(status, body) {
15558
+ const parsed = ApiErrorResponseSchema6.safeParse(body);
15559
+ if (!parsed.success) {
15560
+ throw new SlackApiError(status, "unknown_error");
15561
+ }
15562
+ throw new SlackApiError(status, parsed.data.error);
15563
+ }
15564
+ function buildQuery2(input) {
15565
+ const params = new URLSearchParams();
15566
+ for (const [key, value] of Object.entries(input)) {
15567
+ if (value !== void 0) {
15568
+ params.set(key, String(value));
15569
+ }
15570
+ }
15571
+ const query = params.toString();
15572
+ return query.length === 0 ? "" : `?${query}`;
15573
+ }
15574
+ function createSlackApi(client) {
15575
+ return {
15576
+ async getSlackInstallUrl(input) {
15577
+ const response = await client.request({
15578
+ method: "GET",
15579
+ path: `/v1/slack/app/install-url${buildQuery2({
15580
+ project_id: input.projectId,
15581
+ return_to: input.returnTo
15582
+ })}`,
15583
+ bearerToken: input.bearerToken
15584
+ });
15585
+ if (response.status < 200 || response.status >= 300) {
15586
+ parseApiError6(response.status, response.body);
15587
+ }
15588
+ const parsed = SlackInstallUrlResponseSchema.safeParse(response.body);
15589
+ if (!parsed.success) {
15590
+ throw new SlackApiError(response.status, "invalid_response_shape");
15591
+ }
15592
+ return parsed.data.install_url;
15593
+ },
15594
+ async listSlackDestinations(input) {
15595
+ const response = await client.request({
15596
+ method: "GET",
15597
+ path: `/v1/projects/${input.projectId}/slack/destinations`,
15598
+ bearerToken: input.bearerToken
15599
+ });
15600
+ if (response.status < 200 || response.status >= 300) {
15601
+ parseApiError6(response.status, response.body);
15602
+ }
15603
+ const parsed = SlackDestinationListResponseSchema.safeParse(response.body);
15604
+ if (!parsed.success) {
15605
+ throw new SlackApiError(response.status, "invalid_response_shape");
15606
+ }
15607
+ return parsed.data.destinations;
15608
+ },
15609
+ async testSlackDestination(input) {
15610
+ const response = await client.request({
15611
+ method: "POST",
15612
+ path: `/v1/projects/${input.projectId}/slack/destinations/${input.destinationId}/test`,
15613
+ bearerToken: input.bearerToken
15614
+ });
15615
+ if (response.status < 200 || response.status >= 300) {
15616
+ parseApiError6(response.status, response.body);
15617
+ }
15618
+ const parsed = SlackDestinationTestResponseSchema.safeParse(response.body);
15619
+ if (!parsed.success || parsed.data.delivered !== true) {
15620
+ throw new SlackApiError(response.status, "invalid_response_shape");
15621
+ }
15622
+ return { delivered: true };
15623
+ },
15624
+ async deleteSlackDestination(input) {
15625
+ const response = await client.request({
15626
+ method: "DELETE",
15627
+ path: `/v1/projects/${input.projectId}/slack/destinations/${input.destinationId}`,
15628
+ bearerToken: input.bearerToken
15629
+ });
15630
+ if (response.status < 200 || response.status >= 300) {
15631
+ parseApiError6(response.status, response.body);
15632
+ }
15633
+ return { slack_destination_id: input.destinationId };
15634
+ }
15635
+ };
15636
+ }
15637
+
15523
15638
  // ../../packages/token-management/src/index.ts
15524
15639
  var ProjectTokenSchema = external_exports.object({
15525
15640
  token_id: external_exports.string(),
@@ -15548,7 +15663,7 @@ var TokenListResponseSchema = external_exports.object({
15548
15663
  var TokenCreateResponseSchema = external_exports.object({
15549
15664
  token: external_exports.union([ProjectTokenSchema, MemberTokenSchema])
15550
15665
  }).strict();
15551
- var ApiErrorResponseSchema6 = external_exports.object({
15666
+ var ApiErrorResponseSchema7 = external_exports.object({
15552
15667
  error: external_exports.string()
15553
15668
  }).strict();
15554
15669
  var TokenManagementApiError = class extends Error {
@@ -15560,8 +15675,8 @@ var TokenManagementApiError = class extends Error {
15560
15675
  this.code = code;
15561
15676
  }
15562
15677
  };
15563
- function parseApiError6(status, body) {
15564
- const parsed = ApiErrorResponseSchema6.safeParse(body);
15678
+ function parseApiError7(status, body) {
15679
+ const parsed = ApiErrorResponseSchema7.safeParse(body);
15565
15680
  if (!parsed.success) {
15566
15681
  throw new TokenManagementApiError(status, "unknown_error");
15567
15682
  }
@@ -15570,7 +15685,7 @@ function parseApiError6(status, body) {
15570
15685
  async function expectTokenList(responsePromise) {
15571
15686
  const response = await responsePromise;
15572
15687
  if (response.status < 200 || response.status >= 300) {
15573
- parseApiError6(response.status, response.body);
15688
+ parseApiError7(response.status, response.body);
15574
15689
  }
15575
15690
  const parsed = TokenListResponseSchema.safeParse(response.body);
15576
15691
  if (!parsed.success) {
@@ -15581,7 +15696,7 @@ async function expectTokenList(responsePromise) {
15581
15696
  async function expectToken(responsePromise) {
15582
15697
  const response = await responsePromise;
15583
15698
  if (response.status < 200 || response.status >= 300) {
15584
- parseApiError6(response.status, response.body);
15699
+ parseApiError7(response.status, response.body);
15585
15700
  }
15586
15701
  const parsed = TokenCreateResponseSchema.safeParse(response.body);
15587
15702
  if (!parsed.success) {
@@ -15773,7 +15888,7 @@ var RetryWebhookDeliveryResponseSchema = external_exports.object({
15773
15888
  delivery_id: external_exports.string(),
15774
15889
  event_type: WebhookEventTypeSchema
15775
15890
  }).strict();
15776
- var ApiErrorResponseSchema7 = external_exports.object({
15891
+ var ApiErrorResponseSchema8 = external_exports.object({
15777
15892
  error: external_exports.string()
15778
15893
  }).strict();
15779
15894
  var WebhookApiError = class extends Error {
@@ -15785,14 +15900,14 @@ var WebhookApiError = class extends Error {
15785
15900
  this.code = code;
15786
15901
  }
15787
15902
  };
15788
- function parseApiError7(status, body) {
15789
- const parsed = ApiErrorResponseSchema7.safeParse(body);
15903
+ function parseApiError8(status, body) {
15904
+ const parsed = ApiErrorResponseSchema8.safeParse(body);
15790
15905
  if (!parsed.success) {
15791
15906
  throw new WebhookApiError(status, "unknown_error");
15792
15907
  }
15793
15908
  throw new WebhookApiError(status, parsed.data.error);
15794
15909
  }
15795
- function buildQuery2(input) {
15910
+ function buildQuery3(input) {
15796
15911
  const params = new URLSearchParams();
15797
15912
  for (const [key, value] of Object.entries(input)) {
15798
15913
  if (value !== void 0) {
@@ -15805,7 +15920,7 @@ function buildQuery2(input) {
15805
15920
  async function expectWebhookList(responsePromise) {
15806
15921
  const response = await responsePromise;
15807
15922
  if (response.status < 200 || response.status >= 300) {
15808
- parseApiError7(response.status, response.body);
15923
+ parseApiError8(response.status, response.body);
15809
15924
  }
15810
15925
  const parsed = WebhookListResponseSchema.safeParse(response.body);
15811
15926
  if (!parsed.success) {
@@ -15816,7 +15931,7 @@ async function expectWebhookList(responsePromise) {
15816
15931
  async function expectWebhook(responsePromise) {
15817
15932
  const response = await responsePromise;
15818
15933
  if (response.status < 200 || response.status >= 300) {
15819
- parseApiError7(response.status, response.body);
15934
+ parseApiError8(response.status, response.body);
15820
15935
  }
15821
15936
  const parsed = WebhookResponseSchema.safeParse(response.body);
15822
15937
  if (!parsed.success) {
@@ -15827,7 +15942,7 @@ async function expectWebhook(responsePromise) {
15827
15942
  async function expectCreatedWebhook(responsePromise) {
15828
15943
  const response = await responsePromise;
15829
15944
  if (response.status < 200 || response.status >= 300) {
15830
- parseApiError7(response.status, response.body);
15945
+ parseApiError8(response.status, response.body);
15831
15946
  }
15832
15947
  const parsed = WebhookCreateResponseSchema.safeParse(response.body);
15833
15948
  if (!parsed.success) {
@@ -15838,7 +15953,7 @@ async function expectCreatedWebhook(responsePromise) {
15838
15953
  async function expectWebhookDeliveries(responsePromise) {
15839
15954
  const response = await responsePromise;
15840
15955
  if (response.status < 200 || response.status >= 300) {
15841
- parseApiError7(response.status, response.body);
15956
+ parseApiError8(response.status, response.body);
15842
15957
  }
15843
15958
  const parsed = WebhookDeliveriesResponseSchema.safeParse(response.body);
15844
15959
  if (!parsed.success) {
@@ -15849,7 +15964,7 @@ async function expectWebhookDeliveries(responsePromise) {
15849
15964
  async function expectWebhookTestDelivery(responsePromise) {
15850
15965
  const response = await responsePromise;
15851
15966
  if (response.status < 200 || response.status >= 300) {
15852
- parseApiError7(response.status, response.body);
15967
+ parseApiError8(response.status, response.body);
15853
15968
  }
15854
15969
  const parsed = WebhookTestResponseSchema.safeParse(response.body);
15855
15970
  if (!parsed.success) {
@@ -15860,7 +15975,7 @@ async function expectWebhookTestDelivery(responsePromise) {
15860
15975
  async function expectRetryDelivery(responsePromise) {
15861
15976
  const response = await responsePromise;
15862
15977
  if (response.status < 200 || response.status >= 300) {
15863
- parseApiError7(response.status, response.body);
15978
+ parseApiError8(response.status, response.body);
15864
15979
  }
15865
15980
  const parsed = RetryWebhookDeliveryResponseSchema.safeParse(response.body);
15866
15981
  if (!parsed.success) {
@@ -15874,7 +15989,7 @@ function createWebhookApi(client) {
15874
15989
  return expectWebhookList(
15875
15990
  client.request({
15876
15991
  method: "GET",
15877
- path: `/v1/webhooks${buildQuery2({ project_id: input.projectId, limit: input.limit })}`,
15992
+ path: `/v1/webhooks${buildQuery3({ project_id: input.projectId, limit: input.limit })}`,
15878
15993
  bearerToken: input.bearerToken
15879
15994
  })
15880
15995
  );
@@ -15939,7 +16054,7 @@ function createWebhookApi(client) {
15939
16054
  bearerToken: input.bearerToken
15940
16055
  });
15941
16056
  if (response.status < 200 || response.status >= 300) {
15942
- parseApiError7(response.status, response.body);
16057
+ parseApiError8(response.status, response.body);
15943
16058
  }
15944
16059
  return {
15945
16060
  webhook_id: input.webhookId
@@ -15963,7 +16078,7 @@ function createWebhookApi(client) {
15963
16078
  return expectWebhookDeliveries(
15964
16079
  client.request({
15965
16080
  method: "GET",
15966
- path: `/v1/webhooks/${input.webhookId}/deliveries${buildQuery2({ limit: input.limit })}`,
16081
+ path: `/v1/webhooks/${input.webhookId}/deliveries${buildQuery3({ limit: input.limit })}`,
15967
16082
  bearerToken: input.bearerToken
15968
16083
  })
15969
16084
  );
@@ -16013,7 +16128,7 @@ var WeeklyReportChannelListResponseSchema = external_exports.object({
16013
16128
  var WeeklyReportChannelResponseSchema = external_exports.object({
16014
16129
  channel: WeeklyReportChannelRecordSchema
16015
16130
  }).strict();
16016
- var ApiErrorResponseSchema8 = external_exports.object({
16131
+ var ApiErrorResponseSchema9 = external_exports.object({
16017
16132
  error: external_exports.string()
16018
16133
  }).strict();
16019
16134
  var WeeklyReportApiError = class extends Error {
@@ -16025,14 +16140,14 @@ var WeeklyReportApiError = class extends Error {
16025
16140
  this.code = code;
16026
16141
  }
16027
16142
  };
16028
- function parseApiError8(status, body) {
16029
- const parsed = ApiErrorResponseSchema8.safeParse(body);
16143
+ function parseApiError9(status, body) {
16144
+ const parsed = ApiErrorResponseSchema9.safeParse(body);
16030
16145
  if (!parsed.success) {
16031
16146
  throw new WeeklyReportApiError(status, "unknown_error");
16032
16147
  }
16033
16148
  throw new WeeklyReportApiError(status, parsed.data.error);
16034
16149
  }
16035
- function buildQuery3(input) {
16150
+ function buildQuery4(input) {
16036
16151
  const params = new URLSearchParams();
16037
16152
  for (const [key, value] of Object.entries(input)) {
16038
16153
  if (value !== void 0) {
@@ -16045,7 +16160,7 @@ function buildQuery3(input) {
16045
16160
  async function expectChannelList(responsePromise) {
16046
16161
  const response = await responsePromise;
16047
16162
  if (response.status < 200 || response.status >= 300) {
16048
- parseApiError8(response.status, response.body);
16163
+ parseApiError9(response.status, response.body);
16049
16164
  }
16050
16165
  const parsed = WeeklyReportChannelListResponseSchema.safeParse(response.body);
16051
16166
  if (!parsed.success) {
@@ -16056,7 +16171,7 @@ async function expectChannelList(responsePromise) {
16056
16171
  async function expectChannel(responsePromise) {
16057
16172
  const response = await responsePromise;
16058
16173
  if (response.status < 200 || response.status >= 300) {
16059
- parseApiError8(response.status, response.body);
16174
+ parseApiError9(response.status, response.body);
16060
16175
  }
16061
16176
  const parsed = WeeklyReportChannelResponseSchema.safeParse(response.body);
16062
16177
  if (!parsed.success) {
@@ -16070,13 +16185,13 @@ function createWeeklyReportApi(client) {
16070
16185
  return expectChannelList(
16071
16186
  client.request({
16072
16187
  method: "GET",
16073
- path: `/v1/weekly-report-channels${buildQuery3({ project_id: input.projectId, limit: input.limit })}`,
16188
+ path: `/v1/weekly-report-channels${buildQuery4({ project_id: input.projectId, limit: input.limit })}`,
16074
16189
  bearerToken: input.bearerToken
16075
16190
  })
16076
16191
  );
16077
16192
  },
16078
16193
  async createWeeklyReportChannel(input) {
16079
- const config = input.channel === "email" ? { to: input.config.to } : { webhook_url: input.config.webhookUrl };
16194
+ const config = input.channel === "email" ? { to: input.config.to } : "webhookUrl" in input.config ? { webhook_url: input.config.webhookUrl } : { slack_destination_id: input.config.slackDestinationId };
16080
16195
  return expectChannel(
16081
16196
  client.request({
16082
16197
  method: "POST",
@@ -16099,7 +16214,7 @@ function createWeeklyReportApi(client) {
16099
16214
  async updateWeeklyReportChannel(input) {
16100
16215
  const body = {};
16101
16216
  if (input.config !== void 0) {
16102
- body["config"] = "to" in input.config ? { to: input.config.to } : { webhook_url: input.config.webhookUrl };
16217
+ body["config"] = "to" in input.config ? { to: input.config.to } : "webhookUrl" in input.config ? { webhook_url: input.config.webhookUrl } : { slack_destination_id: input.config.slackDestinationId };
16103
16218
  }
16104
16219
  if (input.schedule !== void 0) {
16105
16220
  body["schedule"] = {
@@ -16127,7 +16242,7 @@ function createWeeklyReportApi(client) {
16127
16242
  bearerToken: input.bearerToken
16128
16243
  });
16129
16244
  if (response.status < 200 || response.status >= 300) {
16130
- parseApiError8(response.status, response.body);
16245
+ parseApiError9(response.status, response.body);
16131
16246
  }
16132
16247
  return { channel_id: input.channelId };
16133
16248
  }
@@ -16159,6 +16274,33 @@ var CaptureBreadcrumbsValues = ["local_only", "exception_only", "standalone"];
16159
16274
  var CaptureBreadcrumbsSchema = external_exports.enum(CaptureBreadcrumbsValues);
16160
16275
  var CaptureProbeEventsValues = ["buffer_only", "standalone_when_activated"];
16161
16276
  var CaptureProbeEventsSchema = external_exports.enum(CaptureProbeEventsValues);
16277
+ var RequestSignalClassificationValues = ["incident_signal", "context_signal"];
16278
+ var RequestSignalClassificationSchema = external_exports.enum(RequestSignalClassificationValues);
16279
+ var RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES = [401, 403, 409, 422];
16280
+ var ImmediateClientErrorStatusSchema = external_exports.number().int().min(400).max(499);
16281
+ function normalizeImmediateClientErrorStatuses(statuses) {
16282
+ return Array.from(new Set(statuses)).sort((left, right) => left - right);
16283
+ }
16284
+ var ImmediateClientErrorStatusesSchema = external_exports.array(ImmediateClientErrorStatusSchema).max(12).transform((statuses) => normalizeImmediateClientErrorStatuses(statuses));
16285
+ var ResolvedCapturePolicySchema = external_exports.object({
16286
+ preset: CapturePresetSchema,
16287
+ capture_logs: CaptureLogsSchema,
16288
+ capture_request_events: CaptureRequestEventsSchema,
16289
+ capture_breadcrumbs: CaptureBreadcrumbsSchema,
16290
+ capture_probe_events: CaptureProbeEventsSchema,
16291
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema
16292
+ });
16293
+ var CapturePolicyOverridesSchema = external_exports.object({
16294
+ capture_logs: CaptureLogsSchema.nullable(),
16295
+ capture_request_events: CaptureRequestEventsSchema.nullable(),
16296
+ capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable(),
16297
+ capture_probe_events: CaptureProbeEventsSchema.nullable(),
16298
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable()
16299
+ });
16300
+ var CapturePolicyResponseSchema = external_exports.object({
16301
+ policy: ResolvedCapturePolicySchema,
16302
+ overrides: CapturePolicyOverridesSchema
16303
+ });
16162
16304
  var CapturePolicySchema = external_exports.object({
16163
16305
  project_id: external_exports.string().uuid(),
16164
16306
  preset: CapturePresetSchema,
@@ -16166,6 +16308,7 @@ var CapturePolicySchema = external_exports.object({
16166
16308
  capture_request_events: CaptureRequestEventsSchema.nullable(),
16167
16309
  capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable(),
16168
16310
  capture_probe_events: CaptureProbeEventsSchema.nullable(),
16311
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable(),
16169
16312
  updated_at: external_exports.string().datetime()
16170
16313
  });
16171
16314
  var CapturePolicyUpdateSchema = external_exports.object({
@@ -16173,8 +16316,84 @@ var CapturePolicyUpdateSchema = external_exports.object({
16173
16316
  capture_logs: CaptureLogsSchema.nullable().optional(),
16174
16317
  capture_request_events: CaptureRequestEventsSchema.nullable().optional(),
16175
16318
  capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable().optional(),
16176
- capture_probe_events: CaptureProbeEventsSchema.nullable().optional()
16319
+ capture_probe_events: CaptureProbeEventsSchema.nullable().optional(),
16320
+ immediate_client_error_statuses: ImmediateClientErrorStatusesSchema.nullable().optional()
16177
16321
  });
16322
+ var PRESET_DEFAULTS = {
16323
+ minimal: {
16324
+ capture_logs: "error",
16325
+ capture_request_events: "failures_only",
16326
+ capture_breadcrumbs: "local_only",
16327
+ capture_probe_events: "buffer_only",
16328
+ immediate_client_error_statuses: []
16329
+ },
16330
+ balanced: {
16331
+ capture_logs: "warning",
16332
+ capture_request_events: "failures_only",
16333
+ capture_breadcrumbs: "exception_only",
16334
+ capture_probe_events: "buffer_only",
16335
+ immediate_client_error_statuses: []
16336
+ },
16337
+ investigative: {
16338
+ capture_logs: "info",
16339
+ capture_request_events: "all",
16340
+ capture_breadcrumbs: "standalone",
16341
+ capture_probe_events: "standalone_when_activated",
16342
+ immediate_client_error_statuses: [...RECOMMENDED_IMMEDIATE_CLIENT_ERROR_STATUSES]
16343
+ }
16344
+ };
16345
+ var BALANCED_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([408, 423, 424, 425, 429]);
16346
+ var INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([...BALANCED_IMMEDIATE_REQUEST_STATUSES, 409]);
16347
+ var BALANCED_STANDARD_ANOMALY_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 409, 422]);
16348
+ var BALANCED_HIGH_VOLUME_ANOMALY_STATUSES = /* @__PURE__ */ new Set([400, 410]);
16349
+ var INVESTIGATIVE_ANOMALY_STATUSES = /* @__PURE__ */ new Set([...BALANCED_STANDARD_ANOMALY_STATUSES, ...BALANCED_HIGH_VOLUME_ANOMALY_STATUSES]);
16350
+ function classifyRequestStatus(input) {
16351
+ const { responseStatus, capturePreset, immediateClientErrorStatuses = [] } = input;
16352
+ if (responseStatus === null || !Number.isFinite(responseStatus)) {
16353
+ return "context_signal";
16354
+ }
16355
+ if (responseStatus >= 500) {
16356
+ return "incident_signal";
16357
+ }
16358
+ if (immediateClientErrorStatuses.includes(responseStatus)) {
16359
+ return "incident_signal";
16360
+ }
16361
+ if (capturePreset === "investigative") {
16362
+ return INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES.has(responseStatus) ? "incident_signal" : "context_signal";
16363
+ }
16364
+ if (capturePreset === "balanced") {
16365
+ return BALANCED_IMMEDIATE_REQUEST_STATUSES.has(responseStatus) ? "incident_signal" : "context_signal";
16366
+ }
16367
+ return "context_signal";
16368
+ }
16369
+ function getRequestAnomalyThreshold(input) {
16370
+ const { responseStatus, capturePreset } = input;
16371
+ if (responseStatus === null || !Number.isFinite(responseStatus) || responseStatus < 400 || responseStatus >= 500) {
16372
+ return null;
16373
+ }
16374
+ if (capturePreset === "minimal") {
16375
+ return null;
16376
+ }
16377
+ if (capturePreset === "investigative") {
16378
+ return INVESTIGATIVE_ANOMALY_STATUSES.has(responseStatus) ? {
16379
+ minimum_occurrences_5m: 8,
16380
+ minimum_ratio_5m_to_1h: 2
16381
+ } : null;
16382
+ }
16383
+ if (BALANCED_STANDARD_ANOMALY_STATUSES.has(responseStatus)) {
16384
+ return {
16385
+ minimum_occurrences_5m: 20,
16386
+ minimum_ratio_5m_to_1h: 3
16387
+ };
16388
+ }
16389
+ if (BALANCED_HIGH_VOLUME_ANOMALY_STATUSES.has(responseStatus)) {
16390
+ return {
16391
+ minimum_occurrences_5m: 50,
16392
+ minimum_ratio_5m_to_1h: 5
16393
+ };
16394
+ }
16395
+ return null;
16396
+ }
16178
16397
 
16179
16398
  // ../../packages/shared-types/src/index.ts
16180
16399
  function createUuidV4() {
@@ -16783,7 +17002,7 @@ function buildCliReference() {
16783
17002
  "- `debugbundle ingest <file> --format <format> [--json]`",
16784
17003
  "- `debugbundle watch --log <file> --format <format> [--json]`",
16785
17004
  "- `debugbundle watch --cloud --log <file> --format <format> [--json]`",
16786
- "- `debugbundle process [--json]`",
17005
+ "- `debugbundle process [--preset <minimal|balanced|investigative>] [--json]`",
16787
17006
  "",
16788
17007
  "## Investigation",
16789
17008
  "",
@@ -17392,16 +17611,6 @@ function createCliHttpClient(input, dependencies) {
17392
17611
  }
17393
17612
 
17394
17613
  // ../cli/src/capture-policy-commands.ts
17395
- var ResolvedCapturePolicySchema = external_exports.object({
17396
- preset: CapturePresetSchema,
17397
- capture_logs: CaptureLogsSchema,
17398
- capture_request_events: CaptureRequestEventsSchema,
17399
- capture_breadcrumbs: CaptureBreadcrumbsSchema,
17400
- capture_probe_events: CaptureProbeEventsSchema
17401
- });
17402
- var CapturePolicyResponseSchema = external_exports.object({
17403
- policy: ResolvedCapturePolicySchema
17404
- });
17405
17614
  var CapturePolicyApiError = class extends Error {
17406
17615
  status;
17407
17616
  constructor(status, message) {
@@ -17431,7 +17640,7 @@ function createCapturePolicyApi(httpClient) {
17431
17640
  if (!parsed.success) {
17432
17641
  throw new CapturePolicyApiError(500, "Invalid capture policy response.");
17433
17642
  }
17434
- return parsed.data.policy;
17643
+ return parsed.data;
17435
17644
  },
17436
17645
  async updateCapturePolicy(input) {
17437
17646
  const response = await httpClient.request({
@@ -17447,7 +17656,7 @@ function createCapturePolicyApi(httpClient) {
17447
17656
  if (!parsed.success) {
17448
17657
  throw new CapturePolicyApiError(500, "Invalid capture policy response.");
17449
17658
  }
17450
- return parsed.data.policy;
17659
+ return parsed.data;
17451
17660
  }
17452
17661
  };
17453
17662
  }
@@ -17875,7 +18084,7 @@ function getRequestResponseStatus(payload) {
17875
18084
  const status = payload?.["response_status"];
17876
18085
  return typeof status === "number" && Number.isFinite(status) ? status : null;
17877
18086
  }
17878
- function classifyEvent(eventType, logLevel, probeActivationId, payload) {
18087
+ function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal", immediateClientErrorStatuses = []) {
17879
18088
  switch (eventType) {
17880
18089
  case "backend_exception":
17881
18090
  case "frontend_exception":
@@ -17887,10 +18096,7 @@ function classifyEvent(eventType, logLevel, probeActivationId, payload) {
17887
18096
  return "context_signal";
17888
18097
  case "request_event": {
17889
18098
  const responseStatus = getRequestResponseStatus(payload);
17890
- if (responseStatus !== null && responseStatus >= 500) {
17891
- return "incident_signal";
17892
- }
17893
- return "context_signal";
18099
+ return classifyRequestStatus({ responseStatus, capturePreset, immediateClientErrorStatuses });
17894
18100
  }
17895
18101
  case "frontend_breadcrumb":
17896
18102
  case "deploy_metadata":
@@ -18052,7 +18258,7 @@ function buildPrivacyPreview() {
18052
18258
  sample_event_type: sampleEvent.event_type,
18053
18259
  sample_event_class: sampleEventClass,
18054
18260
  sample_can_create_incident: sampleEventClass === "incident_signal",
18055
- incident_rule: "request_event with response_status >= 500 is classified as an incident_signal",
18261
+ incident_rule: "request_event incident classification follows the resolved capture preset: 5xx always create incidents, balanced also promotes 408/423/424/425/429, and investigative also promotes 409.",
18056
18262
  redacted_fields,
18057
18263
  omitted_fields: [],
18058
18264
  retained_metadata: {
@@ -18563,7 +18769,8 @@ function buildRedactionRecord(bundleBody) {
18563
18769
  function buildVisibilityRecord(input) {
18564
18770
  const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
18565
18771
  const matchedFields = input.incident.matched_fields.length === 0 ? "none" : input.incident.matched_fields.join(", ");
18566
- const grouping = input.primarySignal.kind === "request_failure_5xx" && input.primarySignal.request_method !== null && routeTarget !== null ? `Repeated 5xx request failures with the same normalized route template, request method, response status, service, and environment reuse this incident fingerprint. This incident currently groups ${input.primarySignal.request_method} ${routeTarget} with matched fields ${matchedFields}.` : `This incident groups repeated failures by fingerprint version ${input.incident.fingerprint_version} inside the service and environment boundary, with matched fields ${matchedFields}.`;
18772
+ const isRequestAnomaly = input.incident.matched_fields.includes("request_anomaly");
18773
+ const grouping = input.primarySignal.kind === "request_failure" && input.primarySignal.request_method !== null && routeTarget !== null ? isRequestAnomaly ? `Repeated request-anomaly incidents with the same normalized route template, request method, response status, service, and environment reuse this incident fingerprint once the anomaly threshold fires. This incident currently groups ${input.primarySignal.request_method} ${routeTarget} with matched fields ${matchedFields}.` : `Repeated request-failure incidents with the same normalized route template, request method, response status, service, and environment reuse this incident fingerprint. This incident currently groups ${input.primarySignal.request_method} ${routeTarget} with matched fields ${matchedFields}.` : `This incident groups repeated failures by fingerprint version ${input.incident.fingerprint_version} inside the service and environment boundary, with matched fields ${matchedFields}.`;
18567
18774
  const spikeLead = input.incident.spike_detected_at === void 0 || input.incident.spike_detected_at === null ? "This incident is not currently marked as spiking." : `This incident was marked as spiking at ${input.incident.spike_detected_at}.`;
18568
18775
  return {
18569
18776
  grouping,
@@ -18574,15 +18781,16 @@ function buildVisibilityRecord(input) {
18574
18781
  }
18575
18782
  function buildSuggestedNextChecks(input) {
18576
18783
  const suggestions = [];
18784
+ const isRequestAnomaly = input.incident.matched_fields.includes("request_anomaly");
18577
18785
  if (input.bundle.status === "pending") {
18578
18786
  suggestions.push("Wait for bundle generation to finish, then rerun the incident context command.");
18579
18787
  } else if (input.bundle.status === "failed") {
18580
18788
  suggestions.push("Inspect bundle generation status or retry bundle retrieval to recover missing context.");
18581
18789
  }
18582
18790
  const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
18583
- if (input.primarySignal.request_method !== null && input.primarySignal.response_status !== null && input.primarySignal.response_status >= 500) {
18791
+ if (input.primarySignal.kind === "request_failure" && input.primarySignal.request_method !== null && routeTarget !== null) {
18584
18792
  suggestions.push(
18585
- `Inspect the ${input.primarySignal.request_method} ${routeTarget ?? "request"} handler behind this 5xx path.`
18793
+ isRequestAnomaly ? `Inspect the ${input.primarySignal.request_method} ${routeTarget} handler behind this repeated request-anomaly path.` : `Inspect the ${input.primarySignal.request_method} ${routeTarget} handler behind this request-failure path.`
18586
18794
  );
18587
18795
  }
18588
18796
  const firstApplicationFrame = input.primarySignal.first_application_frame;
@@ -18671,12 +18879,13 @@ function deriveIncidentReasonFromSignal(input) {
18671
18879
  };
18672
18880
  case "request_event": {
18673
18881
  const responseStatus = typeof input.response_status === "number" && Number.isFinite(input.response_status) ? input.response_status : null;
18882
+ const isRequestAnomaly = input.request_anomaly === true;
18674
18883
  return {
18675
- kind: "request_failure_5xx",
18676
- description: responseStatus !== null && responseStatus >= 500 ? `request_event response_status=${responseStatus} matched the 5xx request incident rule` : "request_event matched the 5xx request incident rule",
18884
+ kind: "request_failure",
18885
+ description: isRequestAnomaly ? responseStatus !== null ? `request_event response_status=${responseStatus} crossed the repeated request anomaly threshold` : "request_event crossed the repeated request anomaly threshold" : responseStatus !== null ? `request_event response_status=${responseStatus} matched the immediate request failure incident rule` : "request_event matched the immediate request failure incident rule",
18677
18886
  event_type: "request_event",
18678
18887
  event_class: "incident_signal",
18679
- matched_policy: "5xx request failures bypass capture_request_events suppression"
18888
+ matched_policy: isRequestAnomaly ? "Repeated contextual request failures crossed the request anomaly threshold" : "Immediate request failure statuses bypass capture_request_events suppression"
18680
18889
  };
18681
18890
  }
18682
18891
  case "log_event": {
@@ -18779,6 +18988,46 @@ var STORAGE_SCHEMA_MIGRATIONS = [
18779
18988
  ON github_device_authorizations (expires_at)
18780
18989
  `
18781
18990
  ]
18991
+ }),
18992
+ defineStorageSchemaMigration({
18993
+ id: "202605130001_allow_synthetic_webhook_test_deliveries_without_incident_fk",
18994
+ description: "Allow webhook test deliveries to persist without requiring a backing incidents row.",
18995
+ statements: [
18996
+ "ALTER TABLE webhook_deliveries ALTER COLUMN incident_id DROP NOT NULL"
18997
+ ]
18998
+ }),
18999
+ defineStorageSchemaMigration({
19000
+ id: "202605130002_add_slack_destinations",
19001
+ description: "Add reusable encrypted Slack alert destinations scoped to organizations.",
19002
+ statements: [
19003
+ `
19004
+ CREATE TABLE IF NOT EXISTS slack_destinations (
19005
+ id uuid PRIMARY KEY,
19006
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
19007
+ slack_team_id text NOT NULL,
19008
+ slack_team_name text,
19009
+ slack_channel_id text NOT NULL,
19010
+ slack_channel_name text,
19011
+ webhook_url_ciphertext text NOT NULL,
19012
+ installed_by_member_id uuid REFERENCES users(id) ON DELETE SET NULL,
19013
+ is_active boolean NOT NULL DEFAULT true,
19014
+ created_at timestamptz NOT NULL DEFAULT now(),
19015
+ updated_at timestamptz NOT NULL DEFAULT now(),
19016
+ UNIQUE (organization_id, slack_team_id, slack_channel_id)
19017
+ )
19018
+ `,
19019
+ `
19020
+ CREATE INDEX IF NOT EXISTS slack_destinations_org_active_idx
19021
+ ON slack_destinations (organization_id, is_active, created_at)
19022
+ `
19023
+ ]
19024
+ }),
19025
+ defineStorageSchemaMigration({
19026
+ id: "202605140001_add_capture_policy_immediate_client_error_statuses",
19027
+ description: "Add nullable immediate client error status overrides to capture policies.",
19028
+ statements: [
19029
+ "ALTER TABLE capture_policies ADD COLUMN IF NOT EXISTS immediate_client_error_statuses jsonb"
19030
+ ]
18782
19031
  })
18783
19032
  ];
18784
19033
 
@@ -19799,11 +20048,17 @@ var EVENT_TYPE_SET = new Set(EventTypeValues);
19799
20048
  function isEventType(value) {
19800
20049
  return typeof value === "string" && EVENT_TYPE_SET.has(value);
19801
20050
  }
19802
- function inferSeverity2(eventType) {
19803
- if (eventType === "backend_exception" || eventType === "frontend_exception") {
20051
+ function inferSeverity2(event, capturePreset, incidentKind = "immediate") {
20052
+ if (incidentKind === "request_anomaly") {
20053
+ return "medium";
20054
+ }
20055
+ if (event.event_type === "request_event") {
20056
+ return classifyRequestStatus({ responseStatus: event.payload.response_status, capturePreset }) === "incident_signal" ? "high" : "low";
20057
+ }
20058
+ if (event.event_type === "backend_exception" || event.event_type === "frontend_exception") {
19804
20059
  return "high";
19805
20060
  }
19806
- if (eventType === "error_suppressed") {
20061
+ if (event.event_type === "error_suppressed") {
19807
20062
  return "medium";
19808
20063
  }
19809
20064
  return "low";
@@ -19827,15 +20082,17 @@ function compareEventEnvelopes(left, right) {
19827
20082
  }
19828
20083
  return left.event_id.localeCompare(right.event_id);
19829
20084
  }
19830
- function classifyEnvelope(envelope) {
20085
+ function classifyEnvelope(envelope, capturePreset) {
19831
20086
  return classifyEvent(
19832
20087
  envelope.event_type,
19833
20088
  envelope.event_type === "log_event" ? envelope.payload.level : void 0,
19834
- envelope.event_type === "probe_event" ? envelope.payload.activation_id : void 0
20089
+ envelope.event_type === "probe_event" ? envelope.payload.activation_id : void 0,
20090
+ envelope.payload,
20091
+ capturePreset
19835
20092
  );
19836
20093
  }
19837
- function isIncidentSignalEnvelope(envelope) {
19838
- return classifyEnvelope(envelope) === "incident_signal";
20094
+ function isIncidentSignalEnvelope(envelope, capturePreset) {
20095
+ return classifyEnvelope(envelope, capturePreset) === "incident_signal";
19839
20096
  }
19840
20097
  function getTraceId(envelope) {
19841
20098
  return envelope.correlation?.trace_id ?? null;
@@ -19880,7 +20137,10 @@ function mergeAggregateGroup(aggregates) {
19880
20137
  newEvents: [...canonicalAggregate.newEvents],
19881
20138
  mergedIncidentIds: new Set(canonicalAggregate.mergedIncidentIds),
19882
20139
  signalEventTypes: new Set(canonicalAggregate.signalEventTypes),
19883
- traceIds: new Set(canonicalAggregate.traceIds)
20140
+ traceIds: new Set(canonicalAggregate.traceIds),
20141
+ title: canonicalAggregate.title,
20142
+ kind: canonicalAggregate.kind,
20143
+ severity: canonicalAggregate.severity
19884
20144
  });
19885
20145
  }
19886
20146
  function hashIdentifier(parts, prefix, length) {
@@ -19906,6 +20166,111 @@ function mergeSourceEvents(existingEvents, nextEvents) {
19906
20166
  }
19907
20167
  return [...merged.values()].sort(compareEventEnvelopes);
19908
20168
  }
20169
+ function stableJson2(value) {
20170
+ if (value === null || typeof value !== "object") {
20171
+ return JSON.stringify(value);
20172
+ }
20173
+ if (Array.isArray(value)) {
20174
+ return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
20175
+ }
20176
+ const record = value;
20177
+ const keys = Object.keys(record).sort();
20178
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
20179
+ }
20180
+ function buildRequestAnomalyFingerprint(input) {
20181
+ return (0, import_node_crypto4.createHash)("sha256").update(
20182
+ stableJson2({
20183
+ kind: "request_status_anomaly",
20184
+ project_id: input.projectId,
20185
+ service_name: input.serviceName,
20186
+ environment: input.environment,
20187
+ method: input.method,
20188
+ route_template: input.routeTemplate,
20189
+ response_status: input.responseStatus
20190
+ })
20191
+ ).digest("hex");
20192
+ }
20193
+ function buildRequestAnomalyTitle(input) {
20194
+ return `Request anomaly: ${input.method} ${input.routeTemplate} returned ${input.responseStatus} repeatedly`;
20195
+ }
20196
+ function toUnixSeconds(occurredAt) {
20197
+ return Math.floor(new Date(occurredAt).getTime() / 1e3);
20198
+ }
20199
+ function countOccurrencesInWindow(events, windowSeconds) {
20200
+ const latestEvent = events.at(-1);
20201
+ if (latestEvent === void 0) {
20202
+ return 0;
20203
+ }
20204
+ const latestOccurredAt = toUnixSeconds(latestEvent.occurred_at);
20205
+ const lowerBound = latestOccurredAt - windowSeconds + 1;
20206
+ return events.filter((event) => {
20207
+ const occurredAt = toUnixSeconds(event.occurred_at);
20208
+ return occurredAt >= lowerBound && occurredAt <= latestOccurredAt;
20209
+ }).length;
20210
+ }
20211
+ function passesRequestAnomalyThreshold(events, threshold) {
20212
+ const occurrences5m = countOccurrencesInWindow(events, 5 * 60);
20213
+ const occurrences1h = countOccurrencesInWindow(events, 60 * 60);
20214
+ const baseline1hPer5m = occurrences1h / 12;
20215
+ const ratio = occurrences5m / Math.max(baseline1hPer5m, 1);
20216
+ return occurrences5m >= threshold.minimum_occurrences_5m && ratio >= threshold.minimum_ratio_5m_to_1h;
20217
+ }
20218
+ function collectRequestAnomalyAggregates(batches, capturePreset) {
20219
+ const grouped = /* @__PURE__ */ new Map();
20220
+ for (const batch of batches) {
20221
+ for (const event of batch.events) {
20222
+ if (event.event_type !== "request_event" || classifyEnvelope(event, capturePreset) !== "context_signal") {
20223
+ continue;
20224
+ }
20225
+ const normalizedEvent = normalizeEvent(event);
20226
+ const responseStatus = normalizedEvent.http_status;
20227
+ const method = normalizedEvent.http_method;
20228
+ const routeTemplate = normalizedEvent.route_template;
20229
+ const threshold = getRequestAnomalyThreshold({ responseStatus, capturePreset });
20230
+ if (threshold === null || responseStatus === null || method === null || routeTemplate === null) {
20231
+ continue;
20232
+ }
20233
+ const projectId = requireProjectId(event);
20234
+ const incidentFingerprint = buildRequestAnomalyFingerprint({
20235
+ projectId,
20236
+ serviceName: event.service.name,
20237
+ environment: event.service.environment,
20238
+ method,
20239
+ routeTemplate,
20240
+ responseStatus
20241
+ });
20242
+ const incidentId = deriveIncidentId(projectId, event.service.name, event.service.environment, incidentFingerprint);
20243
+ const aggregate = grouped.get(incidentId) ?? {
20244
+ incidentId,
20245
+ projectId,
20246
+ serviceName: event.service.name,
20247
+ environment: event.service.environment,
20248
+ fingerprint: incidentFingerprint,
20249
+ matchedFields: /* @__PURE__ */ new Set(["request_anomaly", "route_template", "http_method", "http_status", "environment"]),
20250
+ newEvents: [],
20251
+ mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
20252
+ signalEventTypes: /* @__PURE__ */ new Set(["request_event"]),
20253
+ traceIds: /* @__PURE__ */ new Set(),
20254
+ title: buildRequestAnomalyTitle({ method, routeTemplate, responseStatus }),
20255
+ kind: "request_anomaly",
20256
+ severity: "medium"
20257
+ };
20258
+ aggregate.newEvents.push(event);
20259
+ grouped.set(incidentId, aggregate);
20260
+ }
20261
+ }
20262
+ return [...grouped.values()].filter((aggregate) => {
20263
+ const latestEvent = aggregate.newEvents.at(-1);
20264
+ if (latestEvent === void 0 || latestEvent.event_type !== "request_event") {
20265
+ return false;
20266
+ }
20267
+ const threshold = getRequestAnomalyThreshold({
20268
+ responseStatus: normalizeEvent(latestEvent).http_status,
20269
+ capturePreset
20270
+ });
20271
+ return threshold !== null && passesRequestAnomalyThreshold(aggregate.newEvents, threshold);
20272
+ }).sort((left, right) => left.incidentId.localeCompare(right.incidentId));
20273
+ }
19909
20274
  function buildBundleContext(incident) {
19910
20275
  return {
19911
20276
  incident_id: incident.incident_id,
@@ -19935,12 +20300,12 @@ function formatServiceSummary(services) {
19935
20300
  }
19936
20301
  function formatProcessOutput(summary) {
19937
20302
  if (!summary.processed) {
19938
- return summary.message ?? "No new events to process.";
20303
+ return summary.message;
19939
20304
  }
19940
20305
  return [
19941
20306
  `Processed ${summary.events_processed} events from ${summary.files_processed} files into ${summary.incidents_processed} incidents.`,
19942
20307
  ...formatServiceSummary(summary.services),
19943
- `Last processed event file: ${summary.last_processed_event_file ?? "none"}`
20308
+ `Last processed event file: ${summary.last_processed_event_file}`
19944
20309
  ].join("\n");
19945
20310
  }
19946
20311
  async function pathExists4(path, stat) {
@@ -20180,6 +20545,7 @@ async function processCommand(input, dependencies = {}) {
20180
20545
  const statePath = (0, import_node_path6.join)(rootDirectory, LOCAL_STATE_FILE_PATH);
20181
20546
  const bundleDirectoryPath = (0, import_node_path6.join)(rootDirectory, LOCAL_BUNDLE_DIRECTORY_PATH2);
20182
20547
  const reproductionDirectoryPath = (0, import_node_path6.join)(rootDirectory, LOCAL_REPRODUCTION_DIRECTORY_PATH);
20548
+ const capturePreset = input.preset ?? "minimal";
20183
20549
  await mkdir((0, import_node_path6.join)(rootDirectory, ".debugbundle", "local"), { recursive: true });
20184
20550
  await mkdir(bundleDirectoryPath, { recursive: true });
20185
20551
  await mkdir(reproductionDirectoryPath, { recursive: true });
@@ -20187,22 +20553,26 @@ async function processCommand(input, dependencies = {}) {
20187
20553
  const eventFileNames = await pathExists4(eventsDirectoryPath, stat) ? (await readdir(eventsDirectoryPath)).filter((fileName) => fileName.endsWith(".events.json")).sort() : [];
20188
20554
  const lastProcessedEventFile = previousState?.last_processed_event_file ?? null;
20189
20555
  const newEventFileNames = lastProcessedEventFile === null ? eventFileNames : eventFileNames.filter((fileName) => fileName > lastProcessedEventFile);
20190
- if (newEventFileNames.length === 0) {
20556
+ const processAllEventFiles = input.preset !== void 0;
20557
+ const targetEventFileNames = processAllEventFiles ? eventFileNames : newEventFileNames;
20558
+ if (targetEventFileNames.length === 0) {
20191
20559
  const summary2 = buildNoNewEventsSummary(previousState?.last_processed_event_file ?? eventFileNames.at(-1) ?? null);
20192
20560
  return {
20193
20561
  exitCode: 0,
20194
20562
  output: input.json === true ? JSON.stringify(summary2) : formatProcessOutput(summary2)
20195
20563
  };
20196
20564
  }
20197
- const batches = await readEventBatches(eventsDirectoryPath, newEventFileNames, readFile);
20198
- const incidents = new Map(Object.entries(previousState?.incidents ?? {}));
20565
+ const batches = await readEventBatches(eventsDirectoryPath, targetEventFileNames, readFile);
20566
+ const incidents = new Map(
20567
+ processAllEventFiles ? [] : Object.entries(previousState?.incidents ?? {})
20568
+ );
20199
20569
  const aggregates = /* @__PURE__ */ new Map();
20200
20570
  const traceCorrelationGroups = /* @__PURE__ */ new Map();
20201
20571
  let eventsProcessed = 0;
20202
20572
  for (const batch of batches) {
20203
20573
  for (const event of batch.events) {
20204
20574
  eventsProcessed += 1;
20205
- if (!isIncidentSignalEnvelope(event)) {
20575
+ if (!isIncidentSignalEnvelope(event, capturePreset)) {
20206
20576
  continue;
20207
20577
  }
20208
20578
  const normalizedEvent = normalizeEvent(event);
@@ -20219,7 +20589,10 @@ async function processCommand(input, dependencies = {}) {
20219
20589
  newEvents: [],
20220
20590
  mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
20221
20591
  signalEventTypes: /* @__PURE__ */ new Set(),
20222
- traceIds: /* @__PURE__ */ new Set()
20592
+ traceIds: /* @__PURE__ */ new Set(),
20593
+ title: normalizedEvent.normalized_message,
20594
+ kind: "immediate",
20595
+ severity: inferSeverity2(event, capturePreset)
20223
20596
  };
20224
20597
  for (const matchedField of inferMatchedFields(normalizedEvent)) {
20225
20598
  aggregate.matchedFields.add(matchedField);
@@ -20286,14 +20659,16 @@ async function processCommand(input, dependencies = {}) {
20286
20659
  mergedAggregatesByRoot.set(rootIncidentId, aggregateGroup);
20287
20660
  }
20288
20661
  const mergedAggregates = [...mergedAggregatesByRoot.values()].map((aggregateGroup) => mergeAggregateGroup(aggregateGroup)).sort((left, right) => left.incidentId.localeCompare(right.incidentId));
20662
+ const requestAnomalyAggregates = input.preset === void 0 ? [] : collectRequestAnomalyAggregates(batches, capturePreset);
20663
+ const finalizedAggregates = [...mergedAggregates, ...requestAnomalyAggregates].sort((left, right) => left.incidentId.localeCompare(right.incidentId));
20289
20664
  const services = /* @__PURE__ */ new Map();
20290
- for (const aggregate of mergedAggregates) {
20665
+ for (const aggregate of finalizedAggregates) {
20291
20666
  const incidentId = aggregate.incidentId;
20292
20667
  const existingIncidents = [...aggregate.mergedIncidentIds].map((mergedIncidentId) => incidents.get(mergedIncidentId)).filter((incident2) => incident2 !== void 0);
20293
20668
  const existing = existingIncidents.find((incident2) => incident2.incident_id === incidentId) ?? existingIncidents[0];
20294
20669
  const existingSourceEvents = existingIncidents.flatMap((incident2) => incident2.source_events);
20295
20670
  const combinedSourceEvents = mergeSourceEvents(existingSourceEvents, aggregate.newEvents);
20296
- const signalEvents = combinedSourceEvents.filter(isIncidentSignalEnvelope);
20671
+ const signalEvents = aggregate.kind === "request_anomaly" ? combinedSourceEvents : combinedSourceEvents.filter((event) => isIncidentSignalEnvelope(event, capturePreset));
20297
20672
  if (signalEvents.length === 0) {
20298
20673
  continue;
20299
20674
  }
@@ -20303,8 +20678,7 @@ async function processCommand(input, dependencies = {}) {
20303
20678
  continue;
20304
20679
  }
20305
20680
  const sourceEventTypes = [...new Set(signalEvents.map((event) => event.event_type))].sort();
20306
- const severity = signalEvents.map((event) => inferSeverity2(event.event_type)).sort((left, right) => severityRank(right) - severityRank(left))[0] ?? "low";
20307
- const latestNormalizedEvent = normalizeEvent(latestSignalEvent);
20681
+ const severity = signalEvents.map((event) => inferSeverity2(event, capturePreset, aggregate.kind)).sort((left, right) => severityRank(right) - severityRank(left))[0] ?? aggregate.severity;
20308
20682
  const generationNumber = signalEvents.length;
20309
20683
  const bundlePath = `${LOCAL_BUNDLE_DIRECTORY_PATH2}/${incidentId}.bundle.json`;
20310
20684
  const reproductionPath = `${LOCAL_REPRODUCTION_DIRECTORY_PATH}/${incidentId}.reproduction.json`;
@@ -20319,7 +20693,7 @@ async function processCommand(input, dependencies = {}) {
20319
20693
  environment: aggregate.environment,
20320
20694
  fingerprint: aggregate.fingerprint,
20321
20695
  fingerprint_version: FINGERPRINT_VERSION,
20322
- title: latestNormalizedEvent.normalized_message,
20696
+ title: aggregate.title,
20323
20697
  severity,
20324
20698
  status: existingIncidents.some((incidentState) => incidentState.status === "resolved") ? "open" : existing?.status ?? "open",
20325
20699
  first_seen_at: firstSignalEvent.occurred_at,
@@ -20380,21 +20754,22 @@ async function processCommand(input, dependencies = {}) {
20380
20754
  incidents.set(incidentId, incident);
20381
20755
  services.set(incident.service_name, (services.get(incident.service_name) ?? 0) + 1);
20382
20756
  }
20757
+ const finalProcessedEventFile = targetEventFileNames[targetEventFileNames.length - 1];
20383
20758
  const nextState = {
20384
20759
  version: 1,
20385
- last_processed_event_file: newEventFileNames.at(-1) ?? previousState?.last_processed_event_file ?? null,
20760
+ last_processed_event_file: finalProcessedEventFile,
20386
20761
  incidents: Object.fromEntries([...incidents.entries()].sort(([left], [right]) => left.localeCompare(right)))
20387
20762
  };
20388
20763
  await writeFile(statePath, serializeState(nextState));
20389
20764
  const summary = buildProcessedSummary({
20390
20765
  filesProcessed: newEventFileNames.length,
20391
20766
  eventsProcessed,
20392
- incidentsProcessed: mergedAggregates.length,
20767
+ incidentsProcessed: finalizedAggregates.length,
20393
20768
  services: [...services.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([service, count]) => ({
20394
20769
  service,
20395
20770
  incidents: count
20396
20771
  })),
20397
- lastProcessedEventFile: nextState.last_processed_event_file
20772
+ lastProcessedEventFile: finalProcessedEventFile
20398
20773
  });
20399
20774
  return {
20400
20775
  exitCode: 0,
@@ -20510,7 +20885,11 @@ function parseLocalIncident(candidate) {
20510
20885
  }
20511
20886
  const serviceRuntime = candidate["service_runtime"];
20512
20887
  const serviceFramework = candidate["service_framework"];
20513
- const incidentReason = deriveIncidentReasonFromSourceEventTypes(candidate["source_event_types"]);
20888
+ const incidentReason = candidate["matched_fields"].includes("request_anomaly") ? deriveIncidentReasonFromSignal({
20889
+ event_type: "request_event",
20890
+ event_class: "incident_signal",
20891
+ request_anomaly: true
20892
+ }) : deriveIncidentReasonFromSourceEventTypes(candidate["source_event_types"]);
20514
20893
  if (serviceRuntime !== null && typeof serviceRuntime !== "string") {
20515
20894
  throw createReadError(400, "invalid_local_state");
20516
20895
  }
@@ -20816,14 +21195,14 @@ function localFailureStepName(checks) {
20816
21195
  function cloudVerificationRunId(now) {
20817
21196
  return now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
20818
21197
  }
20819
- function requestFailure5xxReason() {
21198
+ function requestFailureReason() {
20820
21199
  const incidentReason = deriveIncidentReasonFromSignal({
20821
21200
  event_type: "request_event",
20822
21201
  event_class: "incident_signal",
20823
21202
  response_status: 503
20824
21203
  });
20825
21204
  if (incidentReason === null) {
20826
- throw new Error("request_failure_5xx_reason_unavailable");
21205
+ throw new Error("request_failure_reason_unavailable");
20827
21206
  }
20828
21207
  return incidentReason;
20829
21208
  }
@@ -21098,7 +21477,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
21098
21477
  const verification = {
21099
21478
  mode: "active_5xx",
21100
21479
  bundle_status: "unknown",
21101
- classification_reason: requestFailure5xxReason()
21480
+ classification_reason: requestFailureReason()
21102
21481
  };
21103
21482
  const errors = [];
21104
21483
  let exitCode = 0;
@@ -21150,7 +21529,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
21150
21529
  if (candidate !== void 0) {
21151
21530
  incidentId = candidate.incident_id;
21152
21531
  verification.incident_id = candidate.incident_id;
21153
- verification.classification_reason = candidate.incident_reason ?? requestFailure5xxReason();
21532
+ verification.classification_reason = candidate.incident_reason ?? requestFailureReason();
21154
21533
  break;
21155
21534
  }
21156
21535
  if (attempt < pollAttempts) {
@@ -21813,12 +22192,10 @@ function createCapturePolicyMcpTools(api) {
21813
22192
  return {
21814
22193
  async get_capture_policy(input) {
21815
22194
  try {
21816
- return {
21817
- policy: await api.getCapturePolicy({
21818
- bearerToken: String(input["bearerToken"]),
21819
- projectId: String(input["projectId"])
21820
- })
21821
- };
22195
+ return await api.getCapturePolicy({
22196
+ bearerToken: String(input["bearerToken"]),
22197
+ projectId: String(input["projectId"])
22198
+ });
21822
22199
  } catch (error) {
21823
22200
  mapMcpError4(error);
21824
22201
  }
@@ -21826,13 +22203,11 @@ function createCapturePolicyMcpTools(api) {
21826
22203
  async update_capture_policy(input) {
21827
22204
  try {
21828
22205
  const update = typeof input["update"] === "object" && input["update"] !== null ? input["update"] : {};
21829
- return {
21830
- policy: await api.updateCapturePolicy({
21831
- bearerToken: String(input["bearerToken"]),
21832
- projectId: String(input["projectId"]),
21833
- update
21834
- })
21835
- };
22206
+ return await api.updateCapturePolicy({
22207
+ bearerToken: String(input["bearerToken"]),
22208
+ projectId: String(input["projectId"]),
22209
+ update
22210
+ });
21836
22211
  } catch (error) {
21837
22212
  mapMcpError4(error);
21838
22213
  }
@@ -22927,8 +23302,71 @@ function createSetupMcpTools(commands) {
22927
23302
  };
22928
23303
  }
22929
23304
 
22930
- // src/token-tools.ts
23305
+ // src/slack-tools.ts
22931
23306
  function mapMcpError12(error) {
23307
+ if (error instanceof SlackApiError) {
23308
+ throw new Error(`mcp_tool_error:${error.code}`);
23309
+ }
23310
+ throw new Error("mcp_tool_error:unknown_error");
23311
+ }
23312
+ function createSlackMcpTools(api) {
23313
+ return {
23314
+ async list_slack_destinations(input) {
23315
+ try {
23316
+ return {
23317
+ destinations: await api.listSlackDestinations({
23318
+ bearerToken: String(input["bearerToken"]),
23319
+ projectId: String(input["projectId"])
23320
+ })
23321
+ };
23322
+ } catch (error) {
23323
+ mapMcpError12(error);
23324
+ }
23325
+ },
23326
+ async get_slack_connect_url(input) {
23327
+ try {
23328
+ return {
23329
+ install_url: await api.getSlackInstallUrl({
23330
+ bearerToken: String(input["bearerToken"]),
23331
+ projectId: String(input["projectId"]),
23332
+ ...typeof input["returnTo"] === "string" ? { returnTo: input["returnTo"] } : {}
23333
+ })
23334
+ };
23335
+ } catch (error) {
23336
+ mapMcpError12(error);
23337
+ }
23338
+ },
23339
+ async test_slack_destination(input) {
23340
+ try {
23341
+ return {
23342
+ delivery: await api.testSlackDestination({
23343
+ bearerToken: String(input["bearerToken"]),
23344
+ projectId: String(input["projectId"]),
23345
+ destinationId: String(input["destinationId"])
23346
+ })
23347
+ };
23348
+ } catch (error) {
23349
+ mapMcpError12(error);
23350
+ }
23351
+ },
23352
+ async delete_slack_destination(input) {
23353
+ try {
23354
+ return {
23355
+ destination: await api.deleteSlackDestination({
23356
+ bearerToken: String(input["bearerToken"]),
23357
+ projectId: String(input["projectId"]),
23358
+ destinationId: String(input["destinationId"])
23359
+ })
23360
+ };
23361
+ } catch (error) {
23362
+ mapMcpError12(error);
23363
+ }
23364
+ }
23365
+ };
23366
+ }
23367
+
23368
+ // src/token-tools.ts
23369
+ function mapMcpError13(error) {
22932
23370
  if (error instanceof TokenManagementApiError) {
22933
23371
  throw new Error(`mcp_tool_error:${error.code}`);
22934
23372
  }
@@ -22949,7 +23387,7 @@ function createTokenMcpTools(api) {
22949
23387
  tokens: await api.listProjectTokens(requestInput)
22950
23388
  };
22951
23389
  } catch (error) {
22952
- mapMcpError12(error);
23390
+ mapMcpError13(error);
22953
23391
  }
22954
23392
  },
22955
23393
  async create_project_token(input) {
@@ -22962,7 +23400,7 @@ function createTokenMcpTools(api) {
22962
23400
  })
22963
23401
  };
22964
23402
  } catch (error) {
22965
- mapMcpError12(error);
23403
+ mapMcpError13(error);
22966
23404
  }
22967
23405
  },
22968
23406
  async revoke_project_token(input) {
@@ -22975,7 +23413,7 @@ function createTokenMcpTools(api) {
22975
23413
  })
22976
23414
  };
22977
23415
  } catch (error) {
22978
- mapMcpError12(error);
23416
+ mapMcpError13(error);
22979
23417
  }
22980
23418
  },
22981
23419
  async list_member_tokens(input) {
@@ -22990,7 +23428,7 @@ function createTokenMcpTools(api) {
22990
23428
  tokens: await api.listMemberTokens(requestInput)
22991
23429
  };
22992
23430
  } catch (error) {
22993
- mapMcpError12(error);
23431
+ mapMcpError13(error);
22994
23432
  }
22995
23433
  },
22996
23434
  async create_member_token(input) {
@@ -23002,7 +23440,7 @@ function createTokenMcpTools(api) {
23002
23440
  })
23003
23441
  };
23004
23442
  } catch (error) {
23005
- mapMcpError12(error);
23443
+ mapMcpError13(error);
23006
23444
  }
23007
23445
  },
23008
23446
  async revoke_member_token(input) {
@@ -23014,14 +23452,14 @@ function createTokenMcpTools(api) {
23014
23452
  })
23015
23453
  };
23016
23454
  } catch (error) {
23017
- mapMcpError12(error);
23455
+ mapMcpError13(error);
23018
23456
  }
23019
23457
  }
23020
23458
  };
23021
23459
  }
23022
23460
 
23023
23461
  // src/webhook-tools.ts
23024
- function mapMcpError13(error) {
23462
+ function mapMcpError14(error) {
23025
23463
  if (error instanceof WebhookApiError) {
23026
23464
  throw new Error(`mcp_tool_error:${error.code}`);
23027
23465
  }
@@ -23042,7 +23480,7 @@ function createWebhookMcpTools(api) {
23042
23480
  webhooks: await api.listWebhooks(requestInput)
23043
23481
  };
23044
23482
  } catch (error) {
23045
- mapMcpError13(error);
23483
+ mapMcpError14(error);
23046
23484
  }
23047
23485
  },
23048
23486
  async create_webhook(input) {
@@ -23063,7 +23501,7 @@ function createWebhookMcpTools(api) {
23063
23501
  webhook: await api.createWebhook(requestInput)
23064
23502
  };
23065
23503
  } catch (error) {
23066
- mapMcpError13(error);
23504
+ mapMcpError14(error);
23067
23505
  }
23068
23506
  },
23069
23507
  async update_webhook(input) {
@@ -23088,7 +23526,7 @@ function createWebhookMcpTools(api) {
23088
23526
  webhook: await api.updateWebhook(requestInput)
23089
23527
  };
23090
23528
  } catch (error) {
23091
- mapMcpError13(error);
23529
+ mapMcpError14(error);
23092
23530
  }
23093
23531
  },
23094
23532
  async delete_webhook(input) {
@@ -23100,7 +23538,7 @@ function createWebhookMcpTools(api) {
23100
23538
  })
23101
23539
  };
23102
23540
  } catch (error) {
23103
- mapMcpError13(error);
23541
+ mapMcpError14(error);
23104
23542
  }
23105
23543
  },
23106
23544
  async test_webhook(input) {
@@ -23116,7 +23554,7 @@ function createWebhookMcpTools(api) {
23116
23554
  delivery: await api.testWebhook(requestInput)
23117
23555
  };
23118
23556
  } catch (error) {
23119
- mapMcpError13(error);
23557
+ mapMcpError14(error);
23120
23558
  }
23121
23559
  },
23122
23560
  async list_webhook_deliveries(input) {
@@ -23132,7 +23570,7 @@ function createWebhookMcpTools(api) {
23132
23570
  deliveries: await api.listWebhookDeliveries(requestInput)
23133
23571
  };
23134
23572
  } catch (error) {
23135
- mapMcpError13(error);
23573
+ mapMcpError14(error);
23136
23574
  }
23137
23575
  },
23138
23576
  async retry_webhook_delivery(input) {
@@ -23143,14 +23581,14 @@ function createWebhookMcpTools(api) {
23143
23581
  deliveryId: String(input["deliveryId"])
23144
23582
  });
23145
23583
  } catch (error) {
23146
- mapMcpError13(error);
23584
+ mapMcpError14(error);
23147
23585
  }
23148
23586
  }
23149
23587
  };
23150
23588
  }
23151
23589
 
23152
23590
  // src/weekly-report-tools.ts
23153
- function mapMcpError14(error) {
23591
+ function mapMcpError15(error) {
23154
23592
  if (error instanceof WeeklyReportApiError) {
23155
23593
  throw new Error(`mcp_tool_error:${error.code}`);
23156
23594
  }
@@ -23168,7 +23606,7 @@ function createWeeklyReportMcpTools(api) {
23168
23606
  })
23169
23607
  };
23170
23608
  } catch (error) {
23171
- mapMcpError14(error);
23609
+ mapMcpError15(error);
23172
23610
  }
23173
23611
  },
23174
23612
  async create_weekly_report_channel(input) {
@@ -23184,7 +23622,7 @@ function createWeeklyReportMcpTools(api) {
23184
23622
  })
23185
23623
  };
23186
23624
  } catch (error) {
23187
- mapMcpError14(error);
23625
+ mapMcpError15(error);
23188
23626
  }
23189
23627
  },
23190
23628
  async update_weekly_report_channel(input) {
@@ -23199,7 +23637,7 @@ function createWeeklyReportMcpTools(api) {
23199
23637
  })
23200
23638
  };
23201
23639
  } catch (error) {
23202
- mapMcpError14(error);
23640
+ mapMcpError15(error);
23203
23641
  }
23204
23642
  },
23205
23643
  async delete_weekly_report_channel(input) {
@@ -23211,7 +23649,7 @@ function createWeeklyReportMcpTools(api) {
23211
23649
  })
23212
23650
  };
23213
23651
  } catch (error) {
23214
- mapMcpError14(error);
23652
+ mapMcpError15(error);
23215
23653
  }
23216
23654
  }
23217
23655
  };
@@ -23262,6 +23700,7 @@ async function createDefaultMcpTools(input = {}) {
23262
23700
  ...createServicesMcpTools(retrievalApi),
23263
23701
  ...createTokenMcpTools(createTokenManagementApi(httpClient)),
23264
23702
  ...createWebhookMcpTools(createWebhookApi(httpClient)),
23703
+ ...createSlackMcpTools(createSlackApi(httpClient)),
23265
23704
  ...createWeeklyReportMcpTools(createWeeklyReportApi(httpClient)),
23266
23705
  ...createAlertMcpTools(createAlertApi(httpClient)),
23267
23706
  ...createProjectMcpTools(createProjectManagementApi(httpClient)),
@@ -24946,6 +25385,45 @@ var MCP_TOOL_CATALOG = [
24946
25385
  deliveryId: external_exports.string()
24947
25386
  })
24948
25387
  },
25388
+ {
25389
+ name: "list_slack_destinations",
25390
+ group: "slack",
25391
+ description: "List reusable connected Slack destinations for a project organization.",
25392
+ inputSchema: external_exports.object({
25393
+ bearerToken: external_exports.string(),
25394
+ projectId: external_exports.string()
25395
+ })
25396
+ },
25397
+ {
25398
+ name: "get_slack_connect_url",
25399
+ group: "slack",
25400
+ description: "Return a browser Slack connect URL for a project.",
25401
+ inputSchema: external_exports.object({
25402
+ bearerToken: external_exports.string(),
25403
+ projectId: external_exports.string(),
25404
+ returnTo: external_exports.string().optional()
25405
+ })
25406
+ },
25407
+ {
25408
+ name: "test_slack_destination",
25409
+ group: "slack",
25410
+ description: "Send a test message to a connected Slack destination.",
25411
+ inputSchema: external_exports.object({
25412
+ bearerToken: external_exports.string(),
25413
+ projectId: external_exports.string(),
25414
+ destinationId: external_exports.string()
25415
+ })
25416
+ },
25417
+ {
25418
+ name: "delete_slack_destination",
25419
+ group: "slack",
25420
+ description: "Delete a connected Slack destination from a project organization.",
25421
+ inputSchema: external_exports.object({
25422
+ bearerToken: external_exports.string(),
25423
+ projectId: external_exports.string(),
25424
+ destinationId: external_exports.string()
25425
+ })
25426
+ },
24949
25427
  {
24950
25428
  name: "list_weekly_report_channels",
24951
25429
  group: "weekly_reports",
@@ -25101,7 +25579,8 @@ var MCP_TOOL_CATALOG = [
25101
25579
  capture_logs: external_exports.string().nullable().optional(),
25102
25580
  capture_request_events: external_exports.string().nullable().optional(),
25103
25581
  capture_breadcrumbs: external_exports.string().nullable().optional(),
25104
- capture_probe_events: external_exports.string().nullable().optional()
25582
+ capture_probe_events: external_exports.string().nullable().optional(),
25583
+ immediate_client_error_statuses: external_exports.array(external_exports.number().int().min(400).max(499)).nullable().optional()
25105
25584
  })
25106
25585
  })
25107
25586
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@debugbundle/mcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.5",
4
4
  "private": false,
5
5
  "description": "Model Context Protocol server for DebugBundle",
6
6
  "license": "AGPL-3.0-only",