@generative-a11y/devtools 0.1.1 → 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
@@ -100,15 +100,30 @@ subscribes to a runtime.
100
100
  ## Browser delivery correlation
101
101
 
102
102
  The store intentionally does not import `@generative-a11y/dom`. Connect the
103
- announcer's public diagnostic callback yourself to capture a content-free
103
+ active binding's `onDelivery` callback yourself to capture a content-free
104
104
  delivery record alongside runtime decisions:
105
105
 
106
106
  ```ts
107
- const announcer = createDOMAnnouncer({
108
- 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) {
109
116
  store.recordDelivery({ runtimeId: "support", result });
110
117
  },
111
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
+ }
112
127
  ```
113
128
 
114
129
  This exposes the browser-level method and status (`aria-notify`, fallback live
@@ -133,12 +148,28 @@ focus. The overlay does not trap focus, create a live region, modify host
133
148
  layout, or install global shortcuts.
134
149
 
135
150
  ```ts
136
- import { mountDevtoolsOverlay } from "@generative-a11y/devtools/overlay";
151
+ import { mountOverlay } from "@generative-a11y/devtools/overlay";
137
152
 
138
- const overlay = mountDevtoolsOverlay({ store });
139
- overlay.dispose();
153
+ const overlay = mountOverlay({ store });
154
+ // Call overlay.dispose() when removing the workbench.
140
155
  ```
141
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
+
142
173
  ## Documentation
143
174
 
144
175
  - [Devtools guide](https://generativea11y.com/docs/devtools)
@@ -154,3 +185,17 @@ overlay.dispose();
154
185
  - [`@generative-a11y/core/testing`](https://generativea11y.com/api/core/testing)
155
186
  provides deterministic replay and semantic test assertions without another
156
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,6 +33,14 @@ 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 } : {},
37
45
  ..."runId" in event.event && event.event.runId ? { runId: event.event.runId } : {},
38
46
  ..."runInstanceId" in event.event && event.event.runInstanceId ? { runInstanceId: event.event.runInstanceId } : {},
@@ -191,8 +199,27 @@ function copyRuntimeSnapshot(source) {
191
199
  ...source.policy,
192
200
  text: Object.freeze({ ...source.policy.text }),
193
201
  tools: Object.freeze({ ...source.policy.tools }),
194
- workflows: Object.freeze({ ...source.policy.workflows })
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
+ } : {}
195
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
+ } : {},
196
223
  pending: Object.freeze({
197
224
  announcements: Object.freeze(
198
225
  source.pending.announcements.map((item) => Object.freeze({ ...item }))
@@ -220,7 +247,7 @@ function copyRuntimeSnapshot(source) {
220
247
  pendingCount: source.pendingCount
221
248
  });
222
249
  }
223
- function createDevtoolsStore(options = {}) {
250
+ function createStore(options = {}) {
224
251
  const maxEntries = options.maxEntries ?? 250;
225
252
  if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0)
226
253
  throw new RangeError("maxEntries must be a positive safe integer");
@@ -427,5 +454,5 @@ function createDevtoolsStore(options = {}) {
427
454
  }
428
455
  // Annotate the CommonJS export names for ESM import in node:
429
456
  0 && (module.exports = {
430
- createDevtoolsStore
457
+ createStore
431
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;
@@ -113,15 +115,15 @@ interface DevtoolsTraceExportV1 {
113
115
  readonly runtimeSnapshots: Readonly<Record<string, RuntimeDiagnosticSnapshotV1>>;
114
116
  readonly runtimeSources: Readonly<Record<string, DevtoolsRuntimeSource>>;
115
117
  }
116
- interface DevtoolsStoreOptions {
118
+ interface StoreOptions {
117
119
  readonly maxEntries?: number;
118
120
  }
119
121
  interface AttachRuntimeOptions {
120
122
  readonly id: string;
121
- readonly runtime: Pick<GenerativeA11yRuntime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
123
+ readonly runtime: Pick<Runtime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
122
124
  readonly source?: DevtoolsRuntimeSource;
123
125
  }
124
- interface DevtoolsStore {
126
+ interface Store {
125
127
  attachRuntime(options: AttachRuntimeOptions): () => void;
126
128
  getSnapshot(): DevtoolsSnapshot;
127
129
  subscribe(listener: () => void): () => void;
@@ -133,6 +135,6 @@ interface DevtoolsStore {
133
135
  exportTrace(): DevtoolsTraceExportV1;
134
136
  dispose(): void;
135
137
  }
136
- declare function createDevtoolsStore(options?: DevtoolsStoreOptions): DevtoolsStore;
138
+ declare function createStore(options?: StoreOptions): Store;
137
139
 
138
- 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;
@@ -113,15 +115,15 @@ interface DevtoolsTraceExportV1 {
113
115
  readonly runtimeSnapshots: Readonly<Record<string, RuntimeDiagnosticSnapshotV1>>;
114
116
  readonly runtimeSources: Readonly<Record<string, DevtoolsRuntimeSource>>;
115
117
  }
116
- interface DevtoolsStoreOptions {
118
+ interface StoreOptions {
117
119
  readonly maxEntries?: number;
118
120
  }
119
121
  interface AttachRuntimeOptions {
120
122
  readonly id: string;
121
- readonly runtime: Pick<GenerativeA11yRuntime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
123
+ readonly runtime: Pick<Runtime, "subscribeDiagnosticEvents" | "getDiagnosticSnapshot">;
122
124
  readonly source?: DevtoolsRuntimeSource;
123
125
  }
124
- interface DevtoolsStore {
126
+ interface Store {
125
127
  attachRuntime(options: AttachRuntimeOptions): () => void;
126
128
  getSnapshot(): DevtoolsSnapshot;
127
129
  subscribe(listener: () => void): () => void;
@@ -133,6 +135,6 @@ interface DevtoolsStore {
133
135
  exportTrace(): DevtoolsTraceExportV1;
134
136
  dispose(): void;
135
137
  }
136
- declare function createDevtoolsStore(options?: DevtoolsStoreOptions): DevtoolsStore;
138
+ declare function createStore(options?: StoreOptions): Store;
137
139
 
138
- 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,6 +9,14 @@ 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 } : {},
13
21
  ..."runId" in event.event && event.event.runId ? { runId: event.event.runId } : {},
14
22
  ..."runInstanceId" in event.event && event.event.runInstanceId ? { runInstanceId: event.event.runInstanceId } : {},
@@ -167,8 +175,27 @@ function copyRuntimeSnapshot(source) {
167
175
  ...source.policy,
168
176
  text: Object.freeze({ ...source.policy.text }),
169
177
  tools: Object.freeze({ ...source.policy.tools }),
170
- workflows: Object.freeze({ ...source.policy.workflows })
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
+ } : {}
171
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
+ } : {},
172
199
  pending: Object.freeze({
173
200
  announcements: Object.freeze(
174
201
  source.pending.announcements.map((item) => Object.freeze({ ...item }))
@@ -196,7 +223,7 @@ function copyRuntimeSnapshot(source) {
196
223
  pendingCount: source.pendingCount
197
224
  });
198
225
  }
199
- function createDevtoolsStore(options = {}) {
226
+ function createStore(options = {}) {
200
227
  const maxEntries = options.maxEntries ?? 250;
201
228
  if (!Number.isSafeInteger(maxEntries) || maxEntries <= 0)
202
229
  throw new RangeError("maxEntries must be a positive safe integer");
@@ -402,5 +429,5 @@ function createDevtoolsStore(options = {}) {
402
429
  };
403
430
  }
404
431
  export {
405
- createDevtoolsStore
432
+ createStore
406
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");
@@ -284,7 +284,7 @@ function relatedRecords(records, selected) {
284
284
  }
285
285
  function explain(record) {
286
286
  if (record.kind === "event-observed")
287
- 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.";
288
288
  if (record.kind === "dom-delivery")
289
289
  return record.deliveryStatus === "unavailable" ? "The DOM driver was unavailable, so no browser delivery action was observed." : "The DOM driver reported this delivery action.";
290
290
  return {
@@ -292,6 +292,9 @@ function explain(record) {
292
292
  coalesced: "The runtime merged this work with an existing queued announcement.",
293
293
  duplicate: "The runtime suppressed a recently delivered duplicate.",
294
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.",
295
298
  "queue-capacity": "The bounded queue rejected or displaced this work.",
296
299
  "scope-cancelled": "The lifecycle scope ended before this queued work delivered.",
297
300
  "runtime-disposed": "The runtime was disposed and cancelled remaining queued work.",
@@ -443,6 +446,30 @@ function Detail({
443
446
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: "ga-detail-section", children: [
444
447
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", { children: "Policy and scheduling" }),
445
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
+ ] }),
446
473
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { children: [
447
474
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("dt", { children: "Queue" }),
448
475
  /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("dd", { children: [
@@ -532,11 +559,7 @@ function List({
532
559
  }
533
560
  );
534
561
  }
535
- function DevtoolsInspector({
536
- store,
537
- onClose,
538
- onCopy
539
- }) {
562
+ function Inspector({ store, onClose, onCopy }) {
540
563
  const snapshot = useSnapshot(store);
541
564
  const reduceMotion = (0, import_react.useReducedMotion)();
542
565
  const [query, setQuery] = React4.useState("");
@@ -842,7 +865,7 @@ button:focus-visible, input:focus-visible, [role="listbox"]:focus-visible, [role
842
865
  .ga-workspace-feedback { top: 68px; color: #f7f7f7; background: #111; border-color: #111; border-radius: 3px; box-shadow: none; }
843
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; } }
844
867
  `;
845
- function mountDevtoolsOverlay(options) {
868
+ function mountOverlay(options) {
846
869
  const selectedDocument = options.document ?? (typeof document === "undefined" ? void 0 : document);
847
870
  if (!selectedDocument?.body)
848
871
  throw new Error("A mountable document is required");
@@ -897,7 +920,7 @@ function mountDevtoolsOverlay(options) {
897
920
  return clipboard.writeText(value);
898
921
  });
899
922
  root.render(
900
- (0, import_react2.createElement)(DevtoolsInspector, {
923
+ (0, import_react2.createElement)(Inspector, {
901
924
  onClose: close,
902
925
  onCopy: copyText,
903
926
  store: options.store
@@ -936,5 +959,5 @@ function mountDevtoolsOverlay(options) {
936
959
  }
937
960
  // Annotate the CommonJS export names for ESM import in node:
938
961
  0 && (module.exports = {
939
- mountDevtoolsOverlay
962
+ mountOverlay
940
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,7 +187,7 @@ 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";
@@ -250,7 +250,7 @@ function relatedRecords(records, selected) {
250
250
  }
251
251
  function explain(record) {
252
252
  if (record.kind === "event-observed")
253
- 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.";
254
254
  if (record.kind === "dom-delivery")
255
255
  return record.deliveryStatus === "unavailable" ? "The DOM driver was unavailable, so no browser delivery action was observed." : "The DOM driver reported this delivery action.";
256
256
  return {
@@ -258,6 +258,9 @@ function explain(record) {
258
258
  coalesced: "The runtime merged this work with an existing queued announcement.",
259
259
  duplicate: "The runtime suppressed a recently delivered duplicate.",
260
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.",
261
264
  "queue-capacity": "The bounded queue rejected or displaced this work.",
262
265
  "scope-cancelled": "The lifecycle scope ended before this queued work delivered.",
263
266
  "runtime-disposed": "The runtime was disposed and cancelled remaining queued work.",
@@ -409,6 +412,30 @@ function Detail({
409
412
  /* @__PURE__ */ jsxs2("section", { className: "ga-detail-section", children: [
410
413
  /* @__PURE__ */ jsx5("h4", { children: "Policy and scheduling" }),
411
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
+ ] }),
412
439
  /* @__PURE__ */ jsxs2("div", { children: [
413
440
  /* @__PURE__ */ jsx5("dt", { children: "Queue" }),
414
441
  /* @__PURE__ */ jsxs2("dd", { children: [
@@ -498,11 +525,7 @@ function List({
498
525
  }
499
526
  );
500
527
  }
501
- function DevtoolsInspector({
502
- store,
503
- onClose,
504
- onCopy
505
- }) {
528
+ function Inspector({ store, onClose, onCopy }) {
506
529
  const snapshot = useSnapshot(store);
507
530
  const reduceMotion = useReducedMotion();
508
531
  const [query, setQuery] = React4.useState("");
@@ -808,7 +831,7 @@ button:focus-visible, input:focus-visible, [role="listbox"]:focus-visible, [role
808
831
  .ga-workspace-feedback { top: 68px; color: #f7f7f7; background: #111; border-color: #111; border-radius: 3px; box-shadow: none; }
809
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; } }
810
833
  `;
811
- function mountDevtoolsOverlay(options) {
834
+ function mountOverlay(options) {
812
835
  const selectedDocument = options.document ?? (typeof document === "undefined" ? void 0 : document);
813
836
  if (!selectedDocument?.body)
814
837
  throw new Error("A mountable document is required");
@@ -863,7 +886,7 @@ function mountDevtoolsOverlay(options) {
863
886
  return clipboard.writeText(value);
864
887
  });
865
888
  root.render(
866
- createElement(DevtoolsInspector, {
889
+ createElement(Inspector, {
867
890
  onClose: close,
868
891
  onCopy: copyText,
869
892
  store: options.store
@@ -901,5 +924,5 @@ function mountDevtoolsOverlay(options) {
901
924
  };
902
925
  }
903
926
  export {
904
- mountDevtoolsOverlay
927
+ mountOverlay
905
928
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@generative-a11y/devtools",
3
- "version": "0.1.1",
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.3.0"
63
+ "@generative-a11y/core": "0.4.0"
64
64
  },
65
65
  "peerDependencies": {
66
66
  "react": "^19.0.0",