@dx-do/cli 6.0.1 → 6.0.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/README.md +12 -6
- package/dist-node/{03-discover-sources.nassql.data-store-by6sqk23.json5 → 03-discover-sources.nassql.data-store-d6hb6wf7.json5} +4 -3
- package/dist-node/{20-nassql-from-metadata-basic.nassql.data-store-zdf1gp1v.json5 → 20-nassql-from-metadata-basic.nassql.data-store-mq1hn0qz.json5} +4 -2
- package/dist-node/34-nassql-entity-to-metric-ids.nassql-jn6t8zxs.md +76 -0
- package/dist-node/34-nassql-entity-to-metric-ids.nassql.data-store-t8ecm336.json5 +69 -0
- package/dist-node/34-nassql-entity-to-metric-ids.nassql.data-store-tmd-9vbg6p76.json +4 -0
- package/dist-node/40-metadata-filter-by-typeenum.metadata-kmcc85ac.md +66 -0
- package/dist-node/40-metadata-filter-by-typeenum.metadata.data-store-b4erpx6h.json5 +52 -0
- package/dist-node/40-metadata-filter-by-typeenum.metadata.data-store-tmd-3zg3n0j1.json +4 -0
- package/dist-node/41-metadata-frontend-durations.metadata-n2ba62j7.md +50 -0
- package/dist-node/41-metadata-frontend-durations.metadata.data-store-kpkhaf6c.json5 +48 -0
- package/dist-node/41-metadata-frontend-durations.metadata.data-store-tmd-c685fc9v.json +4 -0
- package/dist-node/42-metadata-metric-id-to-entities.metadata-qg0p7y71.md +67 -0
- package/dist-node/42-metadata-metric-id-to-entities.metadata.data-store-tmd-zd99v6pz.json +4 -0
- package/dist-node/42-metadata-metric-id-to-entities.metadata.data-store-vwv8dq0e.json5 +52 -0
- package/dist-node/{SKILL-1xn7r9nt.md → SKILL-86r2cm61.md} +26 -2
- package/dist-node/{agentic-mcp-rycd2gh8.md → agentic-mcp-9nz7zh8d.md} +2 -1
- package/dist-node/alarms-cookbook-xrwbrdte.md +160 -0
- package/dist-node/alarms-quickstart-fhg59mr2.md +100 -0
- package/dist-node/{chunk-RNMHSXZF-pdwasrg7.js → chunk-4L5DIG2E-9p3rrkp9.js} +1 -1
- package/dist-node/{chunk-VV2FJEMA-3rvtkmga.js → chunk-4Q347M53-e6wyjnpc.js} +2 -2
- package/dist-node/{chunk-Q2JA73UH-akkb8bh3.js → chunk-6TL6OWJA-jrr526kw.js} +1 -1
- package/dist-node/chunk-7G4RSOZU-nnmp25yx.js +3753 -0
- package/dist-node/{chunk-YVD3UK5I-9pxr1jka.js → chunk-JYKZ5EMU-6jq5egbw.js} +3 -3
- package/dist-node/{chunk-5VSFINOX-ewzpx7wh.js → chunk-OV4PNSIK-pqs8y3nm.js} +3 -3
- package/dist-node/{chunk-JRM4BLOM-rg32z8w4.js → chunk-P6TRLBVU-rxz4tacs.js} +1 -1
- package/dist-node/{chunk-4I3HBO6U-2ebgf7kh.js → chunk-TFFMCZCS-rhchxvk7.js} +1 -1
- package/dist-node/{chunk-4PMCLJMS-0mqvr4m4.js → chunk-W5FHICA2-x50sz7wk.js} +1 -1
- package/dist-node/{discovery-flow-fw79kbx4.md → discovery-flow-m0zp07e3.md} +13 -0
- package/dist-node/{gotchas-8ab64kcd.md → gotchas-p696dmam.md} +131 -0
- package/dist-node/{index-104hyb1m.html → index-dfkxebky.html} +1 -1
- package/dist-node/{index-mbzg9rhc.json → index-mf7znaf7.json} +30 -0
- package/dist-node/{index-g3hh5wez.json → index-x07qhy6g.json} +53 -0
- package/dist-node/{investigator-flow-jc2s0n46.md → investigator-flow-dcyk8v51.md} +36 -2
- package/dist-node/main-4VTFKCWX-6x4n4v8m.js +13 -0
- package/dist-node/main.js +26106 -18435
- package/dist-node/{metrics-grounding-2h4kkbe3.md → metrics-grounding-8vhfqya9.md} +59 -4
- package/dist-node/{mm-cookbook-23jpw721.md → mm-cookbook-fdwbt989.md} +1 -1
- package/dist-node/{nassql-cookbook-n8kc0mff.md → nassql-cookbook-kp525xra.md} +41 -1
- package/dist-node/{nassql-quickstart-090e0yex.md → nassql-quickstart-mth22qd3.md} +3 -1
- package/package.json +1 -1
- package/dist-node/chunk-72HYG3XZ-kf7hy4vs.js +0 -3625
- package/dist-node/main-SGLYO5YX-ht69eb0y.js +0 -13
|
@@ -34,7 +34,8 @@ The MCP exposes the dx-do client surface as a small set of named **modules**. Ea
|
|
|
34
34
|
|---|---|---|---|
|
|
35
35
|
| `discovery` | Explore the tenant's topology graph — what layers / services / metrics / attributes / attribute-values exist. Cached per session. | All discovery tools (read-only by nature). | Same as `read` — no mutating discovery operations. |
|
|
36
36
|
| `corpus` | Browse the corpus shipped with `@dx-do/corpus` — sections today: `queries` (worked-example payloads), `cookbooks` (quickstart + gotchas + discovery-flow), `entities` (vertex-type reference docs). Future: `metrics`, `lexicon`. | All three generic corpus tools (`corpus_sections` / `corpus_list` / `corpus_get`). | Same as `read` — no mutating corpus operations. |
|
|
37
|
-
| `datastore` | Execute queries against the live tenant's DXO2 DataStore APIs (TAS / NASSQL / Metrics-Metadata). | Run full and partial queries (read against tenant data). | Reserved for future mutating datastore operations
|
|
37
|
+
| `datastore` | Execute queries against the live tenant's DXO2 DataStore APIs (TAS / NASSQL / Metrics-Metadata). | Run full and partial queries (read against tenant data). | Reserved for future mutating datastore operations — currently same as `read`. |
|
|
38
|
+
| `alarms` | OI alarm read surface — search alarms, fetch one, get lifecycle, related alarms, saved alarm queues. | `list_alarms`, `get_alarm`, `get_alarm_lifecycle`, `get_related_alarms`, `list_alarm_queues`. | Reserved for future acknowledge / assign / clear mutations — currently same as `read`. |
|
|
38
39
|
| `ui` | Manage user-authored queries on disk under `~/.dxdo/queries/<alias>/`. Same surface the visual ui exposes. | List folders / list queries / get query. | Adds create / update / move query + create folder. |
|
|
39
40
|
|
|
40
41
|
**Defaults:** `ui=write`, everything else `read`. Override per module — modules you don't mention keep their default.
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: alarms-cookbook
|
|
3
|
+
title: Alarms — full reference (fields, timestamps, queues, lifecycle)
|
|
4
|
+
applies_to: alarms
|
|
5
|
+
tags: [reference, alarms]
|
|
6
|
+
related: [alarms-quickstart, investigator-flow, gotchas]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Alarms cookbook
|
|
10
|
+
|
|
11
|
+
Reference companion to `alarms-quickstart`. Read the quickstart first; come back here for field-level detail, the timestamp map, alarm-queue semantics, and the lifecycle-event taxonomy.
|
|
12
|
+
|
|
13
|
+
## The Alarm document — fields grouped by purpose
|
|
14
|
+
|
|
15
|
+
The Alarm wire shape is open-ended (any `sourceProduct` may add product-specific fields), but the load-bearing fields fall into six groups:
|
|
16
|
+
|
|
17
|
+
### Identity
|
|
18
|
+
|
|
19
|
+
| field | type | notes |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `alarmId` | string | The primary key; what `get_alarm` / `get_alarm_lifecycle` / `get_related_alarms` accept. |
|
|
22
|
+
| `external_ids` | string[] | TAS-compatible entity externalIds. **In practice 0 or 1 elements** — do not assume multi-element arrays. |
|
|
23
|
+
| `vertexId` | string | APM-only — internal vertex id (less stable than `external_ids`). |
|
|
24
|
+
| `ciUniqueId` | string | Configuration-item id (typically empty unless APM-derived). |
|
|
25
|
+
|
|
26
|
+
### Lifecycle and time
|
|
27
|
+
|
|
28
|
+
See "the timestamp map" below — there are six declared timestamp-like fields but only four are populated on the wire.
|
|
29
|
+
|
|
30
|
+
| field | type | notes |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `status` | string | UPPERCASE: `NEW` \| `UPDATED` \| `CLOSED`. "Open" = `!= CLOSED`. |
|
|
33
|
+
| `timeOrigin` | string (epoch ms or ISO) | The user-visible event time. Use this for "when did this happen?". |
|
|
34
|
+
| `lastUpdateTime` | string (epoch ms) | Last time anything on the alarm changed — including the lifecycle. Use for "is this still moving?". |
|
|
35
|
+
| `sourceTimestamp` | string (epoch ms or ISO) | What the source system reported. Usually within a second of `timeOrigin`. |
|
|
36
|
+
| `closedTime` | string (epoch ms) | Present iff `status == "CLOSED"`. NOT declared on the typed interface — projection surfaces it as an optional field. |
|
|
37
|
+
| `startTime` | (not on body) | The interface declares it; the wire does not carry it. Get it from the first lifecycle event (`name: "Alarm Opened"`, `propName: startTime`, ISO time in `propValue[0]`). |
|
|
38
|
+
| `@timestamp` | (not on body) | Same — declared but never populated on the wire. |
|
|
39
|
+
|
|
40
|
+
### Criticality and source
|
|
41
|
+
|
|
42
|
+
| field | type | notes |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| `severity` | string | lowercase: `critical` \| `major` \| `minor` \| `information` \| `unknown`. The spelling is `information` (full word), not `info`. |
|
|
45
|
+
| `sourceProduct` | string | Human-readable product label — see the "sourceProduct vocabulary" section. |
|
|
46
|
+
| `productId` | string | Short code (e.g. `"ao"` for APM). Less useful than `sourceProduct` for users; cite it only when disambiguating product internals. |
|
|
47
|
+
| `alarmType` | string | Per-source categorical label (e.g. `Application` for APM, `Disk`/`CPU`/`Memory` for UIM, `EUM_Real_User` for EUM). The set of values is dense within a `sourceProduct` and sparse across; don't filter `alarmType` without also fixing `sourceProduct`. |
|
|
48
|
+
| `managementModule` | string | Identifies the alert definition (APM management module or platform module) that emitted the alarm. Most APM alarms carry it; UIM does not. |
|
|
49
|
+
|
|
50
|
+
### Location and entity
|
|
51
|
+
|
|
52
|
+
| field | type | notes |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `host` | string | The hostname the alarm is "about". Nearly always present. |
|
|
55
|
+
| `deviceName` | string | Often duplicates `host`; differs when the alarm is about a logical device (e.g. an APM agent name). |
|
|
56
|
+
| `entity` | string | Pipe-delimited path (e.g. `SuperDomain\|<host>\|<agent>\|<perspective>\|<...>`) for APM; bare name for UIM/Spectrum. |
|
|
57
|
+
| `Service` | string (capital S) | The service the alarm is scoped to. Empty when the alarm is not service-scoped. |
|
|
58
|
+
|
|
59
|
+
### Content
|
|
60
|
+
|
|
61
|
+
| field | type | notes |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `message` | string | The user-readable "what happened" text. **Use this** — `alarmDescription` is almost always empty. |
|
|
64
|
+
| `metricName` | string | If a metric breach drove the alarm, the metric name. |
|
|
65
|
+
| `metricValue` | string | The metric value at the time of the breach. |
|
|
66
|
+
| `alarmName` | string | Often duplicates `metricName`. |
|
|
67
|
+
|
|
68
|
+
### Ticketing and links
|
|
69
|
+
|
|
70
|
+
| field | type | notes |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| `ticketID` / `ticketStatus` / `troubleTicketUrl` | string | Populated when the alarm has been ticketed via ITSM integration. Often empty. |
|
|
73
|
+
| `alarmURL` / `metric_view_link` / `isolation_view_link` / `alert_definition_link` / `metric_group_link` | string | Deep links into the DXO2 web UI. The agent doesn't usually need these; surface to the user when a follow-up requires the web UI. |
|
|
74
|
+
|
|
75
|
+
## The timestamp map
|
|
76
|
+
|
|
77
|
+
Six declared timestamp-like fields; four populated.
|
|
78
|
+
|
|
79
|
+
| field | populated? | what to use it for |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `timeOrigin` | always | "When did this happen?" — first choice. |
|
|
82
|
+
| `lastUpdateTime` | always | "Is this still moving?" — most recent activity. |
|
|
83
|
+
| `sourceTimestamp` | always | The source system's reported time. Usually ≈ `timeOrigin`. |
|
|
84
|
+
| `closedTime` | iff CLOSED | When the alarm closed. |
|
|
85
|
+
| `startTime` | **never on the body** | Read from the lifecycle's first event (`name: "Alarm Opened"`). |
|
|
86
|
+
| `@timestamp` | **never on the body** | Don't read it; it's an interface artifact. |
|
|
87
|
+
|
|
88
|
+
## sourceProduct vocabulary
|
|
89
|
+
|
|
90
|
+
The bound tenant typically emits alarms from a small set of `sourceProduct` values. Common examples:
|
|
91
|
+
|
|
92
|
+
| sourceProduct | what it covers | typical alarmType values |
|
|
93
|
+
|---|---|---|
|
|
94
|
+
| `Application Performance Management` | APM agents — application errors, slow transactions, JVM/CLR metrics, management-module alerts. The dominant source on most tenants. | `Application` |
|
|
95
|
+
| `UIM` | Infrastructure monitoring — host CPU/disk/memory, networking, robots/probes/hubs. | `Disk`, `CPU`, `Memory`, `Alarm`, `E2Emonitor`, `OC_Failover`, `OC_Failback`, `Application`, `MySQL`, … |
|
|
96
|
+
| `Spectrum` | Network fault management ingestion. | `Fault`, `ConnectorHealth` |
|
|
97
|
+
| `EUM` | End-user monitoring — real-user browser/mobile telemetry. | `EUM_Real_User` |
|
|
98
|
+
| `DXO2` | Platform-native — service-health, SLI breaches, ingestion conditions. | `ServiceHealth`, `SLI`, `Application` |
|
|
99
|
+
|
|
100
|
+
Filtering by `alarmType` is most useful within a single `sourceProduct`. To narrow to "all APM alarms about applications", pass `sourceProducts: ["Application Performance Management"]` — the alarmType vocabulary inside that source is uniform.
|
|
101
|
+
|
|
102
|
+
## Alarm queues — saved filters
|
|
103
|
+
|
|
104
|
+
`list_alarm_queues` returns the tenant's saved alarm-filter configurations. Each entry has:
|
|
105
|
+
|
|
106
|
+
- `id` — UUID. Pass back into `list_alarms.alarmQueueId`.
|
|
107
|
+
- `filterName` — the label customers chose. The user-visible identifier.
|
|
108
|
+
- Additional UI-display fields (column preferences, etc.) — generally not relevant to the agent.
|
|
109
|
+
|
|
110
|
+
**Multiple queues can share a `filterName`** — they're separate `id`s. When the user names a queue, ask which one if there's ambiguity.
|
|
111
|
+
|
|
112
|
+
When a customer has already curated a filter ("show me the SiteMinder Prod queue"), passing `alarmQueueId` is far more reliable than hand-authoring `severities` / `sourceProducts` / `alarmTypes` — the queue captures customer intent that the agent can't reconstruct from the name alone.
|
|
113
|
+
|
|
114
|
+
## Searching for closed alarms
|
|
115
|
+
|
|
116
|
+
There is no "closed only" filter on the API. To answer "what closed in the last 24 hours?":
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
list_alarms(lookbackHours: 24, includeClosed: true)
|
|
120
|
+
# post-filter: alarms.filter(a => a.status === "CLOSED")
|
|
121
|
+
# order: alarms.sort by closedTime descending
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
When the user asks about a wider window, increase `lookbackHours` (up to 720 = 30 days). For arbitrary historical sweeps that span more than 30 days, the CLI has `dx-do alarm list startTime=P30D relativeEndDuration=P30D` — escape hatches with ISO 8601 duration arguments (`P` for date durations, `PT` for time durations; e.g. `P7D` = 7 days, `PT24H` = 24 hours).
|
|
125
|
+
|
|
126
|
+
## Lifecycle events — what the timeline looks like
|
|
127
|
+
|
|
128
|
+
`get_alarm_lifecycle(alarmId)` returns `{totalCount, lifecycle_events: [...]}` where each event is `{name, propName, propValue[], oldValue[], timestamp, updatedBy, userType}`. Event names observed:
|
|
129
|
+
|
|
130
|
+
| `name` | `propName` | typical `userType` | what it means |
|
|
131
|
+
|---|---|---|---|
|
|
132
|
+
| `Alarm Opened` | `startTime` | `PRODUCT` | First event. `propValue[0]` is the alarm's actual start time (ISO). |
|
|
133
|
+
| `Services Impacted` | `services_impacted` | `AUTOMATIC` | Enrichment: array of impacted service names in `propValue`. **This is the only place to find `services_impacted`** — it is NOT on the alarm body. |
|
|
134
|
+
| `Service Enrichment` | `sa_unique_id` | `AUTOMATIC` | Internal service-association id. |
|
|
135
|
+
| `Status` | `status` | `AUTOMATIC` | One per status change (NEW → UPDATED → CLOSED). |
|
|
136
|
+
| `clusterId` / `clusterStatus` / `isStableCluster` | (same) | `MANUAL` (`SITUATIONS`) | Clustering enrichment from Situations correlation. |
|
|
137
|
+
| `metric_group_link` / `metric_view_link` / `isolation_view_link` / `alert_definition_link` | (same) | `MANUAL` | Portal-link enrichments — added post-creation. |
|
|
138
|
+
|
|
139
|
+
`userType` carries the source category: `PRODUCT`, `AUTOMATIC`, `MANUAL`, `SYSTEM`. `updatedBy` carries a product name or `SYSTEM`/`SITUATIONS`.
|
|
140
|
+
|
|
141
|
+
## Round-trip: alarm → entity (TAS) → metrics (NASSQL)
|
|
142
|
+
|
|
143
|
+
`alarm.external_ids[0]` is a TAS-compatible vertex externalId. The two most useful follow-up patterns:
|
|
144
|
+
|
|
145
|
+
1. **Find the entity** — feed `external_ids[0]` into a TAS query keyed by `externalId`. (`vertex.externalId == "<value>"`.)
|
|
146
|
+
2. **Find the entity's metrics** — chain TAS → Metrics-Metadata via `corpus_get('queries', '34-nassql-entity-to-metric-ids')` (externalId → metric.id rows).
|
|
147
|
+
|
|
148
|
+
Common triage chain when a user asks "what's wrong with this alarm?":
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
list_alarms(...) # find the alarm
|
|
152
|
+
→ get_alarm(alarmId) # the full body
|
|
153
|
+
→ get_alarm_lifecycle(alarmId) # services_impacted, status timeline
|
|
154
|
+
→ TAS query on external_ids[0] # what entity is this on?
|
|
155
|
+
→ NASSQL FROM/JOIN_METADATA # what metrics relate to that entity?
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## What's not here
|
|
159
|
+
|
|
160
|
+
Mutating alarm operations (acknowledge, unacknowledge, assign, clear, trigger-webhook, create-alarm, update-field) are not exposed on the MCP today. They exist on the CLI (`dx-do alarm acknowledge`, `dx-do alarm assign`, `dx-do alarm clear`, etc.) — point users at those when they need to operate on an alarm rather than investigate it.
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: alarms-quickstart
|
|
3
|
+
title: Alarms quickstart — "are there any alarms?" and follow-ups
|
|
4
|
+
applies_to: alarms
|
|
5
|
+
tags: [getting-started, alarms]
|
|
6
|
+
related: [alarms-cookbook, investigator-flow, gotchas]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Alarms quickstart
|
|
10
|
+
|
|
11
|
+
Alarms are notifications about something happening on the tenant — a metric breached a threshold, a host went down, a synthetic transaction failed, a service SLI dropped. Unlike TAS / NASSQL / Metrics-Metadata queries, alarms are NOT served by the DataStore — they have their own API and their own tools (`list_alarms`, `get_alarm`, `get_alarm_lifecycle`, `get_related_alarms`, `list_alarm_queues`).
|
|
12
|
+
|
|
13
|
+
If the user asks "are there any alarms?", you call `list_alarms` — not `run_query`.
|
|
14
|
+
|
|
15
|
+
## Two axes that get confused: `status` vs `severity`
|
|
16
|
+
|
|
17
|
+
Every alarm carries both. They are independent.
|
|
18
|
+
|
|
19
|
+
| axis | what it means | values | casing |
|
|
20
|
+
|---|---|---|---|
|
|
21
|
+
| `status` | lifecycle state | `NEW`, `UPDATED`, `CLOSED` | UPPERCASE on the wire |
|
|
22
|
+
| `severity` | criticality | `critical`, `major`, `minor`, `information`, `unknown` | lowercase on the wire |
|
|
23
|
+
|
|
24
|
+
"**Open**" alarms = `status != "CLOSED"`. This is what users almost always mean when they say "alarms". `list_alarms` defaults to open-only (`includeClosed=false`).
|
|
25
|
+
|
|
26
|
+
The severity value is spelled `information`, not `info`. The `unknown` value also appears (rarely).
|
|
27
|
+
|
|
28
|
+
## Recipe 1 — "Are there any alarms?"
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
list_alarms()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
That's it. Defaults: 1-hour lookback, open-only, top 100. Return the count and the top 3 by severity, in one sentence. Don't ask for clarification before the first call — if the count is zero, then widen.
|
|
35
|
+
|
|
36
|
+
## Recipe 2 — "Any critical alarms in the last day?"
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
list_alarms(lookbackHours: 24, severities: ["critical"])
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The window is configurable via `lookbackHours` (default 1, cap 720 = 30 days). Pass severities as an array — `["critical", "major"]` is fine for "important alarms".
|
|
43
|
+
|
|
44
|
+
## Recipe 3 — "Alarms for host X"
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
list_alarms(hostContains: "<your-host>", lookbackHours: 24)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
`hostContains` does a substring match on the alarm's `host` field. If you have an entity TAS externalId instead of a hostname, fetch the alarm body via `get_alarm` after listing — the alarm carries `external_ids` (an array; in practice 0 or 1 elements) that round-trips to TAS vertices.
|
|
51
|
+
|
|
52
|
+
## Recipe 4 — "Which alarms closed in the last 24 hours?"
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
list_alarms(lookbackHours: 24, includeClosed: true)
|
|
56
|
+
# then post-filter by `status == "CLOSED"`
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**Important**: `includeClosed: true` returns BOTH open and closed alarms in the window, not closed-only. The OI API has no "closed only" mode — the agent does the post-filter. Order results by `closedTime` descending if the user wants the most-recently-closed.
|
|
60
|
+
|
|
61
|
+
`closedTime` is present iff `status == "CLOSED"` and is the wall-clock time the alarm closed. It is NOT declared on the typed Alarm interface — read it from the projection.
|
|
62
|
+
|
|
63
|
+
## Recipe 5 — "Alarms from the [name] queue"
|
|
64
|
+
|
|
65
|
+
DXO2 supports saved alarm filters called **alarm queues**. Customers curate them in the web UI; the agent reaches them via `list_alarm_queues` → pick by `filterName` → pass `id` to `list_alarms`.
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
queues = list_alarm_queues()
|
|
69
|
+
# present queues[*].filterName to the user, ask which they meant
|
|
70
|
+
list_alarms(alarmQueueId: "<id from queues>")
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Multiple queues can share the same `filterName` (different `id`s — often versions or user-private copies). When in doubt, ask the user which one. Prefer passing a queue id over hand-authoring `severities` / `sourceProducts` / `hostContains` — the queue carries customer intent that a hand-rolled filter cannot reconstruct.
|
|
74
|
+
|
|
75
|
+
## Field presence varies by source
|
|
76
|
+
|
|
77
|
+
Not every alarm carries every field. Approximate field-presence in a representative sample:
|
|
78
|
+
|
|
79
|
+
| field | typically present | when absent |
|
|
80
|
+
|---|---|---|
|
|
81
|
+
| `host`, `deviceName`, `entity`, `message` | nearly always | rare |
|
|
82
|
+
| `external_ids` | most alarms (and always 0 or 1 elements) | platform-internal alarms with no entity binding |
|
|
83
|
+
| `metricName`, `metricValue` | most threshold-style alarms | log-driven, service-health alarms |
|
|
84
|
+
| `Service` | most | not all alarms are scoped to a service |
|
|
85
|
+
| `alarmDescription` | almost never populated | use `message` — that's the field with the "what happened" text |
|
|
86
|
+
|
|
87
|
+
The `[key: string]: any` extension on the Alarm interface means each `sourceProduct` may carry product-specific extras (e.g. APM has `apm_alarm_unique_id`; UIM has `robot`/`hub`/`probe`). These reach the agent unchanged through `get_alarm`.
|
|
88
|
+
|
|
89
|
+
## Drilldown patterns
|
|
90
|
+
|
|
91
|
+
After `list_alarms`, the natural follow-ups:
|
|
92
|
+
|
|
93
|
+
1. **Full alarm body** — `get_alarm(alarmId)`. The full document, including source-product-specific fields.
|
|
94
|
+
2. **Lifecycle history** — `get_alarm_lifecycle(alarmId)`. Event-by-event timeline; status changes, enrichments, manual updates. This is also the **only place to find** the alarm's `services_impacted` (lifecycle event `name: "Services Impacted"`, `propValue` is the array of service names) and the alarm's actual `startTime` (lifecycle event `name: "Alarm Opened"`, `propName: startTime`, `propValue[0]` is the ISO time).
|
|
95
|
+
3. **Related alarms** — `get_related_alarms(alarmId)`. Historically correlated via `external_ids`; useful for "has this happened before on this entity?".
|
|
96
|
+
4. **Entity round-trip** — the alarm's `external_ids[0]` is the same format TAS uses for `vertex.externalId`. To go from alarm → entity, take that string and feed it into a TAS query (see `corpus_get('queries', '34-nassql-entity-to-metric-ids')` for the externalId-keyed pattern).
|
|
97
|
+
|
|
98
|
+
## What's deferred
|
|
99
|
+
|
|
100
|
+
Mutating alarm operations — `acknowledge`, `unacknowledge`, `assign`, `clear`, `trigger-webhook`, `create-alarm`, `update-field` — are **not** exposed on the MCP today. If the user asks the agent to operate on an alarm, point them at the CLI commands (`dx-do alarm acknowledge`, `dx-do alarm clear`, etc.).
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{$ as Pn,$a as V,Ab as Ot,Ac as Jn,Bb as It,Cb as je,Cc as C,Db as zn,Dc as Ie,Eb as jn,Ec as on,Fb as xt,Ha as Fn,Hb as N,Ib as J,Jb as ee,Kb as At,La as L,Mb as ge,Nb as be,Ob as Gn,Pc as ei,Qb as Kn,R as T,Ra as $n,Rb as qn,Rc as Nt,S as W,Sb as Yn,Sc as ti,Ta as Lt,Tb as Ge,Tc as Dt,U as F,Ua as Oe,Ub as Zn,Uc as te,Vb as D,W as m,Wa as Hn,Wb as Ke,X as Mn,Xb as qe,Yc as xe,Za as H,Zc as sn,_a as U,a as g,aa as kn,b as wt,ba as _e,bb as X,c as Dn,ca as Rn,cb as x,da as Le,db as Q,dc as P,fc as Qn,g as Xt,ga as We,gb as Vn,gc as tn,ha as _t,k as ke,ka as $,kb as B,la as I,lb as Wn,ma as Bn,mb as Un,na as E,nb as he,ob as fe,oc as Xn,pa as Ue,qc as ot,rc as j,ta as ze,tb as v,ub as Se,uc as G,vb as Ee,vc as f,wb as me,xb as Jt,xc as nn,yb as en,zb as it}from"./chunk-
|
|
1
|
+
import{$ as Pn,$a as V,Ab as Ot,Ac as Jn,Bb as It,Cb as je,Cc as C,Db as zn,Dc as Ie,Eb as jn,Ec as on,Fb as xt,Ha as Fn,Hb as N,Ib as J,Jb as ee,Kb as At,La as L,Mb as ge,Nb as be,Ob as Gn,Pc as ei,Qb as Kn,R as T,Ra as $n,Rb as qn,Rc as Nt,S as W,Sb as Yn,Sc as ti,Ta as Lt,Tb as Ge,Tc as Dt,U as F,Ua as Oe,Ub as Zn,Uc as te,Vb as D,W as m,Wa as Hn,Wb as Ke,X as Mn,Xb as qe,Yc as xe,Za as H,Zc as sn,_a as U,a as g,aa as kn,b as wt,ba as _e,bb as X,c as Dn,ca as Rn,cb as x,da as Le,db as Q,dc as P,fc as Qn,g as Xt,ga as We,gb as Vn,gc as tn,ha as _t,k as ke,ka as $,kb as B,la as I,lb as Wn,ma as Bn,mb as Un,na as E,nb as he,ob as fe,oc as Xn,pa as Ue,qc as ot,rc as j,ta as ze,tb as v,ub as Se,uc as G,vb as Ee,vc as f,wb as me,xb as Jt,xc as nn,yb as en,zb as it}from"./chunk-OV4PNSIK.js";function Ae(...t){if(t){let o=[];for(let e=0;e<t.length;e++){let n=t[e];if(!n)continue;let i=typeof n;if(i==="string"||i==="number")o.push(n);else if(i==="object"){let s=Array.isArray(n)?[Ae(...n)]:Object.entries(n).map(([r,a])=>a?r:void 0);o=s.length?o.concat(s.filter(r=>!!r)):o}}return o.join(" ").trim()}}function Re(t,o){return t?t.classList?t.classList.contains(o):new RegExp("(^| )"+o+"( |$)","gi").test(t.className):!1}function ae(t,o){if(t&&o){let e=n=>{Re(t,n)||(t.classList?t.classList.add(n):t.className+=" "+n)};[o].flat().filter(Boolean).forEach(n=>n.split(" ").forEach(e))}}function No(){return window.innerWidth-document.documentElement.offsetWidth}function ni(t){typeof t=="string"?ae(document.body,t||"p-overflow-hidden"):(t!=null&&t.variableName&&document.body.style.setProperty(t.variableName,No()+"px"),ae(document.body,t?.className||"p-overflow-hidden"))}function le(t,o){if(t&&o){let e=n=>{t.classList?t.classList.remove(n):t.className=t.className.replace(new RegExp("(^|\\b)"+n.split(" ").join("|")+"(\\b|$)","gi")," ")};[o].flat().filter(Boolean).forEach(n=>n.split(" ").forEach(e))}}function ii(t){typeof t=="string"?le(document.body,t||"p-overflow-hidden"):(t!=null&&t.variableName&&document.body.style.removeProperty(t.variableName),le(document.body,t?.className||"p-overflow-hidden"))}function st(t){for(let o of document?.styleSheets)try{for(let e of o?.cssRules)for(let n of e?.style)if(t.test(n))return{name:n,value:e.style.getPropertyValue(n).trim()}}catch(e){}return null}function Mt(t){let o={width:0,height:0};if(t){let[e,n]=[t.style.visibility,t.style.display],i=t.getBoundingClientRect();t.style.visibility="hidden",t.style.display="block",o.width=i.width||t.offsetWidth,o.height=i.height||t.offsetHeight,t.style.display=n,t.style.visibility=e}return o}function Pt(){let t=window,o=document,e=o.documentElement,n=o.getElementsByTagName("body")[0],i=t.innerWidth||e.clientWidth||n.clientWidth,s=t.innerHeight||e.clientHeight||n.clientHeight;return{width:i,height:s}}function an(t){return t?Math.abs(t.scrollLeft):0}function ln(){let t=document.documentElement;return(window.pageXOffset||an(t))-(t.clientLeft||0)}function dn(){let t=document.documentElement;return(window.pageYOffset||t.scrollTop)-(t.clientTop||0)}function Do(t){return t?getComputedStyle(t).direction==="rtl":!1}function Tr(t,o,e=!0){var n,i,s,r;if(t){let a=t.offsetParent?{width:t.offsetWidth,height:t.offsetHeight}:Mt(t),l=a.height,d=a.width,c=o.offsetHeight,u=o.offsetWidth,p=o.getBoundingClientRect(),h=dn(),b=ln(),y=Pt(),S,A,M="top";p.top+c+l>y.height?(S=p.top+h-l,M="bottom",S<0&&(S=h)):S=c+p.top+h,p.left+d>y.width?A=Math.max(0,p.left+b+u-d):A=p.left+b,Do(t)?t.style.insetInlineEnd=A+"px":t.style.insetInlineStart=A+"px",t.style.top=S+"px",t.style.transformOrigin=M,e&&(t.style.marginTop=M==="bottom"?`calc(${(i=(n=st(/-anchor-gutter$/))==null?void 0:n.value)!=null?i:"2px"} * -1)`:(r=(s=st(/-anchor-gutter$/))==null?void 0:s.value)!=null?r:"")}}function Mo(t,o){t&&(typeof o=="string"?t.style.cssText=o:Object.entries(o||{}).forEach(([e,n])=>t.style[e]=n))}function oe(t,o){if(t instanceof HTMLElement){let e=t.offsetWidth;if(o){let n=getComputedStyle(t);e+=parseFloat(n.marginLeft)+parseFloat(n.marginRight)}return e}return 0}function wr(t,o,e=!0,n=void 0){var i;if(t){let s=t.offsetParent?{width:t.offsetWidth,height:t.offsetHeight}:Mt(t),r=o.offsetHeight,a=o.getBoundingClientRect(),l=Pt(),d,c,u=n??"top";if(!n&&a.top+r+s.height>l.height?(d=-1*s.height,u="bottom",a.top+d<0&&(d=-1*a.top)):d=r,s.width>l.width?c=a.left*-1:a.left+s.width>l.width?c=(a.left+s.width-l.width)*-1:c=0,t.style.top=d+"px",t.style.insetInlineStart=c+"px",t.style.transformOrigin=u,e){let p=(i=st(/-anchor-gutter$/))==null?void 0:i.value;t.style.marginTop=u==="bottom"?`calc(${p??"2px"} * -1)`:p??""}}}function oi(t){if(t){let o=t.parentNode;return o&&o instanceof ShadowRoot&&o.host&&(o=o.host),o}return null}function Po(t){return!!(t!==null&&typeof t<"u"&&t.nodeName&&oi(t))}function Ye(t){return typeof Element<"u"?t instanceof Element:t!==null&&typeof t=="object"&&t.nodeType===1&&typeof t.nodeName=="string"}function si(t){let o=t;return t&&typeof t=="object"&&(Object.hasOwn(t,"current")?o=t.current:Object.hasOwn(t,"el")&&(Object.hasOwn(t.el,"nativeElement")?o=t.el.nativeElement:o=t.el)),Ye(o)?o:void 0}function ko(t,o){var e,n,i;if(t)switch(t){case"document":return document;case"window":return window;case"body":return document.body;case"@next":return o?.nextElementSibling;case"@prev":return o?.previousElementSibling;case"@first":return o?.firstElementChild;case"@last":return o?.lastElementChild;case"@child":return(e=o?.children)==null?void 0:e[0];case"@parent":return o?.parentElement;case"@grandparent":return(n=o?.parentElement)==null?void 0:n.parentElement;default:{if(typeof t=="string"){let a=t.match(/^@child\[(\d+)]/);return a?((i=o?.children)==null?void 0:i[parseInt(a[1],10)])||null:document.querySelector(t)||null}let s=(a=>typeof a=="function"&&"call"in a&&"apply"in a)(t)?t():t,r=si(s);return Po(r)?r:s?.nodeType===9?s:void 0}}}function cn(t,o){let e=ko(t,o);if(e)e.appendChild(o);else throw new Error("Cannot append "+o+" to "+t)}var rn;function _r(t){if(t){let o=getComputedStyle(t);return t.offsetWidth-t.clientWidth-parseFloat(o.borderLeftWidth)-parseFloat(o.borderRightWidth)}else{if(rn!=null)return rn;let o=document.createElement("div");Mo(o,{width:"100px",height:"100px",overflow:"scroll",position:"absolute",top:"-9999px"}),document.body.appendChild(o);let e=o.offsetWidth-o.clientWidth;return document.body.removeChild(o),rn=e,e}}function kt(t,o={}){if(Ye(t)){let e=(n,i)=>{var s,r;let a=(s=t?.$attrs)!=null&&s[n]?[(r=t?.$attrs)==null?void 0:r[n]]:[];return[i].flat().reduce((l,d)=>{if(d!=null){let c=typeof d;if(c==="string"||c==="number")l.push(d);else if(c==="object"){let u=Array.isArray(d)?e(n,d):Object.entries(d).map(([p,h])=>n==="style"&&(h||h===0)?`${p.replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase()}:${h}`:h?p:void 0);l=u.length?l.concat(u.filter(p=>!!p)):l}}return l},a)};Object.entries(o).forEach(([n,i])=>{if(i!=null){let s=n.match(/^on(.+)/);s?t.addEventListener(s[1].toLowerCase(),i):n==="p-bind"||n==="pBind"?kt(t,i):(i=n==="class"?[...new Set(e("class",i))].join(" ").trim():n==="style"?e("style",i).join(";").trim():i,(t.$attrs=t.$attrs||{})&&(t.$attrs[n]=i),t.setAttribute(n,i))}})}}function Ne(t,o={},...e){if(t){let n=document.createElement(t);return kt(n,o),n.append(...e),n}}function ri(t,o){if(t){t.style.opacity="0";let e=+new Date,n="0",i=function(){n=`${+t.style.opacity+(new Date().getTime()-e)/o}`,t.style.opacity=n,e=+new Date,+n<1&&("requestAnimationFrame"in window?requestAnimationFrame(i):setTimeout(i,16))};i()}}function Ro(t,o){return Ye(t)?Array.from(t.querySelectorAll(o)):[]}function ye(t,o){return Ye(t)?t.matches(o)?t:t.querySelector(o):null}function Lr(t,o){t&&document.activeElement!==t&&t.focus(o)}function Or(t,o){if(Ye(t)){let e=t.getAttribute(o);return isNaN(e)?e==="true"||e==="false"?e==="true":e:+e}}function ai(t,o=""){let e=Ro(t,`button:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${o},
|
|
2
2
|
[href]:not([tabindex = "-1"]):not([style*="display:none"]):not([hidden])${o},
|
|
3
3
|
input:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${o},
|
|
4
4
|
select:not([tabindex = "-1"]):not([disabled]):not([style*="display:none"]):not([hidden])${o},
|