@aeptus/aexeo-emdash 0.8.8 → 0.8.10

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,6 +6,153 @@ and the project follows [Semantic Versioning](https://semver.org/).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.8.10] - 2026-05-04
10
+
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.
14
+
15
+ ### Added (engine via bridge)
16
+
17
+ - **`SOC006` enabled by default.** Missing `og:image` now
18
+ surfaces on every audit. The rule existed but was gated
19
+ behind `require_social_images = false`; flipped to true.
20
+ - **`SOC009` (heuristic).** Recommends `summary_large_image`
21
+ when `twitter:card` is plain `summary`. Editors can keep
22
+ `summary` if they want; this is a nudge, not a blocker.
23
+ - **`CNT006` (heuristic, low-confidence).** Generic-beneficiary
24
+ detector — flags abstract audience-needs copy
25
+ ("Needs speed and clarity to make decisions") that has no
26
+ concrete anchoring (numbers, named tools, quotes). Skips
27
+ when concrete-anchor tokens (`study`, `research`, etc.)
28
+ appear nearby. Editors can suppress via the new
29
+ `[route_kinds]` config block.
30
+ - **`[route_kinds]` config block.** Named per-pattern rule
31
+ masking that compiles to virtual suppressions:
32
+ ```toml
33
+ [route_kinds.manifesto]
34
+ match = ["/foundations/"]
35
+ skip_rules = ["GEO007", "GEO008", "GEO010"]
36
+ noindex = false
37
+ ```
38
+ Bundles a path-pattern set with a stance (which rules
39
+ to skip, whether routes are intentionally noindex). Lighter
40
+ than scattering one suppression per rule × pattern.
41
+
42
+ ### Fixed
43
+
44
+ - **Findings now attribute to document routes, not synthesized
45
+ HTML filenames.** v0.8.9's bridge set `page.path` to
46
+ `emdash/<route>.html`, which the plugin's
47
+ `evaluateAndPersistAll` then used as the bucket key when
48
+ distributing findings to document routes. The synthesized
49
+ filename never matched the documentRoutes set, so every
50
+ finding landed in a shadow bucket keyed by the filename and
51
+ the document's row in the admin showed zero findings. Bridge
52
+ now sets `page.path` to the document route directly
53
+ (`/about` rather than `emdash/about.html`); `Finding.path`
54
+ matches the bucket the plugin pre-populates.
55
+
56
+ ### Changed
57
+
58
+ - **CMS evaluation suppresses site-wide infrastructure rule
59
+ groups.** The plugin's configured-mode evaluator now passes
60
+ a Config to `evaluateDocuments` that disables `robots`,
61
+ `sitemap`, `llm`, `surfaces`, `well_known`, `headers`, and
62
+ `deployment` rule groups. The CMS document set has no
63
+ robots.txt or sitemap.xml or llms.txt — those are the
64
+ host's deployed-site artifacts, audited by the CLI's
65
+ static-site mode against a real filesystem. Running them
66
+ against the bridge's synthetic CMS site produced
67
+ `missing robots.txt` / `missing sitemap.xml` / `missing
68
+ llms.txt` / `missing markdown mirrors` noise on every
69
+ refresh, none of which the editor could act on from inside
70
+ the CMS.
71
+
72
+ Per-page rule groups stay on: `html`, `social`, `schema`,
73
+ `content`, `structure`, `links`. Those audit per-document
74
+ content editors can actually fix.
75
+
76
+ CLI static-site audits are unaffected — they use
77
+ `Config::default()` with all groups on, against a
78
+ filesystem-rooted Site.
79
+
80
+ ### Notes for hosts upgrading from 0.8.9
81
+
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
+ ```
101
+ - For the infrastructure-level audit (robots/sitemap/llms/
102
+ well-known/etc.), run `aexeo-cli check` against your static
103
+ dist; that's where those rules belong.
104
+
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
+ ## [0.8.9] - 2026-05-04
116
+
117
+ ### Fixed
118
+
119
+ - **`wasm_error: unreachable` on refresh in Astro dev.** v0.8.8
120
+ fixed the Astro/Vite startup regression but a second issue
121
+ remained: refresh evaluation traps with bare
122
+ `wasm_error: unreachable` in Node-loaded WASM. Root cause is
123
+ `std::time::Instant::now()` panicking on
124
+ `wasm32-unknown-unknown` ("time not implemented on this
125
+ platform"). Cloudflare Workers' workerd runtime appears to
126
+ provide a clock shim that masks the panic in production; Node's
127
+ experimental WASM ESM runner does not.
128
+
129
+ Fixed by adding `aexeo_core::time_shim::Instant` — a transparent
130
+ re-export of `std::time::Instant` on non-wasm targets, and a
131
+ no-op `Duration::ZERO` returner on `wasm32-unknown-unknown`.
132
+ Eval-path callers (`static_check.rs` + the intelligence
133
+ modules) swap their import; CLI and native tests still report
134
+ real timings on real OSes. The `RuleTiming` `elapsed_us` value
135
+ in `SiteCheckProfile` is `0` when the bridge runs in the
136
+ plugin, but no host consumes that field from the bridge today.
137
+
138
+ ### Added
139
+
140
+ - **`console_error_panic_hook` in the bridge.** Future Rust
141
+ panics inside the bridge surface as console errors with
142
+ `file:line` + message instead of bare `unreachable` traps.
143
+ Installed lazily at every `#[wasm_bindgen]` entry point;
144
+ `set_once` is idempotent so repeated calls are cheap. Without
145
+ this, the v0.8.7→v0.8.8 `Instant::now()` panic was effectively
146
+ undebuggable from the host side — every future bridge bug now
147
+ carries its own diagnostic.
148
+
149
+ ### Notes for hosts upgrading from 0.8.8
150
+
151
+ - No code changes required. Bump the package; refresh should
152
+ stop trapping in `pnpm dev` / `astro dev`.
153
+ - Production behavior unchanged — the shim is only active on
154
+ the wasm32 build path.
155
+
9
156
  ## [0.8.8] - 2026-05-04
10
157
 
11
158
  ### Fixed
@@ -867,7 +1014,9 @@ First public release.
867
1014
  `astro.config.mjs` for the WASM import to resolve to a
868
1015
  precompiled `WebAssembly.Module`. Not optional.
869
1016
 
870
- [Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.8...HEAD
1017
+ [Unreleased]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.10...HEAD
1018
+ [0.8.10]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.9...aexeo-emdash-v0.8.10
1019
+ [0.8.9]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.8...aexeo-emdash-v0.8.9
871
1020
  [0.8.8]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.7...aexeo-emdash-v0.8.8
872
1021
  [0.8.7]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.6...aexeo-emdash-v0.8.7
873
1022
  [0.8.6]: https://github.com/schiste/Aexeo/compare/aexeo-emdash-v0.8.5...aexeo-emdash-v0.8.6
@@ -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;AAmFrD,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,CA2H3E;AAID,eAAe,YAAY,CAAC"}
@@ -233,7 +233,10 @@ async function readFindings(kv, route) {
233
233
  var aexeo_emdash_bridge_bg_exports = {};
234
234
  __export(aexeo_emdash_bridge_bg_exports, {
235
235
  __wbg_Error_960c155d3d49e4c2: () => __wbg_Error_960c155d3d49e4c2,
236
+ __wbg_error_a6fa202b58aa1cd3: () => __wbg_error_a6fa202b58aa1cd3,
237
+ __wbg_new_227d7c05414eb861: () => __wbg_new_227d7c05414eb861,
236
238
  __wbg_set_wasm: () => __wbg_set_wasm,
239
+ __wbg_stack_3b0d974bbf31e44f: () => __wbg_stack_3b0d974bbf31e44f,
237
240
  __wbindgen_init_externref_table: () => __wbindgen_init_externref_table,
238
241
  evaluateDocuments: () => evaluateDocuments,
239
242
  generateFactsPrompt: () => generateFactsPrompt,
@@ -334,6 +337,28 @@ function __wbg_Error_960c155d3d49e4c2(arg0, arg1) {
334
337
  const ret = Error(getStringFromWasm0(arg0, arg1));
335
338
  return ret;
336
339
  }
340
+ function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
341
+ let deferred0_0;
342
+ let deferred0_1;
343
+ try {
344
+ deferred0_0 = arg0;
345
+ deferred0_1 = arg1;
346
+ console.error(getStringFromWasm0(arg0, arg1));
347
+ } finally {
348
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
349
+ }
350
+ }
351
+ function __wbg_new_227d7c05414eb861() {
352
+ const ret = new Error();
353
+ return ret;
354
+ }
355
+ function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
356
+ const ret = arg1.stack;
357
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
358
+ const len1 = WASM_VECTOR_LEN;
359
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
360
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
361
+ }
337
362
  function __wbindgen_init_externref_table() {
338
363
  const table = wasm.__wbindgen_externrefs;
339
364
  const offset = table.grow(4);
@@ -343,6 +368,13 @@ function __wbindgen_init_externref_table() {
343
368
  table.set(offset + 2, true);
344
369
  table.set(offset + 3, false);
345
370
  }
371
+ var cachedDataViewMemory0 = null;
372
+ function getDataViewMemory0() {
373
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) {
374
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
375
+ }
376
+ return cachedDataViewMemory0;
377
+ }
346
378
  function getStringFromWasm0(ptr, len) {
347
379
  ptr = ptr >>> 0;
348
380
  return decodeText(ptr, len);
@@ -1183,7 +1215,7 @@ function globToMatcher(pattern) {
1183
1215
  }
1184
1216
 
1185
1217
  // src/version.ts
1186
- var PACKAGE_VERSION = "0.8.8";
1218
+ var PACKAGE_VERSION = "0.8.10";
1187
1219
 
1188
1220
  // src/configured.ts
1189
1221
  import { definePlugin } from "emdash";
@@ -1206,9 +1238,28 @@ function resolveCollections(explicit, include, exclude) {
1206
1238
  }
1207
1239
  return result;
1208
1240
  }
1241
+ var CMS_DISABLED_GROUPS = [
1242
+ "robots",
1243
+ "sitemap",
1244
+ "llm",
1245
+ "surfaces",
1246
+ "well_known",
1247
+ "headers",
1248
+ "deployment"
1249
+ ];
1250
+ function buildCmsContextConfig() {
1251
+ const checks = {};
1252
+ for (const group of CMS_DISABLED_GROUPS) {
1253
+ checks[group] = false;
1254
+ }
1255
+ return JSON.stringify({ checks });
1256
+ }
1209
1257
  var inProcessEvaluator = async (documents) => {
1210
1258
  try {
1211
- const raw = await evaluateDocuments2(JSON.stringify(documents));
1259
+ const raw = await evaluateDocuments2(
1260
+ JSON.stringify(documents),
1261
+ buildCmsContextConfig()
1262
+ );
1212
1263
  const findings = JSON.parse(raw);
1213
1264
  if (!Array.isArray(findings)) {
1214
1265
  return {
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.8";
26
+ var PACKAGE_VERSION = "0.8.10";
27
27
 
28
28
  // src/sandbox.ts
29
29
  function aexeoPluginSandboxed(options = {}) {
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const PACKAGE_VERSION = "0.8.8";
1
+ export declare const PACKAGE_VERSION = "0.8.10";
2
2
  //# sourceMappingURL=version.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aeptus/aexeo-emdash",
3
- "version": "0.8.8",
3
+ "version": "0.8.10",
4
4
  "description": "Aexeo SEO/GEO content evaluator as an emdash plugin",
5
5
  "license": "MIT",
6
6
  "author": "Aeptus",
@@ -117,6 +117,28 @@ export function __wbg_Error_960c155d3d49e4c2(arg0, arg1) {
117
117
  const ret = Error(getStringFromWasm0(arg0, arg1));
118
118
  return ret;
119
119
  }
120
+ export function __wbg_error_a6fa202b58aa1cd3(arg0, arg1) {
121
+ let deferred0_0;
122
+ let deferred0_1;
123
+ try {
124
+ deferred0_0 = arg0;
125
+ deferred0_1 = arg1;
126
+ console.error(getStringFromWasm0(arg0, arg1));
127
+ } finally {
128
+ wasm.__wbindgen_free(deferred0_0, deferred0_1, 1);
129
+ }
130
+ }
131
+ export function __wbg_new_227d7c05414eb861() {
132
+ const ret = new Error();
133
+ return ret;
134
+ }
135
+ export function __wbg_stack_3b0d974bbf31e44f(arg0, arg1) {
136
+ const ret = arg1.stack;
137
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
138
+ const len1 = WASM_VECTOR_LEN;
139
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
140
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
141
+ }
120
142
  export function __wbindgen_init_externref_table() {
121
143
  const table = wasm.__wbindgen_externrefs;
122
144
  const offset = table.grow(4);
@@ -126,6 +148,14 @@ export function __wbindgen_init_externref_table() {
126
148
  table.set(offset + 2, true);
127
149
  table.set(offset + 3, false);
128
150
  }
151
+ let cachedDataViewMemory0 = null;
152
+ function getDataViewMemory0() {
153
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
154
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
155
+ }
156
+ return cachedDataViewMemory0;
157
+ }
158
+
129
159
  function getStringFromWasm0(ptr, len) {
130
160
  ptr = ptr >>> 0;
131
161
  return decodeText(ptr, len);
Binary file
@@ -5,9 +5,9 @@ export const evaluateDocuments: (a: number, b: number, c: number, d: number) =>
5
5
  export const generateFactsPrompt: (a: number, b: number) => [number, number, number, number];
6
6
  export const scoreIntelligence: (a: number, b: number, c: number, d: number) => [number, number, number, number];
7
7
  export const validateFactsManifest: (a: number, b: number, c: number, d: number) => [number, number, number, number];
8
- export const __wbindgen_externrefs: WebAssembly.Table;
8
+ export const __wbindgen_free: (a: number, b: number, c: number) => void;
9
9
  export const __wbindgen_malloc: (a: number, b: number) => number;
10
10
  export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
11
+ export const __wbindgen_externrefs: WebAssembly.Table;
11
12
  export const __externref_table_dealloc: (a: number) => void;
12
- export const __wbindgen_free: (a: number, b: number, c: number) => void;
13
13
  export const __wbindgen_start: () => void;