@debugbundle/mcp 0.1.8 → 0.1.9

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 (3) hide show
  1. package/README.md +2 -0
  2. package/dist/main.cjs +2108 -141
  3. package/package.json +3 -3
package/dist/main.cjs CHANGED
@@ -16552,6 +16552,406 @@ function getRequestAnomalyThreshold(input) {
16552
16552
  return null;
16553
16553
  }
16554
16554
 
16555
+ // ../../packages/shared-types/src/capture-rules.ts
16556
+ var CAPTURE_RULE_EVENT_TYPES = [
16557
+ "backend_exception",
16558
+ "request_event",
16559
+ "log_event",
16560
+ "frontend_breadcrumb",
16561
+ "frontend_exception",
16562
+ "deploy_metadata",
16563
+ "error_suppressed",
16564
+ "probe_event"
16565
+ ];
16566
+ var CAPTURE_RULE_RUNTIME_VALUES = [
16567
+ "browser",
16568
+ "node",
16569
+ "python",
16570
+ "php",
16571
+ "java",
16572
+ "go",
16573
+ "ruby",
16574
+ "unknown"
16575
+ ];
16576
+ var CaptureRuleActionValues = ["demote", "sample", "drop"];
16577
+ var CaptureRuleActionSchema = external_exports.enum(CaptureRuleActionValues);
16578
+ var CaptureRuleSampleEventClassValues = ["preserve", "context"];
16579
+ var CaptureRuleSampleEventClassSchema = external_exports.enum(CaptureRuleSampleEventClassValues);
16580
+ var CaptureRuleRuntimeSchema = external_exports.enum(CAPTURE_RULE_RUNTIME_VALUES);
16581
+ var CaptureRuleEventTypeSchema = external_exports.enum(CAPTURE_RULE_EVENT_TYPES);
16582
+ var BrowserEventKindSchema = external_exports.enum(["window_error", "resource_error"]);
16583
+ function normalizeOptionalTrimmedString(value) {
16584
+ const trimmed = value?.trim();
16585
+ return trimmed && trimmed.length > 0 ? trimmed : void 0;
16586
+ }
16587
+ function normalizeOptionalLowercaseHost(value) {
16588
+ const trimmed = normalizeOptionalTrimmedString(value);
16589
+ return trimmed?.toLowerCase();
16590
+ }
16591
+ function normalizeOptionalPath(value) {
16592
+ const trimmed = normalizeOptionalTrimmedString(value);
16593
+ if (trimmed === void 0) {
16594
+ return void 0;
16595
+ }
16596
+ return trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
16597
+ }
16598
+ function hasValue(value) {
16599
+ return value !== void 0 && value !== null;
16600
+ }
16601
+ var UrlMatcherSchema = external_exports.object({
16602
+ host: external_exports.string().min(1).max(255).optional(),
16603
+ host_suffix: external_exports.string().min(1).max(255).optional(),
16604
+ path_prefix: external_exports.string().min(1).max(1024).optional(),
16605
+ path_equals: external_exports.string().min(1).max(1024).optional()
16606
+ }).transform((value) => {
16607
+ const normalized = {};
16608
+ const host = normalizeOptionalLowercaseHost(value.host);
16609
+ const hostSuffix = normalizeOptionalLowercaseHost(value.host_suffix);
16610
+ const pathPrefix = normalizeOptionalPath(value.path_prefix);
16611
+ const pathEquals = normalizeOptionalPath(value.path_equals);
16612
+ if (host !== void 0) {
16613
+ normalized.host = host;
16614
+ }
16615
+ if (hostSuffix !== void 0) {
16616
+ normalized.host_suffix = hostSuffix;
16617
+ }
16618
+ if (pathPrefix !== void 0) {
16619
+ normalized.path_prefix = pathPrefix;
16620
+ }
16621
+ if (pathEquals !== void 0) {
16622
+ normalized.path_equals = pathEquals;
16623
+ }
16624
+ return normalized;
16625
+ }).refine((value) => hasValue(value.host) || hasValue(value.host_suffix) || hasValue(value.path_prefix) || hasValue(value.path_equals), {
16626
+ message: "URL matchers must include at least one host or path constraint."
16627
+ });
16628
+ var StatusRangeSchema = external_exports.object({
16629
+ start: external_exports.number().int().min(100).max(599),
16630
+ end: external_exports.number().int().min(100).max(599)
16631
+ }).refine((value) => value.start <= value.end, {
16632
+ message: "Status range start must be less than or equal to end."
16633
+ });
16634
+ var CaptureRuleFingerprintSchema = external_exports.object({
16635
+ version: external_exports.string().min(1).max(32),
16636
+ value: external_exports.string().min(1).max(256)
16637
+ });
16638
+ function normalizeStringArray(values) {
16639
+ if (values === void 0) {
16640
+ return void 0;
16641
+ }
16642
+ return Array.from(new Set(values.map((value) => value.trim()).filter((value) => value.length > 0)));
16643
+ }
16644
+ function normalizeNumberArray(values) {
16645
+ if (values === void 0) {
16646
+ return void 0;
16647
+ }
16648
+ return Array.from(new Set(values)).sort((left, right) => left - right);
16649
+ }
16650
+ var CaptureRuleMatcherSchema = external_exports.object({
16651
+ event_types: external_exports.array(CaptureRuleEventTypeSchema).min(1).optional(),
16652
+ services: external_exports.array(external_exports.string().min(1).max(120)).min(1).optional(),
16653
+ environments: external_exports.array(external_exports.string().min(1).max(120)).min(1).optional(),
16654
+ runtime: external_exports.array(CaptureRuleRuntimeSchema).min(1).optional(),
16655
+ first_party: external_exports.boolean().optional(),
16656
+ error_name: external_exports.string().min(1).max(120).optional(),
16657
+ message_contains: external_exports.string().min(1).max(500).optional(),
16658
+ message_equals: external_exports.string().min(1).max(500).optional(),
16659
+ browser_event_kind: BrowserEventKindSchema.optional(),
16660
+ resource_url: UrlMatcherSchema.optional(),
16661
+ request_url: UrlMatcherSchema.optional(),
16662
+ status_codes: external_exports.array(external_exports.number().int().min(100).max(599)).min(1).optional(),
16663
+ status_ranges: external_exports.array(StatusRangeSchema).min(1).optional(),
16664
+ fingerprint: CaptureRuleFingerprintSchema.optional()
16665
+ }).transform((value) => {
16666
+ const normalized = {};
16667
+ const eventTypes = normalizeStringArray(value.event_types);
16668
+ const services = normalizeStringArray(value.services);
16669
+ const environments = normalizeStringArray(value.environments);
16670
+ const runtime = normalizeStringArray(value.runtime);
16671
+ const errorName = normalizeOptionalTrimmedString(value.error_name);
16672
+ const messageContains = normalizeOptionalTrimmedString(value.message_contains);
16673
+ const messageEquals = normalizeOptionalTrimmedString(value.message_equals);
16674
+ const statusCodes = normalizeNumberArray(value.status_codes);
16675
+ if (eventTypes !== void 0) {
16676
+ normalized.event_types = eventTypes;
16677
+ }
16678
+ if (services !== void 0) {
16679
+ normalized.services = services;
16680
+ }
16681
+ if (environments !== void 0) {
16682
+ normalized.environments = environments;
16683
+ }
16684
+ if (runtime !== void 0) {
16685
+ normalized.runtime = runtime;
16686
+ }
16687
+ if (value.first_party !== void 0) {
16688
+ normalized.first_party = value.first_party;
16689
+ }
16690
+ if (errorName !== void 0) {
16691
+ normalized.error_name = errorName;
16692
+ }
16693
+ if (messageContains !== void 0) {
16694
+ normalized.message_contains = messageContains;
16695
+ }
16696
+ if (messageEquals !== void 0) {
16697
+ normalized.message_equals = messageEquals;
16698
+ }
16699
+ if (value.browser_event_kind !== void 0) {
16700
+ normalized.browser_event_kind = value.browser_event_kind;
16701
+ }
16702
+ if (value.resource_url !== void 0) {
16703
+ normalized.resource_url = value.resource_url;
16704
+ }
16705
+ if (value.request_url !== void 0) {
16706
+ normalized.request_url = value.request_url;
16707
+ }
16708
+ if (statusCodes !== void 0) {
16709
+ normalized.status_codes = statusCodes;
16710
+ }
16711
+ if (value.status_ranges !== void 0) {
16712
+ normalized.status_ranges = value.status_ranges;
16713
+ }
16714
+ if (value.fingerprint !== void 0) {
16715
+ normalized.fingerprint = value.fingerprint;
16716
+ }
16717
+ return normalized;
16718
+ }).superRefine((value, context) => {
16719
+ const narrowingKeys = [
16720
+ "services",
16721
+ "environments",
16722
+ "runtime",
16723
+ "first_party",
16724
+ "error_name",
16725
+ "message_contains",
16726
+ "message_equals",
16727
+ "browser_event_kind",
16728
+ "resource_url",
16729
+ "request_url",
16730
+ "status_codes",
16731
+ "status_ranges",
16732
+ "fingerprint"
16733
+ ];
16734
+ if (!narrowingKeys.some((key) => hasValue(value[key]))) {
16735
+ context.addIssue({
16736
+ code: external_exports.ZodIssueCode.custom,
16737
+ message: "Capture rules must include at least one narrowing field beyond event_types."
16738
+ });
16739
+ }
16740
+ if (value.browser_event_kind === "resource_error") {
16741
+ const hasResourceConstraint = hasValue(value.resource_url) || hasValue(value.fingerprint);
16742
+ if (!hasResourceConstraint) {
16743
+ context.addIssue({
16744
+ code: external_exports.ZodIssueCode.custom,
16745
+ message: "Resource-error rules require a resource URL constraint or an exact fingerprint."
16746
+ });
16747
+ }
16748
+ }
16749
+ });
16750
+ var CaptureRuleCoreObjectSchema = external_exports.object({
16751
+ name: external_exports.string().trim().min(1).max(120),
16752
+ description: external_exports.string().trim().max(500).nullable(),
16753
+ enabled: external_exports.boolean(),
16754
+ action: CaptureRuleActionSchema,
16755
+ matcher: CaptureRuleMatcherSchema,
16756
+ sample_rate: external_exports.number().min(0).max(1).nullable(),
16757
+ sample_event_class: CaptureRuleSampleEventClassSchema.nullable(),
16758
+ created_by_user_id: external_exports.string().min(1).max(120).nullable(),
16759
+ created_from_incident_id: external_exports.string().min(1).max(120).nullable(),
16760
+ created_from_event_id: external_exports.string().min(1).max(120).nullable(),
16761
+ expires_at: external_exports.string().datetime().nullable()
16762
+ });
16763
+ function addCaptureRuleActionValidation(schema) {
16764
+ return schema.superRefine((value, context) => {
16765
+ if (value["action"] === "sample") {
16766
+ if (value["sample_rate"] === null) {
16767
+ context.addIssue({
16768
+ code: external_exports.ZodIssueCode.custom,
16769
+ path: ["sample_rate"],
16770
+ message: "Sample rules require sample_rate."
16771
+ });
16772
+ }
16773
+ if (value["sample_event_class"] === null) {
16774
+ context.addIssue({
16775
+ code: external_exports.ZodIssueCode.custom,
16776
+ path: ["sample_event_class"],
16777
+ message: "Sample rules require sample_event_class."
16778
+ });
16779
+ }
16780
+ return;
16781
+ }
16782
+ if (value["sample_rate"] !== null) {
16783
+ context.addIssue({
16784
+ code: external_exports.ZodIssueCode.custom,
16785
+ path: ["sample_rate"],
16786
+ message: "Only sample rules can set sample_rate."
16787
+ });
16788
+ }
16789
+ if (value["sample_event_class"] !== null) {
16790
+ context.addIssue({
16791
+ code: external_exports.ZodIssueCode.custom,
16792
+ path: ["sample_event_class"],
16793
+ message: "Only sample rules can set sample_event_class."
16794
+ });
16795
+ }
16796
+ });
16797
+ }
16798
+ var CaptureRuleSchema = addCaptureRuleActionValidation(
16799
+ CaptureRuleCoreObjectSchema.extend({
16800
+ id: external_exports.string().uuid(),
16801
+ project_id: external_exports.string().min(1).max(120),
16802
+ hit_count: external_exports.number().int().nonnegative(),
16803
+ last_matched_at: external_exports.string().datetime().nullable(),
16804
+ created_at: external_exports.string().datetime(),
16805
+ updated_at: external_exports.string().datetime()
16806
+ })
16807
+ );
16808
+ var CaptureRuleCreateSchema = external_exports.object({
16809
+ name: external_exports.string().trim().min(1).max(120),
16810
+ description: external_exports.string().trim().max(500).nullable().default(null),
16811
+ enabled: external_exports.boolean().default(true),
16812
+ action: CaptureRuleActionSchema,
16813
+ matcher: CaptureRuleMatcherSchema,
16814
+ sample_rate: external_exports.number().min(0).max(1).nullable().optional(),
16815
+ sample_event_class: CaptureRuleSampleEventClassSchema.nullable().optional(),
16816
+ created_by_user_id: external_exports.string().min(1).max(120).nullable().default(null),
16817
+ created_from_incident_id: external_exports.string().min(1).max(120).nullable().default(null),
16818
+ created_from_event_id: external_exports.string().min(1).max(120).nullable().default(null),
16819
+ expires_at: external_exports.string().datetime().nullable().default(null)
16820
+ }).superRefine((value, context) => {
16821
+ if (value.action === "sample") {
16822
+ if (value.sample_rate === void 0 || value.sample_rate === null) {
16823
+ context.addIssue({
16824
+ code: external_exports.ZodIssueCode.custom,
16825
+ path: ["sample_rate"],
16826
+ message: "Sample rules require sample_rate."
16827
+ });
16828
+ }
16829
+ return;
16830
+ }
16831
+ if (value.sample_rate !== void 0 && value.sample_rate !== null) {
16832
+ context.addIssue({
16833
+ code: external_exports.ZodIssueCode.custom,
16834
+ path: ["sample_rate"],
16835
+ message: "Only sample rules can set sample_rate."
16836
+ });
16837
+ }
16838
+ if (value.sample_event_class !== void 0 && value.sample_event_class !== null) {
16839
+ context.addIssue({
16840
+ code: external_exports.ZodIssueCode.custom,
16841
+ path: ["sample_event_class"],
16842
+ message: "Only sample rules can set sample_event_class."
16843
+ });
16844
+ }
16845
+ }).transform((value) => ({
16846
+ ...value,
16847
+ sample_rate: value.action === "sample" ? value.sample_rate : null,
16848
+ sample_event_class: value.action === "sample" ? value.sample_event_class ?? "preserve" : null
16849
+ }));
16850
+ var CaptureRuleUpdateSchema = external_exports.object({
16851
+ name: external_exports.string().trim().min(1).max(120).optional(),
16852
+ description: external_exports.string().trim().max(500).nullable().optional(),
16853
+ enabled: external_exports.boolean().optional(),
16854
+ action: CaptureRuleActionSchema.optional(),
16855
+ matcher: CaptureRuleMatcherSchema.optional(),
16856
+ sample_rate: external_exports.number().min(0).max(1).nullable().optional(),
16857
+ sample_event_class: CaptureRuleSampleEventClassSchema.nullable().optional(),
16858
+ expires_at: external_exports.string().datetime().nullable().optional()
16859
+ }).superRefine((value, context) => {
16860
+ if (Object.keys(value).length === 0) {
16861
+ context.addIssue({
16862
+ code: external_exports.ZodIssueCode.custom,
16863
+ message: "At least one capture rule field must be provided."
16864
+ });
16865
+ }
16866
+ const resolvedAction = value.action;
16867
+ if (resolvedAction === "sample") {
16868
+ if (!("sample_rate" in value)) {
16869
+ context.addIssue({
16870
+ code: external_exports.ZodIssueCode.custom,
16871
+ path: ["sample_rate"],
16872
+ message: "Sample rule updates must include sample_rate when changing action to sample."
16873
+ });
16874
+ }
16875
+ if (!("sample_event_class" in value)) {
16876
+ context.addIssue({
16877
+ code: external_exports.ZodIssueCode.custom,
16878
+ path: ["sample_event_class"],
16879
+ message: "Sample rule updates must include sample_event_class when changing action to sample."
16880
+ });
16881
+ }
16882
+ return;
16883
+ }
16884
+ if ("sample_rate" in value) {
16885
+ context.addIssue({
16886
+ code: external_exports.ZodIssueCode.custom,
16887
+ path: ["sample_rate"],
16888
+ message: "Sample rule fields can only be updated while setting action to sample."
16889
+ });
16890
+ }
16891
+ if ("sample_event_class" in value) {
16892
+ context.addIssue({
16893
+ code: external_exports.ZodIssueCode.custom,
16894
+ path: ["sample_event_class"],
16895
+ message: "Sample rule fields can only be updated while setting action to sample."
16896
+ });
16897
+ }
16898
+ });
16899
+ var CaptureRuleResponseSchema = external_exports.object({
16900
+ rule: CaptureRuleSchema
16901
+ });
16902
+ var CaptureRulesResponseSchema = external_exports.object({
16903
+ access_mode: external_exports.enum(["manage", "preview"]),
16904
+ rules: external_exports.array(CaptureRuleSchema)
16905
+ });
16906
+ var CaptureRulesFileSchema = external_exports.object({
16907
+ version: external_exports.literal(1),
16908
+ rules: external_exports.array(CaptureRuleSchema)
16909
+ });
16910
+ var CaptureRuleEvaluationUrlSchema = external_exports.object({
16911
+ host: external_exports.string().min(1).transform((value) => value.toLowerCase()).optional(),
16912
+ path: external_exports.string().min(1).transform((value) => value.startsWith("/") ? value : `/${value}`)
16913
+ });
16914
+ var CaptureRuleEvaluationContextSchema = external_exports.object({
16915
+ project_id: external_exports.string().min(1).max(120),
16916
+ event_id: external_exports.string().uuid(),
16917
+ event_type: CaptureRuleEventTypeSchema,
16918
+ service: external_exports.string().min(1).optional(),
16919
+ environment: external_exports.string().min(1).optional(),
16920
+ runtime: CaptureRuleRuntimeSchema,
16921
+ first_party: external_exports.boolean().optional(),
16922
+ error_name: external_exports.string().min(1).optional(),
16923
+ message: external_exports.string().min(1).optional(),
16924
+ browser_event_kind: BrowserEventKindSchema.optional(),
16925
+ resource_url: CaptureRuleEvaluationUrlSchema.optional(),
16926
+ request_url: CaptureRuleEvaluationUrlSchema.optional(),
16927
+ status_code: external_exports.number().int().min(0).max(599).optional(),
16928
+ fingerprint: CaptureRuleFingerprintSchema.optional()
16929
+ });
16930
+
16931
+ // ../../packages/shared-types/src/capture-rule-suggestions.ts
16932
+ var CaptureRuleSuggestionConfidenceSchema = external_exports.enum(["high", "medium", "low"]);
16933
+ var CaptureRuleSuggestionSchema = external_exports.object({
16934
+ suggestion_id: external_exports.string().min(1).max(120),
16935
+ label: external_exports.string().min(1).max(200),
16936
+ recommended_action: CaptureRuleActionSchema,
16937
+ confidence: CaptureRuleSuggestionConfidenceSchema,
16938
+ reason: external_exports.string().min(1).max(500),
16939
+ requires_confirmation: external_exports.boolean(),
16940
+ rule: CaptureRuleCreateSchema
16941
+ });
16942
+ var CaptureRuleSuggestionsResponseSchema = external_exports.object({
16943
+ suggestions: external_exports.array(CaptureRuleSuggestionSchema),
16944
+ bundle_status: external_exports.enum(["ready", "pending", "failed"]).optional(),
16945
+ bundle_reason: external_exports.string().nullable().optional()
16946
+ });
16947
+ var CreateCaptureRuleFromSuggestionSchema = external_exports.object({
16948
+ suggestion_id: external_exports.string().min(1).max(120),
16949
+ name: external_exports.string().trim().min(1).max(120).optional(),
16950
+ description: external_exports.string().trim().max(500).nullable().optional(),
16951
+ enabled: external_exports.boolean().optional(),
16952
+ expires_at: external_exports.string().datetime().nullable().optional()
16953
+ });
16954
+
16555
16955
  // ../../packages/shared-types/src/improvement-settings.ts
16556
16956
  var ImprovementBundleSensitivityValues = [
16557
16957
  "high_confidence",
@@ -16708,6 +17108,18 @@ var DeviceInfoSchema = external_exports.object({
16708
17108
  connection_type: external_exports.string().nullable(),
16709
17109
  color_scheme_preference: external_exports.enum(["light", "dark", "no-preference"]).nullable()
16710
17110
  }).strict();
17111
+ var BrowserExceptionEventSchema = external_exports.object({
17112
+ kind: external_exports.enum(["window_error", "resource_error"]),
17113
+ message: external_exports.string().nullable(),
17114
+ file_name: external_exports.string().nullable(),
17115
+ line_number: external_exports.number().int().nonnegative().nullable(),
17116
+ column_number: external_exports.number().int().nonnegative().nullable(),
17117
+ target: external_exports.object({
17118
+ tag_name: external_exports.string().nullable(),
17119
+ source_url: external_exports.string().nullable()
17120
+ }).nullable(),
17121
+ opaque: external_exports.boolean()
17122
+ }).strict();
16711
17123
  var FrontendExceptionPayloadSchema = external_exports.object({
16712
17124
  name: external_exports.string().min(1),
16713
17125
  message: external_exports.string().min(1),
@@ -16719,6 +17131,7 @@ var FrontendExceptionPayloadSchema = external_exports.object({
16719
17131
  }),
16720
17132
  breadcrumbs: external_exports.array(FrontendExceptionBreadcrumbSchema).optional(),
16721
17133
  device: DeviceInfoSchema.nullable().optional(),
17134
+ browser_event: BrowserExceptionEventSchema.optional(),
16722
17135
  dom_context: external_exports.object({
16723
17136
  mode: external_exports.literal("lightweight"),
16724
17137
  html_excerpt: external_exports.string().min(1)
@@ -17175,6 +17588,18 @@ function buildSkill() {
17175
17588
  "- Run `debugbundle validate --fix` to restore missing generated setup files without overwriting the profile.",
17176
17589
  "- Run `debugbundle process` after local events land in `.debugbundle/local/events/`.",
17177
17590
  "",
17591
+ "## Browser Capture and Relay Setup",
17592
+ "",
17593
+ "When the repository has a browser frontend, verify capture end to end instead of stopping at backend SDK setup.",
17594
+ "",
17595
+ "1. Add `@debugbundle/sdk-browser` to each browser app that should capture console, error, navigation, or request context.",
17596
+ "2. Initialize the browser SDK from the app entrypoint with the active environment and a browser relay endpoint.",
17597
+ "3. Add a backend relay endpoint at `/debugbundle/browser` using the server SDK relay helper when available.",
17598
+ "4. For same-origin apps, keep the browser endpoint as `/debugbundle/browser`.",
17599
+ "5. For split frontend/backend hosts, configure the browser endpoint to the API host relay URL and require explicit frontend origin allowlisting on the backend.",
17600
+ "6. Ensure auth and CSRF middleware allow the relay path while the relay still enforces origin, content type, body size, schema validation, and rate limits.",
17601
+ "7. Trigger a local browser smoke event, then run `debugbundle process --json` and confirm the incident or context event appears before marking setup complete.",
17602
+ "",
17178
17603
  "## References",
17179
17604
  "",
17180
17605
  "- CLI reference: `references/cli.md`",
@@ -17311,6 +17736,8 @@ function buildProfileEnrichmentReference() {
17311
17736
  "- add critical paths for ingestion, processing, retrieval, SDK capture, auth, billing, and any project-specific high-risk workflows",
17312
17737
  "- confirm `repo.generated_paths` and `repo.do_not_edit_paths` match the local scaffold",
17313
17738
  "- confirm build, test, lint, and install workflows in `developer_workflows`",
17739
+ "- for browser frontends, confirm `@debugbundle/sdk-browser` is initialized and a backend `/debugbundle/browser` relay is reachable",
17740
+ "- for split frontend/backend hosts, confirm the browser SDK uses the API relay URL and the backend allowlists the frontend origin",
17314
17741
  "- update `debugbundle.last_reviewed_at` and set `debugbundle.validation_status` to `agent-validated` when complete",
17315
17742
  ""
17316
17743
  ].join("\n");
@@ -17504,10 +17931,37 @@ async function pathExists(path, stat) {
17504
17931
  }
17505
17932
  }
17506
17933
  function formatZodErrors(error) {
17507
- return error.issues.map((issue) => ({
17508
- path: issue.path.join("."),
17509
- message: issue.message
17510
- }));
17934
+ return error.issues.map((issue) => {
17935
+ const path = issue.path.join(".");
17936
+ if (path === "services" || path.startsWith("services.")) {
17937
+ return {
17938
+ path,
17939
+ message: issue.message,
17940
+ suggestion: "Add service entries with name, kind, runtime, framework, paths, owns_routes, and depends_on.",
17941
+ example: '[{"name":"api","kind":"backend","runtime":"Node.js","framework":"Fastify","paths":["apps/api"],"owns_routes":["POST /checkout"],"depends_on":["worker"]}]'
17942
+ };
17943
+ }
17944
+ if (path === "critical_paths" || path.startsWith("critical_paths.")) {
17945
+ return {
17946
+ path,
17947
+ message: issue.message,
17948
+ suggestion: "Use object entries so each critical path records its owner_service and review notes.",
17949
+ example: '[{"name":"checkout","owner_service":"api","notes":"Creates the order, charges the card, and enqueues fulfillment."}]'
17950
+ };
17951
+ }
17952
+ if (path === "developer_workflows" || path.startsWith("developer_workflows.")) {
17953
+ return {
17954
+ path,
17955
+ message: issue.message,
17956
+ suggestion: "Provide install, build, test, and lint as command strings so agents can run the standard repo workflows.",
17957
+ example: '{"install":"pnpm install","build":"pnpm build","test":"pnpm test","lint":"pnpm lint"}'
17958
+ };
17959
+ }
17960
+ return {
17961
+ path,
17962
+ message: issue.message
17963
+ };
17964
+ });
17511
17965
  }
17512
17966
  async function validateProfile(rootDirectory, dependencies = {}) {
17513
17967
  const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises.readFile)(filePath, "utf8"));
@@ -17854,6 +18308,118 @@ function createCliHttpClient(input, dependencies) {
17854
18308
  };
17855
18309
  }
17856
18310
 
18311
+ // ../cli/src/capture-rule-commands.ts
18312
+ var CaptureRuleApiError = class extends Error {
18313
+ status;
18314
+ constructor(status, message) {
18315
+ super(message);
18316
+ this.name = "CaptureRuleApiError";
18317
+ this.status = status;
18318
+ }
18319
+ };
18320
+ function toApiError(status, body, fallback) {
18321
+ if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
18322
+ return new CaptureRuleApiError(status, body.error);
18323
+ }
18324
+ return new CaptureRuleApiError(status, fallback);
18325
+ }
18326
+ function createCaptureRuleApi(httpClient) {
18327
+ return {
18328
+ async listCaptureRules(input) {
18329
+ const response = await httpClient.request({
18330
+ method: "GET",
18331
+ path: `/v1/projects/${encodeURIComponent(input.projectId)}/capture-rules`,
18332
+ bearerToken: input.bearerToken
18333
+ });
18334
+ if (response.status !== 200) {
18335
+ throw toApiError(response.status, response.body, "Failed to list capture rules.");
18336
+ }
18337
+ const parsed = CaptureRulesResponseSchema.safeParse(response.body);
18338
+ if (!parsed.success) {
18339
+ throw new CaptureRuleApiError(500, "Invalid capture rule list response.");
18340
+ }
18341
+ return parsed.data;
18342
+ },
18343
+ async createCaptureRule(input) {
18344
+ const response = await httpClient.request({
18345
+ method: "POST",
18346
+ path: `/v1/projects/${encodeURIComponent(input.projectId)}/capture-rules`,
18347
+ bearerToken: input.bearerToken,
18348
+ body: input.create
18349
+ });
18350
+ if (response.status !== 201) {
18351
+ throw toApiError(response.status, response.body, "Failed to create capture rule.");
18352
+ }
18353
+ const parsed = CaptureRuleResponseSchema.safeParse(response.body);
18354
+ if (!parsed.success) {
18355
+ throw new CaptureRuleApiError(500, "Invalid capture rule create response.");
18356
+ }
18357
+ return parsed.data;
18358
+ },
18359
+ async suggestCaptureRulesFromIncident(input) {
18360
+ const response = await httpClient.request({
18361
+ method: "POST",
18362
+ path: `/v1/incidents/${encodeURIComponent(input.incidentId)}/capture-rule-suggestion`,
18363
+ bearerToken: input.bearerToken
18364
+ });
18365
+ if (response.status !== 200) {
18366
+ throw toApiError(response.status, response.body, "Failed to suggest capture rules.");
18367
+ }
18368
+ const parsed = CaptureRuleSuggestionsResponseSchema.safeParse(response.body);
18369
+ if (!parsed.success) {
18370
+ throw new CaptureRuleApiError(500, "Invalid capture rule suggestion response.");
18371
+ }
18372
+ return parsed.data;
18373
+ },
18374
+ async createCaptureRuleFromIncidentSuggestion(input) {
18375
+ const response = await httpClient.request({
18376
+ method: "POST",
18377
+ path: `/v1/incidents/${encodeURIComponent(input.incidentId)}/capture-rules`,
18378
+ bearerToken: input.bearerToken,
18379
+ body: input.create
18380
+ });
18381
+ if (response.status !== 201) {
18382
+ throw toApiError(response.status, response.body, "Failed to create capture rule from suggestion.");
18383
+ }
18384
+ const parsed = CaptureRuleResponseSchema.safeParse(response.body);
18385
+ if (!parsed.success) {
18386
+ throw new CaptureRuleApiError(500, "Invalid capture rule create-from-suggestion response.");
18387
+ }
18388
+ return parsed.data;
18389
+ },
18390
+ async updateCaptureRule(input) {
18391
+ const response = await httpClient.request({
18392
+ method: "PATCH",
18393
+ path: `/v1/projects/${encodeURIComponent(input.projectId)}/capture-rules/${encodeURIComponent(input.ruleId)}`,
18394
+ bearerToken: input.bearerToken,
18395
+ body: input.update
18396
+ });
18397
+ if (response.status !== 200) {
18398
+ throw toApiError(response.status, response.body, "Failed to update capture rule.");
18399
+ }
18400
+ const parsed = CaptureRuleResponseSchema.safeParse(response.body);
18401
+ if (!parsed.success) {
18402
+ throw new CaptureRuleApiError(500, "Invalid capture rule update response.");
18403
+ }
18404
+ return parsed.data;
18405
+ },
18406
+ async deleteCaptureRule(input) {
18407
+ const response = await httpClient.request({
18408
+ method: "DELETE",
18409
+ path: `/v1/projects/${encodeURIComponent(input.projectId)}/capture-rules/${encodeURIComponent(input.ruleId)}`,
18410
+ bearerToken: input.bearerToken
18411
+ });
18412
+ if (response.status !== 200) {
18413
+ throw toApiError(response.status, response.body, "Failed to delete capture rule.");
18414
+ }
18415
+ if (typeof response.body !== "object" || response.body === null || !("success" in response.body) || response.body.success !== true) {
18416
+ throw new CaptureRuleApiError(500, "Invalid capture rule delete response.");
18417
+ }
18418
+ return { success: true };
18419
+ }
18420
+ };
18421
+ }
18422
+
17857
18423
  // ../cli/src/capture-policy-commands.ts
17858
18424
  var CapturePolicyApiError = class extends Error {
17859
18425
  status;
@@ -17863,7 +18429,7 @@ var CapturePolicyApiError = class extends Error {
17863
18429
  this.status = status;
17864
18430
  }
17865
18431
  };
17866
- function toApiError(status, body, fallback) {
18432
+ function toApiError2(status, body, fallback) {
17867
18433
  if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
17868
18434
  return new CapturePolicyApiError(status, body.error);
17869
18435
  }
@@ -17878,7 +18444,7 @@ function createCapturePolicyApi(httpClient) {
17878
18444
  bearerToken: input.bearerToken
17879
18445
  });
17880
18446
  if (response.status !== 200) {
17881
- throw toApiError(response.status, response.body, "Failed to get capture policy.");
18447
+ throw toApiError2(response.status, response.body, "Failed to get capture policy.");
17882
18448
  }
17883
18449
  const parsed = CapturePolicyResponseSchema.safeParse(response.body);
17884
18450
  if (!parsed.success) {
@@ -17894,7 +18460,7 @@ function createCapturePolicyApi(httpClient) {
17894
18460
  body: input.update
17895
18461
  });
17896
18462
  if (response.status !== 200) {
17897
- throw toApiError(response.status, response.body, "Failed to update capture policy.");
18463
+ throw toApiError2(response.status, response.body, "Failed to update capture policy.");
17898
18464
  }
17899
18465
  const parsed = CapturePolicyResponseSchema.safeParse(response.body);
17900
18466
  if (!parsed.success) {
@@ -17914,7 +18480,7 @@ var ImprovementSettingsApiError = class extends Error {
17914
18480
  this.status = status;
17915
18481
  }
17916
18482
  };
17917
- function toApiError2(status, body, fallback) {
18483
+ function toApiError3(status, body, fallback) {
17918
18484
  if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
17919
18485
  return new ImprovementSettingsApiError(status, body.error);
17920
18486
  }
@@ -17929,7 +18495,7 @@ function createImprovementSettingsApi(httpClient) {
17929
18495
  bearerToken: input.bearerToken
17930
18496
  });
17931
18497
  if (response.status !== 200) {
17932
- throw toApiError2(response.status, response.body, "Failed to get improvement settings.");
18498
+ throw toApiError3(response.status, response.body, "Failed to get improvement settings.");
17933
18499
  }
17934
18500
  const parsed = ImprovementSettingsResponseSchema.safeParse(response.body);
17935
18501
  if (!parsed.success) {
@@ -17945,7 +18511,7 @@ function createImprovementSettingsApi(httpClient) {
17945
18511
  body: input.update
17946
18512
  });
17947
18513
  if (response.status !== 200) {
17948
- throw toApiError2(response.status, response.body, "Failed to update improvement settings.");
18514
+ throw toApiError3(response.status, response.body, "Failed to update improvement settings.");
17949
18515
  }
17950
18516
  const parsed = ImprovementSettingsResponseSchema.safeParse(response.body);
17951
18517
  if (!parsed.success) {
@@ -17967,7 +18533,7 @@ var MemberApiError = class extends Error {
17967
18533
  this.code = code;
17968
18534
  }
17969
18535
  };
17970
- function toApiError3(status, body) {
18536
+ function toApiError4(status, body) {
17971
18537
  if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
17972
18538
  return new MemberApiError(status, body.error);
17973
18539
  }
@@ -17982,7 +18548,7 @@ function createMemberApi(httpClient) {
17982
18548
  bearerToken: input.bearerToken
17983
18549
  });
17984
18550
  if (response.status !== 200) {
17985
- throw toApiError3(response.status, response.body);
18551
+ throw toApiError4(response.status, response.body);
17986
18552
  }
17987
18553
  return response.body;
17988
18554
  },
@@ -17993,7 +18559,7 @@ function createMemberApi(httpClient) {
17993
18559
  bearerToken: input.bearerToken
17994
18560
  });
17995
18561
  if (response.status !== 200) {
17996
- throw toApiError3(response.status, response.body);
18562
+ throw toApiError4(response.status, response.body);
17997
18563
  }
17998
18564
  return response.body;
17999
18565
  },
@@ -18005,7 +18571,7 @@ function createMemberApi(httpClient) {
18005
18571
  body: { email: input.email, role: input.role }
18006
18572
  });
18007
18573
  if (response.status !== 201) {
18008
- throw toApiError3(response.status, response.body);
18574
+ throw toApiError4(response.status, response.body);
18009
18575
  }
18010
18576
  return response.body;
18011
18577
  },
@@ -18016,7 +18582,7 @@ function createMemberApi(httpClient) {
18016
18582
  bearerToken: input.bearerToken
18017
18583
  });
18018
18584
  if (response.status !== 200) {
18019
- throw toApiError3(response.status, response.body);
18585
+ throw toApiError4(response.status, response.body);
18020
18586
  }
18021
18587
  return response.body;
18022
18588
  },
@@ -18028,7 +18594,7 @@ function createMemberApi(httpClient) {
18028
18594
  body: { role: input.role }
18029
18595
  });
18030
18596
  if (response.status !== 200) {
18031
- throw toApiError3(response.status, response.body);
18597
+ throw toApiError4(response.status, response.body);
18032
18598
  }
18033
18599
  return response.body;
18034
18600
  },
@@ -18039,7 +18605,7 @@ function createMemberApi(httpClient) {
18039
18605
  bearerToken: input.bearerToken
18040
18606
  });
18041
18607
  if (response.status !== 200) {
18042
- throw toApiError3(response.status, response.body);
18608
+ throw toApiError4(response.status, response.body);
18043
18609
  }
18044
18610
  return response.body;
18045
18611
  }
@@ -18057,7 +18623,7 @@ var ProbeApiError = class extends Error {
18057
18623
  this.code = code;
18058
18624
  }
18059
18625
  };
18060
- function toApiError4(status, body) {
18626
+ function toApiError5(status, body) {
18061
18627
  if (typeof body === "object" && body !== null && "error" in body && typeof body.error === "string") {
18062
18628
  return new ProbeApiError(status, body.error);
18063
18629
  }
@@ -18088,7 +18654,7 @@ function createProbeApi(httpClient) {
18088
18654
  body
18089
18655
  });
18090
18656
  if (response.status !== 201) {
18091
- throw toApiError4(response.status, response.body);
18657
+ throw toApiError5(response.status, response.body);
18092
18658
  }
18093
18659
  return response.body;
18094
18660
  },
@@ -18099,7 +18665,7 @@ function createProbeApi(httpClient) {
18099
18665
  bearerToken: input.bearerToken
18100
18666
  });
18101
18667
  if (response.status !== 200) {
18102
- throw toApiError4(response.status, response.body);
18668
+ throw toApiError5(response.status, response.body);
18103
18669
  }
18104
18670
  return response.body;
18105
18671
  },
@@ -18111,7 +18677,7 @@ function createProbeApi(httpClient) {
18111
18677
  body: { activation_id: input.activationId }
18112
18678
  });
18113
18679
  if (response.status !== 200) {
18114
- throw toApiError4(response.status, response.body);
18680
+ throw toApiError5(response.status, response.body);
18115
18681
  }
18116
18682
  return response.body;
18117
18683
  }
@@ -18234,6 +18800,15 @@ function inferMatchedFields(event) {
18234
18800
  if (event.top_frames.length > 0) {
18235
18801
  matchedFields.push("top_frames");
18236
18802
  }
18803
+ if (event.browser_event_kind != null) {
18804
+ matchedFields.push("browser_event_kind");
18805
+ }
18806
+ if (event.resource_host != null) {
18807
+ matchedFields.push("resource_host");
18808
+ }
18809
+ if (event.resource_path != null) {
18810
+ matchedFields.push("resource_path");
18811
+ }
18237
18812
  if (event.http_method !== null) {
18238
18813
  matchedFields.push("http_method");
18239
18814
  }
@@ -18294,6 +18869,39 @@ function selectTopFrames(stack, limit = 5) {
18294
18869
  const frames = normalizedStack.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("at ")).filter((line) => FRAME_NOISE_PATTERNS.every((pattern) => !line.includes(pattern))).slice(0, limit);
18295
18870
  return frames;
18296
18871
  }
18872
+ function normalizeResourceIdentity(value) {
18873
+ if (value === null) {
18874
+ return { host: null, path: null };
18875
+ }
18876
+ const trimmed = value.trim();
18877
+ if (trimmed.length === 0) {
18878
+ return { host: null, path: null };
18879
+ }
18880
+ if (trimmed.startsWith("/")) {
18881
+ return {
18882
+ host: null,
18883
+ path: normalizeRoute(trimmed)
18884
+ };
18885
+ }
18886
+ try {
18887
+ const parsed = new URL(trimmed);
18888
+ if (parsed.protocol === "http:" || parsed.protocol === "https:") {
18889
+ return {
18890
+ host: parsed.hostname.length > 0 ? parsed.hostname.toLowerCase() : null,
18891
+ path: normalizeRoute(parsed.pathname)
18892
+ };
18893
+ }
18894
+ return {
18895
+ host: null,
18896
+ path: parsed.protocol.replace(/:$/, "")
18897
+ };
18898
+ } catch {
18899
+ return {
18900
+ host: null,
18901
+ path: normalizeRoute(trimmed) ?? trimmed
18902
+ };
18903
+ }
18904
+ }
18297
18905
  function stableJson(value) {
18298
18906
  if (value === null || typeof value !== "object") {
18299
18907
  return JSON.stringify(value);
@@ -18321,6 +18929,9 @@ function normalizeEvent(event) {
18321
18929
  http_method: event.payload.request.method,
18322
18930
  http_status: event.payload.response.status_code,
18323
18931
  top_frames: selectTopFrames(event.payload.stack),
18932
+ browser_event_kind: null,
18933
+ resource_host: null,
18934
+ resource_path: null,
18324
18935
  payload: redactedPayload
18325
18936
  };
18326
18937
  }
@@ -18334,6 +18945,9 @@ function normalizeEvent(event) {
18334
18945
  http_method: event.payload.method,
18335
18946
  http_status: event.payload.response_status,
18336
18947
  top_frames: [],
18948
+ browser_event_kind: null,
18949
+ resource_host: null,
18950
+ resource_path: null,
18337
18951
  payload: redactedPayload
18338
18952
  };
18339
18953
  }
@@ -18347,6 +18961,28 @@ function normalizeEvent(event) {
18347
18961
  http_method: null,
18348
18962
  http_status: null,
18349
18963
  top_frames: [],
18964
+ browser_event_kind: null,
18965
+ resource_host: null,
18966
+ resource_path: null,
18967
+ payload: redactedPayload
18968
+ };
18969
+ }
18970
+ if (event.event_type === "frontend_exception") {
18971
+ const browserEvent = event.payload.browser_event;
18972
+ const resourceIdentity = browserEvent?.kind === "resource_error" ? normalizeResourceIdentity(browserEvent.target?.source_url ?? browserEvent.file_name) : { host: null, path: null };
18973
+ const topFrames = browserEvent?.opaque === true ? [] : selectTopFrames(event.payload.stack);
18974
+ return {
18975
+ event_type: event.event_type,
18976
+ environment: event.service.environment,
18977
+ error_type: event.payload.name,
18978
+ normalized_message: normalizeMessage(event.payload.message),
18979
+ route_template: normalizeRoute(event.payload.route ?? null),
18980
+ http_method: null,
18981
+ http_status: null,
18982
+ top_frames: topFrames,
18983
+ browser_event_kind: browserEvent?.kind ?? null,
18984
+ resource_host: resourceIdentity.host,
18985
+ resource_path: resourceIdentity.path,
18350
18986
  payload: redactedPayload
18351
18987
  };
18352
18988
  }
@@ -18359,6 +18995,9 @@ function normalizeEvent(event) {
18359
18995
  http_method: null,
18360
18996
  http_status: null,
18361
18997
  top_frames: [],
18998
+ browser_event_kind: null,
18999
+ resource_host: null,
19000
+ resource_path: null,
18362
19001
  payload: redactedPayload
18363
19002
  };
18364
19003
  }
@@ -18368,6 +19007,9 @@ function fingerprint(event) {
18368
19007
  normalized_message: event.normalized_message,
18369
19008
  top_frames: event.top_frames,
18370
19009
  route_template: event.route_template,
19010
+ browser_event_kind: event.browser_event_kind,
19011
+ resource_host: event.resource_host,
19012
+ resource_path: event.resource_path,
18371
19013
  http_method: event.http_method,
18372
19014
  http_status: event.http_status,
18373
19015
  environment: event.environment
@@ -18422,18 +19064,18 @@ var ConnectionConfigSchema = external_exports.object({
18422
19064
  }).strict();
18423
19065
 
18424
19066
  // ../cli/src/doctor-command.ts
18425
- var ProfileSchema2 = external_exports.object({
18426
- debugbundle: external_exports.object({
18427
- last_reviewed_at: external_exports.string(),
18428
- validation_status: external_exports.enum(["static-analysis-only", "agent-validated"])
18429
- })
18430
- });
18431
19067
  var HealthResponseSchema = external_exports.object({
18432
19068
  status: external_exports.literal("ok")
18433
19069
  });
18434
19070
  var IncidentsProbeResponseSchema = external_exports.object({
18435
19071
  incidents: external_exports.array(external_exports.unknown())
18436
19072
  });
19073
+ var DoctorProfileSchema = external_exports.object({
19074
+ debugbundle: external_exports.object({
19075
+ last_reviewed_at: external_exports.string(),
19076
+ validation_status: external_exports.enum(["static-analysis-only", "agent-validated"])
19077
+ })
19078
+ });
18437
19079
  var PROFILE_STALENESS_THRESHOLD_DAYS = 30;
18438
19080
  var LOCAL_RELAY_SPOOL_DIRECTORY_PATH = ".debugbundle/local/browser-relay-spool";
18439
19081
  var RELAY_SPOOL_DELIVERED_MARKER_SUFFIX = ".delivered";
@@ -18576,6 +19218,12 @@ async function buildFileCheck(rootDirectory, name, filePath, stat) {
18576
19218
  message: exists ? `Found ${filePath}` : `Missing ${filePath}`
18577
19219
  };
18578
19220
  }
19221
+ function formatZodErrors2(error) {
19222
+ return error.issues.map((issue) => ({
19223
+ path: issue.path.join("."),
19224
+ message: issue.message
19225
+ }));
19226
+ }
18579
19227
  async function loadProfile(rootDirectory, dependencies) {
18580
19228
  const profilePath = (0, import_node_path4.join)(rootDirectory, PROFILE_FILE_PATH);
18581
19229
  if (!await pathExists3(profilePath, dependencies.stat)) {
@@ -18585,29 +19233,46 @@ async function loadProfile(rootDirectory, dependencies) {
18585
19233
  status: "missing",
18586
19234
  message: `Missing ${PROFILE_FILE_PATH}`
18587
19235
  },
18588
- profile: null
19236
+ profile: null,
19237
+ validationErrors: []
18589
19238
  };
18590
19239
  }
19240
+ let parsedJson;
18591
19241
  try {
18592
- const parsedProfile = ProfileSchema2.parse(JSON.parse(await dependencies.readFile(profilePath)));
19242
+ parsedJson = JSON.parse(await dependencies.readFile(profilePath));
19243
+ } catch {
18593
19244
  return {
18594
19245
  check: {
18595
19246
  name: "profile",
18596
- status: "ok",
18597
- message: `Found ${PROFILE_FILE_PATH}`
19247
+ status: "error",
19248
+ message: `Invalid ${PROFILE_FILE_PATH}`
18598
19249
  },
18599
- profile: parsedProfile
19250
+ profile: null,
19251
+ validationErrors: []
18600
19252
  };
18601
- } catch {
19253
+ }
19254
+ const parsedDoctorProfile = DoctorProfileSchema.safeParse(parsedJson);
19255
+ if (!parsedDoctorProfile.success) {
18602
19256
  return {
18603
19257
  check: {
18604
19258
  name: "profile",
18605
19259
  status: "error",
18606
19260
  message: `Invalid ${PROFILE_FILE_PATH}`
18607
19261
  },
18608
- profile: null
19262
+ profile: null,
19263
+ validationErrors: formatZodErrors2(parsedDoctorProfile.error)
18609
19264
  };
18610
19265
  }
19266
+ const parsedFullProfile = ProfileSchema.safeParse(parsedJson);
19267
+ return {
19268
+ check: {
19269
+ name: "profile",
19270
+ status: "ok",
19271
+ message: `Found ${PROFILE_FILE_PATH}`
19272
+ },
19273
+ profile: parsedDoctorProfile.data,
19274
+ validationErrors: parsedFullProfile.success ? [] : formatZodErrors2(parsedFullProfile.error)
19275
+ };
18611
19276
  }
18612
19277
  async function loadConnection(rootDirectory, dependencies) {
18613
19278
  const connectionPath = (0, import_node_path4.join)(rootDirectory, CONNECTION_FILE_PATH);
@@ -18659,7 +19324,20 @@ function buildProjectModeCheck(connection) {
18659
19324
  message: `Project mode is ${connection.mode}.`
18660
19325
  };
18661
19326
  }
18662
- function buildProfileValidationCheck(profile) {
19327
+ function formatProfileValidationError(errors) {
19328
+ const firstError = errors[0];
19329
+ const path = firstError.path.length === 0 ? PROFILE_FILE_PATH : firstError.path;
19330
+ const totalErrors = errors.length === 1 ? "" : ` (${errors.length} total errors)`;
19331
+ return `Profile schema validation failed at ${path}: ${firstError.message}${totalErrors}.`;
19332
+ }
19333
+ function buildProfileValidationCheck(profile, validationErrors) {
19334
+ if (validationErrors.length > 0) {
19335
+ return {
19336
+ name: "profile-validation",
19337
+ status: "error",
19338
+ message: formatProfileValidationError(validationErrors)
19339
+ };
19340
+ }
18663
19341
  if (profile === null) {
18664
19342
  return {
18665
19343
  name: "profile-validation",
@@ -18908,7 +19586,7 @@ async function doctorCommand(input, dependencies = {}) {
18908
19586
  const stat = dependencies.stat ?? import_promises4.stat;
18909
19587
  const rootDirectory = cwd();
18910
19588
  const currentTime = now();
18911
- const { check: profileCheck, profile } = await loadProfile(rootDirectory, { readFile, stat });
19589
+ const { check: profileCheck, profile, validationErrors } = await loadProfile(rootDirectory, { readFile, stat });
18912
19590
  const { check: connectionCheck, connection } = await loadConnection(rootDirectory, { readFile, stat });
18913
19591
  const { check: authCheck, authState } = await buildAuthCheck(input, readAuthStateImpl);
18914
19592
  const connectedApiCheck = await buildConnectedApiCheck({
@@ -18923,7 +19601,7 @@ async function doctorCommand(input, dependencies = {}) {
18923
19601
  authCheck,
18924
19602
  buildProjectModeCheck(connection),
18925
19603
  ...connectedApiCheck === null ? [] : [connectedApiCheck],
18926
- buildProfileValidationCheck(profile),
19604
+ buildProfileValidationCheck(profile, validationErrors),
18927
19605
  buildProfileFreshnessCheck(profile, currentTime),
18928
19606
  ...input.checkRelay === true ? [await buildRelaySpoolCheck(rootDirectory, currentTime, { readdir, stat })] : []
18929
19607
  ];
@@ -18935,6 +19613,7 @@ async function doctorCommand(input, dependencies = {}) {
18935
19613
  }
18936
19614
 
18937
19615
  // ../cli/src/verify-command.ts
19616
+ var import_node_crypto6 = require("node:crypto");
18938
19617
  var import_promises7 = require("node:fs/promises");
18939
19618
  var import_node_path9 = require("node:path");
18940
19619
 
@@ -19235,6 +19914,868 @@ var import_ioredis4 = __toESM(require_built3(), 1);
19235
19914
 
19236
19915
  // ../../packages/storage/src/schema-migrations.ts
19237
19916
  var import_node_crypto3 = require("node:crypto");
19917
+
19918
+ // ../../packages/storage/src/migrations.ts
19919
+ var STORAGE_BOOTSTRAP_STATEMENTS = [
19920
+ `
19921
+ CREATE TABLE users (
19922
+ id uuid PRIMARY KEY,
19923
+ email text NOT NULL UNIQUE,
19924
+ accepted_terms_at timestamptz,
19925
+ created_at timestamptz NOT NULL DEFAULT now(),
19926
+ updated_at timestamptz NOT NULL DEFAULT now(),
19927
+ email_verified_at timestamptz,
19928
+ avatar_source text,
19929
+ avatar_object_key text,
19930
+ avatar_content_type text,
19931
+ avatar_updated_at timestamptz
19932
+ )
19933
+ `,
19934
+ `
19935
+ CREATE TABLE organizations (
19936
+ id uuid PRIMARY KEY,
19937
+ name text NOT NULL,
19938
+ slug text NOT NULL UNIQUE,
19939
+ created_at timestamptz NOT NULL DEFAULT now(),
19940
+ updated_at timestamptz NOT NULL DEFAULT now(),
19941
+ suspended_at timestamptz,
19942
+ plan text NOT NULL DEFAULT 'free',
19943
+ stripe_customer_id text,
19944
+ additional_capacity_units integer NOT NULL DEFAULT 0,
19945
+ stripe_subscription_id text,
19946
+ billing_state text,
19947
+ billing_period_ends_at timestamptz,
19948
+ last_billing_sync_at timestamptz,
19949
+ last_billing_event_id text,
19950
+ billing_period_starts_at timestamptz
19951
+ )
19952
+ `,
19953
+ `
19954
+ CREATE UNIQUE INDEX organizations_stripe_customer_id_key
19955
+ ON organizations (stripe_customer_id)
19956
+ WHERE stripe_customer_id IS NOT NULL
19957
+ `,
19958
+ `
19959
+ CREATE TABLE projects (
19960
+ id uuid PRIMARY KEY,
19961
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
19962
+ owner_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
19963
+ name text NOT NULL,
19964
+ slug text NOT NULL,
19965
+ environment_default text NOT NULL DEFAULT 'production',
19966
+ automated_improvement_bundles_enabled boolean NOT NULL DEFAULT true,
19967
+ improvement_bundle_sensitivity text NOT NULL DEFAULT 'high_confidence'
19968
+ CHECK (improvement_bundle_sensitivity IN ('high_confidence', 'balanced', 'verbose')),
19969
+ created_at timestamptz NOT NULL DEFAULT now(),
19970
+ updated_at timestamptz NOT NULL DEFAULT now(),
19971
+ plan text NOT NULL DEFAULT 'free'
19972
+ )
19973
+ `,
19974
+ `
19975
+ CREATE UNIQUE INDEX projects_organization_id_slug_key
19976
+ ON projects (organization_id, slug)
19977
+ `,
19978
+ `
19979
+ CREATE TABLE services (
19980
+ id uuid PRIMARY KEY,
19981
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
19982
+ name text NOT NULL,
19983
+ runtime text,
19984
+ framework text,
19985
+ environment text NOT NULL DEFAULT 'production',
19986
+ created_at timestamptz NOT NULL DEFAULT now(),
19987
+ updated_at timestamptz NOT NULL DEFAULT now(),
19988
+ UNIQUE (project_id, name, environment)
19989
+ )
19990
+ `,
19991
+ `
19992
+ CREATE TABLE project_tokens (
19993
+ id uuid PRIMARY KEY,
19994
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
19995
+ token_hash text UNIQUE NOT NULL,
19996
+ label text NOT NULL,
19997
+ allowed_origins jsonb NOT NULL DEFAULT '[]'::jsonb,
19998
+ last_used_at timestamptz,
19999
+ created_at timestamptz NOT NULL DEFAULT now(),
20000
+ revoked_at timestamptz,
20001
+ expires_at timestamptz
20002
+ )
20003
+ `,
20004
+ `
20005
+ CREATE TABLE member_tokens (
20006
+ id uuid PRIMARY KEY,
20007
+ user_id uuid NOT NULL,
20008
+ organization_id uuid NOT NULL,
20009
+ token_hash text UNIQUE NOT NULL,
20010
+ label text NOT NULL,
20011
+ last_used_at timestamptz,
20012
+ created_at timestamptz NOT NULL DEFAULT now(),
20013
+ revoked_at timestamptz,
20014
+ expires_at timestamptz
20015
+ )
20016
+ `,
20017
+ `
20018
+ CREATE INDEX member_tokens_org_idx
20019
+ ON member_tokens (organization_id)
20020
+ `,
20021
+ `
20022
+ CREATE TABLE audit_logs (
20023
+ id uuid PRIMARY KEY,
20024
+ organization_id uuid,
20025
+ actor_user_id uuid,
20026
+ actor_type text NOT NULL,
20027
+ action text NOT NULL,
20028
+ target_type text NOT NULL,
20029
+ target_id text,
20030
+ status text NOT NULL,
20031
+ ip_address text,
20032
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
20033
+ occurred_at timestamptz NOT NULL,
20034
+ created_at timestamptz NOT NULL DEFAULT now()
20035
+ )
20036
+ `,
20037
+ `
20038
+ CREATE INDEX audit_logs_organization_occurred_at_idx
20039
+ ON audit_logs (organization_id, occurred_at DESC, created_at DESC)
20040
+ `,
20041
+ `
20042
+ CREATE INDEX audit_logs_action_occurred_at_idx
20043
+ ON audit_logs (action, occurred_at DESC, created_at DESC)
20044
+ `,
20045
+ `
20046
+ CREATE TABLE organization_members (
20047
+ id uuid PRIMARY KEY,
20048
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
20049
+ user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20050
+ role text NOT NULL DEFAULT 'member',
20051
+ suspended_at timestamptz,
20052
+ created_at timestamptz NOT NULL DEFAULT now(),
20053
+ UNIQUE (organization_id, user_id)
20054
+ )
20055
+ `,
20056
+ `
20057
+ CREATE INDEX organization_members_org_idx
20058
+ ON organization_members (organization_id)
20059
+ `,
20060
+ `
20061
+ CREATE INDEX organization_members_user_idx
20062
+ ON organization_members (user_id)
20063
+ `,
20064
+ `
20065
+ CREATE TABLE sessions (
20066
+ id uuid PRIMARY KEY,
20067
+ user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20068
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
20069
+ session_token_hash text UNIQUE NOT NULL,
20070
+ created_at timestamptz NOT NULL DEFAULT now(),
20071
+ expires_at timestamptz NOT NULL,
20072
+ revoked_at timestamptz
20073
+ )
20074
+ `,
20075
+ `
20076
+ CREATE INDEX sessions_token_hash_idx
20077
+ ON sessions (session_token_hash)
20078
+ `,
20079
+ `
20080
+ CREATE INDEX sessions_user_org_idx
20081
+ ON sessions (user_id, organization_id)
20082
+ `,
20083
+ `
20084
+ CREATE TABLE email_auth_challenges (
20085
+ id uuid PRIMARY KEY,
20086
+ email text NOT NULL,
20087
+ code_hash text NOT NULL,
20088
+ accepted_terms_at timestamptz,
20089
+ created_at timestamptz NOT NULL DEFAULT now(),
20090
+ expires_at timestamptz NOT NULL,
20091
+ used_at timestamptz
20092
+ )
20093
+ `,
20094
+ `
20095
+ CREATE INDEX email_auth_challenges_email_idx
20096
+ ON email_auth_challenges (lower(email), created_at DESC)
20097
+ `,
20098
+ `
20099
+ CREATE INDEX email_auth_challenges_code_hash_idx
20100
+ ON email_auth_challenges (code_hash)
20101
+ `,
20102
+ `
20103
+ CREATE TABLE github_device_authorizations (
20104
+ id uuid PRIMARY KEY,
20105
+ device_code text NOT NULL UNIQUE,
20106
+ user_code text NOT NULL,
20107
+ verification_uri text NOT NULL,
20108
+ interval_seconds integer NOT NULL,
20109
+ expires_at timestamptz NOT NULL,
20110
+ accepted_terms_at timestamptz,
20111
+ created_at timestamptz NOT NULL DEFAULT now(),
20112
+ completed_at timestamptz,
20113
+ claimed_at timestamptz,
20114
+ terminal_error text,
20115
+ user_id uuid REFERENCES users(id) ON DELETE SET NULL,
20116
+ organization_id uuid REFERENCES organizations(id) ON DELETE SET NULL
20117
+ )
20118
+ `,
20119
+ `
20120
+ CREATE INDEX github_device_authorizations_user_code_idx
20121
+ ON github_device_authorizations (user_code, created_at DESC)
20122
+ `,
20123
+ `
20124
+ CREATE INDEX github_device_authorizations_expires_at_idx
20125
+ ON github_device_authorizations (expires_at)
20126
+ `,
20127
+ `
20128
+ CREATE TABLE project_members (
20129
+ id uuid PRIMARY KEY,
20130
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20131
+ user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20132
+ role text NOT NULL,
20133
+ invited_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
20134
+ created_at timestamptz NOT NULL DEFAULT now(),
20135
+ updated_at timestamptz NOT NULL DEFAULT now(),
20136
+ UNIQUE (project_id, user_id)
20137
+ )
20138
+ `,
20139
+ `
20140
+ CREATE INDEX project_members_project_id_idx
20141
+ ON project_members (project_id, created_at DESC)
20142
+ `,
20143
+ `
20144
+ CREATE INDEX project_members_user_id_idx
20145
+ ON project_members (user_id, created_at DESC)
20146
+ `,
20147
+ `
20148
+ CREATE TABLE project_invites (
20149
+ id uuid PRIMARY KEY,
20150
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20151
+ email text NOT NULL,
20152
+ role text NOT NULL,
20153
+ invited_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
20154
+ invite_token_hash text NOT NULL,
20155
+ accepted_at timestamptz,
20156
+ canceled_at timestamptz,
20157
+ expires_at timestamptz NOT NULL,
20158
+ created_at timestamptz NOT NULL DEFAULT now()
20159
+ )
20160
+ `,
20161
+ `
20162
+ CREATE INDEX project_invites_project_id_idx
20163
+ ON project_invites (project_id, created_at DESC)
20164
+ `,
20165
+ `
20166
+ CREATE UNIQUE INDEX project_invites_pending_project_email_key
20167
+ ON project_invites (project_id, lower(email))
20168
+ WHERE accepted_at IS NULL AND canceled_at IS NULL
20169
+ `,
20170
+ `
20171
+ CREATE UNIQUE INDEX project_invites_invite_token_hash_key
20172
+ ON project_invites (invite_token_hash)
20173
+ `,
20174
+ `
20175
+ CREATE TABLE oauth_identities (
20176
+ id uuid PRIMARY KEY,
20177
+ provider text NOT NULL,
20178
+ provider_user_id text NOT NULL,
20179
+ user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20180
+ created_at timestamptz NOT NULL DEFAULT now(),
20181
+ updated_at timestamptz NOT NULL DEFAULT now(),
20182
+ UNIQUE (provider, provider_user_id)
20183
+ )
20184
+ `,
20185
+ `
20186
+ CREATE INDEX oauth_identities_user_id_idx
20187
+ ON oauth_identities (user_id, provider)
20188
+ `,
20189
+ `
20190
+ CREATE TABLE probe_activations (
20191
+ id uuid PRIMARY KEY,
20192
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20193
+ created_by_member_id uuid NOT NULL,
20194
+ label_pattern text NOT NULL,
20195
+ service text NOT NULL DEFAULT '*',
20196
+ environment text NOT NULL DEFAULT '*',
20197
+ trigger_expires_at timestamptz NOT NULL,
20198
+ expires_at timestamptz NOT NULL,
20199
+ deactivated_at timestamptz,
20200
+ created_at timestamptz NOT NULL DEFAULT now()
20201
+ )
20202
+ `,
20203
+ `
20204
+ CREATE INDEX probe_activations_project_active_idx
20205
+ ON probe_activations (project_id, expires_at DESC)
20206
+ WHERE deactivated_at IS NULL
20207
+ `,
20208
+ `
20209
+ CREATE TABLE capture_policies (
20210
+ project_id uuid PRIMARY KEY REFERENCES projects(id) ON DELETE CASCADE,
20211
+ preset text NOT NULL DEFAULT 'minimal',
20212
+ capture_logs text,
20213
+ capture_request_events text,
20214
+ capture_breadcrumbs text,
20215
+ capture_probe_events text,
20216
+ immediate_client_error_statuses jsonb,
20217
+ updated_at timestamptz NOT NULL DEFAULT now()
20218
+ )
20219
+ `,
20220
+ `
20221
+ CREATE TABLE capture_rules (
20222
+ id uuid PRIMARY KEY,
20223
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20224
+ name text NOT NULL,
20225
+ description text,
20226
+ enabled boolean NOT NULL DEFAULT true,
20227
+ action text NOT NULL,
20228
+ matcher jsonb NOT NULL,
20229
+ sample_rate double precision,
20230
+ sample_event_class text,
20231
+ created_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
20232
+ created_from_incident_id text,
20233
+ created_from_event_id text,
20234
+ expires_at timestamptz,
20235
+ hit_count bigint NOT NULL DEFAULT 0,
20236
+ last_matched_at timestamptz,
20237
+ created_at timestamptz NOT NULL DEFAULT now(),
20238
+ updated_at timestamptz NOT NULL DEFAULT now()
20239
+ )
20240
+ `,
20241
+ `
20242
+ CREATE INDEX capture_rules_project_enabled_idx
20243
+ ON capture_rules (project_id, enabled)
20244
+ `,
20245
+ `
20246
+ CREATE INDEX capture_rules_project_updated_idx
20247
+ ON capture_rules (project_id, updated_at DESC)
20248
+ `,
20249
+ `
20250
+ CREATE TABLE deployments (
20251
+ id uuid PRIMARY KEY,
20252
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20253
+ service_id uuid REFERENCES services(id) ON DELETE SET NULL,
20254
+ environment text NOT NULL,
20255
+ source_event_id uuid UNIQUE NOT NULL,
20256
+ commit_sha text,
20257
+ version text,
20258
+ branch text,
20259
+ deployed_at timestamptz NOT NULL,
20260
+ metadata jsonb NOT NULL DEFAULT '{}'::jsonb,
20261
+ created_at timestamptz NOT NULL DEFAULT now(),
20262
+ updated_at timestamptz NOT NULL DEFAULT now()
20263
+ )
20264
+ `,
20265
+ `
20266
+ CREATE INDEX deployments_project_service_env_deployed_idx
20267
+ ON deployments (project_id, service_id, environment, deployed_at DESC)
20268
+ `,
20269
+ `
20270
+ CREATE TABLE incidents (
20271
+ id uuid PRIMARY KEY,
20272
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20273
+ service_id uuid REFERENCES services(id) ON DELETE SET NULL,
20274
+ environment text NOT NULL DEFAULT 'production',
20275
+ fingerprint text NOT NULL,
20276
+ fingerprint_version text NOT NULL DEFAULT 'v1',
20277
+ title text NOT NULL,
20278
+ severity text NOT NULL,
20279
+ status text NOT NULL DEFAULT 'open',
20280
+ first_seen_at timestamptz NOT NULL,
20281
+ last_seen_at timestamptz NOT NULL,
20282
+ occurrence_count integer NOT NULL DEFAULT 1,
20283
+ matched_fields text[],
20284
+ created_at timestamptz NOT NULL DEFAULT now(),
20285
+ updated_at timestamptz NOT NULL DEFAULT now(),
20286
+ regressed_at timestamptz,
20287
+ spike_detected_at timestamptz,
20288
+ frequency_occurrences_1m integer,
20289
+ frequency_occurrences_5m integer,
20290
+ frequency_occurrences_1h integer,
20291
+ frequency_occurrences_24h integer,
20292
+ frequency_baseline_1h_per_5m double precision,
20293
+ frequency_spike_ratio_5m_to_1h double precision,
20294
+ frequency_has_sufficient_baseline boolean,
20295
+ frequency_is_spiking boolean,
20296
+ frequency_snapshot_at timestamptz,
20297
+ latest_deployment_id uuid REFERENCES deployments(id) ON DELETE SET NULL,
20298
+ bundle_generation_number integer NOT NULL DEFAULT 0,
20299
+ bundle_created_at timestamptz,
20300
+ bundle_updated_at timestamptz,
20301
+ bundle_source_event_id uuid,
20302
+ bundle_source_occurred_at timestamptz,
20303
+ bundle_trigger text,
20304
+ bundle_failure_reason text,
20305
+ resolved_at timestamptz,
20306
+ resolved_by_member_id uuid REFERENCES users(id) ON DELETE SET NULL,
20307
+ UNIQUE (project_id, environment, service_id, fingerprint)
20308
+ )
20309
+ `,
20310
+ `
20311
+ CREATE TABLE processed_events (
20312
+ event_id uuid PRIMARY KEY,
20313
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20314
+ event_type text NOT NULL,
20315
+ fingerprint text NOT NULL,
20316
+ normalized_message text NOT NULL,
20317
+ processed_at timestamptz NOT NULL DEFAULT now()
20318
+ )
20319
+ `,
20320
+ `
20321
+ CREATE TABLE improvement_opportunities (
20322
+ id uuid PRIMARY KEY,
20323
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20324
+ service_id uuid REFERENCES services(id) ON DELETE SET NULL,
20325
+ service_name text NOT NULL,
20326
+ environment text NOT NULL DEFAULT 'production',
20327
+ kind text NOT NULL,
20328
+ status text NOT NULL DEFAULT 'open',
20329
+ severity text NOT NULL,
20330
+ confidence numeric NOT NULL,
20331
+ fingerprint text NOT NULL,
20332
+ title text NOT NULL,
20333
+ summary text NOT NULL,
20334
+ occurrence_count integer NOT NULL DEFAULT 1,
20335
+ evidence jsonb NOT NULL,
20336
+ first_detected_at timestamptz NOT NULL,
20337
+ last_detected_at timestamptz NOT NULL,
20338
+ last_source_event_id uuid,
20339
+ related_incident_ids uuid[] NOT NULL DEFAULT '{}',
20340
+ bundle_generation_number integer NOT NULL DEFAULT 0,
20341
+ bundle_created_at timestamptz,
20342
+ bundle_updated_at timestamptz,
20343
+ bundle_source_event_id uuid,
20344
+ bundle_failure_reason text,
20345
+ resolved_at timestamptz,
20346
+ resolved_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
20347
+ snoozed_until timestamptz,
20348
+ created_at timestamptz NOT NULL DEFAULT now(),
20349
+ updated_at timestamptz NOT NULL DEFAULT now(),
20350
+ UNIQUE (project_id, fingerprint)
20351
+ )
20352
+ `,
20353
+ `
20354
+ CREATE INDEX improvement_opportunities_project_status_detected_idx
20355
+ ON improvement_opportunities (project_id, status, last_detected_at DESC)
20356
+ `,
20357
+ `
20358
+ CREATE INDEX improvement_opportunities_project_kind_detected_idx
20359
+ ON improvement_opportunities (project_id, kind, last_detected_at DESC)
20360
+ `,
20361
+ `
20362
+ CREATE INDEX improvement_opportunities_project_service_env_idx
20363
+ ON improvement_opportunities (project_id, service_id, environment)
20364
+ `,
20365
+ `
20366
+ CREATE TABLE improvement_opportunity_events (
20367
+ improvement_opportunity_id uuid NOT NULL REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
20368
+ event_id uuid NOT NULL,
20369
+ event_type text NOT NULL,
20370
+ occurred_at timestamptz NOT NULL,
20371
+ PRIMARY KEY (improvement_opportunity_id, event_id)
20372
+ )
20373
+ `,
20374
+ `
20375
+ CREATE INDEX improvement_opportunity_events_detected_idx
20376
+ ON improvement_opportunity_events (improvement_opportunity_id, occurred_at DESC, event_id DESC)
20377
+ `,
20378
+ `
20379
+ CREATE TABLE bundle_generations (
20380
+ id uuid PRIMARY KEY,
20381
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20382
+ incident_id uuid REFERENCES incidents(id) ON DELETE CASCADE,
20383
+ improvement_opportunity_id uuid REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
20384
+ bundle_type text NOT NULL,
20385
+ generation_number integer NOT NULL,
20386
+ source_event_id uuid NOT NULL,
20387
+ source_occurred_at timestamptz NOT NULL,
20388
+ trigger text NOT NULL,
20389
+ created_at timestamptz NOT NULL,
20390
+ updated_at timestamptz NOT NULL,
20391
+ CHECK (
20392
+ (incident_id IS NOT NULL AND improvement_opportunity_id IS NULL AND bundle_type = 'failure')
20393
+ OR (incident_id IS NULL AND improvement_opportunity_id IS NOT NULL AND bundle_type = 'improvement')
20394
+ )
20395
+ )
20396
+ `,
20397
+ `
20398
+ CREATE UNIQUE INDEX bundle_generations_incident_source_idx
20399
+ ON bundle_generations (incident_id, source_event_id)
20400
+ WHERE incident_id IS NOT NULL
20401
+ `,
20402
+ `
20403
+ CREATE UNIQUE INDEX bundle_generations_improvement_source_idx
20404
+ ON bundle_generations (improvement_opportunity_id, source_event_id)
20405
+ WHERE improvement_opportunity_id IS NOT NULL
20406
+ `,
20407
+ `
20408
+ CREATE INDEX bundle_generations_project_created_idx
20409
+ ON bundle_generations (project_id, created_at DESC, bundle_type)
20410
+ `,
20411
+ `
20412
+ CREATE INDEX bundle_generations_incident_generation_idx
20413
+ ON bundle_generations (incident_id, generation_number DESC)
20414
+ `,
20415
+ `
20416
+ CREATE INDEX bundle_generations_improvement_generation_idx
20417
+ ON bundle_generations (improvement_opportunity_id, generation_number DESC)
20418
+ WHERE improvement_opportunity_id IS NOT NULL
20419
+ `,
20420
+ `
20421
+ CREATE TABLE incident_events (
20422
+ incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
20423
+ event_id uuid NOT NULL,
20424
+ event_type text NOT NULL,
20425
+ event_class text NOT NULL DEFAULT 'context_signal',
20426
+ occurred_at timestamptz NOT NULL,
20427
+ is_sampled boolean NOT NULL DEFAULT false,
20428
+ level text,
20429
+ retain_first boolean NOT NULL DEFAULT false,
20430
+ retain_latest boolean NOT NULL DEFAULT false,
20431
+ retain_after_deploy boolean NOT NULL DEFAULT false,
20432
+ retain_highest_severity boolean NOT NULL DEFAULT false,
20433
+ retain_deploy_metadata boolean NOT NULL DEFAULT false,
20434
+ severity_rank integer NOT NULL DEFAULT 0,
20435
+ PRIMARY KEY (incident_id, event_id)
20436
+ )
20437
+ `,
20438
+ `
20439
+ CREATE INDEX incident_events_incident_occurred_event_idx
20440
+ ON incident_events (incident_id, occurred_at DESC, event_id DESC)
20441
+ `,
20442
+ `
20443
+ CREATE INDEX incident_events_incident_level_occurred_event_idx
20444
+ ON incident_events (incident_id, level, occurred_at DESC, event_id DESC)
20445
+ `,
20446
+ `
20447
+ CREATE INDEX incident_events_incident_sampled_idx
20448
+ ON incident_events (incident_id, is_sampled, occurred_at ASC, event_id ASC)
20449
+ `,
20450
+ `
20451
+ CREATE TABLE weekly_report_channels (
20452
+ id uuid PRIMARY KEY,
20453
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20454
+ channel text NOT NULL,
20455
+ config jsonb NOT NULL DEFAULT '{}'::jsonb,
20456
+ schedule_day_of_week text NOT NULL,
20457
+ schedule_hour_of_day integer NOT NULL,
20458
+ schedule_timezone text NOT NULL,
20459
+ is_enabled boolean NOT NULL DEFAULT true,
20460
+ created_at timestamptz NOT NULL DEFAULT now(),
20461
+ updated_at timestamptz NOT NULL DEFAULT now()
20462
+ )
20463
+ `,
20464
+ `
20465
+ CREATE INDEX weekly_report_channels_project_created_idx
20466
+ ON weekly_report_channels (project_id, created_at ASC)
20467
+ `,
20468
+ `
20469
+ CREATE UNIQUE INDEX weekly_report_channels_project_email_unique_idx
20470
+ ON weekly_report_channels (project_id)
20471
+ WHERE channel = 'email'
20472
+ `,
20473
+ `
20474
+ CREATE TABLE weekly_report_deliveries (
20475
+ id uuid PRIMARY KEY,
20476
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20477
+ weekly_report_channel_id uuid REFERENCES weekly_report_channels(id) ON DELETE CASCADE,
20478
+ window_start timestamptz NOT NULL,
20479
+ window_end timestamptz NOT NULL,
20480
+ channel text NOT NULL,
20481
+ status text NOT NULL,
20482
+ last_error text,
20483
+ delivered_at timestamptz,
20484
+ created_at timestamptz NOT NULL DEFAULT now(),
20485
+ updated_at timestamptz NOT NULL DEFAULT now()
20486
+ )
20487
+ `,
20488
+ `
20489
+ CREATE INDEX weekly_report_deliveries_project_window_idx
20490
+ ON weekly_report_deliveries (project_id, window_end DESC, channel)
20491
+ `,
20492
+ `
20493
+ CREATE UNIQUE INDEX weekly_report_deliveries_channel_window_idx
20494
+ ON weekly_report_deliveries (weekly_report_channel_id, window_start, window_end)
20495
+ WHERE weekly_report_channel_id IS NOT NULL
20496
+ `,
20497
+ `
20498
+ CREATE INDEX weekly_report_deliveries_channel_idx
20499
+ ON weekly_report_deliveries (weekly_report_channel_id, window_end DESC)
20500
+ `,
20501
+ `
20502
+ CREATE TABLE alert_rules (
20503
+ id uuid PRIMARY KEY,
20504
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20505
+ created_by_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20506
+ service_id uuid REFERENCES services(id) ON DELETE CASCADE,
20507
+ channel text NOT NULL,
20508
+ condition_type text NOT NULL,
20509
+ severity_min text,
20510
+ config jsonb NOT NULL DEFAULT '{}'::jsonb,
20511
+ is_enabled boolean NOT NULL DEFAULT true,
20512
+ created_at timestamptz NOT NULL DEFAULT now(),
20513
+ updated_at timestamptz NOT NULL DEFAULT now()
20514
+ )
20515
+ `,
20516
+ `
20517
+ CREATE INDEX alert_rules_project_enabled_idx
20518
+ ON alert_rules (project_id, is_enabled)
20519
+ `,
20520
+ `
20521
+ CREATE TABLE slack_destinations (
20522
+ id uuid PRIMARY KEY,
20523
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
20524
+ slack_team_id text NOT NULL,
20525
+ slack_team_name text,
20526
+ slack_channel_id text NOT NULL,
20527
+ slack_channel_name text,
20528
+ webhook_url_ciphertext text NOT NULL,
20529
+ installed_by_member_id uuid REFERENCES users(id) ON DELETE SET NULL,
20530
+ is_active boolean NOT NULL DEFAULT true,
20531
+ created_at timestamptz NOT NULL DEFAULT now(),
20532
+ updated_at timestamptz NOT NULL DEFAULT now(),
20533
+ UNIQUE (organization_id, slack_team_id, slack_channel_id)
20534
+ )
20535
+ `,
20536
+ `
20537
+ CREATE INDEX slack_destinations_org_active_idx
20538
+ ON slack_destinations (organization_id, is_active, created_at)
20539
+ `,
20540
+ `
20541
+ CREATE TABLE alert_deliveries (
20542
+ id uuid PRIMARY KEY,
20543
+ alert_id uuid NOT NULL REFERENCES alert_rules(id) ON DELETE CASCADE,
20544
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20545
+ incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
20546
+ condition_type text NOT NULL,
20547
+ dedupe_key text NOT NULL,
20548
+ channel text NOT NULL,
20549
+ status text NOT NULL,
20550
+ payload jsonb NOT NULL,
20551
+ last_error text,
20552
+ delivered_at timestamptz,
20553
+ created_at timestamptz NOT NULL DEFAULT now(),
20554
+ updated_at timestamptz NOT NULL DEFAULT now(),
20555
+ UNIQUE (alert_id, incident_id, dedupe_key)
20556
+ )
20557
+ `,
20558
+ `
20559
+ CREATE INDEX alert_deliveries_project_status_idx
20560
+ ON alert_deliveries (project_id, status, created_at DESC)
20561
+ `,
20562
+ `
20563
+ CREATE TABLE alert_email_digests (
20564
+ id uuid PRIMARY KEY,
20565
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20566
+ recipient text NOT NULL,
20567
+ status text NOT NULL,
20568
+ next_attempt_at timestamptz,
20569
+ claimed_at timestamptz,
20570
+ last_error text,
20571
+ delivered_at timestamptz,
20572
+ created_at timestamptz NOT NULL DEFAULT now(),
20573
+ updated_at timestamptz NOT NULL DEFAULT now()
20574
+ )
20575
+ `,
20576
+ `
20577
+ CREATE UNIQUE INDEX alert_email_digests_project_recipient_pending_idx
20578
+ ON alert_email_digests (project_id, recipient)
20579
+ WHERE status = 'pending' AND claimed_at IS NULL
20580
+ `,
20581
+ `
20582
+ CREATE INDEX alert_email_digests_status_next_attempt_idx
20583
+ ON alert_email_digests (status, next_attempt_at)
20584
+ `,
20585
+ `
20586
+ CREATE TABLE alert_email_digest_items (
20587
+ id uuid PRIMARY KEY,
20588
+ digest_id uuid NOT NULL REFERENCES alert_email_digests(id) ON DELETE CASCADE,
20589
+ alert_id uuid NOT NULL REFERENCES alert_rules(id) ON DELETE CASCADE,
20590
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20591
+ incident_id uuid NOT NULL REFERENCES incidents(id) ON DELETE CASCADE,
20592
+ condition_type text NOT NULL,
20593
+ dedupe_key text NOT NULL,
20594
+ payload jsonb NOT NULL,
20595
+ created_at timestamptz NOT NULL DEFAULT now(),
20596
+ UNIQUE (alert_id, incident_id, dedupe_key)
20597
+ )
20598
+ `,
20599
+ `
20600
+ CREATE INDEX alert_email_digest_items_digest_created_idx
20601
+ ON alert_email_digest_items (digest_id, created_at ASC)
20602
+ `,
20603
+ `
20604
+ CREATE TABLE agent_webhooks (
20605
+ id uuid PRIMARY KEY,
20606
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20607
+ created_by_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20608
+ url text NOT NULL,
20609
+ secret_hash text NOT NULL,
20610
+ events text[] NOT NULL,
20611
+ filters jsonb NOT NULL DEFAULT '{}'::jsonb,
20612
+ is_enabled boolean NOT NULL DEFAULT true,
20613
+ created_at timestamptz NOT NULL DEFAULT now(),
20614
+ updated_at timestamptz NOT NULL DEFAULT now()
20615
+ )
20616
+ `,
20617
+ `
20618
+ CREATE INDEX agent_webhooks_project_enabled_idx
20619
+ ON agent_webhooks (project_id, is_enabled)
20620
+ `,
20621
+ `
20622
+ CREATE TABLE webhook_deliveries (
20623
+ id uuid PRIMARY KEY,
20624
+ webhook_id uuid REFERENCES agent_webhooks(id) ON DELETE CASCADE,
20625
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20626
+ incident_id uuid REFERENCES incidents(id) ON DELETE CASCADE,
20627
+ event_type text NOT NULL,
20628
+ target_url text NOT NULL,
20629
+ signing_secret text NOT NULL,
20630
+ status text NOT NULL DEFAULT 'pending',
20631
+ attempt_count integer NOT NULL DEFAULT 0,
20632
+ occurred_at timestamptz NOT NULL,
20633
+ next_attempt_at timestamptz,
20634
+ last_response_code integer,
20635
+ last_attempted_at timestamptz,
20636
+ last_error text,
20637
+ payload jsonb NOT NULL,
20638
+ created_at timestamptz NOT NULL DEFAULT now(),
20639
+ updated_at timestamptz NOT NULL DEFAULT now()
20640
+ )
20641
+ `,
20642
+ `
20643
+ CREATE INDEX webhook_deliveries_status_next_attempt_idx
20644
+ ON webhook_deliveries (status, next_attempt_at)
20645
+ `,
20646
+ `
20647
+ CREATE TABLE processed_billing_events (
20648
+ event_id text PRIMARY KEY,
20649
+ event_type text NOT NULL,
20650
+ organization_id uuid,
20651
+ processed_at timestamptz NOT NULL DEFAULT now()
20652
+ )
20653
+ `,
20654
+ `
20655
+ CREATE TABLE github_installations (
20656
+ id uuid PRIMARY KEY,
20657
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
20658
+ installation_id bigint NOT NULL UNIQUE,
20659
+ account_login text NOT NULL,
20660
+ account_type text NOT NULL CHECK (account_type IN ('Organization', 'User')),
20661
+ status text NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'suspended', 'removed')),
20662
+ created_at timestamptz NOT NULL DEFAULT now(),
20663
+ updated_at timestamptz NOT NULL DEFAULT now(),
20664
+ UNIQUE (organization_id)
20665
+ )
20666
+ `,
20667
+ `
20668
+ CREATE INDEX github_installations_status_idx
20669
+ ON github_installations (status)
20670
+ `,
20671
+ `
20672
+ CREATE TABLE project_github_repos (
20673
+ id uuid PRIMARY KEY,
20674
+ project_id uuid NOT NULL UNIQUE REFERENCES projects(id) ON DELETE CASCADE,
20675
+ installation_id uuid NOT NULL REFERENCES github_installations(id) ON DELETE CASCADE,
20676
+ repo_owner text NOT NULL,
20677
+ repo_name text NOT NULL,
20678
+ default_branch text NOT NULL DEFAULT 'main',
20679
+ created_at timestamptz NOT NULL DEFAULT now(),
20680
+ updated_at timestamptz NOT NULL DEFAULT now()
20681
+ )
20682
+ `,
20683
+ `
20684
+ CREATE TABLE github_dispatch_rules (
20685
+ id uuid PRIMARY KEY,
20686
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20687
+ created_by_user_id uuid NOT NULL REFERENCES users(id) ON DELETE CASCADE,
20688
+ name text NOT NULL,
20689
+ enabled boolean NOT NULL DEFAULT true,
20690
+ event_types text[] NOT NULL,
20691
+ environments text[],
20692
+ services text[],
20693
+ severity_min text CHECK (severity_min IN ('low', 'medium', 'high', 'critical')),
20694
+ bundle_type text CHECK (bundle_type IN ('failure', 'improvement')),
20695
+ incident_status text NOT NULL DEFAULT 'new_or_reopened'
20696
+ CHECK (incident_status IN ('new_only', 'reopened_only', 'new_or_reopened')),
20697
+ cooldown_seconds integer NOT NULL DEFAULT 300,
20698
+ created_at timestamptz NOT NULL DEFAULT now(),
20699
+ updated_at timestamptz NOT NULL DEFAULT now()
20700
+ )
20701
+ `,
20702
+ `
20703
+ CREATE INDEX github_dispatch_rules_project_enabled_idx
20704
+ ON github_dispatch_rules (project_id, enabled)
20705
+ `,
20706
+ `
20707
+ CREATE TABLE github_dispatch_deliveries (
20708
+ id uuid PRIMARY KEY,
20709
+ rule_id uuid NOT NULL REFERENCES github_dispatch_rules(id) ON DELETE CASCADE,
20710
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20711
+ incident_id uuid REFERENCES incidents(id) ON DELETE CASCADE,
20712
+ improvement_opportunity_id uuid REFERENCES improvement_opportunities(id) ON DELETE CASCADE,
20713
+ target_fingerprint text NOT NULL,
20714
+ installation_id bigint NOT NULL,
20715
+ repo_owner text NOT NULL,
20716
+ repo_name text NOT NULL,
20717
+ status text NOT NULL DEFAULT 'pending'
20718
+ CHECK (status IN ('pending', 'retrying', 'delivered', 'failed', 'skipped')),
20719
+ attempt_count integer NOT NULL DEFAULT 0,
20720
+ next_attempt_at timestamptz,
20721
+ last_attempt_at timestamptz,
20722
+ last_error text,
20723
+ github_status_code integer,
20724
+ dispatch_payload jsonb NOT NULL DEFAULT '{}'::jsonb,
20725
+ created_at timestamptz NOT NULL DEFAULT now(),
20726
+ updated_at timestamptz NOT NULL DEFAULT now(),
20727
+ dedupe_key text NOT NULL,
20728
+ CHECK (
20729
+ (incident_id IS NOT NULL AND improvement_opportunity_id IS NULL)
20730
+ OR (incident_id IS NULL AND improvement_opportunity_id IS NOT NULL)
20731
+ )
20732
+ )
20733
+ `,
20734
+ `
20735
+ CREATE INDEX github_dispatch_deliveries_status_next_attempt_idx
20736
+ ON github_dispatch_deliveries (status, next_attempt_at)
20737
+ `,
20738
+ `
20739
+ CREATE UNIQUE INDEX github_dispatch_deliveries_rule_dedupe_key_idx
20740
+ ON github_dispatch_deliveries (rule_id, target_fingerprint, dedupe_key)
20741
+ `,
20742
+ `
20743
+ CREATE TABLE org_usage_counters (
20744
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
20745
+ period_starts_at timestamptz NOT NULL,
20746
+ raw_ingested_events integer NOT NULL DEFAULT 0,
20747
+ updated_at timestamptz NOT NULL DEFAULT now(),
20748
+ PRIMARY KEY (organization_id, period_starts_at)
20749
+ )
20750
+ `,
20751
+ `
20752
+ CREATE TABLE operational_email_deliveries (
20753
+ id uuid PRIMARY KEY,
20754
+ organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
20755
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
20756
+ kind text NOT NULL
20757
+ CHECK (kind IN ('webhook_auto_disabled', 'allowance_warning_80', 'allowance_limit_reached', 'retention_rotation_notice')),
20758
+ dedupe_key text NOT NULL,
20759
+ payload jsonb NOT NULL DEFAULT '{}'::jsonb,
20760
+ status text NOT NULL DEFAULT 'pending'
20761
+ CHECK (status IN ('pending', 'retrying', 'delivered', 'failed')),
20762
+ attempt_count integer NOT NULL DEFAULT 0,
20763
+ next_attempt_at timestamptz,
20764
+ last_error text,
20765
+ delivered_at timestamptz,
20766
+ created_at timestamptz NOT NULL DEFAULT now(),
20767
+ updated_at timestamptz NOT NULL DEFAULT now(),
20768
+ UNIQUE (organization_id, kind, dedupe_key)
20769
+ )
20770
+ `,
20771
+ `
20772
+ CREATE INDEX operational_email_deliveries_status_next_attempt_idx
20773
+ ON operational_email_deliveries (status, next_attempt_at, created_at)
20774
+ `
20775
+ ];
20776
+ var STORAGE_BOOTSTRAP_SQL = STORAGE_BOOTSTRAP_STATEMENTS.join(";\n\n");
20777
+
20778
+ // ../../packages/storage/src/schema-migrations.ts
19238
20779
  function computeMigrationChecksum(input) {
19239
20780
  return (0, import_node_crypto3.createHash)("sha256").update(JSON.stringify(input)).digest("hex");
19240
20781
  }
@@ -19656,6 +21197,76 @@ var STORAGE_SCHEMA_MIGRATIONS = [
19656
21197
  statements: [
19657
21198
  "ALTER TABLE project_tokens ADD COLUMN IF NOT EXISTS allowed_origins jsonb NOT NULL DEFAULT '[]'::jsonb"
19658
21199
  ]
21200
+ }),
21201
+ defineStorageSchemaMigration({
21202
+ id: "202605260001_fix_weekly_report_delivery_conflict_index",
21203
+ description: "Ensure weekly report delivery dedupe rows and partial unique index exist for conflict claims.",
21204
+ statements: [
21205
+ `
21206
+ DELETE FROM weekly_report_deliveries
21207
+ WHERE id IN (
21208
+ SELECT id
21209
+ FROM (
21210
+ SELECT
21211
+ id,
21212
+ row_number() OVER (
21213
+ PARTITION BY weekly_report_channel_id, window_start, window_end
21214
+ ORDER BY created_at ASC, id ASC
21215
+ ) AS row_number
21216
+ FROM weekly_report_deliveries
21217
+ WHERE weekly_report_channel_id IS NOT NULL
21218
+ ) ranked
21219
+ WHERE ranked.row_number > 1
21220
+ )
21221
+ `,
21222
+ `
21223
+ CREATE UNIQUE INDEX IF NOT EXISTS weekly_report_deliveries_channel_window_idx
21224
+ ON weekly_report_deliveries (weekly_report_channel_id, window_start, window_end)
21225
+ WHERE weekly_report_channel_id IS NOT NULL
21226
+ `
21227
+ ]
21228
+ }),
21229
+ defineStorageSchemaMigration({
21230
+ id: "202605260001_set_high_confidence_as_project_improvement_default",
21231
+ description: "Make high-confidence the default hosted improvement sensitivity for new projects.",
21232
+ statements: [
21233
+ "ALTER TABLE projects ALTER COLUMN improvement_bundle_sensitivity SET DEFAULT 'high_confidence'"
21234
+ ]
21235
+ }),
21236
+ defineStorageSchemaMigration({
21237
+ id: "202605260002_add_capture_rules",
21238
+ description: "Add persisted project capture rules for dynamic demote/sample/drop handling.",
21239
+ statements: [
21240
+ `
21241
+ CREATE TABLE IF NOT EXISTS capture_rules (
21242
+ id uuid PRIMARY KEY,
21243
+ project_id uuid NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
21244
+ name text NOT NULL,
21245
+ description text,
21246
+ enabled boolean NOT NULL DEFAULT true,
21247
+ action text NOT NULL,
21248
+ matcher jsonb NOT NULL,
21249
+ sample_rate double precision,
21250
+ sample_event_class text,
21251
+ created_by_user_id uuid REFERENCES users(id) ON DELETE SET NULL,
21252
+ created_from_incident_id text,
21253
+ created_from_event_id text,
21254
+ expires_at timestamptz,
21255
+ hit_count bigint NOT NULL DEFAULT 0,
21256
+ last_matched_at timestamptz,
21257
+ created_at timestamptz NOT NULL DEFAULT now(),
21258
+ updated_at timestamptz NOT NULL DEFAULT now()
21259
+ )
21260
+ `,
21261
+ `
21262
+ CREATE INDEX IF NOT EXISTS capture_rules_project_enabled_idx
21263
+ ON capture_rules (project_id, enabled)
21264
+ `,
21265
+ `
21266
+ CREATE INDEX IF NOT EXISTS capture_rules_project_updated_idx
21267
+ ON capture_rules (project_id, updated_at DESC)
21268
+ `
21269
+ ]
19659
21270
  })
19660
21271
  ];
19661
21272
 
@@ -19778,11 +21389,17 @@ function normalizeRouteTemplate(path) {
19778
21389
  const normalizedSegments = pathWithoutQueryOrFragment.split("/").filter((segment) => segment.length > 0).map((segment) => isDynamicRouteSegment2(segment) ? "{param}" : segment);
19779
21390
  return normalizedSegments.length === 0 ? "/" : `/${normalizedSegments.join("/")}`;
19780
21391
  }
21392
+ function isBrowserSdkFallbackFrame(frame) {
21393
+ return frame.includes("debugbundle-browser-sdk") && frame.includes("onError");
21394
+ }
19781
21395
  function deriveFirstApplicationFrame(errorContext) {
19782
21396
  const firstFrame = errorContext?.top_frames[0];
19783
21397
  if (firstFrame === void 0) {
19784
21398
  return null;
19785
21399
  }
21400
+ if (isBrowserSdkFallbackFrame(firstFrame)) {
21401
+ return null;
21402
+ }
19786
21403
  const match = /at\s+(.*?)\s+\((.*?):(\d+):(\d+)\)$/.exec(firstFrame) ?? /at\s+(.*?):(\d+):(\d+)$/.exec(firstFrame);
19787
21404
  if (match === null) {
19788
21405
  return {
@@ -19804,6 +21421,20 @@ function deriveFirstApplicationFrame(errorContext) {
19804
21421
  line: Number(match[2])
19805
21422
  };
19806
21423
  }
21424
+ function getPrimaryBrowserExceptionEvent(envelopes, primarySignalEnvelope) {
21425
+ if (primarySignalEnvelope !== null && isFrontendExceptionEnvelope(primarySignalEnvelope)) {
21426
+ return primarySignalEnvelope.payload.browser_event ?? null;
21427
+ }
21428
+ const envelope = selectLatestEnvelopeByType(envelopes, isFrontendExceptionEnvelope);
21429
+ return envelope?.payload.browser_event ?? null;
21430
+ }
21431
+ function isOpaqueBrowserError(errorContext, browserEvent) {
21432
+ if (browserEvent?.opaque === true) {
21433
+ return true;
21434
+ }
21435
+ const firstFrame = errorContext?.top_frames[0];
21436
+ return errorContext?.message === "Window error" && firstFrame !== void 0 && isBrowserSdkFallbackFrame(firstFrame);
21437
+ }
19807
21438
  function buildErrorContext(envelopes, incident, primarySignalEnvelope) {
19808
21439
  if (primarySignalEnvelope !== null && isBackendExceptionEnvelope(primarySignalEnvelope)) {
19809
21440
  return {
@@ -19926,6 +21557,20 @@ function buildSummaryGuidance(input) {
19926
21557
  recommended_action: null
19927
21558
  };
19928
21559
  }
21560
+ if (input.opaqueBrowserError) {
21561
+ if (input.browserEvent?.kind === "resource_error") {
21562
+ return {
21563
+ likely_cause: "The browser reported a resource load error without a usable application stack.",
21564
+ confidence: 0.35,
21565
+ recommended_action: "Inspect the captured resource target, browser network failures, CSP rules, and cross-origin asset configuration."
21566
+ };
21567
+ }
21568
+ return {
21569
+ likely_cause: "The browser reported an opaque window error without a usable application stack.",
21570
+ confidence: 0.35,
21571
+ recommended_action: "Inspect browser console output, resource loading, cross-origin script settings, and framework-level error boundaries for the affected route."
21572
+ };
21573
+ }
19929
21574
  const route = input.requestContext?.route_template ?? input.requestContext?.path ?? null;
19930
21575
  const requestDescription = input.requestContext !== null ? `${input.requestContext.method} ${route ?? input.requestContext.path}` : null;
19931
21576
  const firstDependency = input.dependenciesContext?.items[0] ?? null;
@@ -20112,7 +21757,8 @@ function buildFrontendContext(envelopes) {
20112
21757
  message: envelope.payload.message,
20113
21758
  route: envelope.payload.route ?? null,
20114
21759
  browser: envelope.payload.browser,
20115
- ts: toIsoTimestamp(envelope.occurred_at)
21760
+ ts: toIsoTimestamp(envelope.occurred_at),
21761
+ ...envelope.payload.browser_event !== void 0 ? { browser_event: envelope.payload.browser_event } : {}
20116
21762
  });
20117
21763
  }
20118
21764
  }
@@ -20255,6 +21901,8 @@ function buildBundle(input) {
20255
21901
  const gitContext = buildGitContext(sourceEnvelopes, input.configuredDeploy);
20256
21902
  const deviceContext = buildDeviceContext(sourceEnvelopes);
20257
21903
  const dependenciesContext = buildDependenciesContext(input.incident, errorContext, requestContext);
21904
+ const browserEvent = getPrimaryBrowserExceptionEvent(sourceEnvelopes, primarySignalEnvelope);
21905
+ const opaqueBrowserError = isOpaqueBrowserError(errorContext, browserEvent);
20258
21906
  const primarySignalType = primarySignalEnvelope !== null ? mapSignalType(primarySignalEnvelope.event_type) : inferSignalTypeFromSourceEventTypes(sourceEventTypes);
20259
21907
  const primarySourceEvent = errorContext?.name ?? sourceEventTypes[0] ?? "backend_exception";
20260
21908
  const firstSeenAt = new Date(input.incident.first_seen_at).toISOString();
@@ -20269,7 +21917,9 @@ function buildBundle(input) {
20269
21917
  requestContext,
20270
21918
  responseContext,
20271
21919
  dependenciesContext,
20272
- firstApplicationFrame
21920
+ firstApplicationFrame,
21921
+ browserEvent,
21922
+ opaqueBrowserError
20273
21923
  });
20274
21924
  const candidate = {
20275
21925
  bundle_version: 1,
@@ -21407,7 +23057,7 @@ async function processCommand(input, dependencies = {}) {
21407
23057
 
21408
23058
  // ../cli/src/ingest-command.ts
21409
23059
  var LOCAL_EVENTS_DIRECTORY_PATH2 = ".debugbundle/local/events";
21410
- var ProfileSchema3 = external_exports.object({
23060
+ var ProfileSchema2 = external_exports.object({
21411
23061
  project: external_exports.object({
21412
23062
  name: external_exports.string().min(1),
21413
23063
  repo_url: external_exports.string()
@@ -21432,7 +23082,7 @@ function buildEventFileName(events, filePath) {
21432
23082
  return `${lastOccurredAt}-${digest}-${slugify(events[0]?.service.name ?? (0, import_node_path7.basename)(filePath))}.events.json`;
21433
23083
  }
21434
23084
  async function readProfile(rootDirectory, readFile) {
21435
- const parsedProfile = ProfileSchema3.safeParse(JSON.parse(await readFile((0, import_node_path7.join)(rootDirectory, PROFILE_FILE_PATH))));
23085
+ const parsedProfile = ProfileSchema2.safeParse(JSON.parse(await readFile((0, import_node_path7.join)(rootDirectory, PROFILE_FILE_PATH))));
21436
23086
  if (!parsedProfile.success) {
21437
23087
  throw new Error(`Invalid ${PROFILE_FILE_PATH}`);
21438
23088
  }
@@ -21752,19 +23402,32 @@ function formatResult(input, exitCode, checks, errors, incidentId) {
21752
23402
  output: input.json ? buildJsonOutput(checks, errors, incidentId) : formatHumanOutput(checks, incidentId)
21753
23403
  };
21754
23404
  }
21755
- function buildCloudSuggestedActions(status, incidentId, mode = "passive_recent_incident") {
23405
+ function buildCloudSuggestedActions(status, incidentId, verification) {
23406
+ const mode = verification?.mode ?? "passive_recent_incident";
21756
23407
  if (status === "healthy" && incidentId !== void 0 && (mode === "active_5xx" || mode === "active_4xx")) {
21757
23408
  return [
21758
23409
  `Run debugbundle inspect ${incidentId} --source cloud to inspect why the incident fired.`,
21759
23410
  `Run debugbundle bundle ${incidentId} --source cloud to fetch the generated debug bundle.`
21760
23411
  ];
21761
23412
  }
23413
+ if (status === "healthy" && incidentId !== void 0 && mode === "app_event") {
23414
+ return [
23415
+ `Run debugbundle inspect ${incidentId} --source cloud to inspect the captured app event.`,
23416
+ "Re-run debugbundle verify cloud --expect-app-event after instrumentation or deploy changes, using the same service, environment, and correlation hints when available."
23417
+ ];
23418
+ }
21762
23419
  if (status === "healthy" && incidentId !== void 0) {
21763
23420
  return [
21764
23421
  `Review incident ${incidentId} if you want to inspect the latest production bundle.`,
21765
23422
  "Re-run debugbundle verify cloud after a fresh deploy or instrumentation change."
21766
23423
  ];
21767
23424
  }
23425
+ if (mode === "app_event") {
23426
+ return [
23427
+ "Trigger a real SDK event from the target app, then re-run debugbundle verify cloud --expect-app-event with the same service and environment filters.",
23428
+ "Add --trace-id or --request-id when you have a correlation hint so the verification can match the hosted bundle deterministically."
23429
+ ];
23430
+ }
21768
23431
  return [
21769
23432
  "Run debugbundle login to choose an auth flow, or use debugbundle login --github, debugbundle login --github-device, or debugbundle login <dbundle_mem_...> to create ~/.debugbundle/auth.json before verifying cloud traffic.",
21770
23433
  "Generate a live cloud request, then re-run debugbundle verify cloud with the correct project and service filters."
@@ -21777,7 +23440,7 @@ function buildCloudJsonOutput(checks, errors, incidentId, verification) {
21777
23440
  checks,
21778
23441
  warnings: collectWarnings(checks),
21779
23442
  errors,
21780
- suggested_actions: buildCloudSuggestedActions(status, incidentId, verification?.mode),
23443
+ suggested_actions: buildCloudSuggestedActions(status, incidentId, verification),
21781
23444
  auto_fix_available: false
21782
23445
  };
21783
23446
  if (verification !== void 0) {
@@ -21792,7 +23455,7 @@ function formatCloudHumanOutput(checks, incidentId, verification) {
21792
23455
  "Checks:",
21793
23456
  ...checks.map((check) => `- ${check.name}: ${check.status} - ${check.message}`),
21794
23457
  "Suggested actions:",
21795
- ...buildCloudSuggestedActions(status, incidentId, verification?.mode).map((action) => `- ${action}`)
23458
+ ...buildCloudSuggestedActions(status, incidentId, verification).map((action) => `- ${action}`)
21796
23459
  ].join("\n");
21797
23460
  }
21798
23461
  function formatCloudResult(input, exitCode, checks, errors, incidentId, verification) {
@@ -21823,6 +23486,19 @@ function localFailureStepName(checks) {
21823
23486
  function cloudVerificationRunId(now) {
21824
23487
  return now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
21825
23488
  }
23489
+ function defaultCloudVerificationSuffix() {
23490
+ return (0, import_node_crypto6.randomUUID)().replace(/-/g, "").slice(0, 12);
23491
+ }
23492
+ function normalizeCloudVerificationSuffix(suffix) {
23493
+ const normalized = suffix.toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 12);
23494
+ if (normalized.length > 0) {
23495
+ return normalized;
23496
+ }
23497
+ return defaultCloudVerificationSuffix();
23498
+ }
23499
+ function buildCloudVerificationRunId(now, suffix) {
23500
+ return `${cloudVerificationRunId(now)}-${normalizeCloudVerificationSuffix(suffix)}`;
23501
+ }
21826
23502
  function requestFailureReason(responseStatus) {
21827
23503
  const incidentReason = deriveIncidentReasonFromSignal({
21828
23504
  event_type: "request_event",
@@ -21835,7 +23511,6 @@ function requestFailureReason(responseStatus) {
21835
23511
  return incidentReason;
21836
23512
  }
21837
23513
  function buildCloudVerificationEvent(input) {
21838
- const runId = cloudVerificationRunId(input.now);
21839
23514
  const is5xxVerification = input.responseStatus >= 500;
21840
23515
  const routeTemplate = is5xxVerification ? "/debugbundle/verify/cloud" : `/debugbundle/verify/cloud/client-error/${input.responseStatus}`;
21841
23516
  const verificationLabel = is5xxVerification ? "true" : `client-error-${input.responseStatus}`;
@@ -21856,7 +23531,7 @@ function buildCloudVerificationEvent(input) {
21856
23531
  route_template: routeTemplate,
21857
23532
  query: {
21858
23533
  debugbundle_verification: true,
21859
- run_id: runId,
23534
+ run_id: input.runId,
21860
23535
  synthetic_status: input.responseStatus
21861
23536
  },
21862
23537
  headers: {
@@ -21870,7 +23545,7 @@ function buildCloudVerificationEvent(input) {
21870
23545
  response_body: {
21871
23546
  error: is5xxVerification ? "debugbundle_cloud_verification" : "debugbundle_cloud_client_error_verification",
21872
23547
  synthetic: true,
21873
- run_id: runId,
23548
+ run_id: input.runId,
21874
23549
  response_status: input.responseStatus
21875
23550
  }
21876
23551
  }
@@ -21885,6 +23560,45 @@ function validateActiveCloudVerificationInput(input) {
21885
23560
  }
21886
23561
  return null;
21887
23562
  }
23563
+ function validateCloudVerificationInput(input) {
23564
+ const activeInputError = validateActiveCloudVerificationInput(input);
23565
+ if (activeInputError !== null) {
23566
+ return activeInputError;
23567
+ }
23568
+ const appEventVerificationEnabled = input.expectAppEvent === true || input.traceId !== void 0 || input.requestId !== void 0;
23569
+ if (appEventVerificationEnabled && (input.trigger5xx === true || input.trigger4xxStatus !== void 0)) {
23570
+ return "Choose either a synthetic trigger run or --expect-app-event, not both.";
23571
+ }
23572
+ if (appEventVerificationEnabled && input.service === void 0 && input.traceId === void 0 && input.requestId === void 0) {
23573
+ return "App-event verification requires --service, --trace-id, or --request-id so the check stays scoped.";
23574
+ }
23575
+ return null;
23576
+ }
23577
+ function buildCorrelationHints(input) {
23578
+ return {
23579
+ ...input.service === void 0 ? {} : { service: input.service },
23580
+ environment: input.environment,
23581
+ ...input.traceId === void 0 ? {} : { trace_id: input.traceId },
23582
+ ...input.requestId === void 0 ? {} : { request_id: input.requestId }
23583
+ };
23584
+ }
23585
+ function collectBundleHintMatches(bundle, input) {
23586
+ const serializedBundle = JSON.stringify(bundle);
23587
+ const matches = [];
23588
+ if (input.traceId !== void 0 && serializedBundle.includes(input.traceId)) {
23589
+ matches.push("trace_id");
23590
+ }
23591
+ if (input.requestId !== void 0 && serializedBundle.includes(input.requestId)) {
23592
+ matches.push("request_id");
23593
+ }
23594
+ return matches;
23595
+ }
23596
+ function requestedBundleHints(input) {
23597
+ return [
23598
+ ...input.traceId === void 0 ? [] : ["trace_id"],
23599
+ ...input.requestId === void 0 ? [] : ["request_id"]
23600
+ ];
23601
+ }
21888
23602
  async function sendEventsToApi(input, dependencies = {}) {
21889
23603
  const fetchImpl = dependencies.fetchImpl ?? fetch;
21890
23604
  const baseUrl = input.baseUrl.endsWith("/") ? input.baseUrl.slice(0, -1) : input.baseUrl;
@@ -22076,7 +23790,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
22076
23790
  const checks = [];
22077
23791
  const environment = input.environment ?? "production";
22078
23792
  const maxAgeMinutes = input.maxAgeMinutes ?? 15;
22079
- const activeInputError = validateActiveCloudVerificationInput(input);
23793
+ const activeInputError = validateCloudVerificationInput(input);
22080
23794
  if (activeInputError !== null) {
22081
23795
  checks.push({
22082
23796
  name: "trigger-input",
@@ -22103,23 +23817,138 @@ async function verifyCloudCommand(input, dependencies = {}) {
22103
23817
  });
22104
23818
  return formatCloudResult(input, 2, checks, [message]);
22105
23819
  }
22106
- const httpClient = createCliHttpClient(
22107
- { baseUrl: authState.base_url },
22108
- dependencies.fetchImpl === void 0 ? void 0 : { fetchImpl: dependencies.fetchImpl }
22109
- );
22110
- const retrievalApi = createRetrievalApi(httpClient);
22111
- const tokenApi = createTokenManagementApi(httpClient);
22112
- const listIncidents = dependencies.listIncidents ?? ((requestInput) => retrievalApi.listIncidents(requestInput));
22113
- const getBundle = dependencies.getBundle ?? ((requestInput) => retrievalApi.getBundle(requestInput));
22114
- const createProjectToken = dependencies.createProjectToken ?? ((requestInput) => tokenApi.createProjectToken(requestInput));
22115
- const revokeProjectToken = dependencies.revokeProjectToken ?? ((requestInput) => tokenApi.revokeProjectToken(requestInput));
22116
- const sendEvents = dependencies.sendEvents ?? ((requestInput) => sendEventsToApi(
22117
- requestInput,
22118
- dependencies.fetchImpl === void 0 ? {} : { fetchImpl: dependencies.fetchImpl }
22119
- ));
23820
+ const httpClient = createCliHttpClient(
23821
+ { baseUrl: authState.base_url },
23822
+ dependencies.fetchImpl === void 0 ? void 0 : { fetchImpl: dependencies.fetchImpl }
23823
+ );
23824
+ const retrievalApi = createRetrievalApi(httpClient);
23825
+ const tokenApi = createTokenManagementApi(httpClient);
23826
+ const listIncidents = dependencies.listIncidents ?? ((requestInput) => retrievalApi.listIncidents(requestInput));
23827
+ const getBundle = dependencies.getBundle ?? ((requestInput) => retrievalApi.getBundle(requestInput));
23828
+ const createProjectToken = dependencies.createProjectToken ?? ((requestInput) => tokenApi.createProjectToken(requestInput));
23829
+ const revokeProjectToken = dependencies.revokeProjectToken ?? ((requestInput) => tokenApi.revokeProjectToken(requestInput));
23830
+ const sendEvents = dependencies.sendEvents ?? ((requestInput) => sendEventsToApi(
23831
+ requestInput,
23832
+ dependencies.fetchImpl === void 0 ? {} : { fetchImpl: dependencies.fetchImpl }
23833
+ ));
23834
+ const appEventVerificationEnabled = input.expectAppEvent === true || input.traceId !== void 0 || input.requestId !== void 0;
23835
+ if (appEventVerificationEnabled) {
23836
+ const verificationStartedAt = now();
23837
+ const pollAttempts = dependencies.pollAttempts ?? 6;
23838
+ const pollIntervalMs = dependencies.pollIntervalMs ?? 2e3;
23839
+ const sleep = dependencies.sleep ?? ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
23840
+ const requestedHints = requestedBundleHints(input);
23841
+ const verification = {
23842
+ mode: "app_event",
23843
+ bundle_status: "unknown",
23844
+ correlation_hints: buildCorrelationHints({
23845
+ environment,
23846
+ ...input.service === void 0 ? {} : { service: input.service },
23847
+ ...input.traceId === void 0 ? {} : { traceId: input.traceId },
23848
+ ...input.requestId === void 0 ? {} : { requestId: input.requestId }
23849
+ })
23850
+ };
23851
+ const oldestAcceptedIncidentTimestamp = verificationStartedAt.getTime() - maxAgeMinutes * 6e4;
23852
+ let incidentId;
23853
+ let exitCode = 0;
23854
+ let activeStep = "app-event-visibility";
23855
+ const errors = [];
23856
+ try {
23857
+ for (let attempt = 1; attempt <= pollAttempts; attempt += 1) {
23858
+ const result = await listIncidents({
23859
+ bearerToken: authState.bearer_token,
23860
+ projectId: input.projectId,
23861
+ environment,
23862
+ ...input.service === void 0 ? {} : { service: input.service },
23863
+ limit: 5
23864
+ });
23865
+ const recentIncidents = result.incidents.filter((candidate) => {
23866
+ const lastSeenAt = new Date(candidate.last_seen_at);
23867
+ return !Number.isNaN(lastSeenAt.getTime()) && lastSeenAt.getTime() >= oldestAcceptedIncidentTimestamp;
23868
+ });
23869
+ for (const candidate of recentIncidents) {
23870
+ const lastSeenAt = new Date(candidate.last_seen_at);
23871
+ if (requestedHints.length === 0 && lastSeenAt.getTime() < verificationStartedAt.getTime()) {
23872
+ continue;
23873
+ }
23874
+ if (requestedHints.length === 0) {
23875
+ incidentId = candidate.incident_id;
23876
+ verification.incident_id = candidate.incident_id;
23877
+ break;
23878
+ }
23879
+ activeStep = "bundle-status";
23880
+ const bundle = await getBundle({
23881
+ bearerToken: authState.bearer_token,
23882
+ incidentId: candidate.incident_id
23883
+ });
23884
+ verification.bundle_status = "status" in bundle && bundle.status === "pending" ? "pending" : "ready";
23885
+ if (verification.bundle_status !== "ready") {
23886
+ continue;
23887
+ }
23888
+ const matchedHints = collectBundleHintMatches(bundle, input);
23889
+ verification.matched_hints = matchedHints;
23890
+ if (requestedHints.every((hint) => matchedHints.includes(hint))) {
23891
+ incidentId = candidate.incident_id;
23892
+ verification.incident_id = candidate.incident_id;
23893
+ verification.suggested_next_command = `debugbundle inspect ${candidate.incident_id} --source cloud`;
23894
+ break;
23895
+ }
23896
+ }
23897
+ if (incidentId !== void 0) {
23898
+ break;
23899
+ }
23900
+ if (attempt < pollAttempts) {
23901
+ await sleep(pollIntervalMs);
23902
+ }
23903
+ }
23904
+ if (incidentId === void 0) {
23905
+ if (requestedHints.length > 0) {
23906
+ throw new Error(`No recent cloud incident matched the requested ${requestedHints.join(" and ")} hints within the ${maxAgeMinutes} minute verification window.`);
23907
+ }
23908
+ throw new Error(`No new ${environment} app event was visible within the ${maxAgeMinutes} minute verification window.`);
23909
+ }
23910
+ checks.push({
23911
+ name: "app-event-visibility",
23912
+ status: "ok",
23913
+ message: `Observed cloud incident ${incidentId} for the requested app-driven verification window.`
23914
+ });
23915
+ if (requestedHints.length > 0) {
23916
+ checks.push({
23917
+ name: "bundle-hint-match",
23918
+ status: "ok",
23919
+ message: `Matched ${verification.matched_hints?.join(" and ")} in bundle ${incidentId}.`
23920
+ });
23921
+ } else {
23922
+ const bundle = await getBundle({
23923
+ bearerToken: authState.bearer_token,
23924
+ incidentId
23925
+ });
23926
+ verification.bundle_status = "status" in bundle && bundle.status === "pending" ? "pending" : "ready";
23927
+ verification.suggested_next_command = `debugbundle inspect ${incidentId} --source cloud`;
23928
+ checks.push({
23929
+ name: "bundle-status",
23930
+ status: verification.bundle_status === "ready" ? "ok" : "warning",
23931
+ message: verification.bundle_status === "ready" ? `Bundle for incident ${incidentId} is ready.` : `Bundle for incident ${incidentId} is still pending.`
23932
+ });
23933
+ }
23934
+ } catch (error) {
23935
+ const message = error instanceof Error ? error.message : String(error);
23936
+ checks.push({
23937
+ name: activeStep,
23938
+ status: "error",
23939
+ message
23940
+ });
23941
+ errors.push(message);
23942
+ exitCode = 1;
23943
+ }
23944
+ return formatCloudResult(input, exitCode, checks, errors, incidentId, verification);
23945
+ }
22120
23946
  if (input.trigger5xx === true || input.trigger4xxStatus !== void 0) {
22121
23947
  const verificationStartedAt = now();
22122
- const runId = cloudVerificationRunId(verificationStartedAt);
23948
+ const runId = buildCloudVerificationRunId(
23949
+ verificationStartedAt,
23950
+ (dependencies.randomId ?? defaultCloudVerificationSuffix)()
23951
+ );
22123
23952
  const serviceName = input.service ?? `debugbundle-verify-cloud-${runId}`;
22124
23953
  const tokenLabel = `debugbundle verify cloud ${runId}`;
22125
23954
  const pollAttempts = dependencies.pollAttempts ?? 6;
@@ -22151,6 +23980,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
22151
23980
  }
22152
23981
  const event = buildCloudVerificationEvent({
22153
23982
  now: verificationStartedAt,
23983
+ runId,
22154
23984
  serviceName,
22155
23985
  environment,
22156
23986
  responseStatus
@@ -22870,8 +24700,85 @@ function createBillingMcpTools(api) {
22870
24700
  };
22871
24701
  }
22872
24702
 
22873
- // src/capture-policy-tools.ts
24703
+ // src/capture-rule-tools.ts
22874
24704
  function mapMcpError4(error) {
24705
+ if (error instanceof CaptureRuleApiError) {
24706
+ throw new Error(`mcp_tool_error:${error.message}`);
24707
+ }
24708
+ throw new Error("mcp_tool_error:unknown_error");
24709
+ }
24710
+ function createCaptureRuleMcpTools(api) {
24711
+ return {
24712
+ async list_capture_rules(input) {
24713
+ try {
24714
+ return await api.listCaptureRules({
24715
+ bearerToken: String(input["bearerToken"]),
24716
+ projectId: String(input["projectId"])
24717
+ });
24718
+ } catch (error) {
24719
+ mapMcpError4(error);
24720
+ }
24721
+ },
24722
+ async create_capture_rule(input) {
24723
+ try {
24724
+ return await api.createCaptureRule({
24725
+ bearerToken: String(input["bearerToken"]),
24726
+ projectId: String(input["projectId"]),
24727
+ create: typeof input["create"] === "object" && input["create"] !== null ? input["create"] : {}
24728
+ });
24729
+ } catch (error) {
24730
+ mapMcpError4(error);
24731
+ }
24732
+ },
24733
+ async update_capture_rule(input) {
24734
+ try {
24735
+ return await api.updateCaptureRule({
24736
+ bearerToken: String(input["bearerToken"]),
24737
+ projectId: String(input["projectId"]),
24738
+ ruleId: String(input["ruleId"]),
24739
+ update: typeof input["update"] === "object" && input["update"] !== null ? input["update"] : {}
24740
+ });
24741
+ } catch (error) {
24742
+ mapMcpError4(error);
24743
+ }
24744
+ },
24745
+ async delete_capture_rule(input) {
24746
+ try {
24747
+ return await api.deleteCaptureRule({
24748
+ bearerToken: String(input["bearerToken"]),
24749
+ projectId: String(input["projectId"]),
24750
+ ruleId: String(input["ruleId"])
24751
+ });
24752
+ } catch (error) {
24753
+ mapMcpError4(error);
24754
+ }
24755
+ },
24756
+ async suggest_capture_rules_from_incident(input) {
24757
+ try {
24758
+ return await api.suggestCaptureRulesFromIncident({
24759
+ bearerToken: String(input["bearerToken"]),
24760
+ incidentId: String(input["incidentId"])
24761
+ });
24762
+ } catch (error) {
24763
+ mapMcpError4(error);
24764
+ }
24765
+ },
24766
+ async create_capture_rule_from_incident_suggestion(input) {
24767
+ try {
24768
+ return await api.createCaptureRuleFromIncidentSuggestion({
24769
+ bearerToken: String(input["bearerToken"]),
24770
+ incidentId: String(input["incidentId"]),
24771
+ create: typeof input["create"] === "object" && input["create"] !== null ? input["create"] : {}
24772
+ });
24773
+ } catch (error) {
24774
+ mapMcpError4(error);
24775
+ }
24776
+ }
24777
+ };
24778
+ }
24779
+
24780
+ // src/capture-policy-tools.ts
24781
+ function mapMcpError5(error) {
22875
24782
  if (error instanceof CapturePolicyApiError) {
22876
24783
  throw new Error(`mcp_tool_error:${error.message}`);
22877
24784
  }
@@ -22886,7 +24793,7 @@ function createCapturePolicyMcpTools(api) {
22886
24793
  projectId: String(input["projectId"])
22887
24794
  });
22888
24795
  } catch (error) {
22889
- mapMcpError4(error);
24796
+ mapMcpError5(error);
22890
24797
  }
22891
24798
  },
22892
24799
  async update_capture_policy(input) {
@@ -22898,14 +24805,14 @@ function createCapturePolicyMcpTools(api) {
22898
24805
  update
22899
24806
  });
22900
24807
  } catch (error) {
22901
- mapMcpError4(error);
24808
+ mapMcpError5(error);
22902
24809
  }
22903
24810
  }
22904
24811
  };
22905
24812
  }
22906
24813
 
22907
24814
  // src/github-tools.ts
22908
- function mapMcpError5(error) {
24815
+ function mapMcpError6(error) {
22909
24816
  if (error instanceof GitHubManagementApiError) {
22910
24817
  throw new Error(`mcp_tool_error:${error.code}`);
22911
24818
  }
@@ -22924,7 +24831,7 @@ function createGitHubMcpTools(api) {
22924
24831
  const repo = projectId === void 0 || api.getProjectRepo === void 0 ? void 0 : await api.getProjectRepo({ bearerToken, projectId });
22925
24832
  return repo === void 0 ? { installation } : { installation, repo };
22926
24833
  } catch (error) {
22927
- mapMcpError5(error);
24834
+ mapMcpError6(error);
22928
24835
  }
22929
24836
  },
22930
24837
  async list_github_repositories(input) {
@@ -22936,7 +24843,7 @@ function createGitHubMcpTools(api) {
22936
24843
  })
22937
24844
  };
22938
24845
  } catch (error) {
22939
- mapMcpError5(error);
24846
+ mapMcpError6(error);
22940
24847
  }
22941
24848
  },
22942
24849
  async list_github_dispatch_rules(input) {
@@ -22948,7 +24855,7 @@ function createGitHubMcpTools(api) {
22948
24855
  })
22949
24856
  };
22950
24857
  } catch (error) {
22951
- mapMcpError5(error);
24858
+ mapMcpError6(error);
22952
24859
  }
22953
24860
  },
22954
24861
  async create_github_dispatch_rule(input) {
@@ -22969,7 +24876,7 @@ function createGitHubMcpTools(api) {
22969
24876
  })
22970
24877
  };
22971
24878
  } catch (error) {
22972
- mapMcpError5(error);
24879
+ mapMcpError6(error);
22973
24880
  }
22974
24881
  },
22975
24882
  async update_github_dispatch_rule(input) {
@@ -22991,7 +24898,7 @@ function createGitHubMcpTools(api) {
22991
24898
  })
22992
24899
  };
22993
24900
  } catch (error) {
22994
- mapMcpError5(error);
24901
+ mapMcpError6(error);
22995
24902
  }
22996
24903
  },
22997
24904
  async delete_github_dispatch_rule(input) {
@@ -23007,7 +24914,7 @@ function createGitHubMcpTools(api) {
23007
24914
  rule_id: String(input["ruleId"])
23008
24915
  };
23009
24916
  } catch (error) {
23010
- mapMcpError5(error);
24917
+ mapMcpError6(error);
23011
24918
  }
23012
24919
  },
23013
24920
  async list_github_deliveries(input) {
@@ -23021,7 +24928,7 @@ function createGitHubMcpTools(api) {
23021
24928
  })
23022
24929
  };
23023
24930
  } catch (error) {
23024
- mapMcpError5(error);
24931
+ mapMcpError6(error);
23025
24932
  }
23026
24933
  },
23027
24934
  async retry_github_delivery(input) {
@@ -23034,7 +24941,7 @@ function createGitHubMcpTools(api) {
23034
24941
  })
23035
24942
  };
23036
24943
  } catch (error) {
23037
- mapMcpError5(error);
24944
+ mapMcpError6(error);
23038
24945
  }
23039
24946
  },
23040
24947
  async set_project_github_repo(input) {
@@ -23048,7 +24955,7 @@ function createGitHubMcpTools(api) {
23048
24955
  })
23049
24956
  };
23050
24957
  } catch (error) {
23051
- mapMcpError5(error);
24958
+ mapMcpError6(error);
23052
24959
  }
23053
24960
  },
23054
24961
  async remove_project_github_repo(input) {
@@ -23062,14 +24969,14 @@ function createGitHubMcpTools(api) {
23062
24969
  project_id: String(input["projectId"])
23063
24970
  };
23064
24971
  } catch (error) {
23065
- mapMcpError5(error);
24972
+ mapMcpError6(error);
23066
24973
  }
23067
24974
  }
23068
24975
  };
23069
24976
  }
23070
24977
 
23071
24978
  // src/improvement-tools.ts
23072
- function mapMcpError6(error) {
24979
+ function mapMcpError7(error) {
23073
24980
  if (error instanceof RetrievalApiError) {
23074
24981
  throw new Error(`mcp_tool_error:${error.code}`);
23075
24982
  }
@@ -23102,7 +25009,7 @@ function createImprovementMcpTools(api) {
23102
25009
  ...typeof input["limit"] === "number" ? { limit: input["limit"] } : {}
23103
25010
  });
23104
25011
  } catch (error) {
23105
- mapMcpError6(error);
25012
+ mapMcpError7(error);
23106
25013
  }
23107
25014
  },
23108
25015
  async get_improvement(input) {
@@ -23112,7 +25019,7 @@ function createImprovementMcpTools(api) {
23112
25019
  improvementId: readString2(input, "improvementId")
23113
25020
  });
23114
25021
  } catch (error) {
23115
- mapMcpError6(error);
25022
+ mapMcpError7(error);
23116
25023
  }
23117
25024
  },
23118
25025
  async get_improvement_bundle(input) {
@@ -23123,7 +25030,7 @@ function createImprovementMcpTools(api) {
23123
25030
  improvementId: readString2(input, "improvementId")
23124
25031
  });
23125
25032
  } catch (error) {
23126
- mapMcpError6(error);
25033
+ mapMcpError7(error);
23127
25034
  }
23128
25035
  },
23129
25036
  async resolve_improvement(input) {
@@ -23133,7 +25040,7 @@ function createImprovementMcpTools(api) {
23133
25040
  improvementId: readString2(input, "improvementId")
23134
25041
  });
23135
25042
  } catch (error) {
23136
- mapMcpError6(error);
25043
+ mapMcpError7(error);
23137
25044
  }
23138
25045
  },
23139
25046
  async reopen_improvement(input) {
@@ -23143,7 +25050,7 @@ function createImprovementMcpTools(api) {
23143
25050
  improvementId: readString2(input, "improvementId")
23144
25051
  });
23145
25052
  } catch (error) {
23146
- mapMcpError6(error);
25053
+ mapMcpError7(error);
23147
25054
  }
23148
25055
  },
23149
25056
  async snooze_improvement(input) {
@@ -23154,14 +25061,14 @@ function createImprovementMcpTools(api) {
23154
25061
  snoozedUntil: readString2(input, "snoozedUntil")
23155
25062
  });
23156
25063
  } catch (error) {
23157
- mapMcpError6(error);
25064
+ mapMcpError7(error);
23158
25065
  }
23159
25066
  }
23160
25067
  };
23161
25068
  }
23162
25069
 
23163
25070
  // src/improvement-settings-tools.ts
23164
- function mapMcpError7(error) {
25071
+ function mapMcpError8(error) {
23165
25072
  if (error instanceof ImprovementSettingsApiError) {
23166
25073
  throw new Error(`mcp_tool_error:${error.message}`);
23167
25074
  }
@@ -23176,7 +25083,7 @@ function createImprovementSettingsMcpTools(api) {
23176
25083
  projectId: String(input["projectId"])
23177
25084
  });
23178
25085
  } catch (error) {
23179
- mapMcpError7(error);
25086
+ mapMcpError8(error);
23180
25087
  }
23181
25088
  },
23182
25089
  async update_improvement_settings(input) {
@@ -23188,14 +25095,14 @@ function createImprovementSettingsMcpTools(api) {
23188
25095
  update
23189
25096
  });
23190
25097
  } catch (error) {
23191
- mapMcpError7(error);
25098
+ mapMcpError8(error);
23192
25099
  }
23193
25100
  }
23194
25101
  };
23195
25102
  }
23196
25103
 
23197
25104
  // src/member-tools.ts
23198
- function mapMcpError8(error) {
25105
+ function mapMcpError9(error) {
23199
25106
  if (error instanceof MemberApiError) {
23200
25107
  throw new Error(`mcp_tool_error:${error.code}`);
23201
25108
  }
@@ -23210,7 +25117,7 @@ function createMemberMcpTools(api) {
23210
25117
  projectId: String(input["projectId"])
23211
25118
  });
23212
25119
  } catch (error) {
23213
- mapMcpError8(error);
25120
+ mapMcpError9(error);
23214
25121
  }
23215
25122
  },
23216
25123
  async list_project_member_invites(input) {
@@ -23220,7 +25127,7 @@ function createMemberMcpTools(api) {
23220
25127
  projectId: String(input["projectId"])
23221
25128
  });
23222
25129
  } catch (error) {
23223
- mapMcpError8(error);
25130
+ mapMcpError9(error);
23224
25131
  }
23225
25132
  },
23226
25133
  async invite_project_member(input) {
@@ -23232,7 +25139,7 @@ function createMemberMcpTools(api) {
23232
25139
  role: String(input["role"])
23233
25140
  });
23234
25141
  } catch (error) {
23235
- mapMcpError8(error);
25142
+ mapMcpError9(error);
23236
25143
  }
23237
25144
  },
23238
25145
  async cancel_project_member_invite(input) {
@@ -23243,7 +25150,7 @@ function createMemberMcpTools(api) {
23243
25150
  inviteId: String(input["inviteId"])
23244
25151
  });
23245
25152
  } catch (error) {
23246
- mapMcpError8(error);
25153
+ mapMcpError9(error);
23247
25154
  }
23248
25155
  },
23249
25156
  async update_project_member_role(input) {
@@ -23255,7 +25162,7 @@ function createMemberMcpTools(api) {
23255
25162
  role: String(input["role"])
23256
25163
  });
23257
25164
  } catch (error) {
23258
- mapMcpError8(error);
25165
+ mapMcpError9(error);
23259
25166
  }
23260
25167
  },
23261
25168
  async remove_project_member(input) {
@@ -23266,14 +25173,14 @@ function createMemberMcpTools(api) {
23266
25173
  userId: String(input["userId"])
23267
25174
  });
23268
25175
  } catch (error) {
23269
- mapMcpError8(error);
25176
+ mapMcpError9(error);
23270
25177
  }
23271
25178
  }
23272
25179
  };
23273
25180
  }
23274
25181
 
23275
25182
  // src/probe-tools.ts
23276
- function mapMcpError9(error) {
25183
+ function mapMcpError10(error) {
23277
25184
  if (error instanceof ProbeApiError) {
23278
25185
  throw new Error(`mcp_tool_error:${error.code}`);
23279
25186
  }
@@ -23302,7 +25209,7 @@ function createProbeMcpTools(api) {
23302
25209
  }
23303
25210
  return await api.activateProbe(requestInput);
23304
25211
  } catch (error) {
23305
- mapMcpError9(error);
25212
+ mapMcpError10(error);
23306
25213
  }
23307
25214
  },
23308
25215
  async list_active_probes(input) {
@@ -23312,7 +25219,7 @@ function createProbeMcpTools(api) {
23312
25219
  projectId: String(input["projectId"])
23313
25220
  });
23314
25221
  } catch (error) {
23315
- mapMcpError9(error);
25222
+ mapMcpError10(error);
23316
25223
  }
23317
25224
  },
23318
25225
  async deactivate_probe(input) {
@@ -23323,14 +25230,14 @@ function createProbeMcpTools(api) {
23323
25230
  activationId: String(input["activationId"])
23324
25231
  });
23325
25232
  } catch (error) {
23326
- mapMcpError9(error);
25233
+ mapMcpError10(error);
23327
25234
  }
23328
25235
  }
23329
25236
  };
23330
25237
  }
23331
25238
 
23332
25239
  // src/project-tools.ts
23333
- function mapMcpError10(error) {
25240
+ function mapMcpError11(error) {
23334
25241
  if (error instanceof ProjectManagementApiError) {
23335
25242
  throw new Error(`mcp_tool_error:${error.code}`);
23336
25243
  }
@@ -23348,7 +25255,7 @@ function createProjectMcpTools(api) {
23348
25255
  }
23349
25256
  return { projects: await api.listProjects(requestInput) };
23350
25257
  } catch (error) {
23351
- mapMcpError10(error);
25258
+ mapMcpError11(error);
23352
25259
  }
23353
25260
  },
23354
25261
  async create_project(input) {
@@ -23363,7 +25270,7 @@ function createProjectMcpTools(api) {
23363
25270
  }
23364
25271
  return { project: await api.createProject(requestInput) };
23365
25272
  } catch (error) {
23366
- mapMcpError10(error);
25273
+ mapMcpError11(error);
23367
25274
  }
23368
25275
  },
23369
25276
  async update_project(input) {
@@ -23383,7 +25290,7 @@ function createProjectMcpTools(api) {
23383
25290
  }
23384
25291
  return { project: await api.updateProject(requestInput) };
23385
25292
  } catch (error) {
23386
- mapMcpError10(error);
25293
+ mapMcpError11(error);
23387
25294
  }
23388
25295
  },
23389
25296
  async delete_project(input) {
@@ -23395,7 +25302,7 @@ function createProjectMcpTools(api) {
23395
25302
  })
23396
25303
  };
23397
25304
  } catch (error) {
23398
- mapMcpError10(error);
25305
+ mapMcpError11(error);
23399
25306
  }
23400
25307
  }
23401
25308
  };
@@ -23602,7 +25509,7 @@ async function persistCloudArtifact(directoryPath, fileName, payload, dependenci
23602
25509
  }
23603
25510
 
23604
25511
  // src/retrieval-tools.ts
23605
- function mapMcpError11(error) {
25512
+ function mapMcpError12(error) {
23606
25513
  if (error instanceof RetrievalApiError) {
23607
25514
  throw new Error(`mcp_tool_error:${error.code}`);
23608
25515
  }
@@ -23784,7 +25691,7 @@ function createRetrievalMcpTools(api) {
23784
25691
  incidents: incidents.incidents.map((incident) => attachSourceToRecord(incident, "cloud"))
23785
25692
  };
23786
25693
  } catch (error) {
23787
- mapMcpError11(error);
25694
+ mapMcpError12(error);
23788
25695
  }
23789
25696
  },
23790
25697
  async get_incident(input) {
@@ -23819,7 +25726,7 @@ function createRetrievalMcpTools(api) {
23819
25726
  )
23820
25727
  };
23821
25728
  } catch (error) {
23822
- mapMcpError11(error);
25729
+ mapMcpError12(error);
23823
25730
  }
23824
25731
  },
23825
25732
  async get_incident_context(input) {
@@ -23848,7 +25755,7 @@ function createRetrievalMcpTools(api) {
23848
25755
  "cloud"
23849
25756
  );
23850
25757
  } catch (error) {
23851
- mapMcpError11(error);
25758
+ mapMcpError12(error);
23852
25759
  }
23853
25760
  },
23854
25761
  async resolve_incident(input) {
@@ -23893,7 +25800,7 @@ function createRetrievalMcpTools(api) {
23893
25800
  })()
23894
25801
  };
23895
25802
  } catch (error) {
23896
- mapMcpError11(error);
25803
+ mapMcpError12(error);
23897
25804
  }
23898
25805
  },
23899
25806
  async reopen_incident(input) {
@@ -23938,7 +25845,7 @@ function createRetrievalMcpTools(api) {
23938
25845
  })()
23939
25846
  };
23940
25847
  } catch (error) {
23941
- mapMcpError11(error);
25848
+ mapMcpError12(error);
23942
25849
  }
23943
25850
  },
23944
25851
  async get_bundle(input) {
@@ -23969,7 +25876,7 @@ function createRetrievalMcpTools(api) {
23969
25876
  }
23970
25877
  );
23971
25878
  } catch (error) {
23972
- mapMcpError11(error);
25879
+ mapMcpError12(error);
23973
25880
  }
23974
25881
  },
23975
25882
  async get_logs(input) {
@@ -23989,7 +25896,7 @@ function createRetrievalMcpTools(api) {
23989
25896
  }
23990
25897
  return await api.getLogs(requestInput);
23991
25898
  } catch (error) {
23992
- mapMcpError11(error);
25899
+ mapMcpError12(error);
23993
25900
  }
23994
25901
  },
23995
25902
  async get_reproduction(input) {
@@ -24020,14 +25927,14 @@ function createRetrievalMcpTools(api) {
24020
25927
  }
24021
25928
  );
24022
25929
  } catch (error) {
24023
- mapMcpError11(error);
25930
+ mapMcpError12(error);
24024
25931
  }
24025
25932
  }
24026
25933
  };
24027
25934
  }
24028
25935
 
24029
25936
  // src/services-tools.ts
24030
- function mapMcpError12(error) {
25937
+ function mapMcpError13(error) {
24031
25938
  if (error instanceof RetrievalApiError) {
24032
25939
  throw new Error(`mcp_tool_error:${error.code}`);
24033
25940
  }
@@ -24048,14 +25955,14 @@ function createServicesMcpTools(api) {
24048
25955
  services: await api.listServices(requestInput)
24049
25956
  };
24050
25957
  } catch (error) {
24051
- mapMcpError12(error);
25958
+ mapMcpError13(error);
24052
25959
  }
24053
25960
  }
24054
25961
  };
24055
25962
  }
24056
25963
 
24057
25964
  // src/setup-tools.ts
24058
- function mapMcpError13() {
25965
+ function mapMcpError14() {
24059
25966
  throw new Error("mcp_tool_error:unknown_error");
24060
25967
  }
24061
25968
  function parseJsonOutput2(output) {
@@ -24070,7 +25977,7 @@ async function runJsonCommand2(command) {
24070
25977
  const result = await command();
24071
25978
  return parseJsonOutput2(result.output);
24072
25979
  } catch {
24073
- mapMcpError13();
25980
+ mapMcpError14();
24074
25981
  }
24075
25982
  }
24076
25983
  function createSetupMcpTools(commands) {
@@ -24129,7 +26036,7 @@ function createSetupMcpTools(commands) {
24129
26036
  }
24130
26037
 
24131
26038
  // src/slack-tools.ts
24132
- function mapMcpError14(error) {
26039
+ function mapMcpError15(error) {
24133
26040
  if (error instanceof SlackApiError) {
24134
26041
  throw new Error(`mcp_tool_error:${error.code}`);
24135
26042
  }
@@ -24146,7 +26053,7 @@ function createSlackMcpTools(api) {
24146
26053
  })
24147
26054
  };
24148
26055
  } catch (error) {
24149
- mapMcpError14(error);
26056
+ mapMcpError15(error);
24150
26057
  }
24151
26058
  },
24152
26059
  async get_slack_connect_url(input) {
@@ -24159,7 +26066,7 @@ function createSlackMcpTools(api) {
24159
26066
  })
24160
26067
  };
24161
26068
  } catch (error) {
24162
- mapMcpError14(error);
26069
+ mapMcpError15(error);
24163
26070
  }
24164
26071
  },
24165
26072
  async test_slack_destination(input) {
@@ -24172,7 +26079,7 @@ function createSlackMcpTools(api) {
24172
26079
  })
24173
26080
  };
24174
26081
  } catch (error) {
24175
- mapMcpError14(error);
26082
+ mapMcpError15(error);
24176
26083
  }
24177
26084
  },
24178
26085
  async delete_slack_destination(input) {
@@ -24185,14 +26092,14 @@ function createSlackMcpTools(api) {
24185
26092
  })
24186
26093
  };
24187
26094
  } catch (error) {
24188
- mapMcpError14(error);
26095
+ mapMcpError15(error);
24189
26096
  }
24190
26097
  }
24191
26098
  };
24192
26099
  }
24193
26100
 
24194
26101
  // src/token-tools.ts
24195
- function mapMcpError15(error) {
26102
+ function mapMcpError16(error) {
24196
26103
  if (error instanceof TokenManagementApiError) {
24197
26104
  throw new Error(`mcp_tool_error:${error.code}`);
24198
26105
  }
@@ -24213,7 +26120,7 @@ function createTokenMcpTools(api) {
24213
26120
  tokens: await api.listProjectTokens(requestInput)
24214
26121
  };
24215
26122
  } catch (error) {
24216
- mapMcpError15(error);
26123
+ mapMcpError16(error);
24217
26124
  }
24218
26125
  },
24219
26126
  async create_project_token(input) {
@@ -24228,7 +26135,7 @@ function createTokenMcpTools(api) {
24228
26135
  })
24229
26136
  };
24230
26137
  } catch (error) {
24231
- mapMcpError15(error);
26138
+ mapMcpError16(error);
24232
26139
  }
24233
26140
  },
24234
26141
  async revoke_project_token(input) {
@@ -24241,7 +26148,7 @@ function createTokenMcpTools(api) {
24241
26148
  })
24242
26149
  };
24243
26150
  } catch (error) {
24244
- mapMcpError15(error);
26151
+ mapMcpError16(error);
24245
26152
  }
24246
26153
  },
24247
26154
  async list_member_tokens(input) {
@@ -24256,7 +26163,7 @@ function createTokenMcpTools(api) {
24256
26163
  tokens: await api.listMemberTokens(requestInput)
24257
26164
  };
24258
26165
  } catch (error) {
24259
- mapMcpError15(error);
26166
+ mapMcpError16(error);
24260
26167
  }
24261
26168
  },
24262
26169
  async create_member_token(input) {
@@ -24268,7 +26175,7 @@ function createTokenMcpTools(api) {
24268
26175
  })
24269
26176
  };
24270
26177
  } catch (error) {
24271
- mapMcpError15(error);
26178
+ mapMcpError16(error);
24272
26179
  }
24273
26180
  },
24274
26181
  async revoke_member_token(input) {
@@ -24280,14 +26187,14 @@ function createTokenMcpTools(api) {
24280
26187
  })
24281
26188
  };
24282
26189
  } catch (error) {
24283
- mapMcpError15(error);
26190
+ mapMcpError16(error);
24284
26191
  }
24285
26192
  }
24286
26193
  };
24287
26194
  }
24288
26195
 
24289
26196
  // src/webhook-tools.ts
24290
- function mapMcpError16(error) {
26197
+ function mapMcpError17(error) {
24291
26198
  if (error instanceof WebhookApiError) {
24292
26199
  throw new Error(`mcp_tool_error:${error.code}`);
24293
26200
  }
@@ -24308,7 +26215,7 @@ function createWebhookMcpTools(api) {
24308
26215
  webhooks: await api.listWebhooks(requestInput)
24309
26216
  };
24310
26217
  } catch (error) {
24311
- mapMcpError16(error);
26218
+ mapMcpError17(error);
24312
26219
  }
24313
26220
  },
24314
26221
  async create_webhook(input) {
@@ -24329,7 +26236,7 @@ function createWebhookMcpTools(api) {
24329
26236
  webhook: await api.createWebhook(requestInput)
24330
26237
  };
24331
26238
  } catch (error) {
24332
- mapMcpError16(error);
26239
+ mapMcpError17(error);
24333
26240
  }
24334
26241
  },
24335
26242
  async update_webhook(input) {
@@ -24355,7 +26262,7 @@ function createWebhookMcpTools(api) {
24355
26262
  webhook: await api.updateWebhook(requestInput)
24356
26263
  };
24357
26264
  } catch (error) {
24358
- mapMcpError16(error);
26265
+ mapMcpError17(error);
24359
26266
  }
24360
26267
  },
24361
26268
  async delete_webhook(input) {
@@ -24368,7 +26275,7 @@ function createWebhookMcpTools(api) {
24368
26275
  })
24369
26276
  };
24370
26277
  } catch (error) {
24371
- mapMcpError16(error);
26278
+ mapMcpError17(error);
24372
26279
  }
24373
26280
  },
24374
26281
  async test_webhook(input) {
@@ -24385,7 +26292,7 @@ function createWebhookMcpTools(api) {
24385
26292
  delivery: await api.testWebhook(requestInput)
24386
26293
  };
24387
26294
  } catch (error) {
24388
- mapMcpError16(error);
26295
+ mapMcpError17(error);
24389
26296
  }
24390
26297
  },
24391
26298
  async list_webhook_deliveries(input) {
@@ -24402,7 +26309,7 @@ function createWebhookMcpTools(api) {
24402
26309
  deliveries: await api.listWebhookDeliveries(requestInput)
24403
26310
  };
24404
26311
  } catch (error) {
24405
- mapMcpError16(error);
26312
+ mapMcpError17(error);
24406
26313
  }
24407
26314
  },
24408
26315
  async retry_webhook_delivery(input) {
@@ -24414,14 +26321,14 @@ function createWebhookMcpTools(api) {
24414
26321
  deliveryId: String(input["deliveryId"])
24415
26322
  });
24416
26323
  } catch (error) {
24417
- mapMcpError16(error);
26324
+ mapMcpError17(error);
24418
26325
  }
24419
26326
  }
24420
26327
  };
24421
26328
  }
24422
26329
 
24423
26330
  // src/weekly-report-tools.ts
24424
- function mapMcpError17(error) {
26331
+ function mapMcpError18(error) {
24425
26332
  if (error instanceof WeeklyReportApiError) {
24426
26333
  throw new Error(`mcp_tool_error:${error.code}`);
24427
26334
  }
@@ -24439,7 +26346,7 @@ function createWeeklyReportMcpTools(api) {
24439
26346
  })
24440
26347
  };
24441
26348
  } catch (error) {
24442
- mapMcpError17(error);
26349
+ mapMcpError18(error);
24443
26350
  }
24444
26351
  },
24445
26352
  async create_weekly_report_channel(input) {
@@ -24455,7 +26362,7 @@ function createWeeklyReportMcpTools(api) {
24455
26362
  })
24456
26363
  };
24457
26364
  } catch (error) {
24458
- mapMcpError17(error);
26365
+ mapMcpError18(error);
24459
26366
  }
24460
26367
  },
24461
26368
  async update_weekly_report_channel(input) {
@@ -24470,7 +26377,7 @@ function createWeeklyReportMcpTools(api) {
24470
26377
  })
24471
26378
  };
24472
26379
  } catch (error) {
24473
- mapMcpError17(error);
26380
+ mapMcpError18(error);
24474
26381
  }
24475
26382
  },
24476
26383
  async delete_weekly_report_channel(input) {
@@ -24482,7 +26389,7 @@ function createWeeklyReportMcpTools(api) {
24482
26389
  })
24483
26390
  };
24484
26391
  } catch (error) {
24485
- mapMcpError17(error);
26392
+ mapMcpError18(error);
24486
26393
  }
24487
26394
  }
24488
26395
  };
@@ -24538,6 +26445,7 @@ async function createDefaultMcpTools(input = {}) {
24538
26445
  ...createWeeklyReportMcpTools(createWeeklyReportApi(httpClient)),
24539
26446
  ...createAlertMcpTools(createAlertApi(httpClient)),
24540
26447
  ...createProjectMcpTools(createProjectManagementApi(httpClient)),
26448
+ ...createCaptureRuleMcpTools(createCaptureRuleApi(httpClient)),
24541
26449
  ...createCapturePolicyMcpTools(createCapturePolicyApi(httpClient)),
24542
26450
  ...createImprovementSettingsMcpTools(createImprovementSettingsApi(httpClient)),
24543
26451
  ...createProbeMcpTools(createProbeApi(httpClient)),
@@ -26461,6 +28369,65 @@ var MCP_TOOL_CATALOG = [
26461
28369
  projectId: external_exports.string()
26462
28370
  })
26463
28371
  },
28372
+ {
28373
+ name: "list_capture_rules",
28374
+ group: "capture_rules",
28375
+ description: "List project capture rules.",
28376
+ inputSchema: external_exports.object({
28377
+ bearerToken: external_exports.string(),
28378
+ projectId: external_exports.string()
28379
+ })
28380
+ },
28381
+ {
28382
+ name: "create_capture_rule",
28383
+ group: "capture_rules",
28384
+ description: "Create a project capture rule.",
28385
+ inputSchema: external_exports.object({
28386
+ bearerToken: external_exports.string(),
28387
+ projectId: external_exports.string(),
28388
+ create: jsonObjectSchema
28389
+ })
28390
+ },
28391
+ {
28392
+ name: "update_capture_rule",
28393
+ group: "capture_rules",
28394
+ description: "Update a project capture rule.",
28395
+ inputSchema: external_exports.object({
28396
+ bearerToken: external_exports.string(),
28397
+ projectId: external_exports.string(),
28398
+ ruleId: external_exports.string(),
28399
+ update: jsonObjectSchema
28400
+ })
28401
+ },
28402
+ {
28403
+ name: "delete_capture_rule",
28404
+ group: "capture_rules",
28405
+ description: "Delete a project capture rule.",
28406
+ inputSchema: external_exports.object({
28407
+ bearerToken: external_exports.string(),
28408
+ projectId: external_exports.string(),
28409
+ ruleId: external_exports.string()
28410
+ })
28411
+ },
28412
+ {
28413
+ name: "suggest_capture_rules_from_incident",
28414
+ group: "capture_rules",
28415
+ description: "Generate deterministic capture rule suggestions from an incident bundle.",
28416
+ inputSchema: external_exports.object({
28417
+ bearerToken: external_exports.string(),
28418
+ incidentId: external_exports.string()
28419
+ })
28420
+ },
28421
+ {
28422
+ name: "create_capture_rule_from_incident_suggestion",
28423
+ group: "capture_rules",
28424
+ description: "Create a capture rule from an incident-derived suggestion.",
28425
+ inputSchema: external_exports.object({
28426
+ bearerToken: external_exports.string(),
28427
+ incidentId: external_exports.string(),
28428
+ create: jsonObjectSchema
28429
+ })
28430
+ },
26464
28431
  {
26465
28432
  name: "get_capture_policy",
26466
28433
  group: "capture_policy",