@debugbundle/cli 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +660 -78
- package/package.json +1 -1
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() {
|
|
@@ -15124,7 +15175,7 @@ function buildCliReference() {
|
|
|
15124
15175
|
"- `debugbundle ingest <file> --format <format> [--json]`",
|
|
15125
15176
|
"- `debugbundle watch --log <file> --format <format> [--json]`",
|
|
15126
15177
|
"- `debugbundle watch --cloud --log <file> --format <format> [--json]`",
|
|
15127
|
-
"- `debugbundle process [--json]`",
|
|
15178
|
+
"- `debugbundle process [--preset <minimal|balanced|investigative>] [--json]`",
|
|
15128
15179
|
"",
|
|
15129
15180
|
"## Investigation",
|
|
15130
15181
|
"",
|
|
@@ -15670,7 +15721,7 @@ var import_node_path4 = require("node:path");
|
|
|
15670
15721
|
|
|
15671
15722
|
// ../../packages/retrieval-client/src/index.ts
|
|
15672
15723
|
var IncidentReasonSchema = external_exports.object({
|
|
15673
|
-
kind: external_exports.enum(["backend_exception", "frontend_exception", "
|
|
15724
|
+
kind: external_exports.enum(["backend_exception", "frontend_exception", "request_failure", "error_log"]),
|
|
15674
15725
|
description: external_exports.string(),
|
|
15675
15726
|
event_type: external_exports.enum(["backend_exception", "frontend_exception", "request_event", "log_event"]),
|
|
15676
15727
|
event_class: external_exports.literal("incident_signal"),
|
|
@@ -16091,7 +16142,8 @@ function buildRedactionRecord(bundleBody) {
|
|
|
16091
16142
|
function buildVisibilityRecord(input) {
|
|
16092
16143
|
const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
|
|
16093
16144
|
const matchedFields = input.incident.matched_fields.length === 0 ? "none" : input.incident.matched_fields.join(", ");
|
|
16094
|
-
const
|
|
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}.`;
|
|
16095
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}.`;
|
|
16096
16148
|
return {
|
|
16097
16149
|
grouping,
|
|
@@ -16102,15 +16154,16 @@ function buildVisibilityRecord(input) {
|
|
|
16102
16154
|
}
|
|
16103
16155
|
function buildSuggestedNextChecks(input) {
|
|
16104
16156
|
const suggestions = [];
|
|
16157
|
+
const isRequestAnomaly = input.incident.matched_fields.includes("request_anomaly");
|
|
16105
16158
|
if (input.bundle.status === "pending") {
|
|
16106
16159
|
suggestions.push("Wait for bundle generation to finish, then rerun the incident context command.");
|
|
16107
16160
|
} else if (input.bundle.status === "failed") {
|
|
16108
16161
|
suggestions.push("Inspect bundle generation status or retry bundle retrieval to recover missing context.");
|
|
16109
16162
|
}
|
|
16110
16163
|
const routeTarget = input.primarySignal.route_template ?? input.primarySignal.request_path;
|
|
16111
|
-
if (input.primarySignal.
|
|
16164
|
+
if (input.primarySignal.kind === "request_failure" && input.primarySignal.request_method !== null && routeTarget !== null) {
|
|
16112
16165
|
suggestions.push(
|
|
16113
|
-
`Inspect the ${input.primarySignal.request_method} ${routeTarget
|
|
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.`
|
|
16114
16167
|
);
|
|
16115
16168
|
}
|
|
16116
16169
|
const firstApplicationFrame = input.primarySignal.first_application_frame;
|
|
@@ -16199,12 +16252,13 @@ function deriveIncidentReasonFromSignal(input) {
|
|
|
16199
16252
|
};
|
|
16200
16253
|
case "request_event": {
|
|
16201
16254
|
const responseStatus = typeof input.response_status === "number" && Number.isFinite(input.response_status) ? input.response_status : null;
|
|
16255
|
+
const isRequestAnomaly = input.request_anomaly === true;
|
|
16202
16256
|
return {
|
|
16203
|
-
kind: "
|
|
16204
|
-
description: responseStatus !== null
|
|
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",
|
|
16205
16259
|
event_type: "request_event",
|
|
16206
16260
|
event_class: "incident_signal",
|
|
16207
|
-
matched_policy: "
|
|
16261
|
+
matched_policy: isRequestAnomaly ? "Repeated contextual request failures crossed the request anomaly threshold" : "Immediate request failure statuses bypass capture_request_events suppression"
|
|
16208
16262
|
};
|
|
16209
16263
|
}
|
|
16210
16264
|
case "log_event": {
|
|
@@ -16511,7 +16565,7 @@ function getRequestResponseStatus(payload) {
|
|
|
16511
16565
|
const status = payload?.["response_status"];
|
|
16512
16566
|
return typeof status === "number" && Number.isFinite(status) ? status : null;
|
|
16513
16567
|
}
|
|
16514
|
-
function classifyEvent(eventType, logLevel, probeActivationId, payload) {
|
|
16568
|
+
function classifyEvent(eventType, logLevel, probeActivationId, payload, capturePreset = "minimal") {
|
|
16515
16569
|
switch (eventType) {
|
|
16516
16570
|
case "backend_exception":
|
|
16517
16571
|
case "frontend_exception":
|
|
@@ -16523,10 +16577,7 @@ function classifyEvent(eventType, logLevel, probeActivationId, payload) {
|
|
|
16523
16577
|
return "context_signal";
|
|
16524
16578
|
case "request_event": {
|
|
16525
16579
|
const responseStatus = getRequestResponseStatus(payload);
|
|
16526
|
-
|
|
16527
|
-
return "incident_signal";
|
|
16528
|
-
}
|
|
16529
|
-
return "context_signal";
|
|
16580
|
+
return classifyRequestStatus({ responseStatus, capturePreset });
|
|
16530
16581
|
}
|
|
16531
16582
|
case "frontend_breadcrumb":
|
|
16532
16583
|
case "deploy_metadata":
|
|
@@ -16596,6 +16647,39 @@ var STORAGE_SCHEMA_MIGRATIONS = [
|
|
|
16596
16647
|
ON github_device_authorizations (expires_at)
|
|
16597
16648
|
`
|
|
16598
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
|
+
]
|
|
16657
|
+
}),
|
|
16658
|
+
defineStorageSchemaMigration({
|
|
16659
|
+
id: "202605130002_add_slack_destinations",
|
|
16660
|
+
description: "Add reusable encrypted Slack alert destinations scoped to organizations.",
|
|
16661
|
+
statements: [
|
|
16662
|
+
`
|
|
16663
|
+
CREATE TABLE IF NOT EXISTS slack_destinations (
|
|
16664
|
+
id uuid PRIMARY KEY,
|
|
16665
|
+
organization_id uuid NOT NULL REFERENCES organizations(id) ON DELETE CASCADE,
|
|
16666
|
+
slack_team_id text NOT NULL,
|
|
16667
|
+
slack_team_name text,
|
|
16668
|
+
slack_channel_id text NOT NULL,
|
|
16669
|
+
slack_channel_name text,
|
|
16670
|
+
webhook_url_ciphertext text NOT NULL,
|
|
16671
|
+
installed_by_member_id uuid REFERENCES users(id) ON DELETE SET NULL,
|
|
16672
|
+
is_active boolean NOT NULL DEFAULT true,
|
|
16673
|
+
created_at timestamptz NOT NULL DEFAULT now(),
|
|
16674
|
+
updated_at timestamptz NOT NULL DEFAULT now(),
|
|
16675
|
+
UNIQUE (organization_id, slack_team_id, slack_channel_id)
|
|
16676
|
+
)
|
|
16677
|
+
`,
|
|
16678
|
+
`
|
|
16679
|
+
CREATE INDEX IF NOT EXISTS slack_destinations_org_active_idx
|
|
16680
|
+
ON slack_destinations (organization_id, is_active, created_at)
|
|
16681
|
+
`
|
|
16682
|
+
]
|
|
16599
16683
|
})
|
|
16600
16684
|
];
|
|
16601
16685
|
|
|
@@ -16671,7 +16755,11 @@ function parseLocalIncident(candidate) {
|
|
|
16671
16755
|
}
|
|
16672
16756
|
const serviceRuntime = candidate["service_runtime"];
|
|
16673
16757
|
const serviceFramework = candidate["service_framework"];
|
|
16674
|
-
const incidentReason =
|
|
16758
|
+
const incidentReason = candidate["matched_fields"].includes("request_anomaly") ? deriveIncidentReasonFromSignal({
|
|
16759
|
+
event_type: "request_event",
|
|
16760
|
+
event_class: "incident_signal",
|
|
16761
|
+
request_anomaly: true
|
|
16762
|
+
}) : deriveIncidentReasonFromSourceEventTypes(candidate["source_event_types"]);
|
|
16675
16763
|
if (serviceRuntime !== null && typeof serviceRuntime !== "string") {
|
|
16676
16764
|
throw createReadError(400, "invalid_local_state");
|
|
16677
16765
|
}
|
|
@@ -18255,7 +18343,7 @@ function createWeeklyReportApi(client) {
|
|
|
18255
18343
|
);
|
|
18256
18344
|
},
|
|
18257
18345
|
async createWeeklyReportChannel(input) {
|
|
18258
|
-
const config = input.channel === "email" ? { to: input.config.to } : { webhook_url: input.config.webhookUrl };
|
|
18346
|
+
const config = input.channel === "email" ? { to: input.config.to } : "webhookUrl" in input.config ? { webhook_url: input.config.webhookUrl } : { slack_destination_id: input.config.slackDestinationId };
|
|
18259
18347
|
return expectChannel(
|
|
18260
18348
|
client.request({
|
|
18261
18349
|
method: "POST",
|
|
@@ -18278,7 +18366,7 @@ function createWeeklyReportApi(client) {
|
|
|
18278
18366
|
async updateWeeklyReportChannel(input) {
|
|
18279
18367
|
const body = {};
|
|
18280
18368
|
if (input.config !== void 0) {
|
|
18281
|
-
body["config"] = "to" in input.config ? { to: input.config.to } : { webhook_url: input.config.webhookUrl };
|
|
18369
|
+
body["config"] = "to" in input.config ? { to: input.config.to } : "webhookUrl" in input.config ? { webhook_url: input.config.webhookUrl } : { slack_destination_id: input.config.slackDestinationId };
|
|
18282
18370
|
}
|
|
18283
18371
|
if (input.schedule !== void 0) {
|
|
18284
18372
|
body["schedule"] = {
|
|
@@ -18747,6 +18835,121 @@ function createGitHubManagementApi(client) {
|
|
|
18747
18835
|
};
|
|
18748
18836
|
}
|
|
18749
18837
|
|
|
18838
|
+
// ../../packages/slack-client/src/index.ts
|
|
18839
|
+
var SlackDestinationRecordSchema = external_exports.object({
|
|
18840
|
+
slack_destination_id: external_exports.string(),
|
|
18841
|
+
organization_id: external_exports.string(),
|
|
18842
|
+
slack_team_id: external_exports.string(),
|
|
18843
|
+
slack_team_name: external_exports.string().nullable(),
|
|
18844
|
+
slack_channel_id: external_exports.string(),
|
|
18845
|
+
slack_channel_name: external_exports.string().nullable(),
|
|
18846
|
+
installed_by_member_id: external_exports.string().nullable(),
|
|
18847
|
+
is_active: external_exports.boolean(),
|
|
18848
|
+
created_at: external_exports.string(),
|
|
18849
|
+
updated_at: external_exports.string()
|
|
18850
|
+
}).strict();
|
|
18851
|
+
var SlackDestinationListResponseSchema = external_exports.object({
|
|
18852
|
+
destinations: external_exports.array(SlackDestinationRecordSchema)
|
|
18853
|
+
}).strict();
|
|
18854
|
+
var SlackInstallUrlResponseSchema = external_exports.object({
|
|
18855
|
+
install_url: external_exports.string().url()
|
|
18856
|
+
}).strict();
|
|
18857
|
+
var SlackDestinationTestResponseSchema = external_exports.object({
|
|
18858
|
+
delivered: external_exports.boolean()
|
|
18859
|
+
}).strict();
|
|
18860
|
+
var ApiErrorResponseSchema9 = external_exports.object({
|
|
18861
|
+
error: external_exports.string()
|
|
18862
|
+
}).strict();
|
|
18863
|
+
var SlackApiError = class extends Error {
|
|
18864
|
+
status;
|
|
18865
|
+
code;
|
|
18866
|
+
constructor(status, code) {
|
|
18867
|
+
super(`slack_api_error: ${status}:${code}`);
|
|
18868
|
+
this.status = status;
|
|
18869
|
+
this.code = code;
|
|
18870
|
+
}
|
|
18871
|
+
};
|
|
18872
|
+
function parseApiError9(status, body) {
|
|
18873
|
+
const parsed = ApiErrorResponseSchema9.safeParse(body);
|
|
18874
|
+
if (!parsed.success) {
|
|
18875
|
+
throw new SlackApiError(status, "unknown_error");
|
|
18876
|
+
}
|
|
18877
|
+
throw new SlackApiError(status, parsed.data.error);
|
|
18878
|
+
}
|
|
18879
|
+
function buildQuery4(input) {
|
|
18880
|
+
const params = new URLSearchParams();
|
|
18881
|
+
for (const [key, value] of Object.entries(input)) {
|
|
18882
|
+
if (value !== void 0) {
|
|
18883
|
+
params.set(key, String(value));
|
|
18884
|
+
}
|
|
18885
|
+
}
|
|
18886
|
+
const query = params.toString();
|
|
18887
|
+
return query.length === 0 ? "" : `?${query}`;
|
|
18888
|
+
}
|
|
18889
|
+
function createSlackApi(client) {
|
|
18890
|
+
return {
|
|
18891
|
+
async getSlackInstallUrl(input) {
|
|
18892
|
+
const response = await client.request({
|
|
18893
|
+
method: "GET",
|
|
18894
|
+
path: `/v1/slack/app/install-url${buildQuery4({
|
|
18895
|
+
project_id: input.projectId,
|
|
18896
|
+
return_to: input.returnTo
|
|
18897
|
+
})}`,
|
|
18898
|
+
bearerToken: input.bearerToken
|
|
18899
|
+
});
|
|
18900
|
+
if (response.status < 200 || response.status >= 300) {
|
|
18901
|
+
parseApiError9(response.status, response.body);
|
|
18902
|
+
}
|
|
18903
|
+
const parsed = SlackInstallUrlResponseSchema.safeParse(response.body);
|
|
18904
|
+
if (!parsed.success) {
|
|
18905
|
+
throw new SlackApiError(response.status, "invalid_response_shape");
|
|
18906
|
+
}
|
|
18907
|
+
return parsed.data.install_url;
|
|
18908
|
+
},
|
|
18909
|
+
async listSlackDestinations(input) {
|
|
18910
|
+
const response = await client.request({
|
|
18911
|
+
method: "GET",
|
|
18912
|
+
path: `/v1/projects/${input.projectId}/slack/destinations`,
|
|
18913
|
+
bearerToken: input.bearerToken
|
|
18914
|
+
});
|
|
18915
|
+
if (response.status < 200 || response.status >= 300) {
|
|
18916
|
+
parseApiError9(response.status, response.body);
|
|
18917
|
+
}
|
|
18918
|
+
const parsed = SlackDestinationListResponseSchema.safeParse(response.body);
|
|
18919
|
+
if (!parsed.success) {
|
|
18920
|
+
throw new SlackApiError(response.status, "invalid_response_shape");
|
|
18921
|
+
}
|
|
18922
|
+
return parsed.data.destinations;
|
|
18923
|
+
},
|
|
18924
|
+
async testSlackDestination(input) {
|
|
18925
|
+
const response = await client.request({
|
|
18926
|
+
method: "POST",
|
|
18927
|
+
path: `/v1/projects/${input.projectId}/slack/destinations/${input.destinationId}/test`,
|
|
18928
|
+
bearerToken: input.bearerToken
|
|
18929
|
+
});
|
|
18930
|
+
if (response.status < 200 || response.status >= 300) {
|
|
18931
|
+
parseApiError9(response.status, response.body);
|
|
18932
|
+
}
|
|
18933
|
+
const parsed = SlackDestinationTestResponseSchema.safeParse(response.body);
|
|
18934
|
+
if (!parsed.success || parsed.data.delivered !== true) {
|
|
18935
|
+
throw new SlackApiError(response.status, "invalid_response_shape");
|
|
18936
|
+
}
|
|
18937
|
+
return { delivered: true };
|
|
18938
|
+
},
|
|
18939
|
+
async deleteSlackDestination(input) {
|
|
18940
|
+
const response = await client.request({
|
|
18941
|
+
method: "DELETE",
|
|
18942
|
+
path: `/v1/projects/${input.projectId}/slack/destinations/${input.destinationId}`,
|
|
18943
|
+
bearerToken: input.bearerToken
|
|
18944
|
+
});
|
|
18945
|
+
if (response.status < 200 || response.status >= 300) {
|
|
18946
|
+
parseApiError9(response.status, response.body);
|
|
18947
|
+
}
|
|
18948
|
+
return { slack_destination_id: input.destinationId };
|
|
18949
|
+
}
|
|
18950
|
+
};
|
|
18951
|
+
}
|
|
18952
|
+
|
|
18750
18953
|
// src/auth-context.ts
|
|
18751
18954
|
function normalizeBaseUrl(baseUrl) {
|
|
18752
18955
|
return baseUrl.endsWith("/") ? baseUrl.slice(0, -1) : baseUrl;
|
|
@@ -18922,6 +19125,29 @@ async function createAuthenticatedWeeklyReportApi(input, dependencies) {
|
|
|
18922
19125
|
api: createApi(httpClient)
|
|
18923
19126
|
};
|
|
18924
19127
|
}
|
|
19128
|
+
async function createAuthenticatedSlackApi(input, dependencies) {
|
|
19129
|
+
const readAuthState = dependencies?.readAuthState ?? readCliAuthState;
|
|
19130
|
+
const authStateInput = {};
|
|
19131
|
+
if (input.authFilePath !== void 0) {
|
|
19132
|
+
authStateInput.authFilePath = input.authFilePath;
|
|
19133
|
+
}
|
|
19134
|
+
const authState = await readAuthState(authStateInput);
|
|
19135
|
+
const createHttpClient = dependencies?.createHttpClient ?? ((clientInput) => {
|
|
19136
|
+
const httpClientDependencies = {};
|
|
19137
|
+
if (dependencies?.fetchImpl !== void 0) {
|
|
19138
|
+
httpClientDependencies.fetchImpl = dependencies.fetchImpl;
|
|
19139
|
+
}
|
|
19140
|
+
return createCliHttpClient(clientInput, httpClientDependencies);
|
|
19141
|
+
});
|
|
19142
|
+
const httpClient = createHttpClient({
|
|
19143
|
+
baseUrl: authState.base_url
|
|
19144
|
+
});
|
|
19145
|
+
const createApi = dependencies?.createApi ?? createSlackApi;
|
|
19146
|
+
return {
|
|
19147
|
+
authState,
|
|
19148
|
+
api: createApi(httpClient)
|
|
19149
|
+
};
|
|
19150
|
+
}
|
|
18925
19151
|
async function createAuthenticatedProjectManagementApi(input, dependencies) {
|
|
18926
19152
|
const readAuthState = dependencies?.readAuthState ?? readCliAuthState;
|
|
18927
19153
|
const authStateInput = {};
|
|
@@ -19107,7 +19333,7 @@ var LoginCommandInputSchema = external_exports.object({
|
|
|
19107
19333
|
});
|
|
19108
19334
|
}
|
|
19109
19335
|
});
|
|
19110
|
-
var
|
|
19336
|
+
var ApiErrorResponseSchema10 = external_exports.object({
|
|
19111
19337
|
error: external_exports.string()
|
|
19112
19338
|
}).strict();
|
|
19113
19339
|
var DeviceStartResponseSchema = external_exports.object({
|
|
@@ -19283,7 +19509,7 @@ async function requestJson(input, dependencies) {
|
|
|
19283
19509
|
});
|
|
19284
19510
|
const body = await parseResponseBody2(response);
|
|
19285
19511
|
if (response.status < 200 || response.status >= 300) {
|
|
19286
|
-
const parsedError =
|
|
19512
|
+
const parsedError = ApiErrorResponseSchema10.safeParse(body);
|
|
19287
19513
|
throw new LoginApiError(response.status, parsedError.success ? parsedError.data.error : "unknown_error");
|
|
19288
19514
|
}
|
|
19289
19515
|
return body;
|
|
@@ -19966,7 +20192,7 @@ function buildPrivacyPreview() {
|
|
|
19966
20192
|
sample_event_type: sampleEvent.event_type,
|
|
19967
20193
|
sample_event_class: sampleEventClass,
|
|
19968
20194
|
sample_can_create_incident: sampleEventClass === "incident_signal",
|
|
19969
|
-
incident_rule: "request_event
|
|
20195
|
+
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.",
|
|
19970
20196
|
redacted_fields,
|
|
19971
20197
|
omitted_fields: [],
|
|
19972
20198
|
retained_metadata: {
|
|
@@ -21668,11 +21894,17 @@ var EVENT_TYPE_SET = new Set(EventTypeValues);
|
|
|
21668
21894
|
function isEventType(value) {
|
|
21669
21895
|
return typeof value === "string" && EVENT_TYPE_SET.has(value);
|
|
21670
21896
|
}
|
|
21671
|
-
function inferSeverity2(
|
|
21672
|
-
if (
|
|
21897
|
+
function inferSeverity2(event, capturePreset, incidentKind = "immediate") {
|
|
21898
|
+
if (incidentKind === "request_anomaly") {
|
|
21899
|
+
return "medium";
|
|
21900
|
+
}
|
|
21901
|
+
if (event.event_type === "request_event") {
|
|
21902
|
+
return classifyRequestStatus({ responseStatus: event.payload.response_status, capturePreset }) === "incident_signal" ? "high" : "low";
|
|
21903
|
+
}
|
|
21904
|
+
if (event.event_type === "backend_exception" || event.event_type === "frontend_exception") {
|
|
21673
21905
|
return "high";
|
|
21674
21906
|
}
|
|
21675
|
-
if (
|
|
21907
|
+
if (event.event_type === "error_suppressed") {
|
|
21676
21908
|
return "medium";
|
|
21677
21909
|
}
|
|
21678
21910
|
return "low";
|
|
@@ -21696,15 +21928,17 @@ function compareEventEnvelopes(left, right) {
|
|
|
21696
21928
|
}
|
|
21697
21929
|
return left.event_id.localeCompare(right.event_id);
|
|
21698
21930
|
}
|
|
21699
|
-
function classifyEnvelope(envelope) {
|
|
21931
|
+
function classifyEnvelope(envelope, capturePreset) {
|
|
21700
21932
|
return classifyEvent(
|
|
21701
21933
|
envelope.event_type,
|
|
21702
21934
|
envelope.event_type === "log_event" ? envelope.payload.level : void 0,
|
|
21703
|
-
envelope.event_type === "probe_event" ? envelope.payload.activation_id : void 0
|
|
21935
|
+
envelope.event_type === "probe_event" ? envelope.payload.activation_id : void 0,
|
|
21936
|
+
envelope.payload,
|
|
21937
|
+
capturePreset
|
|
21704
21938
|
);
|
|
21705
21939
|
}
|
|
21706
|
-
function isIncidentSignalEnvelope(envelope) {
|
|
21707
|
-
return classifyEnvelope(envelope) === "incident_signal";
|
|
21940
|
+
function isIncidentSignalEnvelope(envelope, capturePreset) {
|
|
21941
|
+
return classifyEnvelope(envelope, capturePreset) === "incident_signal";
|
|
21708
21942
|
}
|
|
21709
21943
|
function getTraceId(envelope) {
|
|
21710
21944
|
return envelope.correlation?.trace_id ?? null;
|
|
@@ -21749,7 +21983,10 @@ function mergeAggregateGroup(aggregates) {
|
|
|
21749
21983
|
newEvents: [...canonicalAggregate.newEvents],
|
|
21750
21984
|
mergedIncidentIds: new Set(canonicalAggregate.mergedIncidentIds),
|
|
21751
21985
|
signalEventTypes: new Set(canonicalAggregate.signalEventTypes),
|
|
21752
|
-
traceIds: new Set(canonicalAggregate.traceIds)
|
|
21986
|
+
traceIds: new Set(canonicalAggregate.traceIds),
|
|
21987
|
+
title: canonicalAggregate.title,
|
|
21988
|
+
kind: canonicalAggregate.kind,
|
|
21989
|
+
severity: canonicalAggregate.severity
|
|
21753
21990
|
});
|
|
21754
21991
|
}
|
|
21755
21992
|
function hashIdentifier(parts, prefix, length) {
|
|
@@ -21775,6 +22012,111 @@ function mergeSourceEvents(existingEvents, nextEvents) {
|
|
|
21775
22012
|
}
|
|
21776
22013
|
return [...merged.values()].sort(compareEventEnvelopes);
|
|
21777
22014
|
}
|
|
22015
|
+
function stableJson2(value) {
|
|
22016
|
+
if (value === null || typeof value !== "object") {
|
|
22017
|
+
return JSON.stringify(value);
|
|
22018
|
+
}
|
|
22019
|
+
if (Array.isArray(value)) {
|
|
22020
|
+
return `[${value.map((entry) => stableJson2(entry)).join(",")}]`;
|
|
22021
|
+
}
|
|
22022
|
+
const record = value;
|
|
22023
|
+
const keys = Object.keys(record).sort();
|
|
22024
|
+
return `{${keys.map((key) => `${JSON.stringify(key)}:${stableJson2(record[key])}`).join(",")}}`;
|
|
22025
|
+
}
|
|
22026
|
+
function buildRequestAnomalyFingerprint(input) {
|
|
22027
|
+
return (0, import_node_crypto4.createHash)("sha256").update(
|
|
22028
|
+
stableJson2({
|
|
22029
|
+
kind: "request_status_anomaly",
|
|
22030
|
+
project_id: input.projectId,
|
|
22031
|
+
service_name: input.serviceName,
|
|
22032
|
+
environment: input.environment,
|
|
22033
|
+
method: input.method,
|
|
22034
|
+
route_template: input.routeTemplate,
|
|
22035
|
+
response_status: input.responseStatus
|
|
22036
|
+
})
|
|
22037
|
+
).digest("hex");
|
|
22038
|
+
}
|
|
22039
|
+
function buildRequestAnomalyTitle(input) {
|
|
22040
|
+
return `Request anomaly: ${input.method} ${input.routeTemplate} returned ${input.responseStatus} repeatedly`;
|
|
22041
|
+
}
|
|
22042
|
+
function toUnixSeconds(occurredAt) {
|
|
22043
|
+
return Math.floor(new Date(occurredAt).getTime() / 1e3);
|
|
22044
|
+
}
|
|
22045
|
+
function countOccurrencesInWindow(events, windowSeconds) {
|
|
22046
|
+
const latestEvent = events.at(-1);
|
|
22047
|
+
if (latestEvent === void 0) {
|
|
22048
|
+
return 0;
|
|
22049
|
+
}
|
|
22050
|
+
const latestOccurredAt = toUnixSeconds(latestEvent.occurred_at);
|
|
22051
|
+
const lowerBound = latestOccurredAt - windowSeconds + 1;
|
|
22052
|
+
return events.filter((event) => {
|
|
22053
|
+
const occurredAt = toUnixSeconds(event.occurred_at);
|
|
22054
|
+
return occurredAt >= lowerBound && occurredAt <= latestOccurredAt;
|
|
22055
|
+
}).length;
|
|
22056
|
+
}
|
|
22057
|
+
function passesRequestAnomalyThreshold(events, threshold) {
|
|
22058
|
+
const occurrences5m = countOccurrencesInWindow(events, 5 * 60);
|
|
22059
|
+
const occurrences1h = countOccurrencesInWindow(events, 60 * 60);
|
|
22060
|
+
const baseline1hPer5m = occurrences1h / 12;
|
|
22061
|
+
const ratio = occurrences5m / Math.max(baseline1hPer5m, 1);
|
|
22062
|
+
return occurrences5m >= threshold.minimum_occurrences_5m && ratio >= threshold.minimum_ratio_5m_to_1h;
|
|
22063
|
+
}
|
|
22064
|
+
function collectRequestAnomalyAggregates(batches, capturePreset) {
|
|
22065
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
22066
|
+
for (const batch of batches) {
|
|
22067
|
+
for (const event of batch.events) {
|
|
22068
|
+
if (event.event_type !== "request_event" || classifyEnvelope(event, capturePreset) !== "context_signal") {
|
|
22069
|
+
continue;
|
|
22070
|
+
}
|
|
22071
|
+
const normalizedEvent = normalizeEvent(event);
|
|
22072
|
+
const responseStatus = normalizedEvent.http_status;
|
|
22073
|
+
const method = normalizedEvent.http_method;
|
|
22074
|
+
const routeTemplate = normalizedEvent.route_template;
|
|
22075
|
+
const threshold = getRequestAnomalyThreshold({ responseStatus, capturePreset });
|
|
22076
|
+
if (threshold === null || responseStatus === null || method === null || routeTemplate === null) {
|
|
22077
|
+
continue;
|
|
22078
|
+
}
|
|
22079
|
+
const projectId = requireProjectId(event);
|
|
22080
|
+
const incidentFingerprint = buildRequestAnomalyFingerprint({
|
|
22081
|
+
projectId,
|
|
22082
|
+
serviceName: event.service.name,
|
|
22083
|
+
environment: event.service.environment,
|
|
22084
|
+
method,
|
|
22085
|
+
routeTemplate,
|
|
22086
|
+
responseStatus
|
|
22087
|
+
});
|
|
22088
|
+
const incidentId = deriveIncidentId(projectId, event.service.name, event.service.environment, incidentFingerprint);
|
|
22089
|
+
const aggregate = grouped.get(incidentId) ?? {
|
|
22090
|
+
incidentId,
|
|
22091
|
+
projectId,
|
|
22092
|
+
serviceName: event.service.name,
|
|
22093
|
+
environment: event.service.environment,
|
|
22094
|
+
fingerprint: incidentFingerprint,
|
|
22095
|
+
matchedFields: /* @__PURE__ */ new Set(["request_anomaly", "route_template", "http_method", "http_status", "environment"]),
|
|
22096
|
+
newEvents: [],
|
|
22097
|
+
mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
|
|
22098
|
+
signalEventTypes: /* @__PURE__ */ new Set(["request_event"]),
|
|
22099
|
+
traceIds: /* @__PURE__ */ new Set(),
|
|
22100
|
+
title: buildRequestAnomalyTitle({ method, routeTemplate, responseStatus }),
|
|
22101
|
+
kind: "request_anomaly",
|
|
22102
|
+
severity: "medium"
|
|
22103
|
+
};
|
|
22104
|
+
aggregate.newEvents.push(event);
|
|
22105
|
+
grouped.set(incidentId, aggregate);
|
|
22106
|
+
}
|
|
22107
|
+
}
|
|
22108
|
+
return [...grouped.values()].filter((aggregate) => {
|
|
22109
|
+
const latestEvent = aggregate.newEvents.at(-1);
|
|
22110
|
+
if (latestEvent === void 0 || latestEvent.event_type !== "request_event") {
|
|
22111
|
+
return false;
|
|
22112
|
+
}
|
|
22113
|
+
const threshold = getRequestAnomalyThreshold({
|
|
22114
|
+
responseStatus: normalizeEvent(latestEvent).http_status,
|
|
22115
|
+
capturePreset
|
|
22116
|
+
});
|
|
22117
|
+
return threshold !== null && passesRequestAnomalyThreshold(aggregate.newEvents, threshold);
|
|
22118
|
+
}).sort((left, right) => left.incidentId.localeCompare(right.incidentId));
|
|
22119
|
+
}
|
|
21778
22120
|
function buildBundleContext(incident) {
|
|
21779
22121
|
return {
|
|
21780
22122
|
incident_id: incident.incident_id,
|
|
@@ -21804,12 +22146,12 @@ function formatServiceSummary(services) {
|
|
|
21804
22146
|
}
|
|
21805
22147
|
function formatProcessOutput(summary) {
|
|
21806
22148
|
if (!summary.processed) {
|
|
21807
|
-
return summary.message
|
|
22149
|
+
return summary.message;
|
|
21808
22150
|
}
|
|
21809
22151
|
return [
|
|
21810
22152
|
`Processed ${summary.events_processed} events from ${summary.files_processed} files into ${summary.incidents_processed} incidents.`,
|
|
21811
22153
|
...formatServiceSummary(summary.services),
|
|
21812
|
-
`Last processed event file: ${summary.last_processed_event_file
|
|
22154
|
+
`Last processed event file: ${summary.last_processed_event_file}`
|
|
21813
22155
|
].join("\n");
|
|
21814
22156
|
}
|
|
21815
22157
|
async function pathExists4(path, stat) {
|
|
@@ -22049,6 +22391,7 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22049
22391
|
const statePath = (0, import_node_path11.join)(rootDirectory, LOCAL_STATE_FILE_PATH);
|
|
22050
22392
|
const bundleDirectoryPath = (0, import_node_path11.join)(rootDirectory, LOCAL_BUNDLE_DIRECTORY_PATH3);
|
|
22051
22393
|
const reproductionDirectoryPath = (0, import_node_path11.join)(rootDirectory, LOCAL_REPRODUCTION_DIRECTORY_PATH2);
|
|
22394
|
+
const capturePreset = input.preset ?? "minimal";
|
|
22052
22395
|
await mkdir((0, import_node_path11.join)(rootDirectory, ".debugbundle", "local"), { recursive: true });
|
|
22053
22396
|
await mkdir(bundleDirectoryPath, { recursive: true });
|
|
22054
22397
|
await mkdir(reproductionDirectoryPath, { recursive: true });
|
|
@@ -22056,22 +22399,26 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22056
22399
|
const eventFileNames = await pathExists4(eventsDirectoryPath, stat) ? (await readdir(eventsDirectoryPath)).filter((fileName) => fileName.endsWith(".events.json")).sort() : [];
|
|
22057
22400
|
const lastProcessedEventFile = previousState?.last_processed_event_file ?? null;
|
|
22058
22401
|
const newEventFileNames = lastProcessedEventFile === null ? eventFileNames : eventFileNames.filter((fileName) => fileName > lastProcessedEventFile);
|
|
22059
|
-
|
|
22402
|
+
const processAllEventFiles = input.preset !== void 0;
|
|
22403
|
+
const targetEventFileNames = processAllEventFiles ? eventFileNames : newEventFileNames;
|
|
22404
|
+
if (targetEventFileNames.length === 0) {
|
|
22060
22405
|
const summary2 = buildNoNewEventsSummary(previousState?.last_processed_event_file ?? eventFileNames.at(-1) ?? null);
|
|
22061
22406
|
return {
|
|
22062
22407
|
exitCode: 0,
|
|
22063
22408
|
output: input.json === true ? JSON.stringify(summary2) : formatProcessOutput(summary2)
|
|
22064
22409
|
};
|
|
22065
22410
|
}
|
|
22066
|
-
const batches = await readEventBatches(eventsDirectoryPath,
|
|
22067
|
-
const incidents = new Map(
|
|
22411
|
+
const batches = await readEventBatches(eventsDirectoryPath, targetEventFileNames, readFile);
|
|
22412
|
+
const incidents = new Map(
|
|
22413
|
+
processAllEventFiles ? [] : Object.entries(previousState?.incidents ?? {})
|
|
22414
|
+
);
|
|
22068
22415
|
const aggregates = /* @__PURE__ */ new Map();
|
|
22069
22416
|
const traceCorrelationGroups = /* @__PURE__ */ new Map();
|
|
22070
22417
|
let eventsProcessed = 0;
|
|
22071
22418
|
for (const batch of batches) {
|
|
22072
22419
|
for (const event of batch.events) {
|
|
22073
22420
|
eventsProcessed += 1;
|
|
22074
|
-
if (!isIncidentSignalEnvelope(event)) {
|
|
22421
|
+
if (!isIncidentSignalEnvelope(event, capturePreset)) {
|
|
22075
22422
|
continue;
|
|
22076
22423
|
}
|
|
22077
22424
|
const normalizedEvent = normalizeEvent(event);
|
|
@@ -22088,7 +22435,10 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22088
22435
|
newEvents: [],
|
|
22089
22436
|
mergedIncidentIds: /* @__PURE__ */ new Set([incidentId]),
|
|
22090
22437
|
signalEventTypes: /* @__PURE__ */ new Set(),
|
|
22091
|
-
traceIds: /* @__PURE__ */ new Set()
|
|
22438
|
+
traceIds: /* @__PURE__ */ new Set(),
|
|
22439
|
+
title: normalizedEvent.normalized_message,
|
|
22440
|
+
kind: "immediate",
|
|
22441
|
+
severity: inferSeverity2(event, capturePreset)
|
|
22092
22442
|
};
|
|
22093
22443
|
for (const matchedField of inferMatchedFields(normalizedEvent)) {
|
|
22094
22444
|
aggregate.matchedFields.add(matchedField);
|
|
@@ -22155,14 +22505,16 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22155
22505
|
mergedAggregatesByRoot.set(rootIncidentId, aggregateGroup);
|
|
22156
22506
|
}
|
|
22157
22507
|
const mergedAggregates = [...mergedAggregatesByRoot.values()].map((aggregateGroup) => mergeAggregateGroup(aggregateGroup)).sort((left, right) => left.incidentId.localeCompare(right.incidentId));
|
|
22508
|
+
const requestAnomalyAggregates = input.preset === void 0 ? [] : collectRequestAnomalyAggregates(batches, capturePreset);
|
|
22509
|
+
const finalizedAggregates = [...mergedAggregates, ...requestAnomalyAggregates].sort((left, right) => left.incidentId.localeCompare(right.incidentId));
|
|
22158
22510
|
const services = /* @__PURE__ */ new Map();
|
|
22159
|
-
for (const aggregate of
|
|
22511
|
+
for (const aggregate of finalizedAggregates) {
|
|
22160
22512
|
const incidentId = aggregate.incidentId;
|
|
22161
22513
|
const existingIncidents = [...aggregate.mergedIncidentIds].map((mergedIncidentId) => incidents.get(mergedIncidentId)).filter((incident2) => incident2 !== void 0);
|
|
22162
22514
|
const existing = existingIncidents.find((incident2) => incident2.incident_id === incidentId) ?? existingIncidents[0];
|
|
22163
22515
|
const existingSourceEvents = existingIncidents.flatMap((incident2) => incident2.source_events);
|
|
22164
22516
|
const combinedSourceEvents = mergeSourceEvents(existingSourceEvents, aggregate.newEvents);
|
|
22165
|
-
const signalEvents = combinedSourceEvents.filter(isIncidentSignalEnvelope);
|
|
22517
|
+
const signalEvents = aggregate.kind === "request_anomaly" ? combinedSourceEvents : combinedSourceEvents.filter((event) => isIncidentSignalEnvelope(event, capturePreset));
|
|
22166
22518
|
if (signalEvents.length === 0) {
|
|
22167
22519
|
continue;
|
|
22168
22520
|
}
|
|
@@ -22172,8 +22524,7 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22172
22524
|
continue;
|
|
22173
22525
|
}
|
|
22174
22526
|
const sourceEventTypes = [...new Set(signalEvents.map((event) => event.event_type))].sort();
|
|
22175
|
-
const severity = signalEvents.map((event) => inferSeverity2(event.
|
|
22176
|
-
const latestNormalizedEvent = normalizeEvent(latestSignalEvent);
|
|
22527
|
+
const severity = signalEvents.map((event) => inferSeverity2(event, capturePreset, aggregate.kind)).sort((left, right) => severityRank(right) - severityRank(left))[0] ?? aggregate.severity;
|
|
22177
22528
|
const generationNumber = signalEvents.length;
|
|
22178
22529
|
const bundlePath = `${LOCAL_BUNDLE_DIRECTORY_PATH3}/${incidentId}.bundle.json`;
|
|
22179
22530
|
const reproductionPath = `${LOCAL_REPRODUCTION_DIRECTORY_PATH2}/${incidentId}.reproduction.json`;
|
|
@@ -22188,7 +22539,7 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22188
22539
|
environment: aggregate.environment,
|
|
22189
22540
|
fingerprint: aggregate.fingerprint,
|
|
22190
22541
|
fingerprint_version: FINGERPRINT_VERSION,
|
|
22191
|
-
title:
|
|
22542
|
+
title: aggregate.title,
|
|
22192
22543
|
severity,
|
|
22193
22544
|
status: existingIncidents.some((incidentState) => incidentState.status === "resolved") ? "open" : existing?.status ?? "open",
|
|
22194
22545
|
first_seen_at: firstSignalEvent.occurred_at,
|
|
@@ -22249,21 +22600,22 @@ async function processCommand(input, dependencies = {}) {
|
|
|
22249
22600
|
incidents.set(incidentId, incident);
|
|
22250
22601
|
services.set(incident.service_name, (services.get(incident.service_name) ?? 0) + 1);
|
|
22251
22602
|
}
|
|
22603
|
+
const finalProcessedEventFile = targetEventFileNames[targetEventFileNames.length - 1];
|
|
22252
22604
|
const nextState = {
|
|
22253
22605
|
version: 1,
|
|
22254
|
-
last_processed_event_file:
|
|
22606
|
+
last_processed_event_file: finalProcessedEventFile,
|
|
22255
22607
|
incidents: Object.fromEntries([...incidents.entries()].sort(([left], [right]) => left.localeCompare(right)))
|
|
22256
22608
|
};
|
|
22257
22609
|
await writeFile(statePath, serializeState(nextState));
|
|
22258
22610
|
const summary = buildProcessedSummary({
|
|
22259
22611
|
filesProcessed: newEventFileNames.length,
|
|
22260
22612
|
eventsProcessed,
|
|
22261
|
-
incidentsProcessed:
|
|
22613
|
+
incidentsProcessed: finalizedAggregates.length,
|
|
22262
22614
|
services: [...services.entries()].sort(([left], [right]) => left.localeCompare(right)).map(([service, count]) => ({
|
|
22263
22615
|
service,
|
|
22264
22616
|
incidents: count
|
|
22265
22617
|
})),
|
|
22266
|
-
lastProcessedEventFile:
|
|
22618
|
+
lastProcessedEventFile: finalProcessedEventFile
|
|
22267
22619
|
});
|
|
22268
22620
|
return {
|
|
22269
22621
|
exitCode: 0,
|
|
@@ -24248,14 +24600,14 @@ function localFailureStepName(checks) {
|
|
|
24248
24600
|
function cloudVerificationRunId(now) {
|
|
24249
24601
|
return now.toISOString().replace(/[-:.TZ]/g, "").slice(0, 14);
|
|
24250
24602
|
}
|
|
24251
|
-
function
|
|
24603
|
+
function requestFailureReason() {
|
|
24252
24604
|
const incidentReason = deriveIncidentReasonFromSignal({
|
|
24253
24605
|
event_type: "request_event",
|
|
24254
24606
|
event_class: "incident_signal",
|
|
24255
24607
|
response_status: 503
|
|
24256
24608
|
});
|
|
24257
24609
|
if (incidentReason === null) {
|
|
24258
|
-
throw new Error("
|
|
24610
|
+
throw new Error("request_failure_reason_unavailable");
|
|
24259
24611
|
}
|
|
24260
24612
|
return incidentReason;
|
|
24261
24613
|
}
|
|
@@ -24530,7 +24882,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
|
|
|
24530
24882
|
const verification = {
|
|
24531
24883
|
mode: "active_5xx",
|
|
24532
24884
|
bundle_status: "unknown",
|
|
24533
|
-
classification_reason:
|
|
24885
|
+
classification_reason: requestFailureReason()
|
|
24534
24886
|
};
|
|
24535
24887
|
const errors = [];
|
|
24536
24888
|
let exitCode = 0;
|
|
@@ -24582,7 +24934,7 @@ async function verifyCloudCommand(input, dependencies = {}) {
|
|
|
24582
24934
|
if (candidate !== void 0) {
|
|
24583
24935
|
incidentId = candidate.incident_id;
|
|
24584
24936
|
verification.incident_id = candidate.incident_id;
|
|
24585
|
-
verification.classification_reason = candidate.incident_reason ??
|
|
24937
|
+
verification.classification_reason = candidate.incident_reason ?? requestFailureReason();
|
|
24586
24938
|
break;
|
|
24587
24939
|
}
|
|
24588
24940
|
if (attempt < pollAttempts) {
|
|
@@ -24857,7 +25209,7 @@ var CLI_USAGE_LINES = [
|
|
|
24857
25209
|
" debugbundle connect [--auth-file <path>] [--json]",
|
|
24858
25210
|
" debugbundle ingest <file> --format <debugbundle-ndjson|php-error|apache-error> [--json]",
|
|
24859
25211
|
" debugbundle watch [--cloud] --log <file> --format <debugbundle-ndjson|php-error|apache-error> [--json]",
|
|
24860
|
-
" debugbundle process [--json]",
|
|
25212
|
+
" debugbundle process [--preset <minimal|balanced|investigative>] [--json]",
|
|
24861
25213
|
" debugbundle clean [--events] [--bundles] [--all] [--older-than <Nd>] [--json]",
|
|
24862
25214
|
" debugbundle validate [--fix] [--json]",
|
|
24863
25215
|
" debugbundle verify local [--json]",
|
|
@@ -24907,6 +25259,10 @@ var CLI_USAGE_LINES = [
|
|
|
24907
25259
|
" 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]",
|
|
24908
25260
|
" 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]",
|
|
24909
25261
|
" debugbundle alert delete <alert-id> [--auth-file <path>] [--json]",
|
|
25262
|
+
" debugbundle slack list --project-id <id> [--auth-file <path>] [--json]",
|
|
25263
|
+
" debugbundle slack connect-url --project-id <id> [--return-to </projects/...>] [--auth-file <path>] [--json]",
|
|
25264
|
+
" debugbundle slack test <destination-id> --project-id <id> [--auth-file <path>] [--json]",
|
|
25265
|
+
" debugbundle slack delete <destination-id> --project-id <id> [--auth-file <path>] [--json]",
|
|
24910
25266
|
" debugbundle webhook list --project-id <id> [--limit <n>] [--auth-file <path>] [--json]",
|
|
24911
25267
|
" debugbundle webhook create --project-id <id> --url <url> --event <event[,event]> [--environment <env[,env]>] [--service <svc[,svc]>] [--severity-min <level>] [--bundle-type <type[,type]>] [--verification <true|false>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
|
|
24912
25268
|
" debugbundle webhook update <webhook-id> [--url <url>] [--event <event[,event]>] [--environment <env[,env]>] [--service <svc[,svc]>] [--severity-min <level>] [--bundle-type <type[,type]>] [--verification <true|false>] [--is-enabled <true|false>] [--auth-file <path>] [--json]",
|
|
@@ -26684,8 +27040,153 @@ async function deleteWeeklyReportChannelWithAuthCommand(input, dependencies) {
|
|
|
26684
27040
|
});
|
|
26685
27041
|
}
|
|
26686
27042
|
|
|
26687
|
-
// src/
|
|
27043
|
+
// src/slack-commands.ts
|
|
26688
27044
|
function mapErrorToExitCode10(error) {
|
|
27045
|
+
if (!(error instanceof SlackApiError)) {
|
|
27046
|
+
return 1;
|
|
27047
|
+
}
|
|
27048
|
+
if (error.status === 401) {
|
|
27049
|
+
return 2;
|
|
27050
|
+
}
|
|
27051
|
+
if (error.status === 404) {
|
|
27052
|
+
return 3;
|
|
27053
|
+
}
|
|
27054
|
+
if (error.status === 400 || error.status === 403) {
|
|
27055
|
+
return 4;
|
|
27056
|
+
}
|
|
27057
|
+
return 1;
|
|
27058
|
+
}
|
|
27059
|
+
function formatSlackDestinationTable(destinations) {
|
|
27060
|
+
if (destinations.length === 0) {
|
|
27061
|
+
return "No Slack destinations found.";
|
|
27062
|
+
}
|
|
27063
|
+
return destinations.map((destination) => {
|
|
27064
|
+
const workspace = destination.slack_team_name ?? destination.slack_team_id;
|
|
27065
|
+
const channel = destination.slack_channel_name ?? destination.slack_channel_id;
|
|
27066
|
+
return `${destination.slack_destination_id} | ${destination.is_active ? "active" : "inactive"} | ${workspace} | ${channel}`;
|
|
27067
|
+
}).join("\n");
|
|
27068
|
+
}
|
|
27069
|
+
async function listSlackDestinationsCommand(input, api) {
|
|
27070
|
+
try {
|
|
27071
|
+
const destinations = await api.listSlackDestinations({
|
|
27072
|
+
bearerToken: input.bearerToken,
|
|
27073
|
+
projectId: input.projectId
|
|
27074
|
+
});
|
|
27075
|
+
return {
|
|
27076
|
+
exitCode: 0,
|
|
27077
|
+
output: input.json ? JSON.stringify({ destinations }) : formatSlackDestinationTable(destinations)
|
|
27078
|
+
};
|
|
27079
|
+
} catch (error) {
|
|
27080
|
+
return { exitCode: mapErrorToExitCode10(error), output: error instanceof Error ? error.message : String(error) };
|
|
27081
|
+
}
|
|
27082
|
+
}
|
|
27083
|
+
async function listSlackDestinationsWithAuthCommand(input, dependencies) {
|
|
27084
|
+
return runAuthenticatedCliCommand(input, {
|
|
27085
|
+
createApi: createAuthenticatedSlackApi,
|
|
27086
|
+
dependencies,
|
|
27087
|
+
runCommand: (authState, api) => listSlackDestinationsCommand(
|
|
27088
|
+
{
|
|
27089
|
+
bearerToken: authState.bearer_token,
|
|
27090
|
+
projectId: input.projectId,
|
|
27091
|
+
...input.json !== void 0 ? { json: input.json } : {}
|
|
27092
|
+
},
|
|
27093
|
+
api
|
|
27094
|
+
)
|
|
27095
|
+
});
|
|
27096
|
+
}
|
|
27097
|
+
async function getSlackConnectUrlCommand(input, api) {
|
|
27098
|
+
try {
|
|
27099
|
+
const installUrl = await api.getSlackInstallUrl({
|
|
27100
|
+
bearerToken: input.bearerToken,
|
|
27101
|
+
projectId: input.projectId,
|
|
27102
|
+
...input.returnTo !== void 0 ? { returnTo: input.returnTo } : {}
|
|
27103
|
+
});
|
|
27104
|
+
return {
|
|
27105
|
+
exitCode: 0,
|
|
27106
|
+
output: input.json ? JSON.stringify({ install_url: installUrl }) : installUrl
|
|
27107
|
+
};
|
|
27108
|
+
} catch (error) {
|
|
27109
|
+
return { exitCode: mapErrorToExitCode10(error), output: error instanceof Error ? error.message : String(error) };
|
|
27110
|
+
}
|
|
27111
|
+
}
|
|
27112
|
+
async function getSlackConnectUrlWithAuthCommand(input, dependencies) {
|
|
27113
|
+
return runAuthenticatedCliCommand(input, {
|
|
27114
|
+
createApi: createAuthenticatedSlackApi,
|
|
27115
|
+
dependencies,
|
|
27116
|
+
runCommand: (authState, api) => getSlackConnectUrlCommand(
|
|
27117
|
+
{
|
|
27118
|
+
bearerToken: authState.bearer_token,
|
|
27119
|
+
projectId: input.projectId,
|
|
27120
|
+
...input.returnTo !== void 0 ? { returnTo: input.returnTo } : {},
|
|
27121
|
+
...input.json !== void 0 ? { json: input.json } : {}
|
|
27122
|
+
},
|
|
27123
|
+
api
|
|
27124
|
+
)
|
|
27125
|
+
});
|
|
27126
|
+
}
|
|
27127
|
+
async function testSlackDestinationCommand(input, api) {
|
|
27128
|
+
try {
|
|
27129
|
+
const delivery = await api.testSlackDestination({
|
|
27130
|
+
bearerToken: input.bearerToken,
|
|
27131
|
+
projectId: input.projectId,
|
|
27132
|
+
destinationId: input.destinationId
|
|
27133
|
+
});
|
|
27134
|
+
return {
|
|
27135
|
+
exitCode: 0,
|
|
27136
|
+
output: input.json ? JSON.stringify({ delivery }) : `Slack test message delivered for destination: ${input.destinationId}`
|
|
27137
|
+
};
|
|
27138
|
+
} catch (error) {
|
|
27139
|
+
return { exitCode: mapErrorToExitCode10(error), output: error instanceof Error ? error.message : String(error) };
|
|
27140
|
+
}
|
|
27141
|
+
}
|
|
27142
|
+
async function testSlackDestinationWithAuthCommand(input, dependencies) {
|
|
27143
|
+
return runAuthenticatedCliCommand(input, {
|
|
27144
|
+
createApi: createAuthenticatedSlackApi,
|
|
27145
|
+
dependencies,
|
|
27146
|
+
runCommand: (authState, api) => testSlackDestinationCommand(
|
|
27147
|
+
{
|
|
27148
|
+
bearerToken: authState.bearer_token,
|
|
27149
|
+
projectId: input.projectId,
|
|
27150
|
+
destinationId: input.destinationId,
|
|
27151
|
+
...input.json !== void 0 ? { json: input.json } : {}
|
|
27152
|
+
},
|
|
27153
|
+
api
|
|
27154
|
+
)
|
|
27155
|
+
});
|
|
27156
|
+
}
|
|
27157
|
+
async function deleteSlackDestinationCommand(input, api) {
|
|
27158
|
+
try {
|
|
27159
|
+
const deleted = await api.deleteSlackDestination({
|
|
27160
|
+
bearerToken: input.bearerToken,
|
|
27161
|
+
projectId: input.projectId,
|
|
27162
|
+
destinationId: input.destinationId
|
|
27163
|
+
});
|
|
27164
|
+
return {
|
|
27165
|
+
exitCode: 0,
|
|
27166
|
+
output: input.json ? JSON.stringify({ destination: deleted }) : `Slack destination deleted: ${deleted.slack_destination_id}`
|
|
27167
|
+
};
|
|
27168
|
+
} catch (error) {
|
|
27169
|
+
return { exitCode: mapErrorToExitCode10(error), output: error instanceof Error ? error.message : String(error) };
|
|
27170
|
+
}
|
|
27171
|
+
}
|
|
27172
|
+
async function deleteSlackDestinationWithAuthCommand(input, dependencies) {
|
|
27173
|
+
return runAuthenticatedCliCommand(input, {
|
|
27174
|
+
createApi: createAuthenticatedSlackApi,
|
|
27175
|
+
dependencies,
|
|
27176
|
+
runCommand: (authState, api) => deleteSlackDestinationCommand(
|
|
27177
|
+
{
|
|
27178
|
+
bearerToken: authState.bearer_token,
|
|
27179
|
+
projectId: input.projectId,
|
|
27180
|
+
destinationId: input.destinationId,
|
|
27181
|
+
...input.json !== void 0 ? { json: input.json } : {}
|
|
27182
|
+
},
|
|
27183
|
+
api
|
|
27184
|
+
)
|
|
27185
|
+
});
|
|
27186
|
+
}
|
|
27187
|
+
|
|
27188
|
+
// src/billing-commands.ts
|
|
27189
|
+
function mapErrorToExitCode11(error) {
|
|
26689
27190
|
if (!(error instanceof BillingApiError)) {
|
|
26690
27191
|
return 1;
|
|
26691
27192
|
}
|
|
@@ -26733,7 +27234,7 @@ async function getBillingSummaryCommand(input, api) {
|
|
|
26733
27234
|
output: input.json ? JSON.stringify({ billing }) : formatBillingSummary(billing)
|
|
26734
27235
|
};
|
|
26735
27236
|
} catch (error) {
|
|
26736
|
-
return { exitCode:
|
|
27237
|
+
return { exitCode: mapErrorToExitCode11(error), output: error instanceof Error ? error.message : String(error) };
|
|
26737
27238
|
}
|
|
26738
27239
|
}
|
|
26739
27240
|
async function increaseBillingCapacityCommand(input, api) {
|
|
@@ -26748,7 +27249,7 @@ async function increaseBillingCapacityCommand(input, api) {
|
|
|
26748
27249
|
${formatBillingSummary(billing)}`
|
|
26749
27250
|
};
|
|
26750
27251
|
} catch (error) {
|
|
26751
|
-
return { exitCode:
|
|
27252
|
+
return { exitCode: mapErrorToExitCode11(error), output: error instanceof Error ? error.message : String(error) };
|
|
26752
27253
|
}
|
|
26753
27254
|
}
|
|
26754
27255
|
async function scheduleBillingCapacityReductionCommand(input, api) {
|
|
@@ -26763,7 +27264,7 @@ async function scheduleBillingCapacityReductionCommand(input, api) {
|
|
|
26763
27264
|
${formatBillingSummary(billing)}`
|
|
26764
27265
|
};
|
|
26765
27266
|
} catch (error) {
|
|
26766
|
-
return { exitCode:
|
|
27267
|
+
return { exitCode: mapErrorToExitCode11(error), output: error instanceof Error ? error.message : String(error) };
|
|
26767
27268
|
}
|
|
26768
27269
|
}
|
|
26769
27270
|
async function cancelBillingCapacityReductionCommand(input, api) {
|
|
@@ -26775,7 +27276,7 @@ async function cancelBillingCapacityReductionCommand(input, api) {
|
|
|
26775
27276
|
${formatBillingSummary(billing)}`
|
|
26776
27277
|
};
|
|
26777
27278
|
} catch (error) {
|
|
26778
|
-
return { exitCode:
|
|
27279
|
+
return { exitCode: mapErrorToExitCode11(error), output: error instanceof Error ? error.message : String(error) };
|
|
26779
27280
|
}
|
|
26780
27281
|
}
|
|
26781
27282
|
async function getBillingSummaryWithAuthCommand(input, dependencies) {
|
|
@@ -26936,7 +27437,7 @@ function formatInvitesTable(invites) {
|
|
|
26936
27437
|
}
|
|
26937
27438
|
return invites.map((i) => `${i.invite_id} | ${i.email} | ${i.role} | expires=${i.expires_at}`).join("\n");
|
|
26938
27439
|
}
|
|
26939
|
-
function
|
|
27440
|
+
function mapErrorToExitCode12(error) {
|
|
26940
27441
|
if (!(error instanceof MemberApiError)) {
|
|
26941
27442
|
return 1;
|
|
26942
27443
|
}
|
|
@@ -26963,7 +27464,7 @@ async function listMembersCommand(input, api) {
|
|
|
26963
27464
|
};
|
|
26964
27465
|
} catch (error) {
|
|
26965
27466
|
return {
|
|
26966
|
-
exitCode:
|
|
27467
|
+
exitCode: mapErrorToExitCode12(error),
|
|
26967
27468
|
output: error instanceof MemberApiError ? error.code : String(error)
|
|
26968
27469
|
};
|
|
26969
27470
|
}
|
|
@@ -26977,7 +27478,7 @@ async function listInvitesCommand(input, api) {
|
|
|
26977
27478
|
};
|
|
26978
27479
|
} catch (error) {
|
|
26979
27480
|
return {
|
|
26980
|
-
exitCode:
|
|
27481
|
+
exitCode: mapErrorToExitCode12(error),
|
|
26981
27482
|
output: error instanceof MemberApiError ? error.code : String(error)
|
|
26982
27483
|
};
|
|
26983
27484
|
}
|
|
@@ -26991,7 +27492,7 @@ async function inviteMemberCommand(input, api) {
|
|
|
26991
27492
|
};
|
|
26992
27493
|
} catch (error) {
|
|
26993
27494
|
return {
|
|
26994
|
-
exitCode:
|
|
27495
|
+
exitCode: mapErrorToExitCode12(error),
|
|
26995
27496
|
output: error instanceof MemberApiError ? error.code : String(error)
|
|
26996
27497
|
};
|
|
26997
27498
|
}
|
|
@@ -27005,7 +27506,7 @@ async function cancelInviteCommand(input, api) {
|
|
|
27005
27506
|
};
|
|
27006
27507
|
} catch (error) {
|
|
27007
27508
|
return {
|
|
27008
|
-
exitCode:
|
|
27509
|
+
exitCode: mapErrorToExitCode12(error),
|
|
27009
27510
|
output: error instanceof MemberApiError ? error.code : String(error)
|
|
27010
27511
|
};
|
|
27011
27512
|
}
|
|
@@ -27019,7 +27520,7 @@ async function updateMemberRoleCommand(input, api) {
|
|
|
27019
27520
|
};
|
|
27020
27521
|
} catch (error) {
|
|
27021
27522
|
return {
|
|
27022
|
-
exitCode:
|
|
27523
|
+
exitCode: mapErrorToExitCode12(error),
|
|
27023
27524
|
output: error instanceof MemberApiError ? error.code : String(error)
|
|
27024
27525
|
};
|
|
27025
27526
|
}
|
|
@@ -27033,7 +27534,7 @@ async function removeMemberCommand(input, api) {
|
|
|
27033
27534
|
};
|
|
27034
27535
|
} catch (error) {
|
|
27035
27536
|
return {
|
|
27036
|
-
exitCode:
|
|
27537
|
+
exitCode: mapErrorToExitCode12(error),
|
|
27037
27538
|
output: error instanceof MemberApiError ? error.code : String(error)
|
|
27038
27539
|
};
|
|
27039
27540
|
}
|
|
@@ -27182,7 +27683,7 @@ function createProbeApi(httpClient) {
|
|
|
27182
27683
|
}
|
|
27183
27684
|
};
|
|
27184
27685
|
}
|
|
27185
|
-
function
|
|
27686
|
+
function mapErrorToExitCode13(error) {
|
|
27186
27687
|
if (!(error instanceof ProbeApiError)) {
|
|
27187
27688
|
return 1;
|
|
27188
27689
|
}
|
|
@@ -27235,7 +27736,7 @@ async function activateProbeCommand(input, api) {
|
|
|
27235
27736
|
Trigger token: ${result.trigger_token}`
|
|
27236
27737
|
};
|
|
27237
27738
|
} catch (error) {
|
|
27238
|
-
return { exitCode:
|
|
27739
|
+
return { exitCode: mapErrorToExitCode13(error), output: error instanceof Error ? error.message : String(error) };
|
|
27239
27740
|
}
|
|
27240
27741
|
}
|
|
27241
27742
|
async function listActiveProbesCommand(input, api) {
|
|
@@ -27255,7 +27756,7 @@ async function listActiveProbesCommand(input, api) {
|
|
|
27255
27756
|
output: result.activations.map((a) => `${a.activation_id} ${a.label_pattern} (${a.service}/${a.environment}) expires ${a.expires_at}`).join("\n")
|
|
27256
27757
|
};
|
|
27257
27758
|
} catch (error) {
|
|
27258
|
-
return { exitCode:
|
|
27759
|
+
return { exitCode: mapErrorToExitCode13(error), output: error instanceof Error ? error.message : String(error) };
|
|
27259
27760
|
}
|
|
27260
27761
|
}
|
|
27261
27762
|
async function deactivateProbeCommand(input, api) {
|
|
@@ -27273,7 +27774,7 @@ async function deactivateProbeCommand(input, api) {
|
|
|
27273
27774
|
output: result.deactivated ? "Probe deactivated." : "Probe was already inactive."
|
|
27274
27775
|
};
|
|
27275
27776
|
} catch (error) {
|
|
27276
|
-
return { exitCode:
|
|
27777
|
+
return { exitCode: mapErrorToExitCode13(error), output: error instanceof Error ? error.message : String(error) };
|
|
27277
27778
|
}
|
|
27278
27779
|
}
|
|
27279
27780
|
async function createAuthenticatedProbeApi(input, dependencies) {
|
|
@@ -27323,7 +27824,7 @@ async function deactivateProbeWithAuthCommand(input, dependencies) {
|
|
|
27323
27824
|
}
|
|
27324
27825
|
|
|
27325
27826
|
// src/github-commands.ts
|
|
27326
|
-
function
|
|
27827
|
+
function mapErrorToExitCode14(error) {
|
|
27327
27828
|
if (!(error instanceof GitHubManagementApiError)) {
|
|
27328
27829
|
return 1;
|
|
27329
27830
|
}
|
|
@@ -27384,7 +27885,7 @@ async function getGitHubStatusCommand(input, api) {
|
|
|
27384
27885
|
${formatProjectRepo(repo)}`
|
|
27385
27886
|
};
|
|
27386
27887
|
} catch (error) {
|
|
27387
|
-
return { exitCode:
|
|
27888
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27388
27889
|
}
|
|
27389
27890
|
}
|
|
27390
27891
|
async function listGitHubRepositoriesCommand(input, api) {
|
|
@@ -27395,7 +27896,7 @@ async function listGitHubRepositoriesCommand(input, api) {
|
|
|
27395
27896
|
output: input.json ? JSON.stringify({ repositories }) : repositories.length === 0 ? "No GitHub repositories found." : repositories.map((repository) => `${repository.full_name} (${repository.default_branch})`).join("\n")
|
|
27396
27897
|
};
|
|
27397
27898
|
} catch (error) {
|
|
27398
|
-
return { exitCode:
|
|
27899
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27399
27900
|
}
|
|
27400
27901
|
}
|
|
27401
27902
|
async function setProjectGitHubRepoCommand(input, api) {
|
|
@@ -27418,7 +27919,7 @@ async function setProjectGitHubRepoCommand(input, api) {
|
|
|
27418
27919
|
output: input.json ? JSON.stringify({ repo: assignedRepo }) : `Project repo set: ${formatProjectRepo(assignedRepo)}`
|
|
27419
27920
|
};
|
|
27420
27921
|
} catch (error) {
|
|
27421
|
-
return { exitCode:
|
|
27922
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27422
27923
|
}
|
|
27423
27924
|
}
|
|
27424
27925
|
async function removeProjectGitHubRepoCommand(input, api) {
|
|
@@ -27429,7 +27930,7 @@ async function removeProjectGitHubRepoCommand(input, api) {
|
|
|
27429
27930
|
output: input.json ? JSON.stringify({ removed: true, project_id: input.projectId }) : `Project repo removed: ${input.projectId}`
|
|
27430
27931
|
};
|
|
27431
27932
|
} catch (error) {
|
|
27432
|
-
return { exitCode:
|
|
27933
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27433
27934
|
}
|
|
27434
27935
|
}
|
|
27435
27936
|
async function listProjectGitHubRulesCommand(input, api) {
|
|
@@ -27443,7 +27944,7 @@ async function listProjectGitHubRulesCommand(input, api) {
|
|
|
27443
27944
|
output: input.json ? JSON.stringify({ rules }) : formatGitHubRuleTable(rules)
|
|
27444
27945
|
};
|
|
27445
27946
|
} catch (error) {
|
|
27446
|
-
return { exitCode:
|
|
27947
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27447
27948
|
}
|
|
27448
27949
|
}
|
|
27449
27950
|
async function listProjectGitHubDeliveriesCommand(input, api) {
|
|
@@ -27459,7 +27960,7 @@ async function listProjectGitHubDeliveriesCommand(input, api) {
|
|
|
27459
27960
|
output: input.json ? JSON.stringify({ deliveries }) : formatGitHubDeliveryTable(deliveries)
|
|
27460
27961
|
};
|
|
27461
27962
|
} catch (error) {
|
|
27462
|
-
return { exitCode:
|
|
27963
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27463
27964
|
}
|
|
27464
27965
|
}
|
|
27465
27966
|
async function retryProjectGitHubDeliveryCommand(input, api) {
|
|
@@ -27474,7 +27975,7 @@ async function retryProjectGitHubDeliveryCommand(input, api) {
|
|
|
27474
27975
|
output: input.json ? JSON.stringify({ delivery }) : `GitHub delivery retried: ${delivery.delivery_id} | ${delivery.status}`
|
|
27475
27976
|
};
|
|
27476
27977
|
} catch (error) {
|
|
27477
|
-
return { exitCode:
|
|
27978
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27478
27979
|
}
|
|
27479
27980
|
}
|
|
27480
27981
|
async function createProjectGitHubRuleCommand(input, api) {
|
|
@@ -27497,7 +27998,7 @@ async function createProjectGitHubRuleCommand(input, api) {
|
|
|
27497
27998
|
output: input.json ? JSON.stringify({ rule }) : `GitHub rule created: ${rule.rule_id}`
|
|
27498
27999
|
};
|
|
27499
28000
|
} catch (error) {
|
|
27500
|
-
return { exitCode:
|
|
28001
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27501
28002
|
}
|
|
27502
28003
|
}
|
|
27503
28004
|
async function updateProjectGitHubRuleCommand(input, api) {
|
|
@@ -27521,7 +28022,7 @@ async function updateProjectGitHubRuleCommand(input, api) {
|
|
|
27521
28022
|
output: input.json ? JSON.stringify({ rule }) : `GitHub rule updated: ${rule.rule_id}`
|
|
27522
28023
|
};
|
|
27523
28024
|
} catch (error) {
|
|
27524
|
-
return { exitCode:
|
|
28025
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27525
28026
|
}
|
|
27526
28027
|
}
|
|
27527
28028
|
async function deleteProjectGitHubRuleCommand(input, api) {
|
|
@@ -27536,7 +28037,7 @@ async function deleteProjectGitHubRuleCommand(input, api) {
|
|
|
27536
28037
|
output: input.json ? JSON.stringify({ deleted: true, project_id: input.projectId, rule_id: input.ruleId }) : `GitHub rule deleted: ${input.ruleId}`
|
|
27537
28038
|
};
|
|
27538
28039
|
} catch (error) {
|
|
27539
|
-
return { exitCode:
|
|
28040
|
+
return { exitCode: mapErrorToExitCode14(error), output: error instanceof Error ? error.message : String(error) };
|
|
27540
28041
|
}
|
|
27541
28042
|
}
|
|
27542
28043
|
async function getGitHubStatusWithAuthCommand(input, dependencies) {
|
|
@@ -28534,6 +29035,67 @@ async function handleAlertCommand(parsedArgv, dependencies) {
|
|
|
28534
29035
|
}
|
|
28535
29036
|
throw new CliInputError("Unknown alert command.");
|
|
28536
29037
|
}
|
|
29038
|
+
async function handleSlackCommand(parsedArgv, dependencies) {
|
|
29039
|
+
const action = requirePositional(parsedArgv, 1, "action");
|
|
29040
|
+
if (action === "list") {
|
|
29041
|
+
expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project-id"]);
|
|
29042
|
+
ensureNoExtraPositionals(parsedArgv, 2);
|
|
29043
|
+
const projectId = readStringOption(parsedArgv, "project-id");
|
|
29044
|
+
if (projectId === void 0) {
|
|
29045
|
+
throw new CliInputError("Missing required option --project-id.");
|
|
29046
|
+
}
|
|
29047
|
+
return await (dependencies.listSlackDestinationsCommand ?? listSlackDestinationsWithAuthCommand)(
|
|
29048
|
+
appendCommonAuthOptions(parsedArgv, {
|
|
29049
|
+
projectId
|
|
29050
|
+
})
|
|
29051
|
+
);
|
|
29052
|
+
}
|
|
29053
|
+
if (action === "connect-url") {
|
|
29054
|
+
expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project-id", "return-to"]);
|
|
29055
|
+
ensureNoExtraPositionals(parsedArgv, 2);
|
|
29056
|
+
const projectId = readStringOption(parsedArgv, "project-id");
|
|
29057
|
+
if (projectId === void 0) {
|
|
29058
|
+
throw new CliInputError("Missing required option --project-id.");
|
|
29059
|
+
}
|
|
29060
|
+
const input = appendCommonAuthOptions(parsedArgv, {
|
|
29061
|
+
projectId
|
|
29062
|
+
});
|
|
29063
|
+
const returnTo = readStringOption(parsedArgv, "return-to");
|
|
29064
|
+
if (returnTo !== void 0) {
|
|
29065
|
+
input.returnTo = returnTo;
|
|
29066
|
+
}
|
|
29067
|
+
return await (dependencies.getSlackConnectUrlCommand ?? getSlackConnectUrlWithAuthCommand)(input);
|
|
29068
|
+
}
|
|
29069
|
+
if (action === "test") {
|
|
29070
|
+
expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project-id"]);
|
|
29071
|
+
ensureNoExtraPositionals(parsedArgv, 3);
|
|
29072
|
+
const projectId = readStringOption(parsedArgv, "project-id");
|
|
29073
|
+
if (projectId === void 0) {
|
|
29074
|
+
throw new CliInputError("Missing required option --project-id.");
|
|
29075
|
+
}
|
|
29076
|
+
return await (dependencies.testSlackDestinationCommand ?? testSlackDestinationWithAuthCommand)(
|
|
29077
|
+
appendCommonAuthOptions(parsedArgv, {
|
|
29078
|
+
projectId,
|
|
29079
|
+
destinationId: requirePositional(parsedArgv, 2, "destination-id")
|
|
29080
|
+
})
|
|
29081
|
+
);
|
|
29082
|
+
}
|
|
29083
|
+
if (action === "delete") {
|
|
29084
|
+
expectNoUnknownOptions(parsedArgv, ["auth-file", "json", "project-id"]);
|
|
29085
|
+
ensureNoExtraPositionals(parsedArgv, 3);
|
|
29086
|
+
const projectId = readStringOption(parsedArgv, "project-id");
|
|
29087
|
+
if (projectId === void 0) {
|
|
29088
|
+
throw new CliInputError("Missing required option --project-id.");
|
|
29089
|
+
}
|
|
29090
|
+
return await (dependencies.deleteSlackDestinationCommand ?? deleteSlackDestinationWithAuthCommand)(
|
|
29091
|
+
appendCommonAuthOptions(parsedArgv, {
|
|
29092
|
+
projectId,
|
|
29093
|
+
destinationId: requirePositional(parsedArgv, 2, "destination-id")
|
|
29094
|
+
})
|
|
29095
|
+
);
|
|
29096
|
+
}
|
|
29097
|
+
throw new CliInputError("Unknown slack command.");
|
|
29098
|
+
}
|
|
28537
29099
|
async function handleWeeklyReportCommand(parsedArgv, dependencies) {
|
|
28538
29100
|
const action = requirePositional(parsedArgv, 1, "action");
|
|
28539
29101
|
if (action === "list") {
|
|
@@ -28589,10 +29151,20 @@ async function handleWeeklyReportCommand(parsedArgv, dependencies) {
|
|
|
28589
29151
|
if (config === void 0 || typeof config !== "object" || config === null) {
|
|
28590
29152
|
throw new CliInputError("Missing required option --config-json.");
|
|
28591
29153
|
}
|
|
29154
|
+
let weeklyReportConfig;
|
|
29155
|
+
if (channel === "slack") {
|
|
29156
|
+
if (typeof config["slack_destination_id"] === "string") {
|
|
29157
|
+
weeklyReportConfig = { slackDestinationId: String(config["slack_destination_id"]) };
|
|
29158
|
+
} else {
|
|
29159
|
+
weeklyReportConfig = { webhookUrl: String(config["webhook_url"]) };
|
|
29160
|
+
}
|
|
29161
|
+
} else {
|
|
29162
|
+
weeklyReportConfig = { to: config.to };
|
|
29163
|
+
}
|
|
28592
29164
|
const input = appendCommonAuthOptions(parsedArgv, {
|
|
28593
29165
|
projectId,
|
|
28594
29166
|
channel,
|
|
28595
|
-
config:
|
|
29167
|
+
config: weeklyReportConfig,
|
|
28596
29168
|
schedule: {
|
|
28597
29169
|
dayOfWeek,
|
|
28598
29170
|
hourOfDay,
|
|
@@ -28633,7 +29205,7 @@ async function handleWeeklyReportCommand(parsedArgv, dependencies) {
|
|
|
28633
29205
|
if (typeof config !== "object" || config === null) {
|
|
28634
29206
|
throw new CliInputError("Invalid value for --config-json.");
|
|
28635
29207
|
}
|
|
28636
|
-
input.config = "webhook_url" in config ? { webhookUrl: String(config["webhook_url"]) } : { to: config.to };
|
|
29208
|
+
input.config = "slack_destination_id" in config ? { slackDestinationId: String(config["slack_destination_id"]) } : "webhook_url" in config ? { webhookUrl: String(config["webhook_url"]) } : { to: config.to };
|
|
28637
29209
|
}
|
|
28638
29210
|
const isEnabled = readBooleanStringOption(parsedArgv, "is-enabled");
|
|
28639
29211
|
if (isEnabled !== void 0) {
|
|
@@ -28761,10 +29333,17 @@ ${formatUsage()}`
|
|
|
28761
29333
|
});
|
|
28762
29334
|
}
|
|
28763
29335
|
if (command === "process") {
|
|
28764
|
-
expectNoUnknownOptions(parsedArgv, ["json"]);
|
|
29336
|
+
expectNoUnknownOptions(parsedArgv, ["json", "preset"]);
|
|
28765
29337
|
ensureNoExtraPositionals(parsedArgv, 1);
|
|
28766
29338
|
const json = readBooleanOption(parsedArgv, "json");
|
|
28767
|
-
|
|
29339
|
+
const preset = readStringOption(parsedArgv, "preset");
|
|
29340
|
+
if (preset !== void 0 && !CapturePresetSchema.safeParse(preset).success) {
|
|
29341
|
+
throw new CliInputError("Invalid value for --preset.");
|
|
29342
|
+
}
|
|
29343
|
+
return await (dependencies.processCommand ?? processCommand)({
|
|
29344
|
+
...json === true ? { json: true } : {},
|
|
29345
|
+
...preset !== void 0 ? { preset } : {}
|
|
29346
|
+
});
|
|
28768
29347
|
}
|
|
28769
29348
|
if (command === "clean") {
|
|
28770
29349
|
expectNoUnknownOptions(parsedArgv, ["events", "bundles", "all", "older-than", "json"]);
|
|
@@ -29041,6 +29620,9 @@ ${formatUsage()}`
|
|
|
29041
29620
|
if (command === "alert") {
|
|
29042
29621
|
return await handleAlertCommand(parsedArgv, dependencies);
|
|
29043
29622
|
}
|
|
29623
|
+
if (command === "slack") {
|
|
29624
|
+
return await handleSlackCommand(parsedArgv, dependencies);
|
|
29625
|
+
}
|
|
29044
29626
|
if (command === "webhook") {
|
|
29045
29627
|
return await handleWebhookCommand(parsedArgv, dependencies);
|
|
29046
29628
|
}
|