@debugbundle/cli 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/main.cjs +1217 -238
  2. package/package.json +2 -2
package/dist/main.cjs CHANGED
@@ -14483,6 +14483,8 @@ var CaptureBreadcrumbsValues = ["local_only", "exception_only", "standalone"];
14483
14483
  var CaptureBreadcrumbsSchema = external_exports.enum(CaptureBreadcrumbsValues);
14484
14484
  var CaptureProbeEventsValues = ["buffer_only", "standalone_when_activated"];
14485
14485
  var CaptureProbeEventsSchema = external_exports.enum(CaptureProbeEventsValues);
14486
+ var RequestSignalClassificationValues = ["incident_signal", "context_signal"];
14487
+ var RequestSignalClassificationSchema = external_exports.enum(RequestSignalClassificationValues);
14486
14488
  var CapturePolicySchema = external_exports.object({
14487
14489
  project_id: external_exports.string().uuid(),
14488
14490
  preset: CapturePresetSchema,
@@ -14499,6 +14501,55 @@ var CapturePolicyUpdateSchema = external_exports.object({
14499
14501
  capture_breadcrumbs: CaptureBreadcrumbsSchema.nullable().optional(),
14500
14502
  capture_probe_events: CaptureProbeEventsSchema.nullable().optional()
14501
14503
  });
14504
+ var BALANCED_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([408, 423, 424, 425, 429]);
14505
+ var INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES = /* @__PURE__ */ new Set([...BALANCED_IMMEDIATE_REQUEST_STATUSES, 409]);
14506
+ var BALANCED_STANDARD_ANOMALY_STATUSES = /* @__PURE__ */ new Set([401, 403, 404, 409, 422]);
14507
+ var BALANCED_HIGH_VOLUME_ANOMALY_STATUSES = /* @__PURE__ */ new Set([400, 410]);
14508
+ var INVESTIGATIVE_ANOMALY_STATUSES = /* @__PURE__ */ new Set([...BALANCED_STANDARD_ANOMALY_STATUSES, ...BALANCED_HIGH_VOLUME_ANOMALY_STATUSES]);
14509
+ function classifyRequestStatus(input) {
14510
+ const { responseStatus, capturePreset } = input;
14511
+ if (responseStatus === null || !Number.isFinite(responseStatus)) {
14512
+ return "context_signal";
14513
+ }
14514
+ if (responseStatus >= 500) {
14515
+ return "incident_signal";
14516
+ }
14517
+ if (capturePreset === "investigative") {
14518
+ return INVESTIGATIVE_IMMEDIATE_REQUEST_STATUSES.has(responseStatus) ? "incident_signal" : "context_signal";
14519
+ }
14520
+ if (capturePreset === "balanced") {
14521
+ return BALANCED_IMMEDIATE_REQUEST_STATUSES.has(responseStatus) ? "incident_signal" : "context_signal";
14522
+ }
14523
+ return "context_signal";
14524
+ }
14525
+ function getRequestAnomalyThreshold(input) {
14526
+ const { responseStatus, capturePreset } = input;
14527
+ if (responseStatus === null || !Number.isFinite(responseStatus) || responseStatus < 400 || responseStatus >= 500) {
14528
+ return null;
14529
+ }
14530
+ if (capturePreset === "minimal") {
14531
+ return null;
14532
+ }
14533
+ if (capturePreset === "investigative") {
14534
+ return INVESTIGATIVE_ANOMALY_STATUSES.has(responseStatus) ? {
14535
+ minimum_occurrences_5m: 8,
14536
+ minimum_ratio_5m_to_1h: 2
14537
+ } : null;
14538
+ }
14539
+ if (BALANCED_STANDARD_ANOMALY_STATUSES.has(responseStatus)) {
14540
+ return {
14541
+ minimum_occurrences_5m: 20,
14542
+ minimum_ratio_5m_to_1h: 3
14543
+ };
14544
+ }
14545
+ if (BALANCED_HIGH_VOLUME_ANOMALY_STATUSES.has(responseStatus)) {
14546
+ return {
14547
+ minimum_occurrences_5m: 50,
14548
+ minimum_ratio_5m_to_1h: 5
14549
+ };
14550
+ }
14551
+ return null;
14552
+ }
14502
14553
 
14503
14554
  // ../../packages/shared-types/src/index.ts
14504
14555
  function createUuidV4() {
@@ -14547,6 +14598,26 @@ var InlineProbeDataSchema = external_exports.object({
14547
14598
  version: external_exports.literal(1),
14548
14599
  items: external_exports.array(InlineProbeDataItemSchema)
14549
14600
  }).strict();
14601
+ var RuntimeMemoryStatsSchema = external_exports.object({
14602
+ rss: external_exports.number().nonnegative().nullable(),
14603
+ heap_total: external_exports.number().nonnegative().nullable(),
14604
+ heap_used: external_exports.number().nonnegative().nullable(),
14605
+ external: external_exports.number().nonnegative().nullable(),
14606
+ peak: external_exports.number().nonnegative().nullable()
14607
+ }).strict();
14608
+ var BackendRuntimePayloadSchema = external_exports.object({
14609
+ version: external_exports.string().min(1),
14610
+ platform: external_exports.string().min(1).nullable().optional(),
14611
+ arch: external_exports.string().min(1).nullable().optional(),
14612
+ pid: external_exports.number().int().nonnegative().nullable().optional(),
14613
+ cwd: external_exports.string().min(1).nullable().optional(),
14614
+ uptime_sec: external_exports.number().nonnegative().nullable().optional(),
14615
+ hostname: external_exports.string().min(1).nullable().optional(),
14616
+ thread_id: external_exports.union([external_exports.string(), external_exports.number()]).nullable().optional(),
14617
+ framework_version: external_exports.string().min(1).nullable().optional(),
14618
+ memory: RuntimeMemoryStatsSchema.nullable().optional(),
14619
+ framework_extras: external_exports.record(external_exports.string(), external_exports.unknown()).nullable().optional()
14620
+ }).strict();
14550
14621
  var BackendExceptionPayloadSchema = external_exports.object({
14551
14622
  name: external_exports.string().min(1),
14552
14623
  message: external_exports.string().min(1),
@@ -14564,9 +14635,7 @@ var BackendExceptionPayloadSchema = external_exports.object({
14564
14635
  headers: external_exports.record(external_exports.string(), external_exports.unknown()).optional(),
14565
14636
  body: external_exports.unknown().optional()
14566
14637
  }),
14567
- runtime: external_exports.object({
14568
- version: external_exports.string().min(1)
14569
- }),
14638
+ runtime: BackendRuntimePayloadSchema,
14570
14639
  probe_data: InlineProbeDataSchema.optional()
14571
14640
  }).strict();
14572
14641
  var RequestEventPayloadSchema = external_exports.object({
@@ -14837,13 +14906,7 @@ var ContextDeploySchema = external_exports.object({
14837
14906
  deployed_at: external_exports.string().datetime().nullable(),
14838
14907
  regression_window: external_exports.boolean().nullable()
14839
14908
  });
14840
- var MemoryStatsSchema = external_exports.object({
14841
- rss: external_exports.number().nonnegative().nullable(),
14842
- heap_total: external_exports.number().nonnegative().nullable(),
14843
- heap_used: external_exports.number().nonnegative().nullable(),
14844
- external: external_exports.number().nonnegative().nullable(),
14845
- peak: external_exports.number().nonnegative().nullable()
14846
- });
14909
+ var MemoryStatsSchema = RuntimeMemoryStatsSchema;
14847
14910
  var ContextRuntimeSchema = external_exports.object({
14848
14911
  version: external_exports.literal(1),
14849
14912
  name: external_exports.string().min(1),
@@ -15112,7 +15175,7 @@ function buildCliReference() {
15112
15175
  "- `debugbundle ingest <file> --format <format> [--json]`",
15113
15176
  "- `debugbundle watch --log <file> --format <format> [--json]`",
15114
15177
  "- `debugbundle watch --cloud --log <file> --format <format> [--json]`",
15115
- "- `debugbundle process [--json]`",
15178
+ "- `debugbundle process [--preset <minimal|balanced|investigative>] [--json]`",
15116
15179
  "",
15117
15180
  "## Investigation",
15118
15181
  "",
@@ -15658,7 +15721,7 @@ var import_node_path4 = require("node:path");
15658
15721
 
15659
15722
  // ../../packages/retrieval-client/src/index.ts
15660
15723
  var IncidentReasonSchema = external_exports.object({
15661
- kind: external_exports.enum(["backend_exception", "frontend_exception", "request_failure_5xx", "error_log"]),
15724
+ kind: external_exports.enum(["backend_exception", "frontend_exception", "request_failure", "error_log"]),
15662
15725
  description: external_exports.string(),
15663
15726
  event_type: external_exports.enum(["backend_exception", "frontend_exception", "request_event", "log_event"]),
15664
15727
  event_class: external_exports.literal("incident_signal"),
@@ -16079,7 +16142,8 @@ function buildRedactionRecord(bundleBody) {
16079
16142
  function buildVisibilityRecord(input) {
16080
16143
  const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
16081
16144
  const matchedFields = input.incident.matched_fields.length === 0 ? "none" : input.incident.matched_fields.join(", ");
16082
- const grouping = input.primarySignal.kind === "request_failure_5xx" && input.primarySignal.request_method !== null && routeTarget !== null ? `Repeated 5xx request failures with the same normalized route template, request method, response status, service, and environment reuse this incident fingerprint. This incident currently groups ${input.primarySignal.request_method} ${routeTarget} with matched fields ${matchedFields}.` : `This incident groups repeated failures by fingerprint version ${input.incident.fingerprint_version} inside the service and environment boundary, with matched fields ${matchedFields}.`;
16145
+ const isRequestAnomaly = input.incident.matched_fields.includes("request_anomaly");
16146
+ const grouping = input.primarySignal.kind === "request_failure" && input.primarySignal.request_method !== null && routeTarget !== null ? isRequestAnomaly ? `Repeated request-anomaly incidents with the same normalized route template, request method, response status, service, and environment reuse this incident fingerprint once the anomaly threshold fires. This incident currently groups ${input.primarySignal.request_method} ${routeTarget} with matched fields ${matchedFields}.` : `Repeated request-failure incidents with the same normalized route template, request method, response status, service, and environment reuse this incident fingerprint. This incident currently groups ${input.primarySignal.request_method} ${routeTarget} with matched fields ${matchedFields}.` : `This incident groups repeated failures by fingerprint version ${input.incident.fingerprint_version} inside the service and environment boundary, with matched fields ${matchedFields}.`;
16083
16147
  const spikeLead = input.incident.spike_detected_at === void 0 || input.incident.spike_detected_at === null ? "This incident is not currently marked as spiking." : `This incident was marked as spiking at ${input.incident.spike_detected_at}.`;
16084
16148
  return {
16085
16149
  grouping,
@@ -16090,15 +16154,16 @@ function buildVisibilityRecord(input) {
16090
16154
  }
16091
16155
  function buildSuggestedNextChecks(input) {
16092
16156
  const suggestions = [];
16157
+ const isRequestAnomaly = input.incident.matched_fields.includes("request_anomaly");
16093
16158
  if (input.bundle.status === "pending") {
16094
16159
  suggestions.push("Wait for bundle generation to finish, then rerun the incident context command.");
16095
16160
  } else if (input.bundle.status === "failed") {
16096
16161
  suggestions.push("Inspect bundle generation status or retry bundle retrieval to recover missing context.");
16097
16162
  }
16098
16163
  const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
16099
- if (input.primarySignal.request_method !== null && input.primarySignal.response_status !== null && input.primarySignal.response_status >= 500) {
16164
+ if (input.primarySignal.kind === "request_failure" && input.primarySignal.request_method !== null && routeTarget !== null) {
16100
16165
  suggestions.push(
16101
- `Inspect the ${input.primarySignal.request_method} ${routeTarget ?? "request"} handler behind this 5xx path.`
16166
+ isRequestAnomaly ? `Inspect the ${input.primarySignal.request_method} ${routeTarget} handler behind this repeated request-anomaly path.` : `Inspect the ${input.primarySignal.request_method} ${routeTarget} handler behind this request-failure path.`
16102
16167
  );
16103
16168
  }
16104
16169
  const firstApplicationFrame = input.primarySignal.first_application_frame;
@@ -16187,12 +16252,13 @@ function deriveIncidentReasonFromSignal(input) {
16187
16252
  };
16188
16253
  case "request_event": {
16189
16254
  const responseStatus = typeof input.response_status === "number" && Number.isFinite(input.response_status) ? input.response_status : null;
16255
+ const isRequestAnomaly = input.request_anomaly === true;
16190
16256
  return {
16191
- kind: "request_failure_5xx",
16192
- description: responseStatus !== null && responseStatus >= 500 ? `request_event response_status=${responseStatus} matched the 5xx request incident rule` : "request_event matched the 5xx request incident rule",
16257
+ kind: "request_failure",
16258
+ description: isRequestAnomaly ? responseStatus !== null ? `request_event response_status=${responseStatus} crossed the repeated request anomaly threshold` : "request_event crossed the repeated request anomaly threshold" : responseStatus !== null ? `request_event response_status=${responseStatus} matched the immediate request failure incident rule` : "request_event matched the immediate request failure incident rule",
16193
16259
  event_type: "request_event",
16194
16260
  event_class: "incident_signal",
16195
- matched_policy: "5xx request failures bypass capture_request_events suppression"
16261
+ matched_policy: isRequestAnomaly ? "Repeated contextual request failures crossed the request anomaly threshold" : "Immediate request failure statuses bypass capture_request_events suppression"
16196
16262
  };
16197
16263
  }
16198
16264
  case "log_event": {
@@ -16221,9 +16287,11 @@ function deriveIncidentReasonFromSourceEventTypes(eventTypes) {
16221
16287
  return null;
16222
16288
  }
16223
16289
 
16224
- // ../../packages/auth/src/index.ts
16290
+ // ../../packages/auth/src/primitives.ts
16225
16291
  var import_argon2 = require("@node-rs/argon2");
16226
- var DEFAULT_SESSION_LIFETIME_MS = 1e3 * 60 * 60 * 4;
16292
+
16293
+ // ../../packages/auth/src/web-session-auth.ts
16294
+ var DEFAULT_SESSION_LIFETIME_MS = 1e3 * 60 * 60 * 24 * 7;
16227
16295
  var DEFAULT_EMAIL_AUTH_CODE_LIFETIME_MS = 1e3 * 60 * 10;
16228
16296
  var DEFAULT_GITHUB_OAUTH_STATE_LIFETIME_MS = 1e3 * 60 * 10;
16229
16297
 
@@ -16497,7 +16565,7 @@ function getRequestResponseStatus(payload) {
16497
16565
  const status = payload?.["response_status"];
16498
16566
  return typeof status === "number" && Number.isFinite(status) ? status : null;
16499
16567
  }
16500
- function classifyEvent(eventType, logLevel, probeActivationId, payload) {
16568
+ function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal") {
16501
16569
  switch (eventType) {
16502
16570
  case "backend_exception":
16503
16571
  case "frontend_exception":
@@ -16509,10 +16577,7 @@ function classifyEvent(eventType, logLevel, probeActivationId, payload) {
16509
16577
  return "context_signal";
16510
16578
  case "request_event": {
16511
16579
  const responseStatus = getRequestResponseStatus(payload);
16512
- if (responseStatus !== null && responseStatus >= 500) {
16513
- return "incident_signal";
16514
- }
16515
- return "context_signal";
16580
+ return classifyRequestStatus({ responseStatus, capturePreset });
16516
16581
  }
16517
16582
  case "frontend_breadcrumb":
16518
16583
  case "deploy_metadata":
@@ -16551,6 +16616,44 @@ var STORAGE_SCHEMA_MIGRATIONS = [
16551
16616
  "ALTER TABLE organizations ADD COLUMN IF NOT EXISTS suspended_at timestamptz",
16552
16617
  "ALTER TABLE organization_members ADD COLUMN IF NOT EXISTS suspended_at timestamptz"
16553
16618
  ]
16619
+ }),
16620
+ defineStorageSchemaMigration({
16621
+ id: "202605120001_add_github_device_authorizations",
16622
+ description: "Add persisted GitHub CLI bootstrap state for device-flow login.",
16623
+ statements: [
16624
+ `
16625
+ CREATE TABLE IF NOT EXISTS github_device_authorizations (
16626
+ id uuid PRIMARY KEY,
16627
+ device_code text NOT NULL UNIQUE,
16628
+ user_code text NOT NULL,
16629
+ verification_uri text NOT NULL,
16630
+ interval_seconds integer NOT NULL,
16631
+ expires_at timestamptz NOT NULL,
16632
+ accepted_terms_at timestamptz,
16633
+ created_at timestamptz NOT NULL DEFAULT now(),
16634
+ completed_at timestamptz,
16635
+ claimed_at timestamptz,
16636
+ terminal_error text,
16637
+ user_id uuid REFERENCES users(id) ON DELETE SET NULL,
16638
+ organization_id uuid REFERENCES organizations(id) ON DELETE SET NULL
16639
+ )
16640
+ `,
16641
+ `
16642
+ CREATE INDEX IF NOT EXISTS github_device_authorizations_user_code_idx
16643
+ ON github_device_authorizations (user_code, created_at DESC)
16644
+ `,
16645
+ `
16646
+ CREATE INDEX IF NOT EXISTS github_device_authorizations_expires_at_idx
16647
+ ON github_device_authorizations (expires_at)
16648
+ `
16649
+ ]
16650
+ }),
16651
+ defineStorageSchemaMigration({
16652
+ id: "202605130001_allow_synthetic_webhook_test_deliveries_without_incident_fk",
16653
+ description: "Allow webhook test deliveries to persist without requiring a backing incidents row.",
16654
+ statements: [
16655
+ "ALTER TABLE webhook_deliveries ALTER COLUMN incident_id DROP NOT NULL"
16656
+ ]
16554
16657
  })
16555
16658
  ];
16556
16659
 
@@ -16626,7 +16729,11 @@ function parseLocalIncident(candidate) {
16626
16729
  }
16627
16730
  const serviceRuntime = candidate["service_runtime"];
16628
16731
  const serviceFramework = candidate["service_framework"];
16629
- const incidentReason = deriveIncidentReasonFromSourceEventTypes(candidate["source_event_types"]);
16732
+ const incidentReason = candidate["matched_fields"].includes("request_anomaly") ? deriveIncidentReasonFromSignal({
16733
+ event_type: "request_event",
16734
+ event_class: "incident_signal",
16735
+ request_anomaly: true
16736
+ }) : deriveIncidentReasonFromSourceEventTypes(candidate["source_event_types"]);
16630
16737
  if (serviceRuntime !== null && typeof serviceRuntime !== "string") {
16631
16738
  throw createReadError(400, "invalid_local_state");
16632
16739
  }
@@ -17289,7 +17396,7 @@ async function countCloudArtifactCache(dependencies) {
17289
17396
  }
17290
17397
 
17291
17398
  // src/connect-command.ts
17292
- var import_promises7 = require("node:fs/promises");
17399
+ var import_promises8 = require("node:fs/promises");
17293
17400
  var import_node_path9 = require("node:path");
17294
17401
 
17295
17402
  // ../../packages/project-management-client/src/index.ts
@@ -17732,7 +17839,8 @@ function createAlertApi(client) {
17732
17839
  const body = {
17733
17840
  project_id: input.projectId,
17734
17841
  channel: input.channel,
17735
- condition_type: input.conditionType
17842
+ condition_type: input.conditionType,
17843
+ config: input.config
17736
17844
  };
17737
17845
  if (input.serviceId !== void 0) {
17738
17846
  body.service_id = input.serviceId;
@@ -17740,9 +17848,6 @@ function createAlertApi(client) {
17740
17848
  if (input.severityMin !== void 0) {
17741
17849
  body.severity_min = input.severityMin;
17742
17850
  }
17743
- if (input.config !== void 0) {
17744
- body.config = input.config;
17745
- }
17746
17851
  if (input.isEnabled !== void 0) {
17747
17852
  body.is_enabled = input.isEnabled;
17748
17853
  }
@@ -18970,13 +19075,538 @@ async function readConnectionConfig(rootDirectory, readFile) {
18970
19075
  if (typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT") {
18971
19076
  throw new Error(`Missing ${CONNECTION_FILE_PATH}`);
18972
19077
  }
18973
- throw new Error(`Invalid ${CONNECTION_FILE_PATH}`);
18974
- }
18975
- const parsed = ConnectionConfigSchema.safeParse(parsedJson);
18976
- if (!parsed.success) {
18977
- throw new Error(`Invalid ${CONNECTION_FILE_PATH}`);
19078
+ throw new Error(`Invalid ${CONNECTION_FILE_PATH}`);
19079
+ }
19080
+ const parsed = ConnectionConfigSchema.safeParse(parsedJson);
19081
+ if (!parsed.success) {
19082
+ throw new Error(`Invalid ${CONNECTION_FILE_PATH}`);
19083
+ }
19084
+ return parsed.data;
19085
+ }
19086
+
19087
+ // src/interactive-auth.ts
19088
+ var import_node_process = require("node:process");
19089
+ var import_promises7 = require("node:readline/promises");
19090
+ function isInteractiveTerminal() {
19091
+ return import_node_process.stdin.isTTY === true && import_node_process.stdout.isTTY === true;
19092
+ }
19093
+ async function promptForInteractiveLoginSelection() {
19094
+ const readlineInterface = (0, import_promises7.createInterface)({
19095
+ input: import_node_process.stdin,
19096
+ output: import_node_process.stdout
19097
+ });
19098
+ try {
19099
+ import_node_process.stdout.write(
19100
+ [
19101
+ "Choose an authentication method:",
19102
+ "1. GitHub (auto: use gh if available, otherwise device flow)",
19103
+ "2. GitHub device flow",
19104
+ "3. Existing member token",
19105
+ "4. Cancel"
19106
+ ].join("\n") + "\n"
19107
+ );
19108
+ for (; ; ) {
19109
+ const selection = (await readlineInterface.question("Selection [1-4]: ")).trim();
19110
+ if (selection === "1") {
19111
+ return { kind: "github" };
19112
+ }
19113
+ if (selection === "2") {
19114
+ return { kind: "github-device" };
19115
+ }
19116
+ if (selection === "3") {
19117
+ const bearerToken = (await readlineInterface.question("Paste your member token: ")).trim();
19118
+ if (bearerToken.length > 0) {
19119
+ return {
19120
+ kind: "member-token",
19121
+ bearerToken
19122
+ };
19123
+ }
19124
+ import_node_process.stdout.write("Member token cannot be empty.\n");
19125
+ continue;
19126
+ }
19127
+ if (selection === "4") {
19128
+ return { kind: "cancel" };
19129
+ }
19130
+ import_node_process.stdout.write("Enter 1, 2, 3, or 4.\n");
19131
+ }
19132
+ } finally {
19133
+ readlineInterface.close();
19134
+ }
19135
+ }
19136
+
19137
+ // src/login-command.ts
19138
+ var import_node_child_process = require("node:child_process");
19139
+ var import_node_util = require("node:util");
19140
+ var execFile = (0, import_node_util.promisify)(import_node_child_process.execFile);
19141
+ var DEFAULT_BASE_URL = "https://api.debugbundle.com";
19142
+ var DEFAULT_GITHUB_BOOTSTRAP_LABEL = "GitHub bootstrap";
19143
+ var MIN_DEVICE_POLL_INTERVAL_SECONDS = 7;
19144
+ var LoginCommandInputSchema = external_exports.object({
19145
+ bearerToken: external_exports.string().trim().min(1).optional(),
19146
+ baseUrl: external_exports.string().url().default(DEFAULT_BASE_URL),
19147
+ github: external_exports.boolean().optional(),
19148
+ githubCli: external_exports.boolean().optional(),
19149
+ githubDevice: external_exports.boolean().optional(),
19150
+ label: external_exports.string().trim().min(1).max(120).default(DEFAULT_GITHUB_BOOTSTRAP_LABEL)
19151
+ }).superRefine((value, context) => {
19152
+ const githubModeCount = [value.github, value.githubCli, value.githubDevice].filter((flag) => flag === true).length;
19153
+ if (githubModeCount > 1) {
19154
+ context.addIssue({
19155
+ code: external_exports.ZodIssueCode.custom,
19156
+ message: "github_mode_conflict"
19157
+ });
19158
+ }
19159
+ if (value.bearerToken !== void 0 && githubModeCount > 0) {
19160
+ context.addIssue({
19161
+ code: external_exports.ZodIssueCode.custom,
19162
+ message: "login_mode_conflict"
19163
+ });
19164
+ }
19165
+ if (value.bearerToken === void 0 && githubModeCount === 0) {
19166
+ context.addIssue({
19167
+ code: external_exports.ZodIssueCode.custom,
19168
+ message: "login_mode_missing"
19169
+ });
19170
+ }
19171
+ });
19172
+ var ApiErrorResponseSchema9 = external_exports.object({
19173
+ error: external_exports.string()
19174
+ }).strict();
19175
+ var DeviceStartResponseSchema = external_exports.object({
19176
+ request_id: external_exports.string().uuid(),
19177
+ user_code: external_exports.string().min(1),
19178
+ verification_uri: external_exports.string().url(),
19179
+ interval_seconds: external_exports.number().int().positive(),
19180
+ expires_at: external_exports.string().datetime()
19181
+ }).strict();
19182
+ var DevicePollResponseSchema = external_exports.discriminatedUnion("status", [
19183
+ external_exports.object({
19184
+ status: external_exports.literal("pending"),
19185
+ interval_seconds: external_exports.number().int().positive(),
19186
+ expires_at: external_exports.string().datetime()
19187
+ }).strict(),
19188
+ external_exports.object({
19189
+ status: external_exports.enum(["approved", "claimed"]),
19190
+ expires_at: external_exports.string().datetime()
19191
+ }).strict(),
19192
+ external_exports.object({
19193
+ status: external_exports.enum(["denied", "expired", "rejected"]),
19194
+ reason: external_exports.string(),
19195
+ expires_at: external_exports.string().datetime()
19196
+ }).strict()
19197
+ ]);
19198
+ var MemberTokenResponseSchema = external_exports.object({
19199
+ token: external_exports.object({
19200
+ token_id: external_exports.string(),
19201
+ user_id: external_exports.string(),
19202
+ organization_id: external_exports.string(),
19203
+ label: external_exports.string(),
19204
+ created_at: external_exports.string(),
19205
+ last_used_at: external_exports.string().nullable(),
19206
+ revoked_at: external_exports.string().nullable(),
19207
+ expires_at: external_exports.string().nullable(),
19208
+ plaintext: external_exports.string()
19209
+ }).strict()
19210
+ }).strict();
19211
+ var LoginApiError = class extends Error {
19212
+ status;
19213
+ code;
19214
+ constructor(status, code) {
19215
+ super(`login_api_error: ${status}:${code}`);
19216
+ this.status = status;
19217
+ this.code = code;
19218
+ }
19219
+ };
19220
+ function normalizeBaseUrl2(baseUrl) {
19221
+ return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
19222
+ }
19223
+ function formatLoginOutput(authState, authFilePath) {
19224
+ return [
19225
+ "Authenticated: yes",
19226
+ `Base URL: ${authState.base_url}`,
19227
+ `Auth File: ${authFilePath}`,
19228
+ `Token: ${buildTokenPreview(authState.bearer_token)}`
19229
+ ].join("\n");
19230
+ }
19231
+ function validateMemberToken(token) {
19232
+ return token.startsWith("dbundle_mem_");
19233
+ }
19234
+ function resolveLoginMode(input) {
19235
+ if (input.bearerToken !== void 0) {
19236
+ return "token";
19237
+ }
19238
+ if (input.githubCli === true) {
19239
+ return "github-cli";
19240
+ }
19241
+ if (input.githubDevice === true) {
19242
+ return "github-device";
19243
+ }
19244
+ return "github";
19245
+ }
19246
+ function hasExplicitLoginMode(input) {
19247
+ return input.bearerToken !== void 0 || input.github === true || input.githubCli === true || input.githubDevice === true;
19248
+ }
19249
+ async function maybePromptForLoginInput(input, dependencies) {
19250
+ if (hasExplicitLoginMode(input) || input.json === true) {
19251
+ return input;
19252
+ }
19253
+ const interactive = (dependencies?.isInteractiveTerminal ?? isInteractiveTerminal)();
19254
+ if (!interactive) {
19255
+ return input;
19256
+ }
19257
+ const selection = await (dependencies?.promptForInteractiveLogin ?? promptForInteractiveLoginSelection)();
19258
+ if (selection.kind === "cancel") {
19259
+ return {
19260
+ exitCode: 4,
19261
+ output: "Authentication cancelled."
19262
+ };
19263
+ }
19264
+ if (selection.kind === "member-token") {
19265
+ return {
19266
+ ...input,
19267
+ bearerToken: selection.bearerToken
19268
+ };
19269
+ }
19270
+ if (selection.kind === "github-device") {
19271
+ return {
19272
+ ...input,
19273
+ githubDevice: true
19274
+ };
19275
+ }
19276
+ return {
19277
+ ...input,
19278
+ github: true
19279
+ };
19280
+ }
19281
+ function mapInputValidationError(parsedInput) {
19282
+ if (parsedInput.error.issues.some((issue) => issue.message === "github_mode_conflict")) {
19283
+ return "Choose only one of --github, --github-cli, or --github-device.";
19284
+ }
19285
+ if (parsedInput.error.issues.some((issue) => issue.message === "login_mode_conflict")) {
19286
+ return "Use either a member token or a GitHub login mode, not both.";
19287
+ }
19288
+ if (parsedInput.error.issues.some((issue) => issue.message === "login_mode_missing")) {
19289
+ return "Provide either a member token or one of --github, --github-cli, or --github-device.";
19290
+ }
19291
+ return "Invalid login options.";
19292
+ }
19293
+ function mapApiErrorToMessage(error) {
19294
+ switch (error.code) {
19295
+ case "auth_not_configured":
19296
+ return "GitHub login is not configured on this DebugBundle API.";
19297
+ case "github_device_flow_disabled":
19298
+ return "GitHub device flow is not enabled for this DebugBundle API.";
19299
+ case "github_oauth_unavailable":
19300
+ return "GitHub OAuth is temporarily unavailable.";
19301
+ case "invalid_github_token":
19302
+ return "The local GitHub CLI token was rejected by DebugBundle.";
19303
+ case "github_device_request_not_found":
19304
+ return "GitHub device authorization request was not found.";
19305
+ case "github_device_auth_pending":
19306
+ return "GitHub device authorization has not completed yet.";
19307
+ case "github_device_auth_expired":
19308
+ return "GitHub device authorization expired before it could be claimed.";
19309
+ case "github_device_auth_claimed":
19310
+ return "GitHub device authorization was already claimed.";
19311
+ case "github_device_auth_rejected":
19312
+ return "GitHub device authorization was rejected.";
19313
+ case "github_email_unavailable":
19314
+ return "GitHub did not provide a verified primary email address.";
19315
+ case "account_signup_disabled":
19316
+ return "This DebugBundle workspace does not allow new account signups for this GitHub identity.";
19317
+ case "account_suspended":
19318
+ return "This DebugBundle account is suspended.";
19319
+ case "rate_limited":
19320
+ return "GitHub login was rate limited. Please wait and try again.";
19321
+ default:
19322
+ return `GitHub login failed: ${error.code}`;
19323
+ }
19324
+ }
19325
+ async function parseResponseBody2(response) {
19326
+ const rawBody = await response.text();
19327
+ if (rawBody.length === 0) {
19328
+ return null;
19329
+ }
19330
+ try {
19331
+ return JSON.parse(rawBody);
19332
+ } catch {
19333
+ return rawBody;
19334
+ }
19335
+ }
19336
+ async function requestJson(input, dependencies) {
19337
+ const fetchImpl = dependencies?.fetchImpl ?? fetch;
19338
+ const response = await fetchImpl(`${normalizeBaseUrl2(input.baseUrl)}${input.path}`, {
19339
+ method: input.method,
19340
+ headers: {
19341
+ accept: "application/json",
19342
+ "content-type": "application/json"
19343
+ },
19344
+ body: JSON.stringify(input.body)
19345
+ });
19346
+ const body = await parseResponseBody2(response);
19347
+ if (response.status < 200 || response.status >= 300) {
19348
+ const parsedError = ApiErrorResponseSchema9.safeParse(body);
19349
+ throw new LoginApiError(response.status, parsedError.success ? parsedError.data.error : "unknown_error");
19350
+ }
19351
+ return body;
19352
+ }
19353
+ async function readGitHubAccessTokenFromGh() {
19354
+ try {
19355
+ const result = await execFile("gh", ["auth", "token"]);
19356
+ const token = result.stdout.trim();
19357
+ return token.length > 0 ? token : null;
19358
+ } catch {
19359
+ return null;
19360
+ }
19361
+ }
19362
+ async function exchangeGitHubToken(input, dependencies) {
19363
+ const body = await requestJson(
19364
+ {
19365
+ baseUrl: input.baseUrl,
19366
+ method: "POST",
19367
+ path: "/v1/auth/github/token/exchange",
19368
+ body: {
19369
+ github_access_token: input.githubAccessToken,
19370
+ label: input.label,
19371
+ accepted_terms: true
19372
+ }
19373
+ },
19374
+ dependencies
19375
+ );
19376
+ return MemberTokenResponseSchema.parse(body);
19377
+ }
19378
+ async function startGitHubDeviceFlow(input, dependencies) {
19379
+ const body = await requestJson(
19380
+ {
19381
+ baseUrl: input.baseUrl,
19382
+ method: "POST",
19383
+ path: "/v1/auth/github/device/start",
19384
+ body: {
19385
+ accepted_terms: true
19386
+ }
19387
+ },
19388
+ dependencies
19389
+ );
19390
+ return DeviceStartResponseSchema.parse(body);
19391
+ }
19392
+ async function pollGitHubDeviceFlow(input, dependencies) {
19393
+ const body = await requestJson(
19394
+ {
19395
+ baseUrl: input.baseUrl,
19396
+ method: "POST",
19397
+ path: "/v1/auth/github/device/poll",
19398
+ body: {
19399
+ request_id: input.requestId
19400
+ }
19401
+ },
19402
+ dependencies
19403
+ );
19404
+ return DevicePollResponseSchema.parse(body);
19405
+ }
19406
+ async function claimGitHubDeviceFlow(input, dependencies) {
19407
+ const body = await requestJson(
19408
+ {
19409
+ baseUrl: input.baseUrl,
19410
+ method: "POST",
19411
+ path: "/v1/auth/github/device/claim",
19412
+ body: {
19413
+ request_id: input.requestId,
19414
+ label: input.label
19415
+ }
19416
+ },
19417
+ dependencies
19418
+ );
19419
+ return MemberTokenResponseSchema.parse(body);
19420
+ }
19421
+ function formatPersistedSuccess(input, dependencies) {
19422
+ const authState = {
19423
+ bearer_token: input.bearerToken,
19424
+ base_url: input.baseUrl
19425
+ };
19426
+ return dependencies.writeAuthState({
19427
+ ...input.authFilePath === void 0 ? {} : { authFilePath: input.authFilePath },
19428
+ authState
19429
+ }).then((persistedPath) => {
19430
+ const authFilePath = persistedPath ?? input.authFilePath ?? "";
19431
+ const payload = {
19432
+ authenticated: true,
19433
+ auth: {
19434
+ base_url: authState.base_url,
19435
+ token_preview: buildTokenPreview(authState.bearer_token)
19436
+ },
19437
+ auth_file_path: authFilePath
19438
+ };
19439
+ return {
19440
+ exitCode: 0,
19441
+ output: input.json ? JSON.stringify(payload) : formatLoginOutput(authState, authFilePath)
19442
+ };
19443
+ });
19444
+ }
19445
+ function buildProgressReporter(dependency) {
19446
+ if (dependency !== void 0) {
19447
+ return dependency;
19448
+ }
19449
+ return (text) => {
19450
+ process.stderr.write(`${text}
19451
+ `);
19452
+ };
19453
+ }
19454
+ async function loginCommand(input, dependencies) {
19455
+ const promptedInput = await maybePromptForLoginInput(input, dependencies);
19456
+ if ("exitCode" in promptedInput) {
19457
+ return promptedInput;
19458
+ }
19459
+ const parsedInput = LoginCommandInputSchema.safeParse({
19460
+ bearerToken: promptedInput.bearerToken,
19461
+ baseUrl: promptedInput.baseUrl ?? DEFAULT_BASE_URL,
19462
+ github: promptedInput.github,
19463
+ githubCli: promptedInput.githubCli,
19464
+ githubDevice: promptedInput.githubDevice,
19465
+ label: promptedInput.label ?? DEFAULT_GITHUB_BOOTSTRAP_LABEL
19466
+ });
19467
+ if (!parsedInput.success) {
19468
+ return {
19469
+ exitCode: 4,
19470
+ output: mapInputValidationError(parsedInput)
19471
+ };
19472
+ }
19473
+ const normalizedInput = parsedInput.data;
19474
+ const writeAuthState = dependencies?.writeAuthState ?? persistCliAuthState;
19475
+ try {
19476
+ if (resolveLoginMode(normalizedInput) === "token") {
19477
+ if (!validateMemberToken(normalizedInput.bearerToken)) {
19478
+ return {
19479
+ exitCode: 4,
19480
+ output: "Invalid member token."
19481
+ };
19482
+ }
19483
+ return await formatPersistedSuccess(
19484
+ {
19485
+ baseUrl: normalizedInput.baseUrl,
19486
+ bearerToken: normalizedInput.bearerToken,
19487
+ ...promptedInput.json === void 0 ? {} : { json: promptedInput.json },
19488
+ ...promptedInput.authFilePath === void 0 ? {} : { authFilePath: promptedInput.authFilePath }
19489
+ },
19490
+ { writeAuthState }
19491
+ );
19492
+ }
19493
+ const readGitHubAccessToken = dependencies?.readGitHubAccessToken ?? readGitHubAccessTokenFromGh;
19494
+ const sleep = dependencies?.sleep ?? ((ms) => new Promise((resolve) => setTimeout(resolve, ms)));
19495
+ const reportProgress = buildProgressReporter(dependencies?.reportProgress);
19496
+ const loginMode = resolveLoginMode(normalizedInput);
19497
+ if (loginMode !== "github-device") {
19498
+ const githubAccessToken = await readGitHubAccessToken();
19499
+ if (githubAccessToken !== null) {
19500
+ reportProgress("Using existing GitHub CLI authentication.");
19501
+ try {
19502
+ const exchanged = await exchangeGitHubToken(
19503
+ {
19504
+ baseUrl: normalizedInput.baseUrl,
19505
+ githubAccessToken,
19506
+ label: normalizedInput.label
19507
+ },
19508
+ dependencies
19509
+ );
19510
+ return await formatPersistedSuccess(
19511
+ {
19512
+ baseUrl: normalizedInput.baseUrl,
19513
+ bearerToken: exchanged.token.plaintext,
19514
+ ...promptedInput.json === void 0 ? {} : { json: promptedInput.json },
19515
+ ...promptedInput.authFilePath === void 0 ? {} : { authFilePath: promptedInput.authFilePath }
19516
+ },
19517
+ { writeAuthState }
19518
+ );
19519
+ } catch (error) {
19520
+ if (!(error instanceof LoginApiError)) {
19521
+ throw error;
19522
+ }
19523
+ if (loginMode === "github-cli" || error.code !== "invalid_github_token") {
19524
+ return {
19525
+ exitCode: error.status === 401 || error.status === 403 ? 4 : 1,
19526
+ output: mapApiErrorToMessage(error)
19527
+ };
19528
+ }
19529
+ reportProgress("The local GitHub CLI token was not accepted. Falling back to device flow.");
19530
+ }
19531
+ } else if (loginMode === "github-cli") {
19532
+ return {
19533
+ exitCode: 4,
19534
+ output: "GitHub CLI is not authenticated on this machine."
19535
+ };
19536
+ } else {
19537
+ reportProgress("GitHub CLI is not authenticated. Falling back to device flow.");
19538
+ }
19539
+ }
19540
+ const started = await startGitHubDeviceFlow(
19541
+ {
19542
+ baseUrl: normalizedInput.baseUrl
19543
+ },
19544
+ dependencies
19545
+ );
19546
+ reportProgress(`Open ${started.verification_uri} and enter code ${started.user_code}.`);
19547
+ reportProgress("Waiting for GitHub approval...");
19548
+ let intervalSeconds = Math.max(started.interval_seconds, MIN_DEVICE_POLL_INTERVAL_SECONDS);
19549
+ for (; ; ) {
19550
+ await sleep(intervalSeconds * 1e3);
19551
+ const polled = await pollGitHubDeviceFlow(
19552
+ {
19553
+ baseUrl: normalizedInput.baseUrl,
19554
+ requestId: started.request_id
19555
+ },
19556
+ dependencies
19557
+ );
19558
+ if (polled.status === "pending") {
19559
+ intervalSeconds = Math.max(polled.interval_seconds, MIN_DEVICE_POLL_INTERVAL_SECONDS);
19560
+ continue;
19561
+ }
19562
+ if (polled.status === "approved") {
19563
+ const claimed = await claimGitHubDeviceFlow(
19564
+ {
19565
+ baseUrl: normalizedInput.baseUrl,
19566
+ requestId: started.request_id,
19567
+ label: normalizedInput.label
19568
+ },
19569
+ dependencies
19570
+ );
19571
+ return await formatPersistedSuccess(
19572
+ {
19573
+ baseUrl: normalizedInput.baseUrl,
19574
+ bearerToken: claimed.token.plaintext,
19575
+ ...promptedInput.json === void 0 ? {} : { json: promptedInput.json },
19576
+ ...promptedInput.authFilePath === void 0 ? {} : { authFilePath: promptedInput.authFilePath }
19577
+ },
19578
+ { writeAuthState }
19579
+ );
19580
+ }
19581
+ if (polled.status === "claimed") {
19582
+ return {
19583
+ exitCode: 4,
19584
+ output: "GitHub device authorization was already claimed."
19585
+ };
19586
+ }
19587
+ if (polled.status === "denied" || polled.status === "expired" || polled.status === "rejected") {
19588
+ return {
19589
+ exitCode: 4,
19590
+ output: polled.status === "denied" ? "GitHub device authorization was denied." : polled.status === "expired" ? "GitHub device authorization expired." : `GitHub device authorization was rejected: ${polled.reason}`
19591
+ };
19592
+ }
19593
+ return {
19594
+ exitCode: 1,
19595
+ output: "GitHub device authorization returned an unexpected status."
19596
+ };
19597
+ }
19598
+ } catch (error) {
19599
+ if (error instanceof LoginApiError) {
19600
+ return {
19601
+ exitCode: error.status === 400 || error.status === 401 || error.status === 403 || error.status === 409 ? 4 : 1,
19602
+ output: mapApiErrorToMessage(error)
19603
+ };
19604
+ }
19605
+ return {
19606
+ exitCode: 1,
19607
+ output: error instanceof Error ? error.message : String(error)
19608
+ };
18978
19609
  }
18979
- return parsed.data;
18980
19610
  }
18981
19611
 
18982
19612
  // src/connect-command.ts
@@ -19068,9 +19698,9 @@ function buildValidationFailureResult(input) {
19068
19698
  }
19069
19699
  async function connectCommand(input, dependencies = {}) {
19070
19700
  const cwd = dependencies.cwd ?? (() => process.cwd());
19071
- const readFile = dependencies.readFile ?? ((path) => (0, import_promises7.readFile)(path, "utf8"));
19072
- const stat = dependencies.stat ?? import_promises7.stat;
19073
- const writeFile = dependencies.writeFile ?? import_promises7.writeFile;
19701
+ const readFile = dependencies.readFile ?? ((path) => (0, import_promises8.readFile)(path, "utf8"));
19702
+ const stat = dependencies.stat ?? import_promises8.stat;
19703
+ const writeFile = dependencies.writeFile ?? import_promises8.writeFile;
19074
19704
  const readAuthState = dependencies.readAuthState ?? ((authInput) => readCliAuthState(authInput));
19075
19705
  const createHttpClient = dependencies.createHttpClient ?? ((clientInput) => {
19076
19706
  const httpClientDependencies = {};
@@ -19081,6 +19711,7 @@ async function connectCommand(input, dependencies = {}) {
19081
19711
  });
19082
19712
  const createProjectApi = dependencies.createProjectManagementApi ?? createProjectManagementApi;
19083
19713
  const createTokenApi = dependencies.createTokenManagementApi ?? createTokenManagementApi;
19714
+ const loginCommand2 = dependencies.loginCommand ?? loginCommand;
19084
19715
  const rootDirectory = cwd();
19085
19716
  const initialChecks = [];
19086
19717
  const profileValidation = await readValidatedProfileName(rootDirectory, { readFile, stat });
@@ -19137,7 +19768,22 @@ async function connectCommand(input, dependencies = {}) {
19137
19768
  message: `Found ${CONNECTION_FILE_PATH}`
19138
19769
  });
19139
19770
  try {
19140
- const authState = await readAuthState({ ...input.authFilePath === void 0 ? {} : { authFilePath: input.authFilePath } });
19771
+ let authState;
19772
+ try {
19773
+ authState = await readAuthState({ ...input.authFilePath === void 0 ? {} : { authFilePath: input.authFilePath } });
19774
+ } catch (error) {
19775
+ const shouldAttemptInteractiveLogin = error instanceof CliAuthStateError && error.code === "auth_state_missing" && input.json !== true && (dependencies.isInteractiveTerminal ?? isInteractiveTerminal)();
19776
+ if (!shouldAttemptInteractiveLogin) {
19777
+ throw error;
19778
+ }
19779
+ const loginResult = await loginCommand2({
19780
+ ...input.authFilePath === void 0 ? {} : { authFilePath: input.authFilePath }
19781
+ });
19782
+ if (loginResult.exitCode !== 0) {
19783
+ return loginResult;
19784
+ }
19785
+ authState = await readAuthState({ ...input.authFilePath === void 0 ? {} : { authFilePath: input.authFilePath } });
19786
+ }
19141
19787
  const httpClient = createHttpClient({ baseUrl: authState.base_url });
19142
19788
  const projectApi = createProjectApi(httpClient);
19143
19789
  const tokenApi = createTokenApi(httpClient);
@@ -19241,7 +19887,7 @@ async function connectCommand(input, dependencies = {}) {
19241
19887
  message
19242
19888
  }
19243
19889
  ], [
19244
- exitCode === 2 ? "Run debugbundle login before connecting the project to cloud." : "Resolve the cloud API error and retry debugbundle connect."
19890
+ exitCode === 2 ? "Run debugbundle login to choose an auth flow, or use debugbundle login --github, debugbundle login --github-device, or debugbundle login <dbundle_mem_...> before connecting the project to cloud." : "Resolve the cloud API error and retry debugbundle connect."
19245
19891
  ]) : `DebugBundle connect failed.
19246
19892
  - ${message}`
19247
19893
  };
@@ -19249,7 +19895,7 @@ async function connectCommand(input, dependencies = {}) {
19249
19895
  }
19250
19896
 
19251
19897
  // src/doctor-command.ts
19252
- var import_promises8 = require("node:fs/promises");
19898
+ var import_promises9 = require("node:fs/promises");
19253
19899
  var import_node_path10 = require("node:path");
19254
19900
  var ProfileSchema2 = external_exports.object({
19255
19901
  debugbundle: external_exports.object({
@@ -19269,7 +19915,7 @@ var RELAY_SPOOL_DELIVERED_MARKER_SUFFIX2 = ".delivered";
19269
19915
  var RELAY_SPOOL_EVENT_SUFFIX = ".events.json";
19270
19916
  var SUGGESTED_ACTIONS = [
19271
19917
  "Run debugbundle setup if local scaffold files are missing.",
19272
- "Run debugbundle login to create ~/.debugbundle/auth.json.",
19918
+ "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.",
19273
19919
  "Review .debugbundle/profile.json when architecture changes or the profile becomes stale."
19274
19920
  ];
19275
19921
  async function pathExists3(path, stat) {
@@ -19382,7 +20028,7 @@ function buildPrivacyPreview() {
19382
20028
  sample_event_type: sampleEvent.event_type,
19383
20029
  sample_event_class: sampleEventClass,
19384
20030
  sample_can_create_incident: sampleEventClass === "incident_signal",
19385
- incident_rule: "request_event with response_status >= 500 is classified as an incident_signal",
20031
+ incident_rule: "request_event incident classification follows the resolved capture preset: 5xx always create incidents, balanced also promotes 408/423/424/425/429, and investigative also promotes 409.",
19386
20032
  redacted_fields,
19387
20033
  omitted_fields: [],
19388
20034
  retained_metadata: {
@@ -19471,7 +20117,7 @@ async function loadConnection(rootDirectory, dependencies) {
19471
20117
  };
19472
20118
  }
19473
20119
  }
19474
- function normalizeBaseUrl2(baseUrl) {
20120
+ function normalizeBaseUrl3(baseUrl) {
19475
20121
  return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
19476
20122
  }
19477
20123
  function buildProjectModeCheck(connection) {
@@ -19571,7 +20217,7 @@ async function buildAuthCheck(input, readAuthStateImpl) {
19571
20217
  };
19572
20218
  }
19573
20219
  }
19574
- async function parseResponseBody2(response) {
20220
+ async function parseResponseBody3(response) {
19575
20221
  const rawBody = await response.text();
19576
20222
  if (rawBody.length === 0) {
19577
20223
  return null;
@@ -19586,8 +20232,8 @@ async function buildConnectedApiCheck(input) {
19586
20232
  if (input.connection === null || input.connection.mode !== "connected") {
19587
20233
  return null;
19588
20234
  }
19589
- const connectionBaseUrl = input.connection.cloud_base_url === null ? null : normalizeBaseUrl2(input.connection.cloud_base_url);
19590
- const authBaseUrl = input.authState === null ? null : normalizeBaseUrl2(input.authState.base_url);
20235
+ const connectionBaseUrl = input.connection.cloud_base_url === null ? null : normalizeBaseUrl3(input.connection.cloud_base_url);
20236
+ const authBaseUrl = input.authState === null ? null : normalizeBaseUrl3(input.authState.base_url);
19591
20237
  const baseUrl = authBaseUrl ?? connectionBaseUrl;
19592
20238
  if (baseUrl === null) {
19593
20239
  return {
@@ -19611,7 +20257,7 @@ async function buildConnectedApiCheck(input) {
19611
20257
  message: `Connected API ${baseUrl} could not be reached: ${error instanceof Error ? error.message : String(error)}`
19612
20258
  };
19613
20259
  }
19614
- const parsedHealthBody = await parseResponseBody2(healthResponse);
20260
+ const parsedHealthBody = await parseResponseBody3(healthResponse);
19615
20261
  if (healthResponse.status !== 200) {
19616
20262
  return {
19617
20263
  name: "connected-api",
@@ -19649,7 +20295,7 @@ async function buildConnectedApiCheck(input) {
19649
20295
  message: `Connected API ${baseUrl} could not verify member-token auth: ${error instanceof Error ? error.message : String(error)}`
19650
20296
  };
19651
20297
  }
19652
- const parsedIncidentsBody = await parseResponseBody2(incidentsResponse);
20298
+ const parsedIncidentsBody = await parseResponseBody3(incidentsResponse);
19653
20299
  if (incidentsResponse.status !== 200) {
19654
20300
  return {
19655
20301
  name: "connected-api",
@@ -19732,9 +20378,9 @@ async function doctorCommand(input, dependencies = {}) {
19732
20378
  const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
19733
20379
  const fetchImpl = dependencies.fetchImpl ?? fetch;
19734
20380
  const readAuthStateImpl = dependencies.readAuthState ?? readCliAuthState;
19735
- const readdir = dependencies.readdir ?? import_promises8.readdir;
19736
- const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises8.readFile)(filePath, "utf8"));
19737
- const stat = dependencies.stat ?? import_promises8.stat;
20381
+ const readdir = dependencies.readdir ?? import_promises9.readdir;
20382
+ const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises9.readFile)(filePath, "utf8"));
20383
+ const stat = dependencies.stat ?? import_promises9.stat;
19738
20384
  const rootDirectory = cwd();
19739
20385
  const currentTime = now();
19740
20386
  const { check: profileCheck, profile } = await loadProfile(rootDirectory, { readFile, stat });
@@ -19765,7 +20411,7 @@ async function doctorCommand(input, dependencies = {}) {
19765
20411
 
19766
20412
  // src/ingest-command.ts
19767
20413
  var import_node_crypto5 = require("node:crypto");
19768
- var import_promises10 = require("node:fs/promises");
20414
+ var import_promises11 = require("node:fs/promises");
19769
20415
  var import_node_path12 = require("node:path");
19770
20416
 
19771
20417
  // ../../packages/log-parser/src/project-id.ts
@@ -20085,10 +20731,11 @@ function parseLogFile(content, input) {
20085
20731
 
20086
20732
  // src/process-command.ts
20087
20733
  var import_node_crypto4 = require("node:crypto");
20088
- var import_promises9 = require("node:fs/promises");
20734
+ var import_promises10 = require("node:fs/promises");
20089
20735
  var import_node_path11 = require("node:path");
20090
20736
 
20091
20737
  // ../../packages/bundle-engine/src/index.ts
20738
+ var DYNAMIC_SEGMENT_PATTERN2 = /^(?:\d+|[0-9a-f]{8}-[0-9a-f-]{27}|[A-Za-z0-9_-]{24,})$/;
20092
20739
  function toIsoTimestamp(value) {
20093
20740
  return new Date(value).toISOString();
20094
20741
  }
@@ -20162,6 +20809,41 @@ function inferSignalTypeFromSourceEventTypes(sourceEventTypes) {
20162
20809
  function extractTopFrames(stack) {
20163
20810
  return stack.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("at ")).slice(0, 3);
20164
20811
  }
20812
+ function decodeRouteSegment2(segment) {
20813
+ try {
20814
+ return decodeURIComponent(segment);
20815
+ } catch {
20816
+ return segment.replace(
20817
+ /%([0-9A-Fa-f]{2})/g,
20818
+ (_match, hexByte) => String.fromCharCode(parseInt(hexByte, 16))
20819
+ );
20820
+ }
20821
+ }
20822
+ function isDynamicRouteSegment2(segment) {
20823
+ if (DYNAMIC_SEGMENT_PATTERN2.test(segment)) {
20824
+ return true;
20825
+ }
20826
+ const decodedSegment = decodeRouteSegment2(segment);
20827
+ if (decodedSegment.includes("/")) {
20828
+ return true;
20829
+ }
20830
+ if (decodedSegment !== segment && DYNAMIC_SEGMENT_PATTERN2.test(decodedSegment)) {
20831
+ return true;
20832
+ }
20833
+ const strippedMalformedPercent = decodedSegment.replace(/%+/g, "");
20834
+ return strippedMalformedPercent !== decodedSegment && DYNAMIC_SEGMENT_PATTERN2.test(strippedMalformedPercent);
20835
+ }
20836
+ function normalizeRouteTemplate(path) {
20837
+ if (path === null || path.length === 0) {
20838
+ return null;
20839
+ }
20840
+ const pathWithoutQueryOrFragment = path.split(/[?#]/, 1)[0] ?? "";
20841
+ if (pathWithoutQueryOrFragment.length === 0) {
20842
+ return "/";
20843
+ }
20844
+ const normalizedSegments = pathWithoutQueryOrFragment.split("/").filter((segment) => segment.length > 0).map((segment) => isDynamicRouteSegment2(segment) ? "{param}" : segment);
20845
+ return normalizedSegments.length === 0 ? "/" : `/${normalizedSegments.join("/")}`;
20846
+ }
20165
20847
  function deriveFirstApplicationFrame(errorContext) {
20166
20848
  const firstFrame = errorContext?.top_frames[0];
20167
20849
  if (firstFrame === void 0) {
@@ -20255,13 +20937,135 @@ function buildRequestContext(envelopes) {
20255
20937
  version: 1,
20256
20938
  method: exceptionEvent.payload.request.method,
20257
20939
  path: exceptionEvent.payload.request.path,
20258
- route_template: null,
20940
+ route_template: normalizeRouteTemplate(exceptionEvent.payload.request.path),
20259
20941
  query: exceptionEvent.payload.request.query,
20260
20942
  headers: exceptionEvent.payload.request.headers,
20261
20943
  body: exceptionEvent.payload.request.body ?? null,
20262
20944
  request_id: exceptionEvent.correlation?.request_id ?? null
20263
20945
  };
20264
20946
  }
20947
+ function titleCaseWord(value) {
20948
+ if (value.toLowerCase() === "github") {
20949
+ return "GitHub";
20950
+ }
20951
+ if (value.toLowerCase() === "api") {
20952
+ return "API";
20953
+ }
20954
+ return `${value.slice(0, 1).toUpperCase()}${value.slice(1)}`;
20955
+ }
20956
+ function formatDependencyName(name) {
20957
+ return name.split("_").filter((part) => part.length > 0).map(titleCaseWord).join(" ");
20958
+ }
20959
+ function inferDependencyName(text) {
20960
+ const match = /\b([a-z][a-z0-9]*_api)_(?:invalid_response|error|failure|failed|unavailable|timeout)\b/.exec(text);
20961
+ return match?.[1] ?? null;
20962
+ }
20963
+ function buildDependenciesContext(incident, errorContext, requestContext) {
20964
+ if (errorContext === null) {
20965
+ return null;
20966
+ }
20967
+ const text = `${incident.title} ${errorContext.name} ${errorContext.message}`.toLowerCase();
20968
+ const dependencyName = inferDependencyName(text);
20969
+ if (dependencyName === null) {
20970
+ return null;
20971
+ }
20972
+ const displayName = formatDependencyName(dependencyName);
20973
+ const route = requestContext?.route_template ?? requestContext?.path ?? null;
20974
+ const requestDescription = requestContext !== null ? `${requestContext.method} ${route ?? requestContext.path}` : "the failing request";
20975
+ const invalidResponse = text.includes("invalid_response");
20976
+ return {
20977
+ version: 1,
20978
+ items: [
20979
+ {
20980
+ name: dependencyName,
20981
+ status: "failed",
20982
+ notes: invalidResponse ? `${displayName} returned an unexpected response shape while handling ${requestDescription}.` : `${displayName} failed while handling ${requestDescription}.`
20983
+ }
20984
+ ]
20985
+ };
20986
+ }
20987
+ function buildSummaryGuidance(input) {
20988
+ if (input.errorContext === null) {
20989
+ return {
20990
+ likely_cause: null,
20991
+ confidence: 0,
20992
+ recommended_action: null
20993
+ };
20994
+ }
20995
+ const route = input.requestContext?.route_template ?? input.requestContext?.path ?? null;
20996
+ const requestDescription = input.requestContext !== null ? `${input.requestContext.method} ${route ?? input.requestContext.path}` : null;
20997
+ const firstDependency = input.dependenciesContext?.items[0] ?? null;
20998
+ const dependencyDisplayName = firstDependency !== null ? formatDependencyName(firstDependency.name) : null;
20999
+ const firstFrame = input.firstApplicationFrame;
21000
+ const frameDescription = firstFrame?.file !== null && firstFrame?.file !== void 0 ? ` in ${firstFrame.file}` : "";
21001
+ const invalidResponse = input.errorContext.message.toLowerCase().includes("invalid_response");
21002
+ let likelyCause = null;
21003
+ let recommendedAction = null;
21004
+ if (firstDependency !== null && dependencyDisplayName !== null && requestDescription !== null && invalidResponse) {
21005
+ likelyCause = `${dependencyDisplayName} returned a response that did not match the expected schema while handling ${requestDescription}.`;
21006
+ recommendedAction = `Inspect the ${dependencyDisplayName} response handling${frameDescription}, including schema validation and sanitized upstream response shape.`;
21007
+ } else if (firstDependency !== null && dependencyDisplayName !== null && requestDescription !== null) {
21008
+ likelyCause = `${dependencyDisplayName} failed while handling ${requestDescription}.`;
21009
+ recommendedAction = `Inspect the ${dependencyDisplayName} call path${frameDescription} and compare the captured dependency notes with upstream status.`;
21010
+ } else if (requestDescription !== null) {
21011
+ likelyCause = `${input.errorContext.name} occurred while handling ${requestDescription}${frameDescription}.`;
21012
+ recommendedAction = `Inspect the first application frame${frameDescription} and the captured request/response context.`;
21013
+ } else if (firstFrame !== null) {
21014
+ likelyCause = `${input.errorContext.name} originated from the first captured application frame${frameDescription}.`;
21015
+ recommendedAction = `Inspect the first application frame${frameDescription} and surrounding error handling.`;
21016
+ }
21017
+ if (likelyCause === null || recommendedAction === null) {
21018
+ return {
21019
+ likely_cause: null,
21020
+ confidence: 0,
21021
+ recommended_action: null
21022
+ };
21023
+ }
21024
+ let confidence = 0.25;
21025
+ if (input.requestContext !== null) confidence += 0.15;
21026
+ if (input.responseContext !== null) confidence += 0.1;
21027
+ if (firstFrame !== null && firstFrame.file !== null) confidence += 0.1;
21028
+ if (firstDependency !== null) confidence += 0.1;
21029
+ if (input.errorContext.message.length > 0) confidence += 0.05;
21030
+ return {
21031
+ likely_cause: likelyCause,
21032
+ confidence: Math.min(0.8, Number(confidence.toFixed(2))),
21033
+ recommended_action: recommendedAction
21034
+ };
21035
+ }
21036
+ function normalizeBaseUrl4(value) {
21037
+ const trimmed = value?.trim();
21038
+ if (trimmed === void 0 || trimmed.length === 0) {
21039
+ return null;
21040
+ }
21041
+ return trimmed.replace(/\/+$/, "");
21042
+ }
21043
+ function buildLinks(incident, linkBaseUrls) {
21044
+ const apiBaseUrl = normalizeBaseUrl4(linkBaseUrls?.api);
21045
+ const appBaseUrl = normalizeBaseUrl4(linkBaseUrls?.app);
21046
+ const docsBaseUrl = normalizeBaseUrl4(linkBaseUrls?.docs);
21047
+ const incidentPath = `/v1/incidents/${encodeURIComponent(incident.incident_id)}`;
21048
+ const appIncidentPath = `/incidents/${encodeURIComponent(incident.incident_id)}`;
21049
+ const appProjectPath = `/projects/${encodeURIComponent(incident.project_id)}`;
21050
+ return {
21051
+ self: apiBaseUrl !== null ? `${apiBaseUrl}${incidentPath}/bundle` : null,
21052
+ reproduction: apiBaseUrl !== null ? `${apiBaseUrl}${incidentPath}/reproduction` : null,
21053
+ incident: appBaseUrl !== null ? `${appBaseUrl}${appIncidentPath}` : null,
21054
+ project: appBaseUrl !== null ? `${appBaseUrl}${appProjectPath}` : null,
21055
+ docs: docsBaseUrl !== null ? `${docsBaseUrl}/bundles` : null
21056
+ };
21057
+ }
21058
+ function applyBundleRedaction(candidate) {
21059
+ const redactionResult = redact(candidate);
21060
+ const fields = [...new Set(redactionResult.redacted_fields)].sort();
21061
+ const redactedBundle = redactionResult.redacted;
21062
+ redactedBundle["redaction"] = {
21063
+ redacted: true,
21064
+ fields,
21065
+ notes: fields.length > 0 ? "Sensitive bundle fields were redacted before storage." : null
21066
+ };
21067
+ return redactedBundle;
21068
+ }
20265
21069
  function buildResponseContext(envelopes) {
20266
21070
  const requestEvent = selectLatestEnvelopeByType(envelopes, isRequestEventEnvelope);
20267
21071
  if (requestEvent !== null) {
@@ -20394,17 +21198,31 @@ function buildFrontendContext(envelopes) {
20394
21198
  dom_context: domContext
20395
21199
  };
20396
21200
  }
20397
- function buildDeployContext(envelopes, trigger) {
21201
+ function buildDeployContext(envelopes, trigger, configuredDeploy) {
20398
21202
  const envelope = selectLatestEnvelopeByType(envelopes, isDeployMetadataEnvelope);
20399
- if (envelope === null) {
21203
+ if (envelope !== null) {
21204
+ return {
21205
+ version: 1,
21206
+ commit_sha: envelope.payload.commit_sha,
21207
+ deploy_version: envelope.payload.version,
21208
+ branch: envelope.payload.branch,
21209
+ deployed_at: toIsoTimestamp(envelope.payload.deployed_at),
21210
+ regression_window: trigger === "regression_reopen"
21211
+ };
21212
+ }
21213
+ const commitSha = configuredDeploy?.commit_sha ?? null;
21214
+ const deployVersion = configuredDeploy?.deploy_version ?? null;
21215
+ const branch = configuredDeploy?.branch ?? null;
21216
+ const deployedAt = configuredDeploy?.deployed_at ?? null;
21217
+ if (commitSha === null && deployVersion === null && branch === null && deployedAt === null) {
20400
21218
  return null;
20401
21219
  }
20402
21220
  return {
20403
21221
  version: 1,
20404
- commit_sha: envelope.payload.commit_sha,
20405
- deploy_version: envelope.payload.version,
20406
- branch: envelope.payload.branch,
20407
- deployed_at: toIsoTimestamp(envelope.payload.deployed_at),
21222
+ commit_sha: commitSha,
21223
+ deploy_version: deployVersion,
21224
+ branch,
21225
+ deployed_at: deployedAt === null ? null : toIsoTimestamp(deployedAt),
20408
21226
  regression_window: trigger === "regression_reopen"
20409
21227
  };
20410
21228
  }
@@ -20413,34 +21231,49 @@ function buildRuntimeContext(envelopes) {
20413
21231
  if (backendException === null) {
20414
21232
  return null;
20415
21233
  }
21234
+ const runtime = backendException.payload.runtime;
20416
21235
  return {
20417
21236
  version: 1,
20418
21237
  name: backendException.service.runtime ?? "unknown",
20419
- runtime_version: backendException.payload.runtime.version,
20420
- platform: null,
20421
- arch: null,
20422
- pid: null,
20423
- cwd: null,
20424
- uptime_sec: null,
20425
- hostname: null,
20426
- thread_id: null,
21238
+ runtime_version: runtime.version,
21239
+ platform: runtime.platform ?? null,
21240
+ arch: runtime.arch ?? null,
21241
+ pid: runtime.pid ?? null,
21242
+ cwd: runtime.cwd ?? null,
21243
+ uptime_sec: runtime.uptime_sec ?? null,
21244
+ hostname: runtime.hostname ?? null,
21245
+ thread_id: runtime.thread_id ?? null,
20427
21246
  framework: backendException.service.framework ?? null,
20428
- framework_version: null,
20429
- memory: null,
20430
- framework_extras: null
21247
+ framework_version: runtime.framework_version ?? null,
21248
+ memory: runtime.memory ?? null,
21249
+ framework_extras: runtime.framework_extras ?? null
20431
21250
  };
20432
21251
  }
20433
- function buildGitContext(envelopes) {
21252
+ function buildGitContext(envelopes, configuredDeploy) {
20434
21253
  const deployEnvelope = selectLatestEnvelopeByType(envelopes, isDeployMetadataEnvelope);
20435
21254
  if (deployEnvelope === null) {
20436
- return null;
21255
+ const commit = configuredDeploy?.commit_sha ?? null;
21256
+ const branch = configuredDeploy?.branch ?? null;
21257
+ const repo = configuredDeploy?.repo ?? null;
21258
+ if (commit === null && branch === null && repo === null) {
21259
+ return null;
21260
+ }
21261
+ return {
21262
+ version: 1,
21263
+ commit,
21264
+ commit_short: commit === null ? null : commit.slice(0, 7),
21265
+ branch,
21266
+ repo,
21267
+ dirty: false,
21268
+ source: "env"
21269
+ };
20437
21270
  }
20438
21271
  return {
20439
21272
  version: 1,
20440
21273
  commit: deployEnvelope.payload.commit_sha,
20441
21274
  commit_short: deployEnvelope.payload.commit_sha.slice(0, 7),
20442
21275
  branch: deployEnvelope.payload.branch,
20443
- repo: null,
21276
+ repo: configuredDeploy?.repo ?? null,
20444
21277
  dirty: false,
20445
21278
  source: "env"
20446
21279
  };
@@ -20483,10 +21316,11 @@ function buildBundle(input) {
20483
21316
  const responseContext = buildResponseContext(sourceEnvelopes);
20484
21317
  const logsContext = buildLogsContext(sourceEnvelopes);
20485
21318
  const frontendContext = buildFrontendContext(sourceEnvelopes);
20486
- const deployContext = buildDeployContext(sourceEnvelopes, input.job.trigger);
21319
+ const deployContext = buildDeployContext(sourceEnvelopes, input.job.trigger, input.configuredDeploy);
20487
21320
  const runtimeContext = buildRuntimeContext(sourceEnvelopes);
20488
- const gitContext = buildGitContext(sourceEnvelopes);
21321
+ const gitContext = buildGitContext(sourceEnvelopes, input.configuredDeploy);
20489
21322
  const deviceContext = buildDeviceContext(sourceEnvelopes);
21323
+ const dependenciesContext = buildDependenciesContext(input.incident, errorContext, requestContext);
20490
21324
  const primarySignalType = primarySignalEnvelope !== null ? mapSignalType(primarySignalEnvelope.event_type) : inferSignalTypeFromSourceEventTypes(sourceEventTypes);
20491
21325
  const primarySourceEvent = errorContext?.name ?? sourceEventTypes[0] ?? "backend_exception";
20492
21326
  const firstSeenAt = new Date(input.incident.first_seen_at).toISOString();
@@ -20495,7 +21329,15 @@ function buildBundle(input) {
20495
21329
  const serviceRuntime = input.incident.service_runtime ?? selectLatestEnvelope(sourceEnvelopes, (envelope) => envelope.event_type !== "probe_event")?.service.runtime ?? null;
20496
21330
  const serviceFramework = input.incident.service_framework ?? selectLatestEnvelope(sourceEnvelopes, (envelope) => envelope.event_type !== "probe_event")?.service.framework ?? null;
20497
21331
  const customerVisible = frontendContext !== null;
20498
- return BundleV1Schema.parse({
21332
+ const firstApplicationFrame = deriveFirstApplicationFrame(errorContext);
21333
+ const summaryGuidance = buildSummaryGuidance({
21334
+ errorContext,
21335
+ requestContext,
21336
+ responseContext,
21337
+ dependenciesContext,
21338
+ firstApplicationFrame
21339
+ });
21340
+ const candidate = {
20499
21341
  bundle_version: 1,
20500
21342
  bundle_id: `bnd_${input.incident.incident_id}`,
20501
21343
  bundle_type: "failure",
@@ -20530,13 +21372,13 @@ function buildBundle(input) {
20530
21372
  summary: {
20531
21373
  title: input.incident.title,
20532
21374
  description: `Deterministic bundle generated from ${input.job.trigger}`,
20533
- likely_cause: null,
20534
- confidence: 0,
20535
- recommended_action: null,
21375
+ likely_cause: summaryGuidance.likely_cause,
21376
+ confidence: summaryGuidance.confidence,
21377
+ recommended_action: summaryGuidance.recommended_action,
20536
21378
  severity: input.incident.severity,
20537
21379
  error_type: primarySourceEvent,
20538
21380
  error_message: errorContext?.message ?? input.incident.title,
20539
- first_application_frame: deriveFirstApplicationFrame(errorContext),
21381
+ first_application_frame: firstApplicationFrame,
20540
21382
  primary_signal: primarySignalType,
20541
21383
  signals: {
20542
21384
  new_deploy: input.job.trigger === "deploy_metadata",
@@ -20561,7 +21403,7 @@ function buildBundle(input) {
20561
21403
  deploy: deployContext,
20562
21404
  runtime: runtimeContext,
20563
21405
  git: gitContext,
20564
- dependencies: null,
21406
+ dependencies: dependenciesContext,
20565
21407
  probe_data: {
20566
21408
  version: 1,
20567
21409
  items: input.probeDataItems
@@ -20582,11 +21424,7 @@ function buildBundle(input) {
20582
21424
  production_verified: false
20583
21425
  },
20584
21426
  links: {
20585
- self: null,
20586
- reproduction: null,
20587
- incident: null,
20588
- project: null,
20589
- docs: null
21427
+ ...buildLinks(input.incident, input.linkBaseUrls)
20590
21428
  },
20591
21429
  redaction: {
20592
21430
  redacted: true,
@@ -20599,7 +21437,8 @@ function buildBundle(input) {
20599
21437
  generator_version: "worker-build-bundle-v2",
20600
21438
  generation_number: input.bundleMetadata.generation_number
20601
21439
  }
20602
- });
21440
+ };
21441
+ return BundleV1Schema.parse(applyBundleRedaction(candidate));
20603
21442
  }
20604
21443
 
20605
21444
  // ../../packages/repro-engine/src/index.ts
@@ -20619,6 +21458,44 @@ function shellQuote(value) {
20619
21458
  function sortRecordEntries(record) {
20620
21459
  return Object.entries(record).sort(([left], [right]) => left.localeCompare(right));
20621
21460
  }
21461
+ var REPLAY_HEADER_PRIORITY = [
21462
+ "authorization",
21463
+ "cookie",
21464
+ "accept",
21465
+ "content-type",
21466
+ "origin",
21467
+ "accept-language",
21468
+ "access-control-request-method",
21469
+ "access-control-request-headers",
21470
+ "x-request-id",
21471
+ "x-correlation-id",
21472
+ "x-debugbundle-trace-id"
21473
+ ];
21474
+ var DROPPED_REPLAY_HEADERS = /* @__PURE__ */ new Set([
21475
+ "host",
21476
+ "x-forwarded-host",
21477
+ "x-forwarded-proto",
21478
+ "connection",
21479
+ "keep-alive",
21480
+ "transfer-encoding",
21481
+ "upgrade",
21482
+ "te",
21483
+ "trailer",
21484
+ "proxy-connection",
21485
+ "accept-encoding",
21486
+ "content-length",
21487
+ "cache-control",
21488
+ "pragma",
21489
+ "priority",
21490
+ "sec-ch-ua",
21491
+ "sec-ch-ua-mobile",
21492
+ "sec-ch-ua-platform",
21493
+ "sec-fetch-dest",
21494
+ "sec-fetch-mode",
21495
+ "sec-fetch-site",
21496
+ "sec-fetch-user",
21497
+ "user-agent"
21498
+ ]);
20622
21499
  function serializeScalarValue(value) {
20623
21500
  if (typeof value === "string") {
20624
21501
  return value;
@@ -20697,12 +21574,25 @@ function buildStructuredReplayQuery(query) {
20697
21574
  return hasStructuredQueryAmbiguity(normalizedQuery) ? normalizedQuery : void 0;
20698
21575
  }
20699
21576
  function buildReplayHeaders(headers) {
20700
- return Object.fromEntries(
20701
- sortRecordEntries(headers).filter(([headerName]) => !["host", "x-forwarded-host", "x-forwarded-proto"].includes(headerName.toLowerCase())).map(([headerName, headerValue]) => [headerName, normalizeHeaderValue(headerValue)])
20702
- );
21577
+ const entries = sortRecordEntries(headers).filter(([headerName]) => !DROPPED_REPLAY_HEADERS.has(headerName.toLowerCase())).map(([headerName, headerValue]) => [headerName, normalizeHeaderValue(headerValue)]);
21578
+ entries.sort(([left], [right]) => {
21579
+ const leftPriority = REPLAY_HEADER_PRIORITY.indexOf(left.toLowerCase());
21580
+ const rightPriority = REPLAY_HEADER_PRIORITY.indexOf(right.toLowerCase());
21581
+ if (leftPriority !== -1 || rightPriority !== -1) {
21582
+ if (leftPriority === -1) {
21583
+ return 1;
21584
+ }
21585
+ if (rightPriority === -1) {
21586
+ return -1;
21587
+ }
21588
+ return leftPriority - rightPriority;
21589
+ }
21590
+ return left.localeCompare(right);
21591
+ });
21592
+ return Object.fromEntries(entries);
20703
21593
  }
20704
21594
  function expandHeaderValues(headers) {
20705
- return sortRecordEntries(headers).flatMap(([headerName, headerValue]) => {
21595
+ return Object.entries(headers).flatMap(([headerName, headerValue]) => {
20706
21596
  if (Array.isArray(headerValue)) {
20707
21597
  return headerValue.map((item) => [headerName, serializeScalarValue(item)]);
20708
21598
  }
@@ -20840,11 +21730,17 @@ var EVENT_TYPE_SET = new Set(EventTypeValues);
20840
21730
  function isEventType(value) {
20841
21731
  return typeof value === "string" && EVENT_TYPE_SET.has(value);
20842
21732
  }
20843
- function inferSeverity2(eventType) {
20844
- if (eventType === "backend_exception" || eventType === "frontend_exception") {
21733
+ function inferSeverity2(event, capturePreset, incidentKind = "immediate") {
21734
+ if (incidentKind === "request_anomaly") {
21735
+ return "medium";
21736
+ }
21737
+ if (event.event_type === "request_event") {
21738
+ return classifyRequestStatus({ responseStatus: event.payload.response_status, capturePreset }) === "incident_signal" ? "high" : "low";
21739
+ }
21740
+ if (event.event_type === "backend_exception" || event.event_type === "frontend_exception") {
20845
21741
  return "high";
20846
21742
  }
20847
- if (eventType === "error_suppressed") {
21743
+ if (event.event_type === "error_suppressed") {
20848
21744
  return "medium";
20849
21745
  }
20850
21746
  return "low";
@@ -20868,15 +21764,17 @@ function compareEventEnvelopes(left, right) {
20868
21764
  }
20869
21765
  return left.event_id.localeCompare(right.event_id);
20870
21766
  }
20871
- function classifyEnvelope(envelope) {
21767
+ function classifyEnvelope(envelope, capturePreset) {
20872
21768
  return classifyEvent(
20873
21769
  envelope.event_type,
20874
21770
  envelope.event_type === "log_event" ? envelope.payload.level : void 0,
20875
- envelope.event_type === "probe_event" ? envelope.payload.activation_id : void 0
21771
+ envelope.event_type === "probe_event" ? envelope.payload.activation_id : void 0,
21772
+ envelope.payload,
21773
+ capturePreset
20876
21774
  );
20877
21775
  }
20878
- function isIncidentSignalEnvelope(envelope) {
20879
- return classifyEnvelope(envelope) === "incident_signal";
21776
+ function isIncidentSignalEnvelope(envelope, capturePreset) {
21777
+ return classifyEnvelope(envelope, capturePreset) === "incident_signal";
20880
21778
  }
20881
21779
  function getTraceId(envelope) {
20882
21780
  return envelope.correlation?.trace_id ?? null;
@@ -20921,7 +21819,10 @@ function mergeAggregateGroup(aggregates) {
20921
21819
  newEvents: [...canonicalAggregate.newEvents],
20922
21820
  mergedIncidentIds: new Set(canonicalAggregate.mergedIncidentIds),
20923
21821
  signalEventTypes: new Set(canonicalAggregate.signalEventTypes),
20924
- traceIds: new Set(canonicalAggregate.traceIds)
21822
+ traceIds: new Set(canonicalAggregate.traceIds),
21823
+ title: canonicalAggregate.title,
21824
+ kind: canonicalAggregate.kind,
21825
+ severity: canonicalAggregate.severity
20925
21826
  });
20926
21827
  }
20927
21828
  function hashIdentifier(parts, prefix, length) {
@@ -20947,6 +21848,111 @@ function mergeSourceEvents(existingEvents, nextEvents) {
20947
21848
  }
20948
21849
  return [...merged.values()].sort(compareEventEnvelopes);
20949
21850
  }
21851
+ function stableJson2(value) {
21852
+ if (value === null || typeof value !== "object") {
21853
+ return JSON.stringify(value);
21854
+ }
21855
+ if (Array.isArray(value)) {
21856
+ return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
21857
+ }
21858
+ const record = value;
21859
+ const keys = Object.keys(record).sort();
21860
+ return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
21861
+ }
21862
+ function buildRequestAnomalyFingerprint(input) {
21863
+ return (0, import_node_crypto4.createHash)("sha256").update(
21864
+ stableJson2({
21865
+ kind: "request_status_anomaly",
21866
+ project_id: input.projectId,
21867
+ service_name: input.serviceName,
21868
+ environment: input.environment,
21869
+ method: input.method,
21870
+ route_template: input.routeTemplate,
21871
+ response_status: input.responseStatus
21872
+ })
21873
+ ).digest("hex");
21874
+ }
21875
+ function buildRequestAnomalyTitle(input) {
21876
+ return `Request anomaly: ${input.method} ${input.routeTemplate} returned ${input.responseStatus} repeatedly`;
21877
+ }
21878
+ function toUnixSeconds(occurredAt) {
21879
+ return Math.floor(new Date(occurredAt).getTime() / 1e3);
21880
+ }
21881
+ function countOccurrencesInWindow(events, windowSeconds) {
21882
+ const latestEvent = events.at(-1);
21883
+ if (latestEvent === void 0) {
21884
+ return 0;
21885
+ }
21886
+ const latestOccurredAt = toUnixSeconds(latestEvent.occurred_at);
21887
+ const lowerBound = latestOccurredAt - windowSeconds + 1;
21888
+ return events.filter((event) => {
21889
+ const occurredAt = toUnixSeconds(event.occurred_at);
21890
+ return occurredAt >= lowerBound && occurredAt <= latestOccurredAt;
21891
+ }).length;
21892
+ }
21893
+ function passesRequestAnomalyThreshold(events, threshold) {
21894
+ const occurrences5m = countOccurrencesInWindow(events, 5 * 60);
21895
+ const occurrences1h = countOccurrencesInWindow(events, 60 * 60);
21896
+ const baseline1hPer5m = occurrences1h / 12;
21897
+ const ratio = occurrences5m / Math.max(baseline1hPer5m, 1);
21898
+ return occurrences5m >= threshold.minimum_occurrences_5m && ratio >= threshold.minimum_ratio_5m_to_1h;
21899
+ }
21900
+ function collectRequestAnomalyAggregates(batches, capturePreset) {
21901
+ const grouped = /* @__PURE__ */ new Map();
21902
+ for (const batch of batches) {
21903
+ for (const event of batch.events) {
21904
+ if (event.event_type !== "request_event" || classifyEnvelope(event, capturePreset) !== "context_signal") {
21905
+ continue;
21906
+ }
21907
+ const normalizedEvent = normalizeEvent(event);
21908
+ const responseStatus = normalizedEvent.http_status;
21909
+ const method = normalizedEvent.http_method;
21910
+ const routeTemplate = normalizedEvent.route_template;
21911
+ const threshold = getRequestAnomalyThreshold({ responseStatus, capturePreset });
21912
+ if (threshold === null || responseStatus === null || method === null || routeTemplate === null) {
21913
+ continue;
21914
+ }
21915
+ const projectId = requireProjectId(event);
21916
+ const incidentFingerprint = buildRequestAnomalyFingerprint({
21917
+ projectId,
21918
+ serviceName: event.service.name,
21919
+ environment: event.service.environment,
21920
+ method,
21921
+ routeTemplate,
21922
+ responseStatus
21923
+ });
21924
+ const incidentId = deriveIncidentId(projectId, event.service.name, event.service.environment, incidentFingerprint);
21925
+ const aggregate = grouped.get(incidentId) ?? {
21926
+ incidentId,
21927
+ projectId,
21928
+ serviceName: event.service.name,
21929
+ environment: event.service.environment,
21930
+ fingerprint: incidentFingerprint,
21931
+ matchedFields: /* @__PURE__ */ new Set(["request_anomaly", "route_template", "http_method", "http_status", "environment"]),
21932
+ newEvents: [],
21933
+ mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
21934
+ signalEventTypes: /* @__PURE__ */ new Set(["request_event"]),
21935
+ traceIds: /* @__PURE__ */ new Set(),
21936
+ title: buildRequestAnomalyTitle({ method, routeTemplate, responseStatus }),
21937
+ kind: "request_anomaly",
21938
+ severity: "medium"
21939
+ };
21940
+ aggregate.newEvents.push(event);
21941
+ grouped.set(incidentId, aggregate);
21942
+ }
21943
+ }
21944
+ return [...grouped.values()].filter((aggregate) => {
21945
+ const latestEvent = aggregate.newEvents.at(-1);
21946
+ if (latestEvent === void 0 || latestEvent.event_type !== "request_event") {
21947
+ return false;
21948
+ }
21949
+ const threshold = getRequestAnomalyThreshold({
21950
+ responseStatus: normalizeEvent(latestEvent).http_status,
21951
+ capturePreset
21952
+ });
21953
+ return threshold !== null && passesRequestAnomalyThreshold(aggregate.newEvents, threshold);
21954
+ }).sort((left, right) => left.incidentId.localeCompare(right.incidentId));
21955
+ }
20950
21956
  function buildBundleContext(incident) {
20951
21957
  return {
20952
21958
  incident_id: incident.incident_id,
@@ -20976,12 +21982,12 @@ function formatServiceSummary(services) {
20976
21982
  }
20977
21983
  function formatProcessOutput(summary) {
20978
21984
  if (!summary.processed) {
20979
- return summary.message ?? "No new events to process.";
21985
+ return summary.message;
20980
21986
  }
20981
21987
  return [
20982
21988
  `Processed ${summary.events_processed} events from ${summary.files_processed} files into ${summary.incidents_processed} incidents.`,
20983
21989
  ...formatServiceSummary(summary.services),
20984
- `Last processed event file: ${summary.last_processed_event_file ?? "none"}`
21990
+ `Last processed event file: ${summary.last_processed_event_file}`
20985
21991
  ].join("\n");
20986
21992
  }
20987
21993
  async function pathExists4(path, stat) {
@@ -21211,16 +22217,17 @@ function serializeState(state) {
21211
22217
  }
21212
22218
  async function processCommand(input, dependencies = {}) {
21213
22219
  const cwd = dependencies.cwd ?? (() => process.cwd());
21214
- const mkdir = dependencies.mkdir ?? import_promises9.mkdir;
21215
- const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises9.readFile)(filePath, "utf8"));
21216
- const readdir = dependencies.readdir ?? import_promises9.readdir;
21217
- const stat = dependencies.stat ?? import_promises9.stat;
21218
- const writeFile = dependencies.writeFile ?? ((filePath, content) => (0, import_promises9.writeFile)(filePath, content, "utf8"));
22220
+ const mkdir = dependencies.mkdir ?? import_promises10.mkdir;
22221
+ const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises10.readFile)(filePath, "utf8"));
22222
+ const readdir = dependencies.readdir ?? import_promises10.readdir;
22223
+ const stat = dependencies.stat ?? import_promises10.stat;
22224
+ const writeFile = dependencies.writeFile ?? ((filePath, content) => (0, import_promises10.writeFile)(filePath, content, "utf8"));
21219
22225
  const rootDirectory = cwd();
21220
22226
  const eventsDirectoryPath = (0, import_node_path11.join)(rootDirectory, LOCAL_EVENTS_DIRECTORY_PATH2);
21221
22227
  const statePath = (0, import_node_path11.join)(rootDirectory, LOCAL_STATE_FILE_PATH);
21222
22228
  const bundleDirectoryPath = (0, import_node_path11.join)(rootDirectory, LOCAL_BUNDLE_DIRECTORY_PATH3);
21223
22229
  const reproductionDirectoryPath = (0, import_node_path11.join)(rootDirectory, LOCAL_REPRODUCTION_DIRECTORY_PATH2);
22230
+ const capturePreset = input.preset ?? "minimal";
21224
22231
  await mkdir((0, import_node_path11.join)(rootDirectory, ".debugbundle", "local"), { recursive: true });
21225
22232
  await mkdir(bundleDirectoryPath, { recursive: true });
21226
22233
  await mkdir(reproductionDirectoryPath, { recursive: true });
@@ -21228,22 +22235,26 @@ async function processCommand(input, dependencies = {}) {
21228
22235
  const eventFileNames = await pathExists4(eventsDirectoryPath, stat) ? (await readdir(eventsDirectoryPath)).filter((fileName) => fileName.endsWith(".events.json")).sort() : [];
21229
22236
  const lastProcessedEventFile = previousState?.last_processed_event_file ?? null;
21230
22237
  const newEventFileNames = lastProcessedEventFile === null ? eventFileNames : eventFileNames.filter((fileName) => fileName > lastProcessedEventFile);
21231
- if (newEventFileNames.length === 0) {
22238
+ const processAllEventFiles = input.preset !== void 0;
22239
+ const targetEventFileNames = processAllEventFiles ? eventFileNames : newEventFileNames;
22240
+ if (targetEventFileNames.length === 0) {
21232
22241
  const summary2 = buildNoNewEventsSummary(previousState?.last_processed_event_file ?? eventFileNames.at(-1) ?? null);
21233
22242
  return {
21234
22243
  exitCode: 0,
21235
22244
  output: input.json === true ? JSON.stringify(summary2) : formatProcessOutput(summary2)
21236
22245
  };
21237
22246
  }
21238
- const batches = await readEventBatches(eventsDirectoryPath, newEventFileNames, readFile);
21239
- const incidents = new Map(Object.entries(previousState?.incidents ?? {}));
22247
+ const batches = await readEventBatches(eventsDirectoryPath, targetEventFileNames, readFile);
22248
+ const incidents = new Map(
22249
+ processAllEventFiles ? [] : Object.entries(previousState?.incidents ?? {})
22250
+ );
21240
22251
  const aggregates = /* @__PURE__ */ new Map();
21241
22252
  const traceCorrelationGroups = /* @__PURE__ */ new Map();
21242
22253
  let eventsProcessed = 0;
21243
22254
  for (const batch of batches) {
21244
22255
  for (const event of batch.events) {
21245
22256
  eventsProcessed += 1;
21246
- if (!isIncidentSignalEnvelope(event)) {
22257
+ if (!isIncidentSignalEnvelope(event, capturePreset)) {
21247
22258
  continue;
21248
22259
  }
21249
22260
  const normalizedEvent = normalizeEvent(event);
@@ -21260,7 +22271,10 @@ async function processCommand(input, dependencies = {}) {
21260
22271
  newEvents: [],
21261
22272
  mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
21262
22273
  signalEventTypes: /* @__PURE__ */ new Set(),
21263
- traceIds: /* @__PURE__ */ new Set()
22274
+ traceIds: /* @__PURE__ */ new Set(),
22275
+ title: normalizedEvent.normalized_message,
22276
+ kind: "immediate",
22277
+ severity: inferSeverity2(event, capturePreset)
21264
22278
  };
21265
22279
  for (const matchedField of inferMatchedFields(normalizedEvent)) {
21266
22280
  aggregate.matchedFields.add(matchedField);
@@ -21327,14 +22341,16 @@ async function processCommand(input, dependencies = {}) {
21327
22341
  mergedAggregatesByRoot.set(rootIncidentId, aggregateGroup);
21328
22342
  }
21329
22343
  const mergedAggregates = [...mergedAggregatesByRoot.values()].map((aggregateGroup) => mergeAggregateGroup(aggregateGroup)).sort((left, right) => left.incidentId.localeCompare(right.incidentId));
22344
+ const requestAnomalyAggregates = input.preset === void 0 ? [] : collectRequestAnomalyAggregates(batches, capturePreset);
22345
+ const finalizedAggregates = [...mergedAggregates, ...requestAnomalyAggregates].sort((left, right) => left.incidentId.localeCompare(right.incidentId));
21330
22346
  const services = /* @__PURE__ */ new Map();
21331
- for (const aggregate of mergedAggregates) {
22347
+ for (const aggregate of finalizedAggregates) {
21332
22348
  const incidentId = aggregate.incidentId;
21333
22349
  const existingIncidents = [...aggregate.mergedIncidentIds].map((mergedIncidentId) => incidents.get(mergedIncidentId)).filter((incident2) => incident2 !== void 0);
21334
22350
  const existing = existingIncidents.find((incident2) => incident2.incident_id === incidentId) ?? existingIncidents[0];
21335
22351
  const existingSourceEvents = existingIncidents.flatMap((incident2) => incident2.source_events);
21336
22352
  const combinedSourceEvents = mergeSourceEvents(existingSourceEvents, aggregate.newEvents);
21337
- const signalEvents = combinedSourceEvents.filter(isIncidentSignalEnvelope);
22353
+ const signalEvents = aggregate.kind === "request_anomaly" ? combinedSourceEvents : combinedSourceEvents.filter((event) => isIncidentSignalEnvelope(event, capturePreset));
21338
22354
  if (signalEvents.length === 0) {
21339
22355
  continue;
21340
22356
  }
@@ -21344,8 +22360,7 @@ async function processCommand(input, dependencies = {}) {
21344
22360
  continue;
21345
22361
  }
21346
22362
  const sourceEventTypes = [...new Set(signalEvents.map((event) => event.event_type))].sort();
21347
- const severity = signalEvents.map((event) => inferSeverity2(event.event_type)).sort((left, right) => severityRank(right) - severityRank(left))[0] ?? "low";
21348
- const latestNormalizedEvent = normalizeEvent(latestSignalEvent);
22363
+ const severity = signalEvents.map((event) => inferSeverity2(event, capturePreset, aggregate.kind)).sort((left, right) => severityRank(right) - severityRank(left))[0] ?? aggregate.severity;
21349
22364
  const generationNumber = signalEvents.length;
21350
22365
  const bundlePath = `${LOCAL_BUNDLE_DIRECTORY_PATH3}/${incidentId}.bundle.json`;
21351
22366
  const reproductionPath = `${LOCAL_REPRODUCTION_DIRECTORY_PATH2}/${incidentId}.reproduction.json`;
@@ -21360,7 +22375,7 @@ async function processCommand(input, dependencies = {}) {
21360
22375
  environment: aggregate.environment,
21361
22376
  fingerprint: aggregate.fingerprint,
21362
22377
  fingerprint_version: FINGERPRINT_VERSION,
21363
- title: latestNormalizedEvent.normalized_message,
22378
+ title: aggregate.title,
21364
22379
  severity,
21365
22380
  status: existingIncidents.some((incidentState) => incidentState.status === "resolved") ? "open" : existing?.status ?? "open",
21366
22381
  first_seen_at: firstSignalEvent.occurred_at,
@@ -21421,21 +22436,22 @@ async function processCommand(input, dependencies = {}) {
21421
22436
  incidents.set(incidentId, incident);
21422
22437
  services.set(incident.service_name, (services.get(incident.service_name) ?? 0) + 1);
21423
22438
  }
22439
+ const finalProcessedEventFile = targetEventFileNames[targetEventFileNames.length - 1];
21424
22440
  const nextState = {
21425
22441
  version: 1,
21426
- last_processed_event_file: newEventFileNames.at(-1) ?? previousState?.last_processed_event_file ?? null,
22442
+ last_processed_event_file: finalProcessedEventFile,
21427
22443
  incidents: Object.fromEntries([...incidents.entries()].sort(([left], [right]) => left.localeCompare(right)))
21428
22444
  };
21429
22445
  await writeFile(statePath, serializeState(nextState));
21430
22446
  const summary = buildProcessedSummary({
21431
22447
  filesProcessed: newEventFileNames.length,
21432
22448
  eventsProcessed,
21433
- incidentsProcessed: mergedAggregates.length,
22449
+ incidentsProcessed: finalizedAggregates.length,
21434
22450
  services: [...services.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([service, count]) => ({
21435
22451
  service,
21436
22452
  incidents: count
21437
22453
  })),
21438
- lastProcessedEventFile: nextState.last_processed_event_file
22454
+ lastProcessedEventFile: finalProcessedEventFile
21439
22455
  });
21440
22456
  return {
21441
22457
  exitCode: 0,
@@ -21495,11 +22511,11 @@ async function ingestCommand(input, dependencies = {}) {
21495
22511
  };
21496
22512
  }
21497
22513
  const cwd = dependencies.cwd ?? (() => process.cwd());
21498
- const mkdir = dependencies.mkdir ?? (async (path, options) => (0, import_promises10.mkdir)(path, options));
22514
+ const mkdir = dependencies.mkdir ?? (async (path, options) => (0, import_promises11.mkdir)(path, options));
21499
22515
  const processLocalEvents = dependencies.processCommand ?? processCommand;
21500
- const readFile = dependencies.readFile ?? (async (path) => (0, import_promises10.readFile)(path, "utf8"));
21501
- const rename = dependencies.rename ?? (async (sourcePath, destinationPath) => (0, import_promises10.rename)(sourcePath, destinationPath));
21502
- const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises10.writeFile)(path, content, "utf8"));
22516
+ const readFile = dependencies.readFile ?? (async (path) => (0, import_promises11.readFile)(path, "utf8"));
22517
+ const rename = dependencies.rename ?? (async (sourcePath, destinationPath) => (0, import_promises11.rename)(sourcePath, destinationPath));
22518
+ const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises11.writeFile)(path, content, "utf8"));
21503
22519
  try {
21504
22520
  const rootDirectory = cwd();
21505
22521
  const profile = await readProfile(rootDirectory, readFile);
@@ -21556,14 +22572,14 @@ async function ingestCommand(input, dependencies = {}) {
21556
22572
  }
21557
22573
 
21558
22574
  // src/watch-command.ts
21559
- var import_promises11 = require("node:fs/promises");
22575
+ var import_promises12 = require("node:fs/promises");
21560
22576
  var import_node_path13 = require("node:path");
21561
- function normalizeBaseUrl3(baseUrl) {
22577
+ function normalizeBaseUrl5(baseUrl) {
21562
22578
  return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
21563
22579
  }
21564
22580
  async function sendEventsToApi(input, dependencies) {
21565
22581
  const fetchImpl = dependencies?.fetchImpl ?? fetch;
21566
- const response = await fetchImpl(`${normalizeBaseUrl3(input.baseUrl)}/v1/events`, {
22582
+ const response = await fetchImpl(`${normalizeBaseUrl5(input.baseUrl)}/v1/events`, {
21567
22583
  method: "POST",
21568
22584
  headers: {
21569
22585
  accept: "application/json",
@@ -21600,18 +22616,18 @@ async function watchCommand(input, dependencies = {}) {
21600
22616
  };
21601
22617
  }
21602
22618
  const cwd = dependencies.cwd ?? (() => process.cwd());
21603
- const mkdir = dependencies.mkdir ?? (async (path, options) => (0, import_promises11.mkdir)(path, options));
22619
+ const mkdir = dependencies.mkdir ?? (async (path, options) => (0, import_promises12.mkdir)(path, options));
21604
22620
  const pollIntervalMs = dependencies.pollIntervalMs ?? 1e3;
21605
22621
  const processLocalEvents = dependencies.processCommand ?? processCommand;
21606
- const readFile = dependencies.readFile ?? (async (path) => (0, import_promises11.readFile)(path));
22622
+ const readFile = dependencies.readFile ?? (async (path) => (0, import_promises12.readFile)(path));
21607
22623
  const readEnv = dependencies.readEnv ?? ((name) => process.env[name]);
21608
- const rename = dependencies.rename ?? (async (sourcePath, destinationPath) => (0, import_promises11.rename)(sourcePath, destinationPath));
22624
+ const rename = dependencies.rename ?? (async (sourcePath, destinationPath) => (0, import_promises12.rename)(sourcePath, destinationPath));
21609
22625
  const fetchDependencies = dependencies.fetchImpl === void 0 ? void 0 : { fetchImpl: dependencies.fetchImpl };
21610
22626
  const sendEvents = dependencies.sendEvents ?? ((requestInput) => sendEventsToApi(requestInput, fetchDependencies));
21611
22627
  const signal = dependencies.signal;
21612
22628
  const sleep = dependencies.sleep ?? (async (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
21613
- const stat = dependencies.stat ?? import_promises11.stat;
21614
- const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises11.writeFile)(path, content, "utf8"));
22629
+ const stat = dependencies.stat ?? import_promises12.stat;
22630
+ const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises12.writeFile)(path, content, "utf8"));
21615
22631
  try {
21616
22632
  const rootDirectory = cwd();
21617
22633
  const profile = await readProfile(rootDirectory, async (path) => (await readFile(path)).toString("utf8"));
@@ -21733,7 +22749,7 @@ async function watchCommand(input, dependencies = {}) {
21733
22749
  }
21734
22750
 
21735
22751
  // src/setup-command.ts
21736
- var import_promises12 = require("node:fs/promises");
22752
+ var import_promises13 = require("node:fs/promises");
21737
22753
  var import_node_path14 = require("node:path");
21738
22754
  var MANAGED_AGENTS_START = "<!-- debugbundle:start -->";
21739
22755
  var MANAGED_AGENTS_END = "<!-- debugbundle:end -->";
@@ -22280,13 +23296,13 @@ async function buildProfile(rootDirectory, dependencies) {
22280
23296
  async function setupCommand(input, dependencies = {}) {
22281
23297
  const cwd = dependencies.cwd ?? (() => process.cwd());
22282
23298
  const mkdir = dependencies.mkdir ?? (async (path, options) => {
22283
- await (0, import_promises12.mkdir)(path, options);
23299
+ await (0, import_promises13.mkdir)(path, options);
22284
23300
  });
22285
- const readFile = dependencies.readFile ?? (async (path) => (0, import_promises12.readFile)(path, "utf8"));
22286
- const readdir = dependencies.readdir ?? (async (path) => (0, import_promises12.readdir)(path));
22287
- const remove = dependencies.remove ?? (async (path, options) => (0, import_promises12.rm)(path, options));
22288
- const stat = dependencies.stat ?? (async (path) => (0, import_promises12.stat)(path));
22289
- const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises12.writeFile)(path, content, "utf8"));
23301
+ const readFile = dependencies.readFile ?? (async (path) => (0, import_promises13.readFile)(path, "utf8"));
23302
+ const readdir = dependencies.readdir ?? (async (path) => (0, import_promises13.readdir)(path));
23303
+ const remove = dependencies.remove ?? (async (path, options) => (0, import_promises13.rm)(path, options));
23304
+ const stat = dependencies.stat ?? (async (path) => (0, import_promises13.stat)(path));
23305
+ const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises13.writeFile)(path, content, "utf8"));
22290
23306
  const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
22291
23307
  const rootDirectory = cwd();
22292
23308
  const packageJson = await readJsonFile2((0, import_node_path14.join)(rootDirectory, "package.json"), readFile);
@@ -22387,66 +23403,6 @@ async function setupCommand(input, dependencies = {}) {
22387
23403
  }
22388
23404
  }
22389
23405
 
22390
- // src/login-command.ts
22391
- var LoginCommandInputSchema = external_exports.object({
22392
- bearerToken: external_exports.string().trim().min(1),
22393
- baseUrl: external_exports.string().url().default("https://api.debugbundle.com")
22394
- });
22395
- function formatLoginOutput(authState, authFilePath) {
22396
- return [
22397
- "Authenticated: yes",
22398
- `Base URL: ${authState.base_url}`,
22399
- `Auth File: ${authFilePath}`,
22400
- `Token: ${buildTokenPreview(authState.bearer_token)}`
22401
- ].join("\n");
22402
- }
22403
- function validateMemberToken(token) {
22404
- return token.startsWith("dbundle_mem_");
22405
- }
22406
- async function loginCommand(input, dependencies) {
22407
- const parsedInput = LoginCommandInputSchema.safeParse({
22408
- bearerToken: input.bearerToken,
22409
- baseUrl: input.baseUrl ?? "https://api.debugbundle.com"
22410
- });
22411
- if (!parsedInput.success || !validateMemberToken(parsedInput.data.bearerToken)) {
22412
- return {
22413
- exitCode: 4,
22414
- output: "Invalid member token."
22415
- };
22416
- }
22417
- const authState = {
22418
- bearer_token: parsedInput.data.bearerToken,
22419
- base_url: parsedInput.data.baseUrl
22420
- };
22421
- const writeAuthState = dependencies?.writeAuthState ?? persistCliAuthState;
22422
- try {
22423
- const writeInput = {
22424
- authState
22425
- };
22426
- if (input.authFilePath !== void 0) {
22427
- writeInput.authFilePath = input.authFilePath;
22428
- }
22429
- const persistedPath = await writeAuthState(writeInput) ?? (input.authFilePath ?? "");
22430
- const payload = {
22431
- authenticated: true,
22432
- auth: {
22433
- base_url: authState.base_url,
22434
- token_preview: buildTokenPreview(authState.bearer_token)
22435
- },
22436
- auth_file_path: persistedPath
22437
- };
22438
- return {
22439
- exitCode: 0,
22440
- output: input.json ? JSON.stringify(payload) : formatLoginOutput(authState, payload.auth_file_path)
22441
- };
22442
- } catch (error) {
22443
- return {
22444
- exitCode: 1,
22445
- output: error instanceof Error ? error.message : String(error)
22446
- };
22447
- }
22448
- }
22449
-
22450
23406
  // src/profile-command.ts
22451
23407
  function formatProfileValidationErrors(errors) {
22452
23408
  return [
@@ -23350,7 +24306,7 @@ async function listServicesWithAuthCommand(input, dependencies) {
23350
24306
  }
23351
24307
 
23352
24308
  // src/verify-command.ts
23353
- var import_promises13 = require("node:fs/promises");
24309
+ var import_promises14 = require("node:fs/promises");
23354
24310
  var import_node_path15 = require("node:path");
23355
24311
  function resolveOverallStatus2(checks) {
23356
24312
  if (checks.some((check) => check.status === "error" || check.status === "missing")) {
@@ -23423,7 +24379,7 @@ function buildCloudSuggestedActions(status, incidentId, mode = "passive_recent_i
23423
24379
  ];
23424
24380
  }
23425
24381
  return [
23426
- "Run debugbundle login to create ~/.debugbundle/auth.json before verifying cloud traffic.",
24382
+ "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.",
23427
24383
  "Generate a live cloud request, then re-run debugbundle verify cloud with the correct project and service filters."
23428
24384
  ];
23429
24385
  }
@@ -23480,14 +24436,14 @@ function localFailureStepName(checks) {
23480
24436
  function cloudVerificationRunId(now) {
23481
24437
  return now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
23482
24438
  }
23483
- function requestFailure5xxReason() {
24439
+ function requestFailureReason() {
23484
24440
  const incidentReason = deriveIncidentReasonFromSignal({
23485
24441
  event_type: "request_event",
23486
24442
  event_class: "incident_signal",
23487
24443
  response_status: 503
23488
24444
  });
23489
24445
  if (incidentReason === null) {
23490
- throw new Error("request_failure_5xx_reason_unavailable");
24446
+ throw new Error("request_failure_reason_unavailable");
23491
24447
  }
23492
24448
  return incidentReason;
23493
24449
  }
@@ -23608,14 +24564,14 @@ async function writeVerificationEventBatch(input, dependencies) {
23608
24564
  async function verifyLocalCommand(input, dependencies = {}) {
23609
24565
  const cwd = dependencies.cwd ?? (() => process.cwd());
23610
24566
  const mkdir = dependencies.mkdir ?? (async (path, options) => {
23611
- await (0, import_promises13.mkdir)(path, options);
24567
+ await (0, import_promises14.mkdir)(path, options);
23612
24568
  });
23613
24569
  const now = dependencies.now ?? (() => /* @__PURE__ */ new Date());
23614
24570
  const processLocal = dependencies.processCommand ?? processCommand;
23615
24571
  const readVerifiedLocalState = dependencies.readLocalState ?? readLocalState;
23616
24572
  const readVerifiedLocalBundle = dependencies.getLocalBundle ?? getLocalBundle;
23617
- const rename = dependencies.rename ?? (async (sourcePath, destinationPath) => (0, import_promises13.rename)(sourcePath, destinationPath));
23618
- const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises13.writeFile)(path, content, "utf8"));
24573
+ const rename = dependencies.rename ?? (async (sourcePath, destinationPath) => (0, import_promises14.rename)(sourcePath, destinationPath));
24574
+ const writeFile = dependencies.writeFile ?? (async (path, content) => (0, import_promises14.writeFile)(path, content, "utf8"));
23619
24575
  const checks = [];
23620
24576
  function finalize(exitCode, errors, incidentId) {
23621
24577
  return formatResult(input, exitCode, checks, errors, incidentId);
@@ -23636,7 +24592,7 @@ async function verifyLocalCommand(input, dependencies = {}) {
23636
24592
  });
23637
24593
  try {
23638
24594
  const rootDirectory = cwd();
23639
- const profile = await readProfile(rootDirectory, async (path) => (0, import_promises13.readFile)(path, "utf8"));
24595
+ const profile = await readProfile(rootDirectory, async (path) => (0, import_promises14.readFile)(path, "utf8"));
23640
24596
  const projectId = buildProjectId(profile);
23641
24597
  const verificationNow = now();
23642
24598
  const runId = verificationNow.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
@@ -23762,7 +24718,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
23762
24718
  const verification = {
23763
24719
  mode: "active_5xx",
23764
24720
  bundle_status: "unknown",
23765
- classification_reason: requestFailure5xxReason()
24721
+ classification_reason: requestFailureReason()
23766
24722
  };
23767
24723
  const errors = [];
23768
24724
  let exitCode = 0;
@@ -23814,7 +24770,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
23814
24770
  if (candidate !== void 0) {
23815
24771
  incidentId = candidate.incident_id;
23816
24772
  verification.incident_id = candidate.incident_id;
23817
- verification.classification_reason = candidate.incident_reason ?? requestFailure5xxReason();
24773
+ verification.classification_reason = candidate.incident_reason ?? requestFailureReason();
23818
24774
  break;
23819
24775
  }
23820
24776
  if (attempt < pollAttempts) {
@@ -24089,13 +25045,17 @@ var CLI_USAGE_LINES = [
24089
25045
  " debugbundle connect [--auth-file <path>] [--json]",
24090
25046
  " debugbundle ingest <file> --format <debugbundle-ndjson|php-error|apache-error> [--json]",
24091
25047
  " debugbundle watch [--cloud] --log <file> --format <debugbundle-ndjson|php-error|apache-error> [--json]",
24092
- " debugbundle process [--json]",
25048
+ " debugbundle process [--preset <minimal|balanced|investigative>] [--json]",
24093
25049
  " debugbundle clean [--events] [--bundles] [--all] [--older-than <Nd>] [--json]",
24094
25050
  " debugbundle validate [--fix] [--json]",
24095
25051
  " debugbundle verify local [--json]",
24096
25052
  " debugbundle verify cloud --project-id <id> [--trigger-5xx] [--service <name>] [--environment <name>] [--max-age-minutes <n>] [--auth-file <path>] [--json]",
24097
25053
  " debugbundle smoke --project-id <id> [--service <name>] [--environment <name>] [--max-age-minutes <n>] [--auth-file <path>] [--json]",
25054
+ " debugbundle login [--base-url <url>] [--auth-file <path>] [--json]",
24098
25055
  " debugbundle login <member-token> [--base-url <url>] [--auth-file <path>] [--json]",
25056
+ " debugbundle login --github [--label <label>] [--base-url <url>] [--auth-file <path>] [--json]",
25057
+ " debugbundle login --github-cli [--label <label>] [--base-url <url>] [--auth-file <path>] [--json]",
25058
+ " debugbundle login --github-device [--label <label>] [--base-url <url>] [--auth-file <path>] [--json]",
24099
25059
  " debugbundle profile validate [--json]",
24100
25060
  " debugbundle whoami [--auth-file <path>] [--json]",
24101
25061
  " debugbundle incidents [--source <local|cloud>] [--project-id <id>] [--environment <name>] [--service <name>] [--status <status>] [--severity <severity>] [--cursor <cursor>] [--limit <n>] [--auth-file <path>] [--json]",
@@ -24132,7 +25092,7 @@ var CLI_USAGE_LINES = [
24132
25092
  " debugbundle token member create --label <label> [--auth-file <path>] [--json]",
24133
25093
  " debugbundle token member revoke <token-id> [--auth-file <path>] [--json]",
24134
25094
  " debugbundle alert list --project-id <id> [--limit <n>] [--auth-file <path>] [--json]",
24135
- " debugbundle alert create --project-id <id> --channel <channel> --condition <condition> [--service-id <id>] [--severity-min <level>] [--config-json <json>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
25095
+ " debugbundle alert create --project-id <id> --channel <channel> --condition <condition> [--service-id <id>] [--severity-min <level>] --config-json <json> [--is-enabled <true|false>] [--auth-file <path>] [--json]",
24136
25096
  " debugbundle alert update <alert-id> [--service-id <id|null>] [--channel <channel>] [--condition <condition>] [--severity-min <level|null>] [--config-json <json|null>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
24137
25097
  " debugbundle alert delete <alert-id> [--auth-file <path>] [--json]",
24138
25098
  " debugbundle webhook list --project-id <id> [--limit <n>] [--auth-file <path>] [--json]",
@@ -24163,7 +25123,7 @@ function formatUsage() {
24163
25123
  }
24164
25124
 
24165
25125
  // src/validate-command.ts
24166
- var import_promises14 = require("node:fs/promises");
25126
+ var import_promises15 = require("node:fs/promises");
24167
25127
  var import_node_path16 = require("node:path");
24168
25128
  var SUGGESTED_ACTIONS2 = [
24169
25129
  "Run debugbundle setup if .debugbundle/profile.json is missing.",
@@ -24306,11 +25266,11 @@ ${managedSection}
24306
25266
  async function validateCommand(input, dependencies = {}) {
24307
25267
  const cwd = dependencies.cwd ?? (() => process.cwd());
24308
25268
  const mkdir = dependencies.mkdir ?? (async (path, options) => {
24309
- await (0, import_promises14.mkdir)(path, options);
25269
+ await (0, import_promises15.mkdir)(path, options);
24310
25270
  });
24311
- const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises14.readFile)(filePath, "utf8"));
24312
- const stat = dependencies.stat ?? import_promises14.stat;
24313
- const writeFile = dependencies.writeFile ?? (async (filePath, content) => (0, import_promises14.writeFile)(filePath, content, "utf8"));
25271
+ const readFile = dependencies.readFile ?? ((filePath) => (0, import_promises15.readFile)(filePath, "utf8"));
25272
+ const stat = dependencies.stat ?? import_promises15.stat;
25273
+ const writeFile = dependencies.writeFile ?? (async (filePath, content) => (0, import_promises15.writeFile)(filePath, content, "utf8"));
24314
25274
  const rootDirectory = cwd();
24315
25275
  const profileValidation = await validateProfile(rootDirectory, { readFile, stat });
24316
25276
  const checks = [
@@ -24419,7 +25379,7 @@ function parseArgv(argv) {
24419
25379
  positionals.push(token);
24420
25380
  continue;
24421
25381
  }
24422
- if (token === "--fix" || token === "--json" || token === "--check-relay" || token === "--privacy" || token === "--help" || token === "--non-interactive" || token === "--local" || token === "--cloud" || token === "--events" || token === "--bundles" || token === "--all" || token === "--trigger-5xx") {
25382
+ if (token === "--fix" || token === "--json" || token === "--check-relay" || token === "--privacy" || token === "--help" || token === "--non-interactive" || token === "--local" || token === "--cloud" || token === "--events" || token === "--bundles" || token === "--all" || token === "--trigger-5xx" || token === "--github" || token === "--github-cli" || token === "--github-device") {
24423
25383
  options.set(token.slice(2), true);
24424
25384
  continue;
24425
25385
  }
@@ -24660,7 +25620,8 @@ async function createAlertCommand(input, api) {
24660
25620
  bearerToken: input.bearerToken,
24661
25621
  projectId: input.projectId,
24662
25622
  channel: input.channel,
24663
- conditionType: input.conditionType
25623
+ conditionType: input.conditionType,
25624
+ config: input.config
24664
25625
  };
24665
25626
  if (input.serviceId !== void 0) {
24666
25627
  requestInput.serviceId = input.serviceId;
@@ -24668,9 +25629,6 @@ async function createAlertCommand(input, api) {
24668
25629
  if (input.severityMin !== void 0) {
24669
25630
  requestInput.severityMin = input.severityMin;
24670
25631
  }
24671
- if (input.config !== void 0) {
24672
- requestInput.config = input.config;
24673
- }
24674
25632
  if (input.isEnabled !== void 0) {
24675
25633
  requestInput.isEnabled = input.isEnabled;
24676
25634
  }
@@ -24692,7 +25650,8 @@ async function createAlertWithAuthCommand(input, dependencies) {
24692
25650
  bearerToken: authState.bearer_token,
24693
25651
  projectId: input.projectId,
24694
25652
  channel: input.channel,
24695
- conditionType: input.conditionType
25653
+ conditionType: input.conditionType,
25654
+ config: input.config
24696
25655
  };
24697
25656
  if (input.serviceId !== void 0) {
24698
25657
  commandInput.serviceId = input.serviceId;
@@ -24700,9 +25659,6 @@ async function createAlertWithAuthCommand(input, dependencies) {
24700
25659
  if (input.severityMin !== void 0) {
24701
25660
  commandInput.severityMin = input.severityMin;
24702
25661
  }
24703
- if (input.config !== void 0) {
24704
- commandInput.config = input.config;
24705
- }
24706
25662
  if (input.isEnabled !== void 0) {
24707
25663
  commandInput.isEnabled = input.isEnabled;
24708
25664
  }
@@ -27701,9 +28657,10 @@ async function handleAlertCommand(parsedArgv, dependencies) {
27701
28657
  input.severityMin = severityMin;
27702
28658
  }
27703
28659
  const config = readJsonOption(parsedArgv, "config-json");
27704
- if (config !== void 0) {
27705
- input.config = config;
28660
+ if (config === void 0 || typeof config !== "object" || config === null) {
28661
+ throw new CliInputError("Missing required option --config-json.");
27706
28662
  }
28663
+ input.config = config;
27707
28664
  const isEnabled = readBooleanStringOption(parsedArgv, "is-enabled");
27708
28665
  if (isEnabled !== void 0) {
27709
28666
  input.isEnabled = isEnabled;
@@ -27992,10 +28949,17 @@ ${formatUsage()}`
27992
28949
  });
27993
28950
  }
27994
28951
  if (command === "process") {
27995
- expectNoUnknownOptions(parsedArgv, ["json"]);
28952
+ expectNoUnknownOptions(parsedArgv, ["json", "preset"]);
27996
28953
  ensureNoExtraPositionals(parsedArgv, 1);
27997
28954
  const json = readBooleanOption(parsedArgv, "json");
27998
- return await (dependencies.processCommand ?? processCommand)(json === true ? { json: true } : {});
28955
+ const preset = readStringOption(parsedArgv, "preset");
28956
+ if (preset !== void 0 && !CapturePresetSchema.safeParse(preset).success) {
28957
+ throw new CliInputError("Invalid value for --preset.");
28958
+ }
28959
+ return await (dependencies.processCommand ?? processCommand)({
28960
+ ...json === true ? { json: true } : {},
28961
+ ...preset !== void 0 ? { preset } : {}
28962
+ });
27999
28963
  }
28000
28964
  if (command === "clean") {
28001
28965
  expectNoUnknownOptions(parsedArgv, ["events", "bundles", "all", "older-than", "json"]);
@@ -28082,15 +29046,30 @@ ${formatUsage()}`
28082
29046
  return await (dependencies.smokeCommand ?? smokeCommand)(input);
28083
29047
  }
28084
29048
  if (command === "login") {
28085
- expectNoUnknownOptions(parsedArgv, ["auth-file", "base-url", "json"]);
29049
+ expectNoUnknownOptions(parsedArgv, ["auth-file", "base-url", "json", "github", "github-cli", "github-device", "label"]);
28086
29050
  ensureNoExtraPositionals(parsedArgv, 2);
28087
- const input = appendCommonAuthOptions(parsedArgv, {
28088
- bearerToken: requirePositional(parsedArgv, 1, "member-token")
28089
- });
29051
+ const bearerToken = parsedArgv.positionals[1];
29052
+ const input = appendCommonAuthOptions(parsedArgv, {});
29053
+ if (bearerToken !== void 0) {
29054
+ input.bearerToken = bearerToken;
29055
+ }
28090
29056
  const baseUrl = readStringOption(parsedArgv, "base-url");
28091
29057
  if (baseUrl !== void 0) {
28092
29058
  input.baseUrl = baseUrl;
28093
29059
  }
29060
+ if (readBooleanOption(parsedArgv, "github") === true) {
29061
+ input.github = true;
29062
+ }
29063
+ if (readBooleanOption(parsedArgv, "github-cli") === true) {
29064
+ input.githubCli = true;
29065
+ }
29066
+ if (readBooleanOption(parsedArgv, "github-device") === true) {
29067
+ input.githubDevice = true;
29068
+ }
29069
+ const label = readStringOption(parsedArgv, "label");
29070
+ if (label !== void 0) {
29071
+ input.label = label;
29072
+ }
28094
29073
  return await (dependencies.loginCommand ?? loginCommand)(input);
28095
29074
  }
28096
29075
  if (command === "whoami") {
@@ -28295,7 +29274,7 @@ ${formatUsage()}`
28295
29274
  }
28296
29275
  async function main(dependencies = {}) {
28297
29276
  const argv = dependencies.argv ?? process.argv.slice(2);
28298
- const stdout = dependencies.stdout ?? ((text) => process.stdout.write(text));
29277
+ const stdout2 = dependencies.stdout ?? ((text) => process.stdout.write(text));
28299
29278
  const stderr = dependencies.stderr ?? ((text) => process.stderr.write(text));
28300
29279
  const setExitCode = dependencies.setExitCode ?? ((code) => {
28301
29280
  process.exitCode = code;
@@ -28303,7 +29282,7 @@ async function main(dependencies = {}) {
28303
29282
  const result = await runCli(argv, dependencies);
28304
29283
  if (result.output.length > 0) {
28305
29284
  if (result.exitCode === 0) {
28306
- stdout(`${result.output}
29285
+ stdout2(`${result.output}
28307
29286
  `);
28308
29287
  } else {
28309
29288
  stderr(`${result.output}