@50arms/session-telemetry 0.0.0-stage → 0.1.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/README.md +68 -2
  2. package/dist/.source-hash +1 -0
  3. package/dist/activity-observer.d.ts +186 -0
  4. package/dist/activity-observer.js +917 -0
  5. package/dist/api-tool-names.d.ts +12 -0
  6. package/dist/api-tool-names.js +19 -0
  7. package/dist/browser.d.ts +29 -0
  8. package/dist/browser.js +10 -0
  9. package/dist/catalog-prices.d.ts +27 -0
  10. package/dist/catalog-prices.js +31 -0
  11. package/dist/claim-tracker.d.ts +53 -0
  12. package/dist/claim-tracker.js +213 -0
  13. package/dist/dispatch-usage.d.ts +321 -0
  14. package/dist/dispatch-usage.js +657 -0
  15. package/dist/git-head.d.ts +1 -0
  16. package/dist/git-head.js +19 -0
  17. package/dist/index.d.ts +35 -0
  18. package/dist/index.js +49 -0
  19. package/dist/internal-logger.d.ts +16 -0
  20. package/dist/internal-logger.js +27 -0
  21. package/dist/ledger-timing.d.ts +26 -0
  22. package/dist/ledger-timing.js +31 -0
  23. package/dist/pricing.d.ts +93 -0
  24. package/dist/pricing.js +77 -0
  25. package/dist/real-work.d.ts +13 -0
  26. package/dist/real-work.js +57 -0
  27. package/dist/session-log-watcher.d.ts +616 -0
  28. package/dist/session-log-watcher.js +1285 -0
  29. package/dist/session-title-marks.d.ts +2 -0
  30. package/dist/session-title-marks.js +16 -0
  31. package/dist/stats-wire.d.ts +345 -0
  32. package/dist/stats-wire.js +636 -0
  33. package/dist/subagent-live.d.ts +36 -0
  34. package/dist/subagent-live.js +153 -0
  35. package/dist/tool-summary.d.ts +19 -0
  36. package/dist/tool-summary.js +58 -0
  37. package/dist/transcript-timing.d.ts +100 -0
  38. package/dist/transcript-timing.js +231 -0
  39. package/dist/types.d.ts +25 -0
  40. package/dist/types.js +1 -0
  41. package/dist/usage-ledger.d.ts +256 -0
  42. package/dist/usage-ledger.js +581 -0
  43. package/dist/write-queue.d.ts +9 -0
  44. package/dist/write-queue.js +16 -0
  45. package/package.json +43 -4
@@ -0,0 +1,2 @@
1
+ /** `title` without the plugin's leading marks (and the whitespace after them). */
2
+ export declare function stripSessionTitleMarks(title: string): string;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * DX-6078 (from DX-5975 / DX-5992 / DX-5995 / DX-6004 / DX-6021): the 50arms plugin leads a desktop session's title with one mark
3
+ * (`sessionTitle`, claude-plugins `danxbot/hooks/plan/words.ts`): a hand (U+270B) while its plan has Needs You cards, a pause sign (U+23F8)
4
+ * while its agent has paused itself, a hammer (U+1F528), a warning sign (U+26A0) while it waits only on a person, or a green or red circle
5
+ * (U+1F7E2 / U+1F534) for a live or lost connection; the first four may carry the emoji selector U+FE0F. The marks are display only: they
6
+ * belong to the desktop app's label and never to the stored title.
7
+ *
8
+ * THE ONE LIST. The dashboard strips it on every session-title write (`optionalTitle`), so a session on an older MCP cannot store a mark, and a new mark needs only this list. The dashboard MCP's
9
+ * transcript reader (`session-title.ts`) takes this list over once the package carrying it is published and the MCP pins it. A run of marks is dropped, since two plugin versions marking one title in
10
+ * turn can stack several.
11
+ */
12
+ const TITLE_MARKS = /^(?:(?:\u{270B}\u{FE0F}?|\u{23F8}\u{FE0F}?|\u{1F528}\u{FE0F}?|\u{26A0}\u{FE0F}?|\u{1F7E2}|\u{1F534})\s*)+/u;
13
+ /** `title` without the plugin's leading marks (and the whitespace after them). */
14
+ export function stripSessionTitleMarks(title) {
15
+ return title.replace(TITLE_MARKS, "");
16
+ }
@@ -0,0 +1,345 @@
1
+ /**
2
+ * DX-2963 — the stats-write wire contract, shared by the worker (sender) and
3
+ * the dashboard (the one server writer, `usage-ledger.ts`). DB-free so a
4
+ * DB-less worker can import it.
5
+ *
6
+ * A stats write carries ONLY ledger entries (one per reply: the per-field
7
+ * maximum usage seen so far, the reply's tool-use ids) that are new or changed
8
+ * since the last acknowledged write — never totals. Every total, the cost,
9
+ * the turn count and the tool-call count are derived from the ledger on the
10
+ * server, and the response hands them back.
11
+ */
12
+ import { type CompactionEntry, type LedgerEntry, type LedgerUsage } from "./usage-ledger.js";
13
+ import { type ClaimState } from "./claim-tracker.js";
14
+ /**
15
+ * DX-2963 — cap on entries per stats write. A from-0 backlog (a reattach, a
16
+ * session read from the start) is sent as consecutive capped batches, so one
17
+ * request never carries an unbounded body or holds the dispatch lock for an
18
+ * unbounded time. 500 entries is well under a second of upsert work.
19
+ */
20
+ export declare const STATS_BATCH_CAP = 500;
21
+ /**
22
+ * DX-2954 — the two offsets a collector keeps per `(dispatch, source)`, where
23
+ * `source` is the value the ledger keys by (`main`, or a sub-agent id).
24
+ *
25
+ * - `acked` — the RESUME point: every line before it has had its ledger
26
+ * entry acknowledged (and, once DX-2956 ships, its log line too).
27
+ * - `delivered` — the highest line already handed to transcript subscribers.
28
+ *
29
+ * Lines between them are re-read on a restart and handed on as REPLAYS.
30
+ *
31
+ * `claims` (DX-3962) is the source's claim state AS OF `acked` - the card(s) the
32
+ * sub-agent holds, so a collector that resumes at `acked` attributes the next
33
+ * reply to the right card without re-reading the pickup that sits before it.
34
+ * A worker's is always empty: it has no claim tracker.
35
+ *
36
+ * "None stored" is the ABSENCE of a source's key, never `{acked: 0}` — 0 is a
37
+ * legitimate stored cursor meaning "start of file", and CP1 forbids a reader
38
+ * defaulting a missing persisted value.
39
+ */
40
+ export interface SourceCursor {
41
+ acked: number;
42
+ delivered: number;
43
+ claims: ClaimState;
44
+ }
45
+ /** DX-2954 — per-source cursors. An absent key means none stored (never 0). */
46
+ export type SourceCursors = Record<string, SourceCursor>;
47
+ /**
48
+ * DX-2954 — the collector found its stored cursor PAST the end of the file (it
49
+ * was replaced or truncated) and restarted that source at 0. Reported so the
50
+ * server can record a `transcript_cursor_past_eof` event with both numbers.
51
+ *
52
+ * This is the ONE sanctioned backwards move of a stored `acked`: without it the
53
+ * write would be refused as a `cursor_regression` and the source would tail
54
+ * nothing for the rest of the dispatch (the pre-card watcher's `size <=
55
+ * byteOffset` early return, silently).
56
+ */
57
+ export interface PastEofReset {
58
+ storedOffset: number;
59
+ fileSize: number;
60
+ }
61
+ /** DX-2954 — the payload form of a cursor: what a collector REPORTS. */
62
+ export interface SourceCursorReport extends SourceCursor {
63
+ pastEof?: PastEofReset;
64
+ }
65
+ /** DX-2954 — per-source cursor reports, as a stats write carries them. */
66
+ export type SourceCursorReports = Record<string, SourceCursorReport>;
67
+ /**
68
+ * DX-2954 — the running set's two kinds. `agent` is a sub-agent, produced from
69
+ * the TRANSCRIPT: one row per sub-agent transcript file the session-log watcher
70
+ * discovers (`packages/danx-session-telemetry/src/activity-observer.ts`; orchestrator decision, DX-2954
71
+ * comment 8004), and — for an operator session — from the plugin's
72
+ * `SubagentStart` / `SubagentStop` hooks. The transcript ends a row from the
73
+ * spawner's spawn result (foreground, DX-5576) or task notification
74
+ * (background, DX-4498); `SubagentStop` is the fallback finish. `bash` is a
75
+ * background script, produced only by the plugin's `PostToolUse` hook on a
76
+ * backgrounded Bash call (DX-3284; the transcript cannot see it). No hook event
77
+ * observes a background shell FINISHING (verified against the hooks reference —
78
+ * see the Step 0 note on DX-2954), so an open `bash` row is closed by the
79
+ * dispatch's own terminal write, never by inferring an end from transcript
80
+ * lines.
81
+ */
82
+ export declare const ACTIVITY_KINDS: readonly ["agent", "bash"];
83
+ export type ActivityKind = (typeof ACTIVITY_KINDS)[number];
84
+ /**
85
+ * DX-2954 — one activity's current state, as a stats write reports it. Applied
86
+ * as an idempotent upsert keyed by `(dispatch, kind, activityId)`: a hook that
87
+ * fires twice, or a batch resent after a failed flush, must not duplicate it.
88
+ *
89
+ * `activityId` for a sub-agent is its transcript file's basename
90
+ * (`agent-<agent_id>`) — the SAME value the ledger credits its tokens under as
91
+ * `source`, which is how per-sub-agent tokens join to the running set without
92
+ * this table carrying a token column. A hook producer builds it from the hook's
93
+ * `agent_id` as `agent-${agent_id}` (never the bare `agent_id`, and never from
94
+ * `transcript_path`, which on these events is the MAIN session's transcript) or
95
+ * it upserts a duplicate row. For a background script it is the Bash call's
96
+ * `tool_use_id`.
97
+ */
98
+ export interface ActivityChange {
99
+ kind: ActivityKind;
100
+ activityId: string;
101
+ /** The `agent_type` hook field; null for a background script. */
102
+ agentType: string | null;
103
+ /** The Bash call's `description`; null for a sub-agent. */
104
+ description: string | null;
105
+ startedAt: number;
106
+ lastActivityAt: number;
107
+ /** Epoch ms when it finished, or null while it is still running. */
108
+ finishedAt: number | null;
109
+ /**
110
+ * DX-4498 — the sub-agent that spawned this one (`agent-<parentAgentId>` from its `meta.json`), or null for a
111
+ * sub-agent the session itself spawned and for a background script.
112
+ */
113
+ parentActivityId: string | null;
114
+ /** DX-4498 — the reasoning effort its latest reply ran at (the assistant line's own `effort`); null until one is read. */
115
+ effort: string | null;
116
+ /**
117
+ * DX-4498 — what it is doing now: its latest tool call as `<Tool>` or `<Tool>: <label>`, where the label is only ever
118
+ * text the agent wrote AS a label (see {@link describeToolCall}); null until it calls a tool.
119
+ */
120
+ currentActivity: string | null;
121
+ /** DX-4498 — how it ended, when an explicit end event named it; null while running and for an end that named none. */
122
+ endStatus: ActivityEndStatus | null;
123
+ /**
124
+ * DX-4508 — the card its spawning `Agent` call names: the first card id in its (redacted) `description`, else the
125
+ * first anywhere in its brief; null when neither names one. The name stays `briefIssueId` (and the column
126
+ * `brief_issue_id`): renaming a required wire field would make every relay already published fail the strict parser.
127
+ */
128
+ briefIssueId: string | null;
129
+ /**
130
+ * DX-5333 — the repo HEAD in the sub-agent's checkout when it started (`git rev-parse HEAD` at its first transcript line's
131
+ * `cwd`), so a replay can start from the same code. Optional on the wire like `activityMessages`: absent means "this collector
132
+ * does not report it" (an older one), never "reset"; null means it could not be read (no git checkout, or a source the
133
+ * collector found already running). The first stamp wins, server-side and in {@link collapseActivityChanges}.
134
+ */
135
+ startSha?: string | null;
136
+ /**
137
+ * DX-5898 - the leading word of its brief when shaped like an agent profile name (`<profile> <CARD-ID>`, DX-5899), else null. Optional
138
+ * like {@link startSha}: absent means an older collector; the first non-null word wins, server-side and in {@link collapseActivityChanges}.
139
+ */
140
+ briefProfile?: string | null;
141
+ }
142
+ /**
143
+ * DX-5333 — which part of a sub-agent's conversation a stored message is: `brief` (the prompt its spawner gave it), `followup`
144
+ * (a later message sent to it) or `final` (a reply that ended its turn).
145
+ */
146
+ export declare const ACTIVITY_MESSAGE_KINDS: readonly ["brief", "followup", "final"];
147
+ export type ActivityMessageKind = (typeof ACTIVITY_MESSAGE_KINDS)[number];
148
+ /** DX-5333 — the longest message text a collector sends (and the server stores); a longer one is cut by the collector. */
149
+ export declare const ACTIVITY_MESSAGE_MAX_CHARS = 100000;
150
+ /** DX-5333 — cap on messages per stats write, so one write's lock hold stays bounded; the rest stay queued for the next. */
151
+ export declare const ACTIVITY_MESSAGE_BATCH_CAP = 100;
152
+ /**
153
+ * DX-5333 — one message of a sub-agent's conversation, as a stats write reports it. Applied as an idempotent insert keyed by
154
+ * `(dispatch, activityId, messageKey)`: `messageKey` is the transcript line's own `uuid`, so a collector that re-reads a
155
+ * file after a restart, or a batch resent after a failed flush, never stores a message twice. `text` has had its secrets
156
+ * masked (`redactSecrets`) before it leaves the collector, and the server masks it again.
157
+ */
158
+ export interface ActivityMessage {
159
+ activityId: string;
160
+ kind: ActivityMessageKind;
161
+ messageKey: string;
162
+ text: string;
163
+ /** Epoch ms of the transcript line. */
164
+ at: number;
165
+ /** The checkout the sub-agent was in when the line was written (the line's own `cwd`), or null when it carried none. */
166
+ cwd: string | null;
167
+ /** The git branch the line was written on (the line's own `gitBranch`), or null when it carried none. */
168
+ gitBranch: string | null;
169
+ }
170
+ /**
171
+ * DX-5333 — a card problem the sub-agent itself created (its own `50arms_api` `POST /api/issues/<id>/problems` call and the
172
+ * 201 that answered it), so a replay can tell the builder's problems from its spawner's: `issue_history.via_key` is the
173
+ * spawner's key and cannot.
174
+ */
175
+ export interface ActivityProblemLink {
176
+ activityId: string;
177
+ /** DX-5516 (PLAN-50 G-2): the problem's number within its team (the n of `PBLM-n`), as the create answer names it (`ref_num`); the dashboard resolves it within the dispatch's team. */
178
+ problemRefNum: number;
179
+ }
180
+ /** DX-5333 — cap on problem links per stats write. */
181
+ export declare const ACTIVITY_PROBLEM_BATCH_CAP = 100;
182
+ /**
183
+ * DX-4498 / DX-5576 — how an activity ended, when something explicitly said so: a foreground spawn's own
184
+ * `tool_result` (`completed`; `failed` if errored; `stopped` if interrupted or rejected), Claude Code's
185
+ * background-task notification (`completed`, `failed`, and `killed`/`stopped` as `stopped`), or the session ending
186
+ * while it still ran (`stopped`).
187
+ */
188
+ export declare const ACTIVITY_END_STATUSES: readonly ["completed", "failed", "stopped"];
189
+ export type ActivityEndStatus = (typeof ACTIVITY_END_STATUSES)[number];
190
+ /** DX-4498 — the longest `currentActivity` a collector sends (and the server stores). */
191
+ export declare const CURRENT_ACTIVITY_MAX_CHARS = 120;
192
+ export interface StatsPayload {
193
+ entries: LedgerEntry[];
194
+ /**
195
+ * DX-2954 — this collector's cursors for every source it has opened. Optional
196
+ * because an old worker in the deploy window sends none; absent means
197
+ * "nothing to store", never "reset to 0".
198
+ */
199
+ sourceCursors?: SourceCursorReports;
200
+ /**
201
+ * DX-2954 — the running set's changes since the last write. Optional for the
202
+ * same deploy-window reason as {@link StatsPayload.sourceCursors}.
203
+ */
204
+ activities?: ActivityChange[];
205
+ /**
206
+ * DX-5333 — the messages of sub-agent conversations read since the last write (see {@link ActivityMessage}), at most
207
+ * {@link ACTIVITY_MESSAGE_BATCH_CAP} per payload. Optional for the same deploy-window reason as {@link StatsPayload.compactions}:
208
+ * absent means "none to report", never "none exist".
209
+ */
210
+ activityMessages?: ActivityMessage[];
211
+ /** DX-5333 — the problems sub-agents created since the last write (see {@link ActivityProblemLink}); optional like {@link StatsPayload.activityMessages}. */
212
+ activityProblems?: ActivityProblemLink[];
213
+ /**
214
+ * DX-4922 — compactions read since the last write, at most {@link COMPACTION_BATCH_CAP} per payload; each an idempotent
215
+ * upsert keyed by the boundary's id. Optional for the same deploy-window reason as {@link StatsPayload.sourceCursors}:
216
+ * a collector that predates compaction detection sends none; absent means "none to report", never "none exist".
217
+ */
218
+ compactions?: CompactionEntry[];
219
+ /**
220
+ * DX-2954 — the session's own transcript file path, recorded on the
221
+ * dispatch's `jsonl_path`.
222
+ *
223
+ * **This is the ONE path field of a heartbeat's ledger and cursors, and the ONE
224
+ * exception to the card's privacy rule** that they carry only numbers, ids,
225
+ * model names, the `speed` value and timestamps. It is sent once, in the
226
+ * first stats-bearing write, because an operator session has no other way to
227
+ * tell the server where its transcript lives (a worker's tracker already
228
+ * records it from the watcher). The strict parser below allows a path HERE
229
+ * and in {@link ActivityMessage.cwd} (DX-5333, with the sub-agent's text,
230
+ * admin-readable only) and nowhere else — no other key may carry one.
231
+ */
232
+ transcriptPath?: string;
233
+ }
234
+ /** The dispatch's flat totals, as derived from its ledger. */
235
+ export interface UsageTotals {
236
+ tokensIn: number;
237
+ tokensOut: number;
238
+ cacheRead: number;
239
+ /** 5-minute + 1-hour (+ any pre-card unsplit baseline) cache writes. */
240
+ cacheWrite: number;
241
+ tokensTotal: number;
242
+ costUsd: number;
243
+ turnCount: number;
244
+ toolCallCount: number;
245
+ }
246
+ /** Per-source (main / sub-agent id) credited usage. */
247
+ export interface SourceUsage extends LedgerUsage {
248
+ costUsd: number;
249
+ }
250
+ export interface StatsResponse {
251
+ totals: UsageTotals;
252
+ bySource: Record<string, SourceUsage>;
253
+ /**
254
+ * Per sent `message_id`, the per-field total now credited for that reply
255
+ * across ALL dispatches — what the worker's ceiling estimate subtracts.
256
+ */
257
+ perMessage: Record<string, LedgerUsage>;
258
+ /**
259
+ * DX-2954 — the dispatch's STORED cursors after this write, per source. This
260
+ * is what a process takes at start to know where to read on from; an absent
261
+ * source key means none stored (distinct from 0).
262
+ */
263
+ sourceCursors: SourceCursors;
264
+ /**
265
+ * DX-2954 — sources whose reported `acked` was LOWER than the stored one and
266
+ * was therefore refused (a `cursor_regression` event was recorded for each).
267
+ * The rest of the write still applied. Empty on the happy path.
268
+ */
269
+ cursorRegressions: string[];
270
+ /** DX-2954 — running (`finished_at IS NULL`) activities after this write. */
271
+ runningActivities: number;
272
+ }
273
+ export declare function chunkEntries(entries: readonly LedgerEntry[], cap?: number): LedgerEntry[][];
274
+ export declare class StatsPayloadError extends Error {
275
+ }
276
+ /**
277
+ * DX-2954 — cap on activity rows per stats write. The running set is bounded by
278
+ * how many sub-agents and background scripts one dispatch has ever started;
279
+ * this keeps a malformed or runaway sender from holding the dispatch lock while
280
+ * it upserts an unbounded list.
281
+ */
282
+ export declare const ACTIVITY_BATCH_CAP = 500;
283
+ /** DX-4922 — cap on compaction rows per stats write; a session compacts a handful of times, so a longer list is a defect. */
284
+ export declare const COMPACTION_BATCH_CAP = 100;
285
+ /** DX-2954 — cap on sources per stats write, for the same reason. */
286
+ export declare const CURSOR_BATCH_CAP = 500;
287
+ /**
288
+ * DX-2954 — collapse a queue of activity changes to ONE per
289
+ * `(kind, activityId)`, applying the SAME merge the server's upsert applies.
290
+ *
291
+ * Both sides need this rule, so it is stated once, here, beside the wire types:
292
+ * the server merges an incoming row against what it has stored, and a SENDER
293
+ * merges the changes it has queued since its last write against each other. The
294
+ * two are the same operation on the same monotone fields, so a client-side
295
+ * collapse is lossless — the server reaches the identical row either way.
296
+ *
297
+ * Why a sender needs it at all: a producer reports an activity's full current
298
+ * state every time anything about it moves, and a chatty sub-agent moves its
299
+ * `lastActivityAt` continuously. Queuing those raw would grow one entry per
300
+ * change between writes, blow {@link ACTIVITY_BATCH_CAP}, and take the WHOLE
301
+ * stats write down with it — not merely the activity part — for a payload that
302
+ * describes a handful of activities.
303
+ *
304
+ * A plain last-one-wins would be WRONG here, which is why this merges field by
305
+ * field: a still-running report queued after a finish must not un-finish the row unless its activity is later than the finish ({@link mergedFinish}).
306
+ */
307
+ export declare function collapseActivityChanges(changes: readonly ActivityChange[]): ActivityChange[];
308
+ /**
309
+ * DX-6815 — a finish this close to (or before) an activity's latest activity still ends it. A finish is stamped from the line that reports it,
310
+ * which Claude Code writes after the sub-agent's last line: in production the gap is 0 to 90 ms, and the next gap seen is 11 seconds, a sub-agent
311
+ * resumed with `SendMessage`. The server's upsert and {@link collapseActivityChanges} both read it from here.
312
+ */
313
+ export declare const ACTIVITY_RESUME_GRACE_MS = 10000;
314
+ /**
315
+ * DX-6815 — the finish and end status both sides apply when `incoming` meets `stored`. The latest finish known stands only while the latest activity
316
+ * is not later than it by more than {@link ACTIVITY_RESUME_GRACE_MS}: later activity means the sub-agent was resumed, so it is running again
317
+ * (`finishedAt` and `endStatus` null), and a finish older than the activity is one of an earlier life. While it stands, the latest explicit end status wins
318
+ * (a notification read after the session's own close names how it really ended). Every operand is a maximum, so writes may arrive in any order.
319
+ */
320
+ export declare function mergedFinish(stored: Pick<ActivityChange, "lastActivityAt" | "finishedAt" | "endStatus">, incoming: Pick<ActivityChange, "lastActivityAt" | "finishedAt" | "endStatus">): Pick<ActivityChange, "finishedAt" | "endStatus">;
321
+ /**
322
+ * DX-3962 - whether `raw` is a well-formed claim state. A STORED cursor from a server that predates attribution has
323
+ * none, and a collector must refuse such an answer instead of dereferencing it.
324
+ */
325
+ export declare function isClaimState(raw: unknown): raw is ClaimState;
326
+ /** DX-5898: the longest profile word stored. */
327
+ export declare const PROFILE_WORD_MAX_LENGTH = 64;
328
+ /** DX-5333 - a full git object id (SHA-1 or SHA-256), as `git rev-parse HEAD` prints it. */
329
+ export declare const GIT_OBJECT_ID: RegExp;
330
+ /**
331
+ * Strict parse of a stats body (fail loud — a malformed entry is a worker
332
+ * bug, never coerced). Refuses more than {@link STATS_BATCH_CAP} entries, and
333
+ * (DX-2954) any key outside {@link STATS_PAYLOAD_KEYS}.
334
+ */
335
+ export declare function parseStatsPayload(body: unknown): StatsPayload;
336
+ /**
337
+ * DX-2963 — a terminal dispatch is never written: the server refuses a stats
338
+ * write for one. Defined here (DB-free) so both sinks throw the SAME error —
339
+ * the getPool-direct writer directly, the worker client on the route's 409.
340
+ */
341
+ export declare class DispatchUsageTerminalError extends Error {
342
+ readonly dispatchId: string;
343
+ readonly status: string;
344
+ constructor(dispatchId: string, status: string);
345
+ }