@generative-a11y/devtools 0.1.0 → 0.2.0

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 CHANGED
@@ -11,17 +11,17 @@ npm install --save-dev @generative-a11y/devtools
11
11
  ```
12
12
 
13
13
  ```ts
14
- import { createDevtoolsStore } from "@generative-a11y/devtools";
15
- import { THREAD_ADAPTER_METADATA } from "@generative-a11y/assistant-ui";
14
+ import { createStore } from "@generative-a11y/devtools";
15
+ import { adapterInfo } from "@generative-a11y/assistant-ui";
16
16
 
17
- const store = createDevtoolsStore({ maxEntries: 250 });
17
+ const store = createStore({ maxEntries: 250 });
18
18
  const detach = store.attachRuntime({
19
19
  id: "support",
20
20
  runtime,
21
21
  source: {
22
- adapter: THREAD_ADAPTER_METADATA.name,
23
- fidelity: THREAD_ADAPTER_METADATA.fidelity,
24
- evidence: THREAD_ADAPTER_METADATA.observedRuntimeMethods,
22
+ adapter: adapterInfo.name,
23
+ fidelity: adapterInfo.fidelity,
24
+ evidence: adapterInfo.observedRuntimeMethods,
25
25
  },
26
26
  });
27
27
  const unsubscribe = store.subscribe(renderDiagnostics);
@@ -39,9 +39,9 @@ store.dispose();
39
39
 
40
40
  ## Store API
41
41
 
42
- - `createDevtoolsStore({ maxEntries })` creates an isolated store. `maxEntries`
43
- defaults to `250`, must be a positive safe integer, and bounds the retained
44
- ring buffer. `droppedCount` reports records evicted since the last `clear()`.
42
+ - `createStore({ maxEntries })` creates an isolated store. `maxEntries` defaults
43
+ to `250`, must be a positive safe integer, and bounds the retained ring
44
+ buffer. `droppedCount` reports records evicted since the last `clear()`.
45
45
  - `attachRuntime({ id, runtime })` validates a non-empty ID, subscribes only to
46
46
  public diagnostics, captures an initial safe snapshot, and returns an
47
47
  idempotent detach function. Attaching the same ID replaces its subscription
@@ -75,15 +75,20 @@ Pass `source` when attaching a runtime driven by an adapter. This is an
75
75
  explicit, serializable declaration from the integration, not framework detection
76
76
  by devtools. It lets an inspector show the adapter name, documented public
77
77
  evidence and declared fidelity without filling gaps in the lifecycle trace.
78
- `interruption` and `retries` accept `exact`, `action-wrapper`, or `unavailable`.
79
- `connection` accepts those values plus `inferred`, because some integrations can
80
- only derive connection state from another documented public signal. The store
81
- freezes a copy of this metadata and includes it in its redacted export. Each
82
- captured record references an opaque `runtimeSourceId`. Source revisions remain
83
- immutable and exportable for as long as a retained record references them, even
84
- after a runtime detaches or the same runtime ID is reattached with different
85
- metadata. Unreferenced revisions are removed with ring-buffer eviction so
86
- repeated attachment cannot create unbounded source history.
78
+ Workflow fidelity distinguishes runs, steps, hierarchy, tools, interactions,
79
+ replay, reconnection, and unsupported custom events as exact, partial, or
80
+ unavailable where applicable. The inspector also shows content-free run and step
81
+ parentage, attempt boundaries, active or terminal state, and associated entity
82
+ IDs from the core diagnostic snapshot. `interruption` and `retries` accept
83
+ `exact`, `action-wrapper`, or `unavailable`. `connection` accepts those values
84
+ plus `inferred`, because some integrations can only derive connection state from
85
+ another documented public signal. The store freezes a copy of this metadata and
86
+ includes it in its redacted export. Each captured record references an opaque
87
+ `runtimeSourceId`. Source revisions remain immutable and exportable for as long
88
+ as a retained record references them, even after a runtime detaches or the same
89
+ runtime ID is reattached with different metadata. Unreferenced revisions are
90
+ removed with ring-buffer eviction so repeated attachment cannot create unbounded
91
+ source history.
87
92
 
88
93
  Use an adapter package's exported metadata where it fits the integration. For
89
94
  custom adapters, provide only public signals that justify normalized events. Do
@@ -95,15 +100,30 @@ subscribes to a runtime.
95
100
  ## Browser delivery correlation
96
101
 
97
102
  The store intentionally does not import `@generative-a11y/dom`. Connect the
98
- announcer's public diagnostic callback yourself to capture a content-free
103
+ active binding's `onDelivery` callback yourself to capture a content-free
99
104
  delivery record alongside runtime decisions:
100
105
 
101
106
  ```ts
102
- const announcer = createDOMAnnouncer({
103
- onDiagnostic(result) {
107
+ import { createRuntime } from "@generative-a11y/core";
108
+ import { bindRuntime } from "@generative-a11y/dom";
109
+ import { createStore } from "@generative-a11y/devtools";
110
+
111
+ export const runtime = createRuntime();
112
+ export const store = createStore();
113
+ const detach = store.attachRuntime({ id: "support", runtime });
114
+ const delivery = bindRuntime(runtime, {
115
+ onDelivery(result) {
104
116
  store.recordDelivery({ runtimeId: "support", result });
105
117
  },
106
118
  });
119
+
120
+ // Dispatch your host events through runtime. Keep this binding for the session.
121
+ export function disposeChat() {
122
+ delivery.dispose();
123
+ detach();
124
+ store.dispose();
125
+ runtime.dispose();
126
+ }
107
127
  ```
108
128
 
109
129
  This exposes the browser-level method and status (`aria-notify`, fallback live
@@ -128,12 +148,28 @@ focus. The overlay does not trap focus, create a live region, modify host
128
148
  layout, or install global shortcuts.
129
149
 
130
150
  ```ts
131
- import { mountDevtoolsOverlay } from "@generative-a11y/devtools/overlay";
151
+ import { mountOverlay } from "@generative-a11y/devtools/overlay";
132
152
 
133
- const overlay = mountDevtoolsOverlay({ store });
134
- overlay.dispose();
153
+ const overlay = mountOverlay({ store });
154
+ // Call overlay.dispose() when removing the workbench.
135
155
  ```
136
156
 
157
+ ## Attention decisions
158
+
159
+ When core attention control is enabled, runtime snapshots include the observed
160
+ mode, explicit user override, and effective normal/quiet state. The inspector
161
+ shows these values under policy and scheduling. `attention-updated` explains
162
+ control transitions; `attention-quiet` explains discarded routine output without
163
+ an announcement backlog.
164
+
165
+ `DevtoolsRecord.attentionMode` and `attentionOverride` preserve only recognized
166
+ enum values from control events. Invalid mode payloads are omitted. Exports
167
+ contain no DOM targets or reading history; the observation named
168
+ `reading-history` means only the latest registered response is outside the
169
+ intersection while the document is visible and focused. It does not track a
170
+ screen-reader virtual cursor or prove what someone read. Existing trace schema 1
171
+ consumers can ignore the optional fields.
172
+
137
173
  ## Documentation
138
174
 
139
175
  - [Devtools guide](https://generativea11y.com/docs/devtools)
@@ -149,3 +185,17 @@ overlay.dispose();
149
185
  - [`@generative-a11y/core/testing`](https://generativea11y.com/api/core/testing)
150
186
  provides deterministic replay and semantic test assertions without another
151
187
  package installation.
188
+
189
+ ## Localized announcements
190
+
191
+ Runtime snapshots include optional `messages: { catalogId, locale }`. The
192
+ inspector exposes only these fields and `catalog-format-error`; catalog
193
+ messages, formatter arguments/functions and error text are not retained. Use a
194
+ non-sensitive catalog ID.
195
+
196
+ See the
197
+ [localization guide](https://generativea11y.com/docs/localized-announcements).
198
+
199
+ For React, pass the same callback through
200
+ `<A11yProvider delivery={{ onDelivery }}>`. Do not create another announcer
201
+ beside the provider; its existing delivery path supplies the reports.
package/dist/index.cjs CHANGED
@@ -20,7 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- createDevtoolsStore: () => createDevtoolsStore
23
+ createStore: () => createStore
24
24
  });
25
25
  module.exports = __toCommonJS(index_exports);
26
26
  function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
@@ -33,7 +33,27 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
33
33
  at: event.at,
34
34
  kind: event.kind,
35
35
  sourceType: event.event.type,
36
+ ...event.event.type === "attention.changed" && [
37
+ "foreground",
38
+ "background",
39
+ "reading-history",
40
+ "away",
41
+ "unknown"
42
+ ].includes(event.event.mode) ? { attentionMode: event.event.mode } : {},
43
+ ...event.event.type === "attention.override" && ["auto", "normal", "quiet"].includes(event.event.mode) ? { attentionOverride: event.event.mode } : {},
36
44
  ...event.event.eventId ? { sourceEventId: event.event.eventId } : {},
45
+ ..."runId" in event.event && event.event.runId ? { runId: event.event.runId } : {},
46
+ ..."runInstanceId" in event.event && event.event.runInstanceId ? { runInstanceId: event.event.runInstanceId } : {},
47
+ ..."nextRunInstanceId" in event.event && event.event.nextRunInstanceId ? { nextRunInstanceId: event.event.nextRunInstanceId } : {},
48
+ ..."parentRunId" in event.event && event.event.parentRunId ? { parentRunId: event.event.parentRunId } : {},
49
+ ..."parentRunInstanceId" in event.event && event.event.parentRunInstanceId ? { parentRunInstanceId: event.event.parentRunInstanceId } : {},
50
+ ..."stepId" in event.event && event.event.stepId ? { stepId: event.event.stepId } : {},
51
+ ..."stepInstanceId" in event.event && event.event.stepInstanceId ? { stepInstanceId: event.event.stepInstanceId } : {},
52
+ ..."nextStepInstanceId" in event.event && event.event.nextStepInstanceId ? { nextStepInstanceId: event.event.nextStepInstanceId } : {},
53
+ ..."parentStepId" in event.event && event.event.parentStepId ? { parentStepId: event.event.parentStepId } : {},
54
+ ..."parentStepInstanceId" in event.event && event.event.parentStepInstanceId ? { parentStepInstanceId: event.event.parentStepInstanceId } : {},
55
+ ..."parentToolId" in event.event && event.event.parentToolId ? { parentToolId: event.event.parentToolId } : {},
56
+ ..."parentResponseId" in event.event && event.event.parentResponseId ? { parentResponseId: event.event.parentResponseId } : {},
37
57
  ..."responseId" in event.event ? { responseId: event.event.responseId } : {},
38
58
  ..."responseInstanceId" in event.event && event.event.responseInstanceId ? { responseInstanceId: event.event.responseInstanceId } : {},
39
59
  ..."nextResponseInstanceId" in event.event && event.event.nextResponseInstanceId ? { nextResponseInstanceId: event.event.nextResponseInstanceId } : {},
@@ -63,6 +83,10 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
63
83
  ...event.decision.responseId ? { responseId: event.decision.responseId } : {},
64
84
  ...event.decision.toolId ? { toolId: event.decision.toolId } : {},
65
85
  ...event.decision.interactionId ? { interactionId: event.decision.interactionId } : {},
86
+ ...event.decision.runId ? { runId: event.decision.runId } : {},
87
+ ...event.decision.runInstanceId ? { runInstanceId: event.decision.runInstanceId } : {},
88
+ ...event.decision.stepId ? { stepId: event.decision.stepId } : {},
89
+ ...event.decision.stepInstanceId ? { stepInstanceId: event.decision.stepInstanceId } : {},
66
90
  ...event.decision.scheduledAt !== void 0 ? { scheduledAt: event.decision.scheduledAt } : {},
67
91
  ...event.decision.dueAt !== void 0 ? { dueAt: event.decision.dueAt } : {},
68
92
  ...event.decision.delayMs !== void 0 ? { delayMs: event.decision.delayMs } : {},
@@ -86,6 +110,25 @@ function copyRuntimeSource(source) {
86
110
  throw new TypeError("source fidelity must be an object");
87
111
  const lifecycleFidelity = /* @__PURE__ */ new Set(["exact", "action-wrapper", "unavailable"]);
88
112
  const connectionFidelity = /* @__PURE__ */ new Set([...lifecycleFidelity, "inferred"]);
113
+ const workflowFidelity = /* @__PURE__ */ new Set(["exact", "partial", "unavailable"]);
114
+ for (const field of [
115
+ "runs",
116
+ "steps",
117
+ "hierarchy",
118
+ "tools",
119
+ "interactions",
120
+ "replay",
121
+ "reconnection"
122
+ ]) {
123
+ if (fidelity[field] !== void 0 && !workflowFidelity.has(fidelity[field]))
124
+ throw new TypeError(
125
+ `source ${field} fidelity contains an unsupported value`
126
+ );
127
+ }
128
+ if (fidelity.customEvents !== void 0 && fidelity.customEvents !== "explicit-mapping" && fidelity.customEvents !== "unsupported")
129
+ throw new TypeError(
130
+ "source custom event fidelity contains an unsupported value"
131
+ );
89
132
  if (!lifecycleFidelity.has(fidelity.interruption))
90
133
  throw new TypeError(
91
134
  "source interruption fidelity contains an unsupported value"
@@ -109,6 +152,14 @@ function copyRuntimeSource(source) {
109
152
  adapter: source.adapter.trim(),
110
153
  evidence: Object.freeze(source.evidence.map((item) => item.trim())),
111
154
  fidelity: Object.freeze({
155
+ ...fidelity.runs ? { runs: fidelity.runs } : {},
156
+ ...fidelity.steps ? { steps: fidelity.steps } : {},
157
+ ...fidelity.hierarchy ? { hierarchy: fidelity.hierarchy } : {},
158
+ ...fidelity.tools ? { tools: fidelity.tools } : {},
159
+ ...fidelity.interactions ? { interactions: fidelity.interactions } : {},
160
+ ...fidelity.replay ? { replay: fidelity.replay } : {},
161
+ ...fidelity.reconnection ? { reconnection: fidelity.reconnection } : {},
162
+ ...fidelity.customEvents ? { customEvents: fidelity.customEvents } : {},
112
163
  interruption: fidelity.interruption,
113
164
  retries: fidelity.retries,
114
165
  connection: fidelity.connection,
@@ -133,6 +184,10 @@ function asDeliveryRecord(input, captureSequence, runtimeSourceId) {
133
184
  ...result.responseId ? { responseId: result.responseId } : {},
134
185
  ...result.toolId ? { toolId: result.toolId } : {},
135
186
  ...result.interactionId ? { interactionId: result.interactionId } : {},
187
+ ...result.runId ? { runId: result.runId } : {},
188
+ ...result.runInstanceId ? { runInstanceId: result.runInstanceId } : {},
189
+ ...result.stepId ? { stepId: result.stepId } : {},
190
+ ...result.stepInstanceId ? { stepInstanceId: result.stepInstanceId } : {},
136
191
  ...result.error?.name ? { errorName: result.error.name } : {}
137
192
  });
138
193
  }
@@ -143,8 +198,28 @@ function copyRuntimeSnapshot(source) {
143
198
  policy: Object.freeze({
144
199
  ...source.policy,
145
200
  text: Object.freeze({ ...source.policy.text }),
146
- tools: Object.freeze({ ...source.policy.tools })
201
+ tools: Object.freeze({ ...source.policy.tools }),
202
+ workflows: Object.freeze({ ...source.policy.workflows }),
203
+ ...source.policy.attention ? {
204
+ attention: Object.freeze({
205
+ ...source.policy.attention,
206
+ quietWhen: Object.freeze([...source.policy.attention.quietWhen])
207
+ })
208
+ } : {}
147
209
  }),
210
+ ...source.messages ? {
211
+ messages: Object.freeze({
212
+ catalogId: source.messages.catalogId,
213
+ locale: source.messages.locale
214
+ })
215
+ } : {},
216
+ ...source.attention ? {
217
+ attention: Object.freeze({
218
+ observed: source.attention.observed,
219
+ override: source.attention.override,
220
+ effective: source.attention.effective
221
+ })
222
+ } : {},
148
223
  pending: Object.freeze({
149
224
  announcements: Object.freeze(
150
225
  source.pending.announcements.map((item) => Object.freeze({ ...item }))
@@ -159,10 +234,20 @@ function copyRuntimeSnapshot(source) {
159
234
  tools: Object.freeze(
160
235
  source.tools.map((item) => Object.freeze({ ...item }))
161
236
  ),
237
+ ...source.runs ? {
238
+ runs: Object.freeze(
239
+ source.runs.map((item) => Object.freeze({ ...item }))
240
+ )
241
+ } : {},
242
+ ...source.steps ? {
243
+ steps: Object.freeze(
244
+ source.steps.map((item) => Object.freeze({ ...item }))
245
+ )
246
+ } : {},
162
247
  pendingCount: source.pendingCount
163
248
  });
164
249
  }
165
- function createDevtoolsStore(options = {}) {
250
+ function createStore(options = {}) {
166
251
  const maxEntries = options.maxEntries ?? 250;
167
252
  if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0)
168
253
  throw new RangeError("maxEntries must be a positive safe integer");
@@ -369,5 +454,5 @@ function createDevtoolsStore(options = {}) {
369
454
  }
370
455
  // Annotate the CommonJS export names for ESM import in node:
371
456
  0 && (module.exports = {
372
- createDevtoolsStore
457
+ createStore
373
458
  });
package/dist/index.d.cts CHANGED
@@ -1,7 +1,9 @@
1
- import { GenerativeA11yRuntime, AdapterFidelity, RuntimeDiagnosticEventV1, RuntimeDiagnosticSnapshotV1 } from '@generative-a11y/core';
1
+ import { Runtime, AdapterFidelity, AttentionMode, AttentionOverride, RuntimeDiagnosticEventV1, RuntimeDiagnosticSnapshotV1 } from '@generative-a11y/core';
2
2
 
3
3
  type DevtoolsRecordKind = RuntimeDiagnosticEventV1["kind"] | "dom-delivery";
4
4
  interface DevtoolsRecord {
5
+ readonly attentionMode?: AttentionMode;
6
+ readonly attentionOverride?: AttentionOverride;
5
7
  readonly runtimeId: string;
6
8
  /** Opaque key for the immutable adapter evidence captured with this record. */
7
9
  readonly runtimeSourceId?: string;
@@ -22,6 +24,30 @@ interface DevtoolsRecord {
22
24
  readonly toolInstanceId?: string;
23
25
  readonly interactionId?: string;
24
26
  readonly approvalId?: string;
27
+ /** Stable logical run identity retained as content-free correlation data. */
28
+ readonly runId?: string;
29
+ /** Stable run attempt identity retained as correlation data. */
30
+ readonly runInstanceId?: string;
31
+ /** Replacement run attempt identity on retry evidence. */
32
+ readonly nextRunInstanceId?: string;
33
+ /** Explicit logical parent run identity. */
34
+ readonly parentRunId?: string;
35
+ /** Explicit parent run attempt identity. */
36
+ readonly parentRunInstanceId?: string;
37
+ /** Stable logical step identity retained as content-free correlation data. */
38
+ readonly stepId?: string;
39
+ /** Stable step attempt identity retained as correlation data. */
40
+ readonly stepInstanceId?: string;
41
+ /** Replacement step attempt identity on retry evidence. */
42
+ readonly nextStepInstanceId?: string;
43
+ /** Explicit logical parent step identity. */
44
+ readonly parentStepId?: string;
45
+ /** Explicit parent step attempt identity. */
46
+ readonly parentStepInstanceId?: string;
47
+ /** Explicit tool that delegated to a child run. */
48
+ readonly parentToolId?: string;
49
+ /** Explicit response that owns a child run. */
50
+ readonly parentResponseId?: string;
25
51
  readonly progress?: number;
26
52
  readonly outcome?: string;
27
53
  readonly count?: number;
@@ -41,7 +67,7 @@ interface DevtoolsRecord {
41
67
  interface DevtoolsRuntimeSource {
42
68
  readonly adapter: string;
43
69
  readonly evidence: readonly string[];
44
- readonly fidelity: Readonly<Omit<AdapterFidelity, "optionalEvents"> & {
70
+ readonly fidelity: Readonly<Pick<AdapterFidelity, "interruption" | "retries" | "connection"> & Partial<Pick<AdapterFidelity, "runs" | "steps" | "hierarchy" | "tools" | "interactions" | "replay" | "reconnection" | "customEvents">> & {
45
71
  readonly optionalEvents?: readonly NonNullable<AdapterFidelity["optionalEvents"]>[number][];
46
72
  }>;
47
73
  }
@@ -58,6 +84,14 @@ interface DeliveryRecordInput {
58
84
  readonly responseId?: string;
59
85
  readonly toolId?: string;
60
86
  readonly interactionId?: string;
87
+ /** Stable logical run identity copied from the delivered intent. */
88
+ readonly runId?: string;
89
+ /** Stable run attempt identity copied from the delivered intent. */
90
+ readonly runInstanceId?: string;
91
+ /** Stable logical step identity copied from the delivered intent. */
92
+ readonly stepId?: string;
93
+ /** Stable step attempt identity copied from the delivered intent. */
94
+ readonly stepInstanceId?: string;
61
95
  readonly error?: {
62
96
  readonly name: string;
63
97
  readonly message?: string;
@@ -81,15 +115,15 @@ interface DevtoolsTraceExportV1 {
81
115
  readonly runtimeSnapshots: Readonly<Record<string, RuntimeDiagnosticSnapshotV1>>;
82
116
  readonly runtimeSources: Readonly<Record<string, DevtoolsRuntimeSource>>;
83
117
  }
84
- interface DevtoolsStoreOptions {
118
+ interface StoreOptions {
85
119
  readonly maxEntries?: number;
86
120
  }
87
121
  interface AttachRuntimeOptions {
88
122
  readonly id: string;
89
- readonly runtime: Pick<GenerativeA11yRuntime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
123
+ readonly runtime: Pick<Runtime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
90
124
  readonly source?: DevtoolsRuntimeSource;
91
125
  }
92
- interface DevtoolsStore {
126
+ interface Store {
93
127
  attachRuntime(options: AttachRuntimeOptions): () => void;
94
128
  getSnapshot(): DevtoolsSnapshot;
95
129
  subscribe(listener: () => void): () => void;
@@ -101,6 +135,6 @@ interface DevtoolsStore {
101
135
  exportTrace(): DevtoolsTraceExportV1;
102
136
  dispose(): void;
103
137
  }
104
- declare function createDevtoolsStore(options?: DevtoolsStoreOptions): DevtoolsStore;
138
+ declare function createStore(options?: StoreOptions): Store;
105
139
 
106
- export { type AttachRuntimeOptions, type DeliveryRecordInput, type DevtoolsRecord, type DevtoolsRecordKind, type DevtoolsRuntimeSource, type DevtoolsSnapshot, type DevtoolsStore, type DevtoolsStoreOptions, type DevtoolsTraceExportV1, createDevtoolsStore };
140
+ export { type AttachRuntimeOptions, type DeliveryRecordInput, type DevtoolsRecord, type DevtoolsRecordKind, type DevtoolsRuntimeSource, type DevtoolsSnapshot, type DevtoolsTraceExportV1, type Store, type StoreOptions, createStore };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { GenerativeA11yRuntime, AdapterFidelity, RuntimeDiagnosticEventV1, RuntimeDiagnosticSnapshotV1 } from '@generative-a11y/core';
1
+ import { Runtime, AdapterFidelity, AttentionMode, AttentionOverride, RuntimeDiagnosticEventV1, RuntimeDiagnosticSnapshotV1 } from '@generative-a11y/core';
2
2
 
3
3
  type DevtoolsRecordKind = RuntimeDiagnosticEventV1["kind"] | "dom-delivery";
4
4
  interface DevtoolsRecord {
5
+ readonly attentionMode?: AttentionMode;
6
+ readonly attentionOverride?: AttentionOverride;
5
7
  readonly runtimeId: string;
6
8
  /** Opaque key for the immutable adapter evidence captured with this record. */
7
9
  readonly runtimeSourceId?: string;
@@ -22,6 +24,30 @@ interface DevtoolsRecord {
22
24
  readonly toolInstanceId?: string;
23
25
  readonly interactionId?: string;
24
26
  readonly approvalId?: string;
27
+ /** Stable logical run identity retained as content-free correlation data. */
28
+ readonly runId?: string;
29
+ /** Stable run attempt identity retained as correlation data. */
30
+ readonly runInstanceId?: string;
31
+ /** Replacement run attempt identity on retry evidence. */
32
+ readonly nextRunInstanceId?: string;
33
+ /** Explicit logical parent run identity. */
34
+ readonly parentRunId?: string;
35
+ /** Explicit parent run attempt identity. */
36
+ readonly parentRunInstanceId?: string;
37
+ /** Stable logical step identity retained as content-free correlation data. */
38
+ readonly stepId?: string;
39
+ /** Stable step attempt identity retained as correlation data. */
40
+ readonly stepInstanceId?: string;
41
+ /** Replacement step attempt identity on retry evidence. */
42
+ readonly nextStepInstanceId?: string;
43
+ /** Explicit logical parent step identity. */
44
+ readonly parentStepId?: string;
45
+ /** Explicit parent step attempt identity. */
46
+ readonly parentStepInstanceId?: string;
47
+ /** Explicit tool that delegated to a child run. */
48
+ readonly parentToolId?: string;
49
+ /** Explicit response that owns a child run. */
50
+ readonly parentResponseId?: string;
25
51
  readonly progress?: number;
26
52
  readonly outcome?: string;
27
53
  readonly count?: number;
@@ -41,7 +67,7 @@ interface DevtoolsRecord {
41
67
  interface DevtoolsRuntimeSource {
42
68
  readonly adapter: string;
43
69
  readonly evidence: readonly string[];
44
- readonly fidelity: Readonly<Omit<AdapterFidelity, "optionalEvents"> & {
70
+ readonly fidelity: Readonly<Pick<AdapterFidelity, "interruption" | "retries" | "connection"> & Partial<Pick<AdapterFidelity, "runs" | "steps" | "hierarchy" | "tools" | "interactions" | "replay" | "reconnection" | "customEvents">> & {
45
71
  readonly optionalEvents?: readonly NonNullable<AdapterFidelity["optionalEvents"]>[number][];
46
72
  }>;
47
73
  }
@@ -58,6 +84,14 @@ interface DeliveryRecordInput {
58
84
  readonly responseId?: string;
59
85
  readonly toolId?: string;
60
86
  readonly interactionId?: string;
87
+ /** Stable logical run identity copied from the delivered intent. */
88
+ readonly runId?: string;
89
+ /** Stable run attempt identity copied from the delivered intent. */
90
+ readonly runInstanceId?: string;
91
+ /** Stable logical step identity copied from the delivered intent. */
92
+ readonly stepId?: string;
93
+ /** Stable step attempt identity copied from the delivered intent. */
94
+ readonly stepInstanceId?: string;
61
95
  readonly error?: {
62
96
  readonly name: string;
63
97
  readonly message?: string;
@@ -81,15 +115,15 @@ interface DevtoolsTraceExportV1 {
81
115
  readonly runtimeSnapshots: Readonly<Record<string, RuntimeDiagnosticSnapshotV1>>;
82
116
  readonly runtimeSources: Readonly<Record<string, DevtoolsRuntimeSource>>;
83
117
  }
84
- interface DevtoolsStoreOptions {
118
+ interface StoreOptions {
85
119
  readonly maxEntries?: number;
86
120
  }
87
121
  interface AttachRuntimeOptions {
88
122
  readonly id: string;
89
- readonly runtime: Pick<GenerativeA11yRuntime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
123
+ readonly runtime: Pick<Runtime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
90
124
  readonly source?: DevtoolsRuntimeSource;
91
125
  }
92
- interface DevtoolsStore {
126
+ interface Store {
93
127
  attachRuntime(options: AttachRuntimeOptions): () => void;
94
128
  getSnapshot(): DevtoolsSnapshot;
95
129
  subscribe(listener: () => void): () => void;
@@ -101,6 +135,6 @@ interface DevtoolsStore {
101
135
  exportTrace(): DevtoolsTraceExportV1;
102
136
  dispose(): void;
103
137
  }
104
- declare function createDevtoolsStore(options?: DevtoolsStoreOptions): DevtoolsStore;
138
+ declare function createStore(options?: StoreOptions): Store;
105
139
 
106
- export { type AttachRuntimeOptions, type DeliveryRecordInput, type DevtoolsRecord, type DevtoolsRecordKind, type DevtoolsRuntimeSource, type DevtoolsSnapshot, type DevtoolsStore, type DevtoolsStoreOptions, type DevtoolsTraceExportV1, createDevtoolsStore };
140
+ export { type AttachRuntimeOptions, type DeliveryRecordInput, type DevtoolsRecord, type DevtoolsRecordKind, type DevtoolsRuntimeSource, type DevtoolsSnapshot, type DevtoolsTraceExportV1, type Store, type StoreOptions, createStore };
package/dist/index.js CHANGED
@@ -9,7 +9,27 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
9
9
  at: event.at,
10
10
  kind: event.kind,
11
11
  sourceType: event.event.type,
12
+ ...event.event.type === "attention.changed" && [
13
+ "foreground",
14
+ "background",
15
+ "reading-history",
16
+ "away",
17
+ "unknown"
18
+ ].includes(event.event.mode) ? { attentionMode: event.event.mode } : {},
19
+ ...event.event.type === "attention.override" && ["auto", "normal", "quiet"].includes(event.event.mode) ? { attentionOverride: event.event.mode } : {},
12
20
  ...event.event.eventId ? { sourceEventId: event.event.eventId } : {},
21
+ ..."runId" in event.event && event.event.runId ? { runId: event.event.runId } : {},
22
+ ..."runInstanceId" in event.event && event.event.runInstanceId ? { runInstanceId: event.event.runInstanceId } : {},
23
+ ..."nextRunInstanceId" in event.event && event.event.nextRunInstanceId ? { nextRunInstanceId: event.event.nextRunInstanceId } : {},
24
+ ..."parentRunId" in event.event && event.event.parentRunId ? { parentRunId: event.event.parentRunId } : {},
25
+ ..."parentRunInstanceId" in event.event && event.event.parentRunInstanceId ? { parentRunInstanceId: event.event.parentRunInstanceId } : {},
26
+ ..."stepId" in event.event && event.event.stepId ? { stepId: event.event.stepId } : {},
27
+ ..."stepInstanceId" in event.event && event.event.stepInstanceId ? { stepInstanceId: event.event.stepInstanceId } : {},
28
+ ..."nextStepInstanceId" in event.event && event.event.nextStepInstanceId ? { nextStepInstanceId: event.event.nextStepInstanceId } : {},
29
+ ..."parentStepId" in event.event && event.event.parentStepId ? { parentStepId: event.event.parentStepId } : {},
30
+ ..."parentStepInstanceId" in event.event && event.event.parentStepInstanceId ? { parentStepInstanceId: event.event.parentStepInstanceId } : {},
31
+ ..."parentToolId" in event.event && event.event.parentToolId ? { parentToolId: event.event.parentToolId } : {},
32
+ ..."parentResponseId" in event.event && event.event.parentResponseId ? { parentResponseId: event.event.parentResponseId } : {},
13
33
  ..."responseId" in event.event ? { responseId: event.event.responseId } : {},
14
34
  ..."responseInstanceId" in event.event && event.event.responseInstanceId ? { responseInstanceId: event.event.responseInstanceId } : {},
15
35
  ..."nextResponseInstanceId" in event.event && event.event.nextResponseInstanceId ? { nextResponseInstanceId: event.event.nextResponseInstanceId } : {},
@@ -39,6 +59,10 @@ function asRecord(runtimeId, event, captureSequence, runtimeSourceId) {
39
59
  ...event.decision.responseId ? { responseId: event.decision.responseId } : {},
40
60
  ...event.decision.toolId ? { toolId: event.decision.toolId } : {},
41
61
  ...event.decision.interactionId ? { interactionId: event.decision.interactionId } : {},
62
+ ...event.decision.runId ? { runId: event.decision.runId } : {},
63
+ ...event.decision.runInstanceId ? { runInstanceId: event.decision.runInstanceId } : {},
64
+ ...event.decision.stepId ? { stepId: event.decision.stepId } : {},
65
+ ...event.decision.stepInstanceId ? { stepInstanceId: event.decision.stepInstanceId } : {},
42
66
  ...event.decision.scheduledAt !== void 0 ? { scheduledAt: event.decision.scheduledAt } : {},
43
67
  ...event.decision.dueAt !== void 0 ? { dueAt: event.decision.dueAt } : {},
44
68
  ...event.decision.delayMs !== void 0 ? { delayMs: event.decision.delayMs } : {},
@@ -62,6 +86,25 @@ function copyRuntimeSource(source) {
62
86
  throw new TypeError("source fidelity must be an object");
63
87
  const lifecycleFidelity = /* @__PURE__ */ new Set(["exact", "action-wrapper", "unavailable"]);
64
88
  const connectionFidelity = /* @__PURE__ */ new Set([...lifecycleFidelity, "inferred"]);
89
+ const workflowFidelity = /* @__PURE__ */ new Set(["exact", "partial", "unavailable"]);
90
+ for (const field of [
91
+ "runs",
92
+ "steps",
93
+ "hierarchy",
94
+ "tools",
95
+ "interactions",
96
+ "replay",
97
+ "reconnection"
98
+ ]) {
99
+ if (fidelity[field] !== void 0 && !workflowFidelity.has(fidelity[field]))
100
+ throw new TypeError(
101
+ `source ${field} fidelity contains an unsupported value`
102
+ );
103
+ }
104
+ if (fidelity.customEvents !== void 0 && fidelity.customEvents !== "explicit-mapping" && fidelity.customEvents !== "unsupported")
105
+ throw new TypeError(
106
+ "source custom event fidelity contains an unsupported value"
107
+ );
65
108
  if (!lifecycleFidelity.has(fidelity.interruption))
66
109
  throw new TypeError(
67
110
  "source interruption fidelity contains an unsupported value"
@@ -85,6 +128,14 @@ function copyRuntimeSource(source) {
85
128
  adapter: source.adapter.trim(),
86
129
  evidence: Object.freeze(source.evidence.map((item) => item.trim())),
87
130
  fidelity: Object.freeze({
131
+ ...fidelity.runs ? { runs: fidelity.runs } : {},
132
+ ...fidelity.steps ? { steps: fidelity.steps } : {},
133
+ ...fidelity.hierarchy ? { hierarchy: fidelity.hierarchy } : {},
134
+ ...fidelity.tools ? { tools: fidelity.tools } : {},
135
+ ...fidelity.interactions ? { interactions: fidelity.interactions } : {},
136
+ ...fidelity.replay ? { replay: fidelity.replay } : {},
137
+ ...fidelity.reconnection ? { reconnection: fidelity.reconnection } : {},
138
+ ...fidelity.customEvents ? { customEvents: fidelity.customEvents } : {},
88
139
  interruption: fidelity.interruption,
89
140
  retries: fidelity.retries,
90
141
  connection: fidelity.connection,
@@ -109,6 +160,10 @@ function asDeliveryRecord(input, captureSequence, runtimeSourceId) {
109
160
  ...result.responseId ? { responseId: result.responseId } : {},
110
161
  ...result.toolId ? { toolId: result.toolId } : {},
111
162
  ...result.interactionId ? { interactionId: result.interactionId } : {},
163
+ ...result.runId ? { runId: result.runId } : {},
164
+ ...result.runInstanceId ? { runInstanceId: result.runInstanceId } : {},
165
+ ...result.stepId ? { stepId: result.stepId } : {},
166
+ ...result.stepInstanceId ? { stepInstanceId: result.stepInstanceId } : {},
112
167
  ...result.error?.name ? { errorName: result.error.name } : {}
113
168
  });
114
169
  }
@@ -119,8 +174,28 @@ function copyRuntimeSnapshot(source) {
119
174
  policy: Object.freeze({
120
175
  ...source.policy,
121
176
  text: Object.freeze({ ...source.policy.text }),
122
- tools: Object.freeze({ ...source.policy.tools })
177
+ tools: Object.freeze({ ...source.policy.tools }),
178
+ workflows: Object.freeze({ ...source.policy.workflows }),
179
+ ...source.policy.attention ? {
180
+ attention: Object.freeze({
181
+ ...source.policy.attention,
182
+ quietWhen: Object.freeze([...source.policy.attention.quietWhen])
183
+ })
184
+ } : {}
123
185
  }),
186
+ ...source.messages ? {
187
+ messages: Object.freeze({
188
+ catalogId: source.messages.catalogId,
189
+ locale: source.messages.locale
190
+ })
191
+ } : {},
192
+ ...source.attention ? {
193
+ attention: Object.freeze({
194
+ observed: source.attention.observed,
195
+ override: source.attention.override,
196
+ effective: source.attention.effective
197
+ })
198
+ } : {},
124
199
  pending: Object.freeze({
125
200
  announcements: Object.freeze(
126
201
  source.pending.announcements.map((item) => Object.freeze({ ...item }))
@@ -135,10 +210,20 @@ function copyRuntimeSnapshot(source) {
135
210
  tools: Object.freeze(
136
211
  source.tools.map((item) => Object.freeze({ ...item }))
137
212
  ),
213
+ ...source.runs ? {
214
+ runs: Object.freeze(
215
+ source.runs.map((item) => Object.freeze({ ...item }))
216
+ )
217
+ } : {},
218
+ ...source.steps ? {
219
+ steps: Object.freeze(
220
+ source.steps.map((item) => Object.freeze({ ...item }))
221
+ )
222
+ } : {},
138
223
  pendingCount: source.pendingCount
139
224
  });
140
225
  }
141
- function createDevtoolsStore(options = {}) {
226
+ function createStore(options = {}) {
142
227
  const maxEntries = options.maxEntries ?? 250;
143
228
  if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0)
144
229
  throw new RangeError("maxEntries must be a positive safe integer");
@@ -344,5 +429,5 @@ function createDevtoolsStore(options = {}) {
344
429
  };
345
430
  }
346
431
  export {
347
- createDevtoolsStore
432
+ createStore
348
433
  };
package/dist/overlay.cjs CHANGED
@@ -30,7 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/overlay.ts
31
31
  var overlay_exports = {};
32
32
  __export(overlay_exports, {
33
- mountDevtoolsOverlay: () => mountDevtoolsOverlay
33
+ mountOverlay: () => mountOverlay
34
34
  });
35
35
  module.exports = __toCommonJS(overlay_exports);
36
36
  var import_react2 = require("react");
@@ -226,23 +226,65 @@ var key = (record) => String(record.captureSequence);
226
226
  var time = (value) => value >= 1e10 ? new Date(value).toISOString().slice(11, 23) : `+${(value / 1e3).toFixed(2)}s`;
227
227
  var stage = (record) => record.kind === "event-observed" ? "Source evidence" : record.kind === "decision" ? "Runtime decision" : "DOM delivery";
228
228
  var title = (record) => record.kind === "event-observed" ? record.sourceType ?? "Observed event" : record.kind === "dom-delivery" ? `${record.deliveryStatus ?? "Delivery"} via ${record.deliveryMethod ?? "browser"}` : record.reason ?? record.disposition ?? "Runtime decision";
229
- function correlation(record) {
229
+ function correlationKeys(record) {
230
230
  const prefix = `${record.runtimeId}:`;
231
- if (record.sourceEventId) return `${prefix}event:${record.sourceEventId}`;
232
- if (record.responseId)
233
- return `${prefix}response:${record.responseId}:${record.sourceType ?? "unknown"}`;
234
- if (record.toolId)
235
- return `${prefix}tool:${record.toolId}:${record.sourceType ?? "unknown"}`;
231
+ const keys = /* @__PURE__ */ new Set();
232
+ if (record.sourceEventId) keys.add(`${prefix}event:${record.sourceEventId}`);
233
+ if (record.responseId) keys.add(`${prefix}response:${record.responseId}`);
234
+ if (record.toolId) keys.add(`${prefix}tool:${record.toolId}`);
236
235
  if (record.interactionId)
237
- return `${prefix}interaction:${record.interactionId}`;
238
- if (record.approvalId) return `${prefix}approval:${record.approvalId}`;
236
+ keys.add(`${prefix}interaction:${record.interactionId}`);
237
+ if (record.approvalId) keys.add(`${prefix}approval:${record.approvalId}`);
239
238
  if (record.announcementId)
240
- return `${prefix}announcement:${record.announcementId}`;
241
- return `${prefix}record:${record.captureSequence}`;
239
+ keys.add(`${prefix}announcement:${record.announcementId}`);
240
+ if (record.runId)
241
+ keys.add(
242
+ `${prefix}run:${record.runId}:${record.runInstanceId ?? "unidentified"}`
243
+ );
244
+ if (record.runId && record.nextRunInstanceId)
245
+ keys.add(`${prefix}run:${record.runId}:${record.nextRunInstanceId}`);
246
+ if (record.parentRunId)
247
+ keys.add(
248
+ `${prefix}run:${record.parentRunId}:${record.parentRunInstanceId ?? "unidentified"}`
249
+ );
250
+ if (record.stepId)
251
+ keys.add(
252
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.stepInstanceId ?? "unidentified"}`
253
+ );
254
+ if (record.stepId && record.nextStepInstanceId)
255
+ keys.add(
256
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.nextStepInstanceId}`
257
+ );
258
+ if (record.parentStepId)
259
+ keys.add(
260
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.parentStepId}:${record.parentStepInstanceId ?? "unidentified"}`
261
+ );
262
+ if (record.parentToolId) keys.add(`${prefix}tool:${record.parentToolId}`);
263
+ if (record.parentResponseId)
264
+ keys.add(`${prefix}response:${record.parentResponseId}`);
265
+ if (keys.size === 0) keys.add(`${prefix}record:${record.captureSequence}`);
266
+ return [...keys];
267
+ }
268
+ function relatedRecords(records, selected) {
269
+ const related = /* @__PURE__ */ new Set();
270
+ const keys = new Set(correlationKeys(selected));
271
+ let changed = true;
272
+ while (changed) {
273
+ changed = false;
274
+ for (const record of records) {
275
+ if (related.has(record)) continue;
276
+ const recordKeys = correlationKeys(record);
277
+ if (!recordKeys.some((value) => keys.has(value))) continue;
278
+ related.add(record);
279
+ for (const value of recordKeys) keys.add(value);
280
+ changed = true;
281
+ }
282
+ }
283
+ return [...related];
242
284
  }
243
285
  function explain(record) {
244
286
  if (record.kind === "event-observed")
245
- return "The adapter supplied this normalized public lifecycle signal.";
287
+ return record.sourceType?.startsWith("attention.") ? "The host supplied an attention observation or explicit user override. Browser evidence does not establish what someone is reading." : "The adapter supplied this normalized public lifecycle signal.";
246
288
  if (record.kind === "dom-delivery")
247
289
  return record.deliveryStatus === "unavailable" ? "The DOM driver was unavailable, so no browser delivery action was observed." : "The DOM driver reported this delivery action.";
248
290
  return {
@@ -250,6 +292,9 @@ function explain(record) {
250
292
  coalesced: "The runtime merged this work with an existing queued announcement.",
251
293
  duplicate: "The runtime suppressed a recently delivered duplicate.",
252
294
  "policy-silent": "The active policy intentionally made this event silent.",
295
+ "catalog-format-error": "The host message formatter failed; the runtime used a generic English notice without retaining the error or parameters.",
296
+ "attention-quiet": "Quiet mode discarded routine output without retaining an announcement backlog.",
297
+ "attention-updated": "The runtime updated its attention observation or user override without announcing the control event.",
253
298
  "queue-capacity": "The bounded queue rejected or displaced this work.",
254
299
  "scope-cancelled": "The lifecycle scope ended before this queued work delivered.",
255
300
  "runtime-disposed": "The runtime was disposed and cancelled remaining queued work.",
@@ -302,6 +347,12 @@ function Detail({
302
347
  ] }) });
303
348
  const source = snapshot.runtimeSources[record.runtimeSourceId ?? record.runtimeId];
304
349
  const runtime = snapshot.runtimeSnapshots[record.runtimeId];
350
+ const run = record.runInstanceId ? runtime?.runs?.find(
351
+ (item) => item.runId === record.runId && item.instanceId === record.runInstanceId
352
+ ) : void 0;
353
+ const step = record.runInstanceId && record.stepInstanceId ? runtime?.steps?.find(
354
+ (item) => item.runId === record.runId && item.stepId === record.stepId && item.runInstanceId === record.runInstanceId && item.instanceId === record.stepInstanceId
355
+ ) : void 0;
305
356
  const deliveries = related.filter((item) => item.kind === "dom-delivery");
306
357
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("aside", { className: "ga-trace-detail", "data-testid": "trace-detail", children: [
307
358
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: "ga-detail-intro", children: [
@@ -314,6 +365,43 @@ function Detail({
314
365
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { children: record.reason?.startsWith("stale") ? "Compare the instance with the current runtime snapshot." : "Inspect related evidence and queue context if this was unexpected." })
315
366
  ] }),
316
367
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(CausalChain, { records: related }),
368
+ record.runId ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
369
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Workflow hierarchy" }),
370
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
371
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
372
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Run" }),
373
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.runId })
374
+ ] }),
375
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
376
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Run attempt" }),
377
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.runInstanceId ?? run?.instanceId ?? "Not supplied" })
378
+ ] }),
379
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
380
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Parent run" }),
381
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.parentRunId ?? run?.parentRunId ?? "None" })
382
+ ] }),
383
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
384
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Run state" }),
385
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: run?.status ?? "Not retained" })
386
+ ] }),
387
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
388
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Step" }),
389
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.stepId ?? "Partial identity" })
390
+ ] }),
391
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
392
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Step attempt" }),
393
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.stepInstanceId ?? step?.instanceId ?? "Not supplied" })
394
+ ] }),
395
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
396
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Parent step" }),
397
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: record.parentStepId ?? step?.parentStepId ?? "None" })
398
+ ] }),
399
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
400
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Step state" }),
401
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: step?.status ?? "Not retained" })
402
+ ] })
403
+ ] })
404
+ ] }) : null,
317
405
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
318
406
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Source evidence" }),
319
407
  source ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
@@ -321,6 +409,22 @@ function Detail({
321
409
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Adapter" }),
322
410
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.adapter })
323
411
  ] }),
412
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
413
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Runs" }),
414
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.runs ?? "Not declared" })
415
+ ] }),
416
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
417
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Steps" }),
418
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.steps ?? "Not declared" })
419
+ ] }),
420
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
421
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Hierarchy" }),
422
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.hierarchy ?? "Not declared" })
423
+ ] }),
424
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
425
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Replay" }),
426
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.replay ?? "Not declared" })
427
+ ] }),
324
428
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
325
429
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Interruption" }),
326
430
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: source.fidelity.interruption })
@@ -342,6 +446,30 @@ function Detail({
342
446
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
343
447
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Policy and scheduling" }),
344
448
  runtime ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dl", { className: "ga-key-values", children: [
449
+ runtime.messages && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
450
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
451
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Announcement catalog" }),
452
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: runtime.messages.catalogId })
453
+ ] }),
454
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
455
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Notice language" }),
456
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: runtime.messages.locale })
457
+ ] })
458
+ ] }),
459
+ runtime.attention && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
460
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
461
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Effective announcements" }),
462
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: runtime.attention.effective })
463
+ ] }),
464
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
465
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Observed attention" }),
466
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: runtime.attention.observed })
467
+ ] }),
468
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
469
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "User override" }),
470
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dd", { children: runtime.attention.override })
471
+ ] })
472
+ ] }),
345
473
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
346
474
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Queue" }),
347
475
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dd", { children: [
@@ -431,11 +559,7 @@ function List({
431
559
  }
432
560
  );
433
561
  }
434
- function DevtoolsInspector({
435
- store,
436
- onClose,
437
- onCopy
438
- }) {
562
+ function Inspector({ store, onClose, onCopy }) {
439
563
  const snapshot = useSnapshot(store);
440
564
  const reduceMotion = (0, import_react.useReducedMotion)();
441
565
  const [query, setQuery] = React4.useState("");
@@ -453,13 +577,15 @@ function DevtoolsInspector({
453
577
  record.responseId,
454
578
  record.toolId,
455
579
  record.interactionId,
456
- record.approvalId
580
+ record.approvalId,
581
+ record.runId,
582
+ record.runInstanceId,
583
+ record.stepId,
584
+ record.stepInstanceId
457
585
  ].filter(Boolean).join(" ").toLowerCase().includes(query.trim().toLowerCase())
458
586
  ).slice().reverse();
459
587
  const selected = visible.find((record) => key(record) === selectedKey) ?? visible[0];
460
- const related = selected ? snapshot.records.filter(
461
- (record) => correlation(record) === correlation(selected)
462
- ) : [];
588
+ const related = selected ? relatedRecords(snapshot.records, selected) : [];
463
589
  React4.useEffect(
464
590
  () => () => {
465
591
  if (feedbackTimer.current !== void 0)
@@ -739,7 +865,7 @@ button:focus-visible, input:focus-visible, [role="listbox"]:focus-visible, [role
739
865
  .ga-workspace-feedback { top: 68px; color: #f7f7f7; background: #111; border-color: #111; border-radius: 3px; box-shadow: none; }
740
866
  @media (max-width: 760px) { .ga-bottom-dock { height: min(720px, 80vh); } .ga-inspector-header, .ga-session-toolbar { padding-right: 12px; padding-left: 12px; } .ga-session-toolbar { flex-wrap: wrap; } .ga-inspector-search { width: 100%; } .ga-session-count { margin-left: 0; } .ga-explorer-layout { flex-direction: column; } [data-slot="resizable-handle"] { width: 100%; height: 1px; } .ga-trace-row { grid-template-columns: 70px 1fr; padding: 8px 12px; } .ga-trace-row span, .ga-trace-row code { grid-column: 2; } .ga-trace-detail { padding: 18px 12px; } .ga-key-values { grid-template-columns: 1fr; } .ga-key-values-wide { grid-column: auto; } }
741
867
  `;
742
- function mountDevtoolsOverlay(options) {
868
+ function mountOverlay(options) {
743
869
  const selectedDocument = options.document ?? (typeof document === "undefined" ? void 0 : document);
744
870
  if (!selectedDocument?.body)
745
871
  throw new Error("A mountable document is required");
@@ -794,7 +920,7 @@ function mountDevtoolsOverlay(options) {
794
920
  return clipboard.writeText(value);
795
921
  });
796
922
  root.render(
797
- (0, import_react2.createElement)(DevtoolsInspector, {
923
+ (0, import_react2.createElement)(Inspector, {
798
924
  onClose: close,
799
925
  onCopy: copyText,
800
926
  store: options.store
@@ -833,5 +959,5 @@ function mountDevtoolsOverlay(options) {
833
959
  }
834
960
  // Annotate the CommonJS export names for ESM import in node:
835
961
  0 && (module.exports = {
836
- mountDevtoolsOverlay
962
+ mountOverlay
837
963
  });
@@ -1,15 +1,15 @@
1
- import { DevtoolsStore } from './index.cjs';
1
+ import { Store } from './index.cjs';
2
2
  import '@generative-a11y/core';
3
3
 
4
- interface MountDevtoolsOverlayOptions {
5
- readonly store: DevtoolsStore;
4
+ interface OverlayOptions {
5
+ readonly store: Store;
6
6
  readonly document?: Document;
7
7
  readonly copyText?: (value: string) => void | Promise<void>;
8
8
  }
9
- interface MountedDevtoolsOverlay {
9
+ interface Overlay {
10
10
  readonly host: HTMLElement;
11
11
  dispose(): void;
12
12
  }
13
- declare function mountDevtoolsOverlay(options: MountDevtoolsOverlayOptions): MountedDevtoolsOverlay;
13
+ declare function mountOverlay(options: OverlayOptions): Overlay;
14
14
 
15
- export { type MountDevtoolsOverlayOptions, type MountedDevtoolsOverlay, mountDevtoolsOverlay };
15
+ export { type Overlay, type OverlayOptions, mountOverlay };
package/dist/overlay.d.ts CHANGED
@@ -1,15 +1,15 @@
1
- import { DevtoolsStore } from './index.js';
1
+ import { Store } from './index.js';
2
2
  import '@generative-a11y/core';
3
3
 
4
- interface MountDevtoolsOverlayOptions {
5
- readonly store: DevtoolsStore;
4
+ interface OverlayOptions {
5
+ readonly store: Store;
6
6
  readonly document?: Document;
7
7
  readonly copyText?: (value: string) => void | Promise<void>;
8
8
  }
9
- interface MountedDevtoolsOverlay {
9
+ interface Overlay {
10
10
  readonly host: HTMLElement;
11
11
  dispose(): void;
12
12
  }
13
- declare function mountDevtoolsOverlay(options: MountDevtoolsOverlayOptions): MountedDevtoolsOverlay;
13
+ declare function mountOverlay(options: OverlayOptions): Overlay;
14
14
 
15
- export { type MountDevtoolsOverlayOptions, type MountedDevtoolsOverlay, mountDevtoolsOverlay };
15
+ export { type Overlay, type OverlayOptions, mountOverlay };
package/dist/overlay.js CHANGED
@@ -187,28 +187,70 @@ function ScrollBar({
187
187
  }
188
188
 
189
189
  // src/inspector.tsx
190
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
190
+ import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
191
191
  var key = (record) => String(record.captureSequence);
192
192
  var time = (value) => value >= 1e10 ? new Date(value).toISOString().slice(11, 23) : `+${(value / 1e3).toFixed(2)}s`;
193
193
  var stage = (record) => record.kind === "event-observed" ? "Source evidence" : record.kind === "decision" ? "Runtime decision" : "DOM delivery";
194
194
  var title = (record) => record.kind === "event-observed" ? record.sourceType ?? "Observed event" : record.kind === "dom-delivery" ? `${record.deliveryStatus ?? "Delivery"} via ${record.deliveryMethod ?? "browser"}` : record.reason ?? record.disposition ?? "Runtime decision";
195
- function correlation(record) {
195
+ function correlationKeys(record) {
196
196
  const prefix = `${record.runtimeId}:`;
197
- if (record.sourceEventId) return `${prefix}event:${record.sourceEventId}`;
198
- if (record.responseId)
199
- return `${prefix}response:${record.responseId}:${record.sourceType ?? "unknown"}`;
200
- if (record.toolId)
201
- return `${prefix}tool:${record.toolId}:${record.sourceType ?? "unknown"}`;
197
+ const keys = /* @__PURE__ */ new Set();
198
+ if (record.sourceEventId) keys.add(`${prefix}event:${record.sourceEventId}`);
199
+ if (record.responseId) keys.add(`${prefix}response:${record.responseId}`);
200
+ if (record.toolId) keys.add(`${prefix}tool:${record.toolId}`);
202
201
  if (record.interactionId)
203
- return `${prefix}interaction:${record.interactionId}`;
204
- if (record.approvalId) return `${prefix}approval:${record.approvalId}`;
202
+ keys.add(`${prefix}interaction:${record.interactionId}`);
203
+ if (record.approvalId) keys.add(`${prefix}approval:${record.approvalId}`);
205
204
  if (record.announcementId)
206
- return `${prefix}announcement:${record.announcementId}`;
207
- return `${prefix}record:${record.captureSequence}`;
205
+ keys.add(`${prefix}announcement:${record.announcementId}`);
206
+ if (record.runId)
207
+ keys.add(
208
+ `${prefix}run:${record.runId}:${record.runInstanceId ?? "unidentified"}`
209
+ );
210
+ if (record.runId && record.nextRunInstanceId)
211
+ keys.add(`${prefix}run:${record.runId}:${record.nextRunInstanceId}`);
212
+ if (record.parentRunId)
213
+ keys.add(
214
+ `${prefix}run:${record.parentRunId}:${record.parentRunInstanceId ?? "unidentified"}`
215
+ );
216
+ if (record.stepId)
217
+ keys.add(
218
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.stepInstanceId ?? "unidentified"}`
219
+ );
220
+ if (record.stepId && record.nextStepInstanceId)
221
+ keys.add(
222
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.stepId}:${record.nextStepInstanceId}`
223
+ );
224
+ if (record.parentStepId)
225
+ keys.add(
226
+ `${prefix}step:${record.runId ?? "unknown"}:${record.runInstanceId ?? "unidentified"}:${record.parentStepId}:${record.parentStepInstanceId ?? "unidentified"}`
227
+ );
228
+ if (record.parentToolId) keys.add(`${prefix}tool:${record.parentToolId}`);
229
+ if (record.parentResponseId)
230
+ keys.add(`${prefix}response:${record.parentResponseId}`);
231
+ if (keys.size === 0) keys.add(`${prefix}record:${record.captureSequence}`);
232
+ return [...keys];
233
+ }
234
+ function relatedRecords(records, selected) {
235
+ const related = /* @__PURE__ */ new Set();
236
+ const keys = new Set(correlationKeys(selected));
237
+ let changed = true;
238
+ while (changed) {
239
+ changed = false;
240
+ for (const record of records) {
241
+ if (related.has(record)) continue;
242
+ const recordKeys = correlationKeys(record);
243
+ if (!recordKeys.some((value) => keys.has(value))) continue;
244
+ related.add(record);
245
+ for (const value of recordKeys) keys.add(value);
246
+ changed = true;
247
+ }
248
+ }
249
+ return [...related];
208
250
  }
209
251
  function explain(record) {
210
252
  if (record.kind === "event-observed")
211
- return "The adapter supplied this normalized public lifecycle signal.";
253
+ return record.sourceType?.startsWith("attention.") ? "The host supplied an attention observation or explicit user override. Browser evidence does not establish what someone is reading." : "The adapter supplied this normalized public lifecycle signal.";
212
254
  if (record.kind === "dom-delivery")
213
255
  return record.deliveryStatus === "unavailable" ? "The DOM driver was unavailable, so no browser delivery action was observed." : "The DOM driver reported this delivery action.";
214
256
  return {
@@ -216,6 +258,9 @@ function explain(record) {
216
258
  coalesced: "The runtime merged this work with an existing queued announcement.",
217
259
  duplicate: "The runtime suppressed a recently delivered duplicate.",
218
260
  "policy-silent": "The active policy intentionally made this event silent.",
261
+ "catalog-format-error": "The host message formatter failed; the runtime used a generic English notice without retaining the error or parameters.",
262
+ "attention-quiet": "Quiet mode discarded routine output without retaining an announcement backlog.",
263
+ "attention-updated": "The runtime updated its attention observation or user override without announcing the control event.",
219
264
  "queue-capacity": "The bounded queue rejected or displaced this work.",
220
265
  "scope-cancelled": "The lifecycle scope ended before this queued work delivered.",
221
266
  "runtime-disposed": "The runtime was disposed and cancelled remaining queued work.",
@@ -268,6 +313,12 @@ function Detail({
268
313
  ] }) });
269
314
  const source = snapshot.runtimeSources[record.runtimeSourceId ?? record.runtimeId];
270
315
  const runtime = snapshot.runtimeSnapshots[record.runtimeId];
316
+ const run = record.runInstanceId ? runtime?.runs?.find(
317
+ (item) => item.runId === record.runId && item.instanceId === record.runInstanceId
318
+ ) : void 0;
319
+ const step = record.runInstanceId && record.stepInstanceId ? runtime?.steps?.find(
320
+ (item) => item.runId === record.runId && item.stepId === record.stepId && item.runInstanceId === record.runInstanceId && item.instanceId === record.stepInstanceId
321
+ ) : void 0;
271
322
  const deliveries = related.filter((item) => item.kind === "dom-delivery");
272
323
  return /* @__PURE__ */ jsxs2("aside", { className: "ga-trace-detail", "data-testid": "trace-detail", children: [
273
324
  /* @__PURE__ */ jsxs2("div", { className: "ga-detail-intro", children: [
@@ -280,6 +331,43 @@ function Detail({
280
331
  /* @__PURE__ */ jsx5("p", { children: record.reason?.startsWith("stale") ? "Compare the instance with the current runtime snapshot." : "Inspect related evidence and queue context if this was unexpected." })
281
332
  ] }),
282
333
  /* @__PURE__ */ jsx5(CausalChain, { records: related }),
334
+ record.runId ? /* @__PURE__ */ jsxs2("section", { className: "ga-detail-section", children: [
335
+ /* @__PURE__ */ jsx5("h4", { children: "Workflow hierarchy" }),
336
+ /* @__PURE__ */ jsxs2("dl", { className: "ga-key-values", children: [
337
+ /* @__PURE__ */ jsxs2("div", { children: [
338
+ /* @__PURE__ */ jsx5("dt", { children: "Run" }),
339
+ /* @__PURE__ */ jsx5("dd", { children: record.runId })
340
+ ] }),
341
+ /* @__PURE__ */ jsxs2("div", { children: [
342
+ /* @__PURE__ */ jsx5("dt", { children: "Run attempt" }),
343
+ /* @__PURE__ */ jsx5("dd", { children: record.runInstanceId ?? run?.instanceId ?? "Not supplied" })
344
+ ] }),
345
+ /* @__PURE__ */ jsxs2("div", { children: [
346
+ /* @__PURE__ */ jsx5("dt", { children: "Parent run" }),
347
+ /* @__PURE__ */ jsx5("dd", { children: record.parentRunId ?? run?.parentRunId ?? "None" })
348
+ ] }),
349
+ /* @__PURE__ */ jsxs2("div", { children: [
350
+ /* @__PURE__ */ jsx5("dt", { children: "Run state" }),
351
+ /* @__PURE__ */ jsx5("dd", { children: run?.status ?? "Not retained" })
352
+ ] }),
353
+ /* @__PURE__ */ jsxs2("div", { children: [
354
+ /* @__PURE__ */ jsx5("dt", { children: "Step" }),
355
+ /* @__PURE__ */ jsx5("dd", { children: record.stepId ?? "Partial identity" })
356
+ ] }),
357
+ /* @__PURE__ */ jsxs2("div", { children: [
358
+ /* @__PURE__ */ jsx5("dt", { children: "Step attempt" }),
359
+ /* @__PURE__ */ jsx5("dd", { children: record.stepInstanceId ?? step?.instanceId ?? "Not supplied" })
360
+ ] }),
361
+ /* @__PURE__ */ jsxs2("div", { children: [
362
+ /* @__PURE__ */ jsx5("dt", { children: "Parent step" }),
363
+ /* @__PURE__ */ jsx5("dd", { children: record.parentStepId ?? step?.parentStepId ?? "None" })
364
+ ] }),
365
+ /* @__PURE__ */ jsxs2("div", { children: [
366
+ /* @__PURE__ */ jsx5("dt", { children: "Step state" }),
367
+ /* @__PURE__ */ jsx5("dd", { children: step?.status ?? "Not retained" })
368
+ ] })
369
+ ] })
370
+ ] }) : null,
283
371
  /* @__PURE__ */ jsxs2("section", { className: "ga-detail-section", children: [
284
372
  /* @__PURE__ */ jsx5("h4", { children: "Source evidence" }),
285
373
  source ? /* @__PURE__ */ jsxs2("dl", { className: "ga-key-values", children: [
@@ -287,6 +375,22 @@ function Detail({
287
375
  /* @__PURE__ */ jsx5("dt", { children: "Adapter" }),
288
376
  /* @__PURE__ */ jsx5("dd", { children: source.adapter })
289
377
  ] }),
378
+ /* @__PURE__ */ jsxs2("div", { children: [
379
+ /* @__PURE__ */ jsx5("dt", { children: "Runs" }),
380
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.runs ?? "Not declared" })
381
+ ] }),
382
+ /* @__PURE__ */ jsxs2("div", { children: [
383
+ /* @__PURE__ */ jsx5("dt", { children: "Steps" }),
384
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.steps ?? "Not declared" })
385
+ ] }),
386
+ /* @__PURE__ */ jsxs2("div", { children: [
387
+ /* @__PURE__ */ jsx5("dt", { children: "Hierarchy" }),
388
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.hierarchy ?? "Not declared" })
389
+ ] }),
390
+ /* @__PURE__ */ jsxs2("div", { children: [
391
+ /* @__PURE__ */ jsx5("dt", { children: "Replay" }),
392
+ /* @__PURE__ */ jsx5("dd", { children: source.fidelity.replay ?? "Not declared" })
393
+ ] }),
290
394
  /* @__PURE__ */ jsxs2("div", { children: [
291
395
  /* @__PURE__ */ jsx5("dt", { children: "Interruption" }),
292
396
  /* @__PURE__ */ jsx5("dd", { children: source.fidelity.interruption })
@@ -308,6 +412,30 @@ function Detail({
308
412
  /* @__PURE__ */ jsxs2("section", { className: "ga-detail-section", children: [
309
413
  /* @__PURE__ */ jsx5("h4", { children: "Policy and scheduling" }),
310
414
  runtime ? /* @__PURE__ */ jsxs2("dl", { className: "ga-key-values", children: [
415
+ runtime.messages && /* @__PURE__ */ jsxs2(Fragment, { children: [
416
+ /* @__PURE__ */ jsxs2("div", { children: [
417
+ /* @__PURE__ */ jsx5("dt", { children: "Announcement catalog" }),
418
+ /* @__PURE__ */ jsx5("dd", { children: runtime.messages.catalogId })
419
+ ] }),
420
+ /* @__PURE__ */ jsxs2("div", { children: [
421
+ /* @__PURE__ */ jsx5("dt", { children: "Notice language" }),
422
+ /* @__PURE__ */ jsx5("dd", { children: runtime.messages.locale })
423
+ ] })
424
+ ] }),
425
+ runtime.attention && /* @__PURE__ */ jsxs2(Fragment, { children: [
426
+ /* @__PURE__ */ jsxs2("div", { children: [
427
+ /* @__PURE__ */ jsx5("dt", { children: "Effective announcements" }),
428
+ /* @__PURE__ */ jsx5("dd", { children: runtime.attention.effective })
429
+ ] }),
430
+ /* @__PURE__ */ jsxs2("div", { children: [
431
+ /* @__PURE__ */ jsx5("dt", { children: "Observed attention" }),
432
+ /* @__PURE__ */ jsx5("dd", { children: runtime.attention.observed })
433
+ ] }),
434
+ /* @__PURE__ */ jsxs2("div", { children: [
435
+ /* @__PURE__ */ jsx5("dt", { children: "User override" }),
436
+ /* @__PURE__ */ jsx5("dd", { children: runtime.attention.override })
437
+ ] })
438
+ ] }),
311
439
  /* @__PURE__ */ jsxs2("div", { children: [
312
440
  /* @__PURE__ */ jsx5("dt", { children: "Queue" }),
313
441
  /* @__PURE__ */ jsxs2("dd", { children: [
@@ -397,11 +525,7 @@ function List({
397
525
  }
398
526
  );
399
527
  }
400
- function DevtoolsInspector({
401
- store,
402
- onClose,
403
- onCopy
404
- }) {
528
+ function Inspector({ store, onClose, onCopy }) {
405
529
  const snapshot = useSnapshot(store);
406
530
  const reduceMotion = useReducedMotion();
407
531
  const [query, setQuery] = React4.useState("");
@@ -419,13 +543,15 @@ function DevtoolsInspector({
419
543
  record.responseId,
420
544
  record.toolId,
421
545
  record.interactionId,
422
- record.approvalId
546
+ record.approvalId,
547
+ record.runId,
548
+ record.runInstanceId,
549
+ record.stepId,
550
+ record.stepInstanceId
423
551
  ].filter(Boolean).join(" ").toLowerCase().includes(query.trim().toLowerCase())
424
552
  ).slice().reverse();
425
553
  const selected = visible.find((record) => key(record) === selectedKey) ?? visible[0];
426
- const related = selected ? snapshot.records.filter(
427
- (record) => correlation(record) === correlation(selected)
428
- ) : [];
554
+ const related = selected ? relatedRecords(snapshot.records, selected) : [];
429
555
  React4.useEffect(
430
556
  () => () => {
431
557
  if (feedbackTimer.current !== void 0)
@@ -705,7 +831,7 @@ button:focus-visible, input:focus-visible, [role="listbox"]:focus-visible, [role
705
831
  .ga-workspace-feedback { top: 68px; color: #f7f7f7; background: #111; border-color: #111; border-radius: 3px; box-shadow: none; }
706
832
  @media (max-width: 760px) { .ga-bottom-dock { height: min(720px, 80vh); } .ga-inspector-header, .ga-session-toolbar { padding-right: 12px; padding-left: 12px; } .ga-session-toolbar { flex-wrap: wrap; } .ga-inspector-search { width: 100%; } .ga-session-count { margin-left: 0; } .ga-explorer-layout { flex-direction: column; } [data-slot="resizable-handle"] { width: 100%; height: 1px; } .ga-trace-row { grid-template-columns: 70px 1fr; padding: 8px 12px; } .ga-trace-row span, .ga-trace-row code { grid-column: 2; } .ga-trace-detail { padding: 18px 12px; } .ga-key-values { grid-template-columns: 1fr; } .ga-key-values-wide { grid-column: auto; } }
707
833
  `;
708
- function mountDevtoolsOverlay(options) {
834
+ function mountOverlay(options) {
709
835
  const selectedDocument = options.document ?? (typeof document === "undefined" ? void 0 : document);
710
836
  if (!selectedDocument?.body)
711
837
  throw new Error("A mountable document is required");
@@ -760,7 +886,7 @@ function mountDevtoolsOverlay(options) {
760
886
  return clipboard.writeText(value);
761
887
  });
762
888
  root.render(
763
- createElement(DevtoolsInspector, {
889
+ createElement(Inspector, {
764
890
  onClose: close,
765
891
  onCopy: copyText,
766
892
  store: options.store
@@ -798,5 +924,5 @@ function mountDevtoolsOverlay(options) {
798
924
  };
799
925
  }
800
926
  export {
801
- mountDevtoolsOverlay
927
+ mountOverlay
802
928
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@generative-a11y/devtools",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Development-only accessibility diagnostics and a redacted trace explorer for screen-reader announcements in AI runtimes.",
5
5
  "keywords": [
6
6
  "accessibility",
@@ -56,11 +56,11 @@
56
56
  "class-variance-authority": "0.7.1",
57
57
  "clsx": "2.1.1",
58
58
  "lucide-react": "1.31.0",
59
- "motion": "^12.23.12",
59
+ "motion": "^13.1.1",
60
60
  "radix-ui": "1.6.7",
61
61
  "react-resizable-panels": "^4.12.3",
62
62
  "tailwind-merge": "3.6.0",
63
- "@generative-a11y/core": "0.2.0"
63
+ "@generative-a11y/core": "0.4.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "react": "^19.0.0",