@aeptus/aexeo-emdash 0.8.10 → 0.8.12

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/CHANGELOG.md CHANGED
@@ -6,11 +6,97 @@ and the project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
- ## [0.8.10] - 2026-05-04
9
+ ## [0.8.12] - 2026-05-06
10
+
11
+ Adds **Accessibility (A11Y)** as a fifth audit pillar alongside
12
+ the four GEO axes. Per Aeptus's third-axis proposal, accessibility
13
+ is its own primary layer rather than cross-tags onto existing
14
+ pillars; the admin sidebar now has five pillar pages and the
15
+ shared `Layer` type carries `"accessibility"` as a value.
16
+
17
+ ### Added (engine via bridge)
18
+
19
+ - **Layer::Accessibility**, the fifth value of the `Layer`
20
+ enum / TS union. Mirror of the new `Accessibility` variant
21
+ added in `aexeo-contracts`. Findings produced by A11Y rules
22
+ carry `layers.primary === "accessibility"` and group under
23
+ the new pillar.
24
+ - **Six static A11Y rules** — pattern-matched on raw HTML
25
+ (no DOM, no browser; consistent with the rest of the
26
+ static auditor):
27
+ - `A11Y001` (error) — `<img>` missing `alt`. Default mode
28
+ skips images marked decorative via `alt=""`,
29
+ `role="presentation"`, `role="none"`, or
30
+ `aria-hidden="true"`. Strict mode (CLI flag
31
+ `--a11y-strict` on `aexeo-cli check` / `crawl`, or
32
+ `[accessibility] strict = true` in `aexeo.toml`) treats
33
+ only `alt=""` as decorative.
34
+ - `A11Y002` (error) — `<a>` / `<button>` with no
35
+ accessible text or label. Exempts elements whose only
36
+ inner content is `<img alt="...">` per ARIA accessible-
37
+ name calculation, plus those carrying `aria-label`,
38
+ `aria-labelledby`, or `title`.
39
+ - `A11Y003` (error) — duplicate `id="..."` values within
40
+ a single page. `<script>` and `<style>` blocks are
41
+ masked before scanning so JS/CSS string literals don't
42
+ trigger false positives.
43
+ - `A11Y004` (warn) — heading hierarchy jump (e.g. `h2 → h4`).
44
+ - `A11Y005` (warn) — page has no `<main>` landmark or
45
+ `role="main"` element. Skipped on non-content page kinds
46
+ (search, admin, feed, utility, notfound, legal).
47
+ - `A11Y006` (warn) — `alt` text matches the image filename
48
+ (placeholder/auto-generated alt text).
49
+
50
+ ### Cross-axis behavior
51
+
52
+ - Per-rule layer overrides give A11Y rules secondary GEO
53
+ layers where the signal genuinely feeds discovery or
54
+ citation: `A11Y001` / `A11Y006` add Retrievability
55
+ (alt → image search); `A11Y002` / `A11Y004` / `A11Y005`
56
+ add Citability (link graph, heading shape, landmarks all
57
+ feed citability).
58
+ - **A11Y findings ALWAYS bypass the `route_kinds` skip mask.**
59
+ Accessibility is for human users on every route — utility,
60
+ admin, and legal pages are not exempted. Per-rule
61
+ `[policy.suppressions]` still apply when an exception is
62
+ genuinely needed.
63
+ - The CMS plugin context does NOT disable the accessibility
64
+ group (unlike robots/sitemap/llm/surfaces/well_known/
65
+ headers/deployment, which describe the deployed-site
66
+ surface the CMS doesn't own). A missing alt or duplicate
67
+ id is exactly as wrong in a CMS preview as on the
68
+ deployed site.
69
+
70
+ ### Added (admin)
71
+
72
+ - **`/accessibility` admin page** — fifth pillar in the
73
+ sidebar, between Entity legitimacy and Document SEO.
74
+ Renders via the existing `PillarView` component
75
+ (parameterized by `layer` prop). Same finding-list shape
76
+ as the GEO pillars; nothing new for editors to learn.
77
+ - `Layer` union, `LAYERS_ORDERED`, `layerHumanLabel`, and
78
+ `layerOneLineDescription` extended with the new value;
79
+ every TS switch statement that consumed Layer was
80
+ updated.
81
+
82
+ ### Fixed
83
+
84
+ - **Rule-id prefix extractor now handles alphanumeric
85
+ prefixes.** Previously `take_while(is_ascii_uppercase)`
86
+ was used, which would silently truncate `A11Y001` to
87
+ `"A"` and fall through to the default citability layer.
88
+ Replaced with `trim_end_matches(is_ascii_digit)` based
89
+ on the structural rule (rule ids are `<PREFIX><NNN>`,
90
+ prefixes never end in a digit). No existing rule used
91
+ an alphanumeric prefix so this is forward-compatible
92
+ only. Locked in by new unit tests in `aexeo-core`.
10
93
 
11
- Two follow-up quality fixes from Aeptus's 0.8.9 retest, plus
12
- four new product-level capabilities from the post-retest
13
- roadmap discussion.
94
+ ## [0.8.11] - 2026-05-05
95
+
96
+ Picks up the post-0.8.10 product additions and the FACTS003
97
+ quality fixes Aeptus reported after running 0.8.10 in
98
+ preview. 0.8.10 was already on npm before these landed; this
99
+ release bundles them into one consumer-visible bump.
14
100
 
15
101
  ### Added (engine via bridge)
16
102
 
@@ -41,6 +127,68 @@ roadmap discussion.
41
127
 
42
128
  ### Fixed
43
129
 
130
+ - **FACTS003 schema half no longer fires on no-schema input.**
131
+ Configured-mode CMS document sets don't carry rendered JSON-LD,
132
+ so `pages_with_schema = 0`. The previous logic emitted
133
+ `organization_schema.name` (Error) and `organization_schema.url`
134
+ (Warning) with empty `observed` — `iter().any()` is trivially
135
+ false on an empty set, so the negation always fired. Aeptus
136
+ reported this as the first half of FACTS003 noise after
137
+ installing 0.8.10. Schema block is now gated on
138
+ `pages_with_schema > 0`; the `structured_truth_source` enum
139
+ (`Manifest` vs `SchemaAndManifest`) still records whether
140
+ schema participated, so downstream consumers can tell the
141
+ difference between "schema agreed" and "schema wasn't part
142
+ of the assessment".
143
+ - **FACTS003 title check no longer fires on legal/utility
144
+ pages or on pages whose JSON-LD declares the brand.** Aeptus
145
+ reported title warnings on `/privacy`, `/terms`, `/principles`,
146
+ `/references`, `/signup` simply because their titles weren't
147
+ "Aeptus". The check now (a) skips pages classified as
148
+ `PageKind::{Search, Admin, Feed, Utility, NotFound, Legal}`,
149
+ and (b) treats per-page identity-bearing schema with a name
150
+ matching the brand as another `identity_present_elsewhere`
151
+ signal. Content pages that genuinely never mention the brand
152
+ in any identity-bearing surface still fire — the user can
153
+ silence those via the `[route_kinds]` block from this same
154
+ release.
155
+
156
+ ### Notes for hosts upgrading from 0.8.10
157
+
158
+ - No code changes required.
159
+ - After bumping, the admin's findings page will show:
160
+ - **New** SOC006 findings on every document missing og:image.
161
+ - **New** SOC009 nudges on documents declaring
162
+ `twitter:card = summary`.
163
+ - **New** CNT006 nudges on documents whose visible text has
164
+ generic-beneficiary copy without concrete anchors.
165
+ - **Fewer** FACTS003 findings: schema-half mismatches gone
166
+ when the CMS doc set lacks JSON-LD; title warnings gone
167
+ on legal/utility pages.
168
+ - If the new SOC/CNT findings are too noisy on a specific
169
+ route family, declare a `[route_kinds.X]` block in
170
+ `aexeo.toml` with `match` patterns and a `skip_rules` list.
171
+ - For the infrastructure-level audit (robots/sitemap/llms/
172
+ well-known/etc.), run `aexeo-cli check` against your static
173
+ dist; that's where those rules belong.
174
+
175
+ ### CLI side (aexeo-cli v0.0.16, same release window)
176
+
177
+ - **`aexeo-cli crawl --cf-access-id … --cf-access-secret …`**
178
+ injects Cloudflare Access service-token headers
179
+ (`CF-Access-Client-Id` + `CF-Access-Client-Secret`) on every
180
+ fetch. Falls back to env vars `CF_ACCESS_CLIENT_ID` /
181
+ `CF_ACCESS_CLIENT_SECRET` when flags are absent. Closes the
182
+ loop for hosts whose preview deploys are behind Cloudflare
183
+ Access (Aeptus's CI was blocked on this).
184
+
185
+ ## [0.8.10] - 2026-05-04
186
+
187
+ Two follow-up quality fixes from Aeptus's 0.8.9 retest. The
188
+ local refresh path is now end-to-end correct.
189
+
190
+ ### Fixed
191
+
44
192
  - **Findings now attribute to document routes, not synthesized
45
193
  HTML filenames.** v0.8.9's bridge set `page.path` to
46
194
  `emdash/<route>.html`, which the plugin's
@@ -79,39 +227,14 @@ roadmap discussion.
79
227
 
80
228
  ### Notes for hosts upgrading from 0.8.9
81
229
 
82
- - No code changes required for any of the fixes or additions.
83
- - After bumping, the admin's findings page will show:
84
- - Fewer findings overall (infrastructure noise is gone) and
85
- every finding correctly attributed to its document route.
86
- - **New** SOC006 findings on every document missing og:image.
87
- - **New** SOC009 nudges on documents declaring
88
- `twitter:card = summary`.
89
- - **New** CNT006 nudges on documents whose visible text has
90
- generic-beneficiary copy without concrete anchors.
91
- - If the new SOC/CNT findings are too noisy on a specific
92
- route family, declare a `[route_kinds.X]` block in
93
- `aexeo.toml` with `match` patterns and a `skip_rules` list.
94
- Example:
95
- ```toml
96
- [route_kinds.manifesto]
97
- match = ["/foundations/"]
98
- skip_rules = ["CNT006", "GEO007"]
99
- noindex = false
100
- ```
230
+ - No code changes required.
231
+ - After bumping, the admin's findings page will show fewer
232
+ findings (infrastructure noise gone) and every finding
233
+ correctly attributed to its document route.
101
234
  - For the infrastructure-level audit (robots/sitemap/llms/
102
235
  well-known/etc.), run `aexeo-cli check` against your static
103
236
  dist; that's where those rules belong.
104
237
 
105
- ### CLI side (aexeo-cli, same release)
106
-
107
- - **`aexeo-cli crawl --cf-access-id … --cf-access-secret …`**
108
- injects Cloudflare Access service-token headers
109
- (`CF-Access-Client-Id` + `CF-Access-Client-Secret`) on every
110
- fetch. Falls back to env vars `CF_ACCESS_CLIENT_ID` /
111
- `CF_ACCESS_CLIENT_SECRET` when flags are absent. Closes the
112
- loop for hosts whose preview deploys are behind Cloudflare
113
- Access (Aeptus's CI was blocked on this).
114
-
115
238
  ## [0.8.9] - 2026-05-04
116
239
 
117
240
  ### Fixed
@@ -1014,7 +1137,8 @@ First public release.
1014
1137
  `astro.config.mjs` for the WASM import to resolve to a
1015
1138
  precompiled `WebAssembly.Module`. Not optional.
1016
1139
 
1017
- [Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.10...HEAD
1140
+ [Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.11...HEAD
1141
+ [0.8.11]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.10...aexeo-emdash-v0.8.11
1018
1142
  [0.8.10]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.9...aexeo-emdash-v0.8.10
1019
1143
  [0.8.9]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.8...aexeo-emdash-v0.8.9
1020
1144
  [0.8.8]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.7...aexeo-emdash-v0.8.8
@@ -0,0 +1,3 @@
1
+ import * as React from "react";
2
+ export declare function Accessibility(): React.JSX.Element;
3
+ //# sourceMappingURL=Accessibility.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Accessibility.d.ts","sourceRoot":"","sources":["../../src/admin/Accessibility.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAG/B,wBAAgB,aAAa,IAAI,KAAK,CAAC,GAAG,CAAC,OAAO,CAEjD"}
package/dist/admin.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Absorbability } from "./admin/Absorbability.js";
2
+ import { Accessibility } from "./admin/Accessibility.js";
2
3
  import { Citability } from "./admin/Citability.js";
3
4
  import { EntityLegitimacy } from "./admin/EntityLegitimacy.js";
4
5
  import { Facts } from "./admin/Facts.js";
@@ -9,6 +10,7 @@ export declare const pages: {
9
10
  "/citability": typeof Citability;
10
11
  "/absorbability": typeof Absorbability;
11
12
  "/entity-legitimacy": typeof EntityLegitimacy;
13
+ "/accessibility": typeof Accessibility;
12
14
  "/findings": typeof Findings;
13
15
  "/facts": typeof Facts;
14
16
  };
@@ -1 +1 @@
1
- {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,eAAO,MAAM,KAAK;;;;;;;CAajB,CAAC"}
1
+ {"version":3,"file":"admin.d.ts","sourceRoot":"","sources":["../src/admin.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,eAAO,MAAM,KAAK;;;;;;;;CAcjB,CAAC"}
package/dist/admin.js CHANGED
@@ -12,6 +12,8 @@ function layerHumanLabel(layer) {
12
12
  return "Absorbability";
13
13
  case "entity_legitimacy":
14
14
  return "Entity legitimacy";
15
+ case "accessibility":
16
+ return "Accessibility";
15
17
  }
16
18
  }
17
19
  function layerOneLineDescription(layer) {
@@ -24,6 +26,8 @@ function layerOneLineDescription(layer) {
24
26
  return "Does the answer actually use this content? Cite-ready evidence, mirrors, llms.txt.";
25
27
  case "entity_legitimacy":
26
28
  return "Does the entity exist strongly enough to be selected at all? Aexeo surfaces this layer; it does not fix it.";
29
+ case "accessibility":
30
+ return "Can humans use the page? Alt text, accessible labels, valid id usage, heading shape, landmarks.";
27
31
  }
28
32
  }
29
33
 
@@ -255,15 +259,21 @@ function Absorbability() {
255
259
  return /* @__PURE__ */ jsx2(PillarView, { layer: "absorbability" });
256
260
  }
257
261
 
258
- // src/admin/Citability.tsx
262
+ // src/admin/Accessibility.tsx
259
263
  import { jsx as jsx3 } from "react/jsx-runtime";
264
+ function Accessibility() {
265
+ return /* @__PURE__ */ jsx3(PillarView, { layer: "accessibility" });
266
+ }
267
+
268
+ // src/admin/Citability.tsx
269
+ import { jsx as jsx4 } from "react/jsx-runtime";
260
270
  function Citability() {
261
- return /* @__PURE__ */ jsx3(PillarView, { layer: "citability" });
271
+ return /* @__PURE__ */ jsx4(PillarView, { layer: "citability" });
262
272
  }
263
273
 
264
274
  // src/admin/EntityPresence.tsx
265
275
  import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
266
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
276
+ import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
267
277
  var PLUGIN_ID2 = "aexeo-emdash";
268
278
  var API_BASE2 = "/_emdash/api";
269
279
  var SOURCE_LABELS = {
@@ -315,36 +325,36 @@ function EntityPresence() {
315
325
  ] });
316
326
  }
317
327
  if (data === null) {
318
- return /* @__PURE__ */ jsx4("div", { className: "text-sm text-kumo-subtle", children: "Loading presence data\u2026" });
328
+ return /* @__PURE__ */ jsx5("div", { className: "text-sm text-kumo-subtle", children: "Loading presence data\u2026" });
319
329
  }
320
330
  if (data.state === "no_manifest") {
321
- return /* @__PURE__ */ jsx4("div", { className: "rounded border border-kumo-line bg-kumo-canvas p-3 text-sm", children: "Author the truth manifest first (above). The presence checks need at least an organization name and website." });
331
+ return /* @__PURE__ */ jsx5("div", { className: "rounded border border-kumo-line bg-kumo-canvas p-3 text-sm", children: "Author the truth manifest first (above). The presence checks need at least an organization name and website." });
322
332
  }
323
333
  if (data.state === "no_organization") {
324
334
  return /* @__PURE__ */ jsxs2("div", { className: "rounded border border-kumo-line bg-kumo-canvas p-3 text-sm", children: [
325
335
  "The manifest exists but has no organization. Add an",
326
336
  " ",
327
- /* @__PURE__ */ jsx4("code", { children: "organization" }),
337
+ /* @__PURE__ */ jsx5("code", { children: "organization" }),
328
338
  " entry with at least a ",
329
- /* @__PURE__ */ jsx4("code", { children: "name" }),
339
+ /* @__PURE__ */ jsx5("code", { children: "name" }),
330
340
  " ",
331
341
  "and ideally a ",
332
- /* @__PURE__ */ jsx4("code", { children: "website" }),
342
+ /* @__PURE__ */ jsx5("code", { children: "website" }),
333
343
  ", then refresh."
334
344
  ] });
335
345
  }
336
346
  return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
337
347
  /* @__PURE__ */ jsxs2("header", { className: "flex items-baseline justify-between gap-3", children: [
338
348
  /* @__PURE__ */ jsxs2("div", { children: [
339
- /* @__PURE__ */ jsx4("h3", { className: "text-sm font-medium", children: "Public web presence" }),
349
+ /* @__PURE__ */ jsx5("h3", { className: "text-sm font-medium", children: "Public web presence" }),
340
350
  /* @__PURE__ */ jsxs2("p", { className: "mt-1 text-xs text-kumo-subtle", children: [
341
351
  "What the open web shows about",
342
352
  " ",
343
- /* @__PURE__ */ jsx4("strong", { children: data.entityName ?? "this entity" }),
353
+ /* @__PURE__ */ jsx5("strong", { children: data.entityName ?? "this entity" }),
344
354
  ". Aexeo does not score this layer \u2014 it surfaces it. Click through each row to verify."
345
355
  ] })
346
356
  ] }),
347
- /* @__PURE__ */ jsx4(
357
+ /* @__PURE__ */ jsx5(
348
358
  "button",
349
359
  {
350
360
  type: "button",
@@ -358,7 +368,7 @@ function EntityPresence() {
358
368
  data.state === "empty" && /* @__PURE__ */ jsxs2("div", { className: "rounded border border-kumo-line bg-kumo-canvas p-3 text-sm", children: [
359
369
  "No checks have been run yet for",
360
370
  " ",
361
- /* @__PURE__ */ jsx4("strong", { children: data.entityName }),
371
+ /* @__PURE__ */ jsx5("strong", { children: data.entityName }),
362
372
  ". Hit Refresh to query the five sources."
363
373
  ] }),
364
374
  data.state === "stale" && data.ageMinutes !== null && /* @__PURE__ */ jsxs2("div", { className: "rounded border border-amber-200 bg-amber-50 p-2 text-xs text-amber-900", children: [
@@ -371,28 +381,28 @@ function EntityPresence() {
371
381
  formatAge(data.ageMinutes),
372
382
  " ago."
373
383
  ] }),
374
- (data.state === "fresh" || data.state === "stale") && /* @__PURE__ */ jsx4("ul", { className: "space-y-2", children: orderResults(data.results).map((result) => /* @__PURE__ */ jsx4(SourceCard, { result }, result.source)) })
384
+ (data.state === "fresh" || data.state === "stale") && /* @__PURE__ */ jsx5("ul", { className: "space-y-2", children: orderResults(data.results).map((result) => /* @__PURE__ */ jsx5(SourceCard, { result }, result.source)) })
375
385
  ] });
376
386
  }
377
387
  function SourceCard({ result }) {
378
388
  const label = SOURCE_LABELS[result.source] ?? result.source;
379
389
  const tone = toneFor(result.status);
380
- return /* @__PURE__ */ jsx4(
390
+ return /* @__PURE__ */ jsx5(
381
391
  "li",
382
392
  {
383
393
  className: `rounded border p-3 ${tone.border} ${tone.bg} text-sm`,
384
394
  children: /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
385
395
  /* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
386
396
  /* @__PURE__ */ jsxs2("div", { className: "flex items-center gap-2", children: [
387
- /* @__PURE__ */ jsx4("span", { className: `text-xs font-medium ${tone.icon}`, children: tone.symbol }),
388
- /* @__PURE__ */ jsx4("span", { className: "font-medium", children: label }),
389
- /* @__PURE__ */ jsx4("span", { className: `text-xs ${tone.statusText}`, children: statusLabel(result.status) })
397
+ /* @__PURE__ */ jsx5("span", { className: `text-xs font-medium ${tone.icon}`, children: tone.symbol }),
398
+ /* @__PURE__ */ jsx5("span", { className: "font-medium", children: label }),
399
+ /* @__PURE__ */ jsx5("span", { className: `text-xs ${tone.statusText}`, children: statusLabel(result.status) })
390
400
  ] }),
391
- result.label !== void 0 && /* @__PURE__ */ jsx4("div", { className: "mt-1 truncate", children: result.label }),
392
- result.extra !== void 0 && /* @__PURE__ */ jsx4("div", { className: "mt-0.5 text-xs text-kumo-subtle", children: result.extra }),
393
- result.error !== void 0 && /* @__PURE__ */ jsx4("div", { className: "mt-0.5 text-xs italic text-kumo-subtle", children: result.error })
401
+ result.label !== void 0 && /* @__PURE__ */ jsx5("div", { className: "mt-1 truncate", children: result.label }),
402
+ result.extra !== void 0 && /* @__PURE__ */ jsx5("div", { className: "mt-0.5 text-xs text-kumo-subtle", children: result.extra }),
403
+ result.error !== void 0 && /* @__PURE__ */ jsx5("div", { className: "mt-0.5 text-xs italic text-kumo-subtle", children: result.error })
394
404
  ] }),
395
- result.url !== void 0 && /* @__PURE__ */ jsx4(
405
+ result.url !== void 0 && /* @__PURE__ */ jsx5(
396
406
  "a",
397
407
  {
398
408
  href: result.url,
@@ -497,7 +507,7 @@ async function callPresenceRoute(kind) {
497
507
 
498
508
  // src/admin/Facts.tsx
499
509
  import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
500
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
510
+ import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
501
511
  var PLUGIN_ID3 = "aexeo-emdash";
502
512
  var API_BASE3 = "/_emdash/api";
503
513
  function Facts() {
@@ -575,13 +585,13 @@ function Facts() {
575
585
  const validationOk = validation !== null && validation.validation.valid && validation.validation.errors.length === 0 && validation.assessment.mismatches.filter((m) => m.severity === "error").length === 0;
576
586
  return /* @__PURE__ */ jsxs3("div", { className: "space-y-6 p-4", children: [
577
587
  /* @__PURE__ */ jsxs3("header", { children: [
578
- /* @__PURE__ */ jsx5("h1", { className: "text-xl font-semibold", children: "Truth manifest" }),
588
+ /* @__PURE__ */ jsx6("h1", { className: "text-xl font-semibold", children: "Truth manifest" }),
579
589
  /* @__PURE__ */ jsxs3("p", { className: "mt-1 text-sm text-kumo-subtle", children: [
580
590
  "Author a ",
581
- /* @__PURE__ */ jsx5("code", { children: "facts.json" }),
591
+ /* @__PURE__ */ jsx6("code", { children: "facts.json" }),
582
592
  " using your LLM of choice. The plugin frames the question, validates the answer, and stores the result. Read",
583
593
  " ",
584
- /* @__PURE__ */ jsx5(
594
+ /* @__PURE__ */ jsx6(
585
595
  "a",
586
596
  {
587
597
  href: "https://github.com/schiste/Aexeo/blob/main/docs/facts-manifest.md",
@@ -600,13 +610,13 @@ function Facts() {
600
610
  loadError
601
611
  ] }),
602
612
  /* @__PURE__ */ jsxs3("section", { className: "rounded border border-kumo-line p-3", children: [
603
- /* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "Status" }),
604
- /* @__PURE__ */ jsx5("p", { className: "mt-2 text-sm", children: data === null ? "Loading\u2026" : data.present ? "\u2713 A truth manifest is stored. Editing the JSON below replaces it on Save." : "No truth manifest stored. Generate the prompt below to author one." })
613
+ /* @__PURE__ */ jsx6("h2", { className: "text-sm font-medium", children: "Status" }),
614
+ /* @__PURE__ */ jsx6("p", { className: "mt-2 text-sm", children: data === null ? "Loading\u2026" : data.present ? "\u2713 A truth manifest is stored. Editing the JSON below replaces it on Save." : "No truth manifest stored. Generate the prompt below to author one." })
605
615
  ] }),
606
616
  /* @__PURE__ */ jsxs3("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
607
- /* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "1. Generate authoring prompt" }),
608
- /* @__PURE__ */ jsx5("p", { className: "text-sm text-kumo-subtle", children: "Copies a populated prompt to your clipboard. Paste it into Claude/GPT/etc., answer the LLM's questions, and bring the resulting JSON back here." }),
609
- /* @__PURE__ */ jsx5(
617
+ /* @__PURE__ */ jsx6("h2", { className: "text-sm font-medium", children: "1. Generate authoring prompt" }),
618
+ /* @__PURE__ */ jsx6("p", { className: "text-sm text-kumo-subtle", children: "Copies a populated prompt to your clipboard. Paste it into Claude/GPT/etc., answer the LLM's questions, and bring the resulting JSON back here." }),
619
+ /* @__PURE__ */ jsx6(
610
620
  "button",
611
621
  {
612
622
  type: "button",
@@ -618,8 +628,8 @@ function Facts() {
618
628
  )
619
629
  ] }),
620
630
  /* @__PURE__ */ jsxs3("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
621
- /* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "2. Paste & validate" }),
622
- /* @__PURE__ */ jsx5(
631
+ /* @__PURE__ */ jsx6("h2", { className: "text-sm font-medium", children: "2. Paste & validate" }),
632
+ /* @__PURE__ */ jsx6(
623
633
  "textarea",
624
634
  {
625
635
  value: draft,
@@ -631,7 +641,7 @@ function Facts() {
631
641
  }
632
642
  ),
633
643
  /* @__PURE__ */ jsxs3("div", { className: "flex gap-2", children: [
634
- /* @__PURE__ */ jsx5(
644
+ /* @__PURE__ */ jsx6(
635
645
  "button",
636
646
  {
637
647
  type: "button",
@@ -641,7 +651,7 @@ function Facts() {
641
651
  children: busy === "validate" ? "Validating\u2026" : "Validate"
642
652
  }
643
653
  ),
644
- /* @__PURE__ */ jsx5(
654
+ /* @__PURE__ */ jsx6(
645
655
  "button",
646
656
  {
647
657
  type: "button",
@@ -654,8 +664,8 @@ function Facts() {
654
664
  )
655
665
  ] })
656
666
  ] }),
657
- toast !== null && /* @__PURE__ */ jsx5("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
658
- validation !== null && /* @__PURE__ */ jsx5(ValidationReport, { result: validation })
667
+ toast !== null && /* @__PURE__ */ jsx6("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
668
+ validation !== null && /* @__PURE__ */ jsx6(ValidationReport, { result: validation })
659
669
  ] });
660
670
  }
661
671
  function ValidationReport({
@@ -668,12 +678,12 @@ function ValidationReport({
668
678
  (m) => m.severity === "warning"
669
679
  );
670
680
  return /* @__PURE__ */ jsxs3("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
671
- /* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "Validation result" }),
681
+ /* @__PURE__ */ jsx6("h2", { className: "text-sm font-medium", children: "Validation result" }),
672
682
  /* @__PURE__ */ jsxs3("div", { className: "text-sm", children: [
673
683
  /* @__PURE__ */ jsxs3("div", { children: [
674
684
  "Shape:",
675
685
  " ",
676
- /* @__PURE__ */ jsx5("strong", { children: result.validation.valid ? "valid" : "invalid" }),
686
+ /* @__PURE__ */ jsx6("strong", { children: result.validation.valid ? "valid" : "invalid" }),
677
687
  " ",
678
688
  "\xB7 org",
679
689
  " ",
@@ -691,12 +701,12 @@ function ValidationReport({
691
701
  ] }),
692
702
  /* @__PURE__ */ jsxs3("div", { children: [
693
703
  "Score: ",
694
- /* @__PURE__ */ jsx5("strong", { children: result.assessment.score }),
704
+ /* @__PURE__ */ jsx6("strong", { children: result.assessment.score }),
695
705
  "/",
696
706
  result.assessment.score_ceiling,
697
707
  " \xB7 source =",
698
708
  " ",
699
- /* @__PURE__ */ jsx5("code", { children: result.assessment.structured_truth_source }),
709
+ /* @__PURE__ */ jsx6("code", { children: result.assessment.structured_truth_source }),
700
710
  " \xB7",
701
711
  " ",
702
712
  result.assessment.pages_analyzed,
@@ -707,20 +717,20 @@ function ValidationReport({
707
717
  ] })
708
718
  ] }),
709
719
  result.validation.errors.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-2 text-sm", children: [
710
- /* @__PURE__ */ jsx5("strong", { children: "Schema errors:" }),
711
- /* @__PURE__ */ jsx5("ul", { className: "mt-1 list-disc pl-5", children: result.validation.errors.map((e, i) => /* @__PURE__ */ jsx5("li", { children: e }, i)) })
720
+ /* @__PURE__ */ jsx6("strong", { children: "Schema errors:" }),
721
+ /* @__PURE__ */ jsx6("ul", { className: "mt-1 list-disc pl-5", children: result.validation.errors.map((e, i) => /* @__PURE__ */ jsx6("li", { children: e }, i)) })
712
722
  ] }),
713
723
  result.validation.warnings.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-yellow-500/40 bg-yellow-500/10 p-2 text-sm", children: [
714
- /* @__PURE__ */ jsx5("strong", { children: "Schema warnings:" }),
715
- /* @__PURE__ */ jsx5("ul", { className: "mt-1 list-disc pl-5", children: result.validation.warnings.map((w, i) => /* @__PURE__ */ jsx5("li", { children: w }, i)) })
724
+ /* @__PURE__ */ jsx6("strong", { children: "Schema warnings:" }),
725
+ /* @__PURE__ */ jsx6("ul", { className: "mt-1 list-disc pl-5", children: result.validation.warnings.map((w, i) => /* @__PURE__ */ jsx6("li", { children: w }, i)) })
716
726
  ] }),
717
727
  errMismatches.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-2 text-sm", children: [
718
- /* @__PURE__ */ jsx5("strong", { children: "Mismatches with site (errors):" }),
719
- /* @__PURE__ */ jsx5(MismatchList, { items: errMismatches })
728
+ /* @__PURE__ */ jsx6("strong", { children: "Mismatches with site (errors):" }),
729
+ /* @__PURE__ */ jsx6(MismatchList, { items: errMismatches })
720
730
  ] }),
721
731
  warnMismatches.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-yellow-500/40 bg-yellow-500/10 p-2 text-sm", children: [
722
- /* @__PURE__ */ jsx5("strong", { children: "Mismatches with site (warnings):" }),
723
- /* @__PURE__ */ jsx5(MismatchList, { items: warnMismatches })
732
+ /* @__PURE__ */ jsx6("strong", { children: "Mismatches with site (warnings):" }),
733
+ /* @__PURE__ */ jsx6(MismatchList, { items: warnMismatches })
724
734
  ] }),
725
735
  result.validation.errors.length === 0 && result.assessment.mismatches.length === 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-green-500/40 bg-green-500/10 p-2 text-sm", children: [
726
736
  "\u2713 Manifest is valid and agrees with on-page schema.org. Click",
@@ -732,16 +742,16 @@ function ValidationReport({
732
742
  function MismatchList({
733
743
  items
734
744
  }) {
735
- return /* @__PURE__ */ jsx5("ul", { className: "mt-1 list-disc pl-5", children: items.map((m, i) => /* @__PURE__ */ jsxs3("li", { children: [
736
- /* @__PURE__ */ jsx5("code", { className: "text-xs", children: m.route }),
745
+ return /* @__PURE__ */ jsx6("ul", { className: "mt-1 list-disc pl-5", children: items.map((m, i) => /* @__PURE__ */ jsxs3("li", { children: [
746
+ /* @__PURE__ */ jsx6("code", { className: "text-xs", children: m.route }),
737
747
  " \xB7 ",
738
748
  m.field,
739
749
  ": expected",
740
750
  " ",
741
- /* @__PURE__ */ jsx5("code", { className: "text-xs", children: m.expected }),
751
+ /* @__PURE__ */ jsx6("code", { className: "text-xs", children: m.expected }),
742
752
  ", observed",
743
753
  " ",
744
- /* @__PURE__ */ jsx5("code", { className: "text-xs", children: m.observed }),
754
+ /* @__PURE__ */ jsx6("code", { className: "text-xs", children: m.observed }),
745
755
  " ",
746
756
  /* @__PURE__ */ jsxs3("span", { className: "text-xs text-kumo-subtle", children: [
747
757
  "(",
@@ -770,19 +780,19 @@ async function callRoute(kind, extra) {
770
780
  }
771
781
 
772
782
  // src/admin/EntityLegitimacy.tsx
773
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
783
+ import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
774
784
  function EntityLegitimacy() {
775
- return /* @__PURE__ */ jsx6(
785
+ return /* @__PURE__ */ jsx7(
776
786
  PillarView,
777
787
  {
778
788
  layer: "entity_legitimacy",
779
789
  extraSlot: /* @__PURE__ */ jsxs4("div", { className: "space-y-3", children: [
780
790
  /* @__PURE__ */ jsxs4("section", { className: "rounded border border-kumo-line p-3", children: [
781
- /* @__PURE__ */ jsx6("h2", { className: "text-sm font-medium", children: "Truth manifest" }),
782
- /* @__PURE__ */ jsx6("p", { className: "mt-1 text-xs text-kumo-subtle", children: "The structured assertion of who the organization is, what the products are, and the terminology to use/avoid. This is the primary entity-legitimacy signal Aexeo can write \u2014 the rest comes from third-party presence Aexeo can only observe." }),
783
- /* @__PURE__ */ jsx6("div", { className: "mt-3", children: /* @__PURE__ */ jsx6(Facts, {}) })
791
+ /* @__PURE__ */ jsx7("h2", { className: "text-sm font-medium", children: "Truth manifest" }),
792
+ /* @__PURE__ */ jsx7("p", { className: "mt-1 text-xs text-kumo-subtle", children: "The structured assertion of who the organization is, what the products are, and the terminology to use/avoid. This is the primary entity-legitimacy signal Aexeo can write \u2014 the rest comes from third-party presence Aexeo can only observe." }),
793
+ /* @__PURE__ */ jsx7("div", { className: "mt-3", children: /* @__PURE__ */ jsx7(Facts, {}) })
784
794
  ] }),
785
- /* @__PURE__ */ jsx6("section", { className: "rounded border border-kumo-line p-3", children: /* @__PURE__ */ jsx6(EntityPresence, {}) })
795
+ /* @__PURE__ */ jsx7("section", { className: "rounded border border-kumo-line p-3", children: /* @__PURE__ */ jsx7(EntityPresence, {}) })
786
796
  ] })
787
797
  }
788
798
  );
@@ -790,7 +800,7 @@ function EntityLegitimacy() {
790
800
 
791
801
  // src/admin/Findings.tsx
792
802
  import { useCallback as useCallback4, useEffect as useEffect4, useState as useState4 } from "react";
793
- import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
803
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
794
804
  var PLUGIN_ID4 = "aexeo-emdash";
795
805
  var API_BASE4 = "/_emdash/api";
796
806
  function Findings() {
@@ -854,16 +864,16 @@ function Findings() {
854
864
  void load();
855
865
  }, [load]);
856
866
  if (state.loading && state.payload === null) {
857
- return /* @__PURE__ */ jsx7("div", { className: "p-4 text-sm text-kumo-subtle", children: "Loading findings\u2026" });
867
+ return /* @__PURE__ */ jsx8("div", { className: "p-4 text-sm text-kumo-subtle", children: "Loading findings\u2026" });
858
868
  }
859
869
  if (state.error !== null) {
860
870
  return /* @__PURE__ */ jsxs5("div", { className: "p-4", children: [
861
- /* @__PURE__ */ jsx7("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
871
+ /* @__PURE__ */ jsx8("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
862
872
  /* @__PURE__ */ jsxs5("p", { className: "mt-2 rounded border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-700", children: [
863
873
  "Failed to load: ",
864
874
  state.error
865
875
  ] }),
866
- /* @__PURE__ */ jsx7(
876
+ /* @__PURE__ */ jsx8(
867
877
  "button",
868
878
  {
869
879
  type: "button",
@@ -876,7 +886,7 @@ function Findings() {
876
886
  }
877
887
  const payload = state.payload;
878
888
  if (payload === null) {
879
- return /* @__PURE__ */ jsx7("div", { className: "p-4 text-sm text-kumo-subtle", children: "No data." });
889
+ return /* @__PURE__ */ jsx8("div", { className: "p-4 text-sm text-kumo-subtle", children: "No data." });
880
890
  }
881
891
  const routesByPath = /* @__PURE__ */ new Map();
882
892
  for (const route of payload.routes) {
@@ -885,8 +895,8 @@ function Findings() {
885
895
  return /* @__PURE__ */ jsxs5("div", { className: "space-y-4 p-4", children: [
886
896
  /* @__PURE__ */ jsxs5("header", { className: "flex items-center justify-between gap-4", children: [
887
897
  /* @__PURE__ */ jsxs5("div", { children: [
888
- /* @__PURE__ */ jsx7("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
889
- /* @__PURE__ */ jsx7("p", { className: "mt-1 text-sm text-kumo-subtle", children: payload.totals.findings === 0 ? /* @__PURE__ */ jsx7(Fragment2, { children: "No findings yet \u2014 click Refresh to evaluate the site." }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
898
+ /* @__PURE__ */ jsx8("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
899
+ /* @__PURE__ */ jsx8("p", { className: "mt-1 text-sm text-kumo-subtle", children: payload.totals.findings === 0 ? /* @__PURE__ */ jsx8(Fragment2, { children: "No findings yet \u2014 click Refresh to evaluate the site." }) : /* @__PURE__ */ jsxs5(Fragment2, { children: [
890
900
  payload.totals.findings,
891
901
  " findings across ",
892
902
  payload.totals.routes,
@@ -898,7 +908,7 @@ function Findings() {
898
908
  " warnings."
899
909
  ] }) })
900
910
  ] }),
901
- /* @__PURE__ */ jsx7(
911
+ /* @__PURE__ */ jsx8(
902
912
  "button",
903
913
  {
904
914
  type: "button",
@@ -909,29 +919,29 @@ function Findings() {
909
919
  }
910
920
  )
911
921
  ] }),
912
- toast !== null && /* @__PURE__ */ jsx7("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
922
+ toast !== null && /* @__PURE__ */ jsx8("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
913
923
  payload.sitewideFindings.length > 0 && /* @__PURE__ */ jsxs5("section", { className: "rounded border border-kumo-line p-3", children: [
914
- /* @__PURE__ */ jsx7("h2", { className: "text-sm font-medium", children: "Sitewide" }),
915
- /* @__PURE__ */ jsx7("ul", { className: "mt-2 space-y-1 text-sm", children: payload.sitewideFindings.map((finding, i) => /* @__PURE__ */ jsxs5("li", { className: "flex items-start gap-2", children: [
916
- /* @__PURE__ */ jsx7(SeverityBadge2, { severity: finding.severity }),
917
- /* @__PURE__ */ jsx7("code", { className: "font-mono text-xs", children: finding.rule_id }),
918
- /* @__PURE__ */ jsx7("span", { className: "flex-1", children: finding.message })
924
+ /* @__PURE__ */ jsx8("h2", { className: "text-sm font-medium", children: "Sitewide" }),
925
+ /* @__PURE__ */ jsx8("ul", { className: "mt-2 space-y-1 text-sm", children: payload.sitewideFindings.map((finding, i) => /* @__PURE__ */ jsxs5("li", { className: "flex items-start gap-2", children: [
926
+ /* @__PURE__ */ jsx8(SeverityBadge2, { severity: finding.severity }),
927
+ /* @__PURE__ */ jsx8("code", { className: "font-mono text-xs", children: finding.rule_id }),
928
+ /* @__PURE__ */ jsx8("span", { className: "flex-1", children: finding.message })
919
929
  ] }, i)) })
920
930
  ] }),
921
- payload.findings.length === 0 ? /* @__PURE__ */ jsx7("p", { className: "text-sm text-kumo-subtle", children: payload.totals.documentsIndexed === 0 ? "No documents indexed \u2014 click Refresh to do an initial sweep." : "All indexed documents are clean." }) : /* @__PURE__ */ jsx7("div", { className: "overflow-x-auto rounded border border-kumo-line", children: /* @__PURE__ */ jsxs5("table", { className: "w-full text-left text-sm", children: [
922
- /* @__PURE__ */ jsx7("thead", { className: "bg-kumo-tint", children: /* @__PURE__ */ jsxs5("tr", { children: [
923
- /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Route" }),
924
- /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Rule" }),
925
- /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Severity" }),
926
- /* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Message" })
931
+ payload.findings.length === 0 ? /* @__PURE__ */ jsx8("p", { className: "text-sm text-kumo-subtle", children: payload.totals.documentsIndexed === 0 ? "No documents indexed \u2014 click Refresh to do an initial sweep." : "All indexed documents are clean." }) : /* @__PURE__ */ jsx8("div", { className: "overflow-x-auto rounded border border-kumo-line", children: /* @__PURE__ */ jsxs5("table", { className: "w-full text-left text-sm", children: [
932
+ /* @__PURE__ */ jsx8("thead", { className: "bg-kumo-tint", children: /* @__PURE__ */ jsxs5("tr", { children: [
933
+ /* @__PURE__ */ jsx8("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Route" }),
934
+ /* @__PURE__ */ jsx8("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Rule" }),
935
+ /* @__PURE__ */ jsx8("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Severity" }),
936
+ /* @__PURE__ */ jsx8("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Message" })
927
937
  ] }) }),
928
- /* @__PURE__ */ jsx7("tbody", { children: payload.findings.map((finding, i) => {
938
+ /* @__PURE__ */ jsx8("tbody", { children: payload.findings.map((finding, i) => {
929
939
  const routeInfo = routesByPath.get(finding.route);
930
940
  return /* @__PURE__ */ jsxs5("tr", { className: "border-t border-kumo-line", children: [
931
- /* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx7(RouteLinks2, { finding, info: routeInfo }) }),
932
- /* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx7("code", { className: "rounded bg-kumo-tint px-1.5 py-0.5 font-mono text-xs", children: finding.rule_id }) }),
933
- /* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx7(SeverityBadge2, { severity: finding.severity }) }),
934
- /* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: finding.message })
941
+ /* @__PURE__ */ jsx8("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx8(RouteLinks2, { finding, info: routeInfo }) }),
942
+ /* @__PURE__ */ jsx8("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx8("code", { className: "rounded bg-kumo-tint px-1.5 py-0.5 font-mono text-xs", children: finding.rule_id }) }),
943
+ /* @__PURE__ */ jsx8("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx8(SeverityBadge2, { severity: finding.severity }) }),
944
+ /* @__PURE__ */ jsx8("td", { className: "px-3 py-2 align-top", children: finding.message })
935
945
  ] }, i);
936
946
  }) })
937
947
  ] }) })
@@ -942,18 +952,18 @@ function RouteLinks2({
942
952
  info
943
953
  }) {
944
954
  if (info === void 0) {
945
- return /* @__PURE__ */ jsx7("span", { className: "font-mono text-xs", children: finding.route });
955
+ return /* @__PURE__ */ jsx8("span", { className: "font-mono text-xs", children: finding.route });
946
956
  }
947
957
  return /* @__PURE__ */ jsxs5("span", { className: "space-x-2", children: [
948
- info.editUrl !== "" ? /* @__PURE__ */ jsx7(
958
+ info.editUrl !== "" ? /* @__PURE__ */ jsx8(
949
959
  "a",
950
960
  {
951
961
  href: info.editUrl,
952
962
  className: "font-mono text-xs text-kumo-link hover:underline",
953
963
  children: finding.route
954
964
  }
955
- ) : /* @__PURE__ */ jsx7("span", { className: "font-mono text-xs", children: finding.route }),
956
- info.publishedUrl !== "" && /* @__PURE__ */ jsx7(
965
+ ) : /* @__PURE__ */ jsx8("span", { className: "font-mono text-xs", children: finding.route }),
966
+ info.publishedUrl !== "" && /* @__PURE__ */ jsx8(
957
967
  "a",
958
968
  {
959
969
  href: info.publishedUrl,
@@ -963,12 +973,12 @@ function RouteLinks2({
963
973
  children: "live \u2197"
964
974
  }
965
975
  ),
966
- info.status !== "" && info.status !== "published" && /* @__PURE__ */ jsx7("span", { className: "text-xs text-kumo-subtle", children: info.status })
976
+ info.status !== "" && info.status !== "published" && /* @__PURE__ */ jsx8("span", { className: "text-xs text-kumo-subtle", children: info.status })
967
977
  ] });
968
978
  }
969
979
  function SeverityBadge2({ severity }) {
970
980
  const classes = severity === "error" ? "bg-red-500/10 text-red-700 border-red-500/40" : severity === "warning" ? "bg-yellow-500/10 text-yellow-800 border-yellow-500/40" : "bg-kumo-tint text-kumo-subtle border-kumo-line";
971
- return /* @__PURE__ */ jsx7(
981
+ return /* @__PURE__ */ jsx8(
972
982
  "span",
973
983
  {
974
984
  className: `inline-block rounded border px-1.5 py-0.5 text-xs font-medium ${classes}`,
@@ -996,18 +1006,19 @@ function unwrap2(body, res) {
996
1006
  }
997
1007
 
998
1008
  // src/admin/Retrievability.tsx
999
- import { jsx as jsx8 } from "react/jsx-runtime";
1009
+ import { jsx as jsx9 } from "react/jsx-runtime";
1000
1010
  function Retrievability() {
1001
- return /* @__PURE__ */ jsx8(PillarView, { layer: "retrievability" });
1011
+ return /* @__PURE__ */ jsx9(PillarView, { layer: "retrievability" });
1002
1012
  }
1003
1013
 
1004
1014
  // src/admin.tsx
1005
1015
  var pages = {
1006
- // Four pillar pages — the canonical organization going forward.
1016
+ // Pillar pages — the canonical organization going forward.
1007
1017
  "/retrievability": Retrievability,
1008
1018
  "/citability": Citability,
1009
1019
  "/absorbability": Absorbability,
1010
1020
  "/entity-legitimacy": EntityLegitimacy,
1021
+ "/accessibility": Accessibility,
1011
1022
  // /findings stays as a cross-pillar flat view for users who want
1012
1023
  // every finding in one list. Not removed because it's still useful
1013
1024
  // for triage — "show me everything that's wrong" is a real workflow.
@@ -1 +1 @@
1
- {"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../src/configured.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA0HrD,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CA2H3E;AAID,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"configured.d.ts","sourceRoot":"","sources":["../src/configured.ts"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AA0HrD,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEhC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;OAGG;IACH,kBAAkB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAEvC;;;;;OAKG;IACH,YAAY,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CA4H3E;AAID,eAAe,YAAY,CAAC"}
@@ -1215,7 +1215,7 @@ function globToMatcher(pattern) {
1215
1215
  }
1216
1216
 
1217
1217
  // src/version.ts
1218
- var PACKAGE_VERSION = "0.8.10";
1218
+ var PACKAGE_VERSION = "0.8.12";
1219
1219
 
1220
1220
  // src/configured.ts
1221
1221
  import { definePlugin } from "emdash";
@@ -1360,6 +1360,7 @@ function createPlugin(options = {}) {
1360
1360
  { path: "/citability", label: "Citability" },
1361
1361
  { path: "/absorbability", label: "Absorbability" },
1362
1362
  { path: "/entity-legitimacy", label: "Entity legitimacy" },
1363
+ { path: "/accessibility", label: "Accessibility" },
1363
1364
  { path: "/document", label: "Document SEO" },
1364
1365
  { path: "/findings", label: "All findings" }
1365
1366
  ],
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ function buildAllowedHosts(evaluatorHost) {
23
23
  }
24
24
 
25
25
  // src/version.ts
26
- var PACKAGE_VERSION = "0.8.10";
26
+ var PACKAGE_VERSION = "0.8.12";
27
27
 
28
28
  // src/sandbox.ts
29
29
  function aexeoPluginSandboxed(options = {}) {
package/dist/types.d.ts CHANGED
@@ -38,7 +38,7 @@ export interface EmdashDocument {
38
38
  }
39
39
  export type FindingSeverity = "error" | "warning";
40
40
  export type FindingScope = "page" | "template" | "sitewide";
41
- export type Layer = "retrievability" | "citability" | "absorbability" | "entity_legitimacy";
41
+ export type Layer = "retrievability" | "citability" | "absorbability" | "entity_legitimacy" | "accessibility";
42
42
  export interface RuleLayers {
43
43
  primary: Layer;
44
44
  secondaries: Layer[];
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "0.8.10";
1
+ export declare const PACKAGE_VERSION = "0.8.12";
2
2
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeptus/aexeo-emdash",
3
- "version": "0.8.10",
3
+ "version": "0.8.12",
4
4
  "description": "Aexeo SEO/GEO content evaluator as an emdash plugin",
5
5
  "license": "MIT",
6
6
  "author": "Aeptus",
Binary file