@aeptus/aexeo-emdash 0.5.0 → 0.8.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/CHANGELOG.md +186 -1
- package/dist/admin/Absorbability.d.ts +3 -0
- package/dist/admin/Absorbability.d.ts.map +1 -0
- package/dist/admin/Citability.d.ts +3 -0
- package/dist/admin/Citability.d.ts.map +1 -0
- package/dist/admin/EntityLegitimacy.d.ts +3 -0
- package/dist/admin/EntityLegitimacy.d.ts.map +1 -0
- package/dist/admin/EntityPresence.d.ts +3 -0
- package/dist/admin/EntityPresence.d.ts.map +1 -0
- package/dist/admin/PillarView.d.ts +7 -0
- package/dist/admin/PillarView.d.ts.map +1 -0
- package/dist/admin/Retrievability.d.ts +3 -0
- package/dist/admin/Retrievability.d.ts.map +1 -0
- package/dist/admin.d.ts +8 -0
- package/dist/admin.d.ts.map +1 -1
- package/dist/admin.js +644 -123
- package/dist/configured.d.ts.map +1 -1
- package/dist/configured.js +423 -16
- package/dist/data-route.d.ts +8 -0
- package/dist/data-route.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/presence-check.d.ts +22 -0
- package/dist/presence-check.d.ts.map +1 -0
- package/dist/presence-route.d.ts +7 -0
- package/dist/presence-route.d.ts.map +1 -0
- package/dist/types.d.ts +26 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
- package/wasm/aexeo_emdash_bridge_bg.wasm +0 -0
package/dist/admin.js
CHANGED
|
@@ -1,16 +1,505 @@
|
|
|
1
|
-
// src/admin/
|
|
1
|
+
// src/admin/PillarView.tsx
|
|
2
2
|
import { useCallback, useEffect, useState } from "react";
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
// src/types.ts
|
|
5
|
+
function layerHumanLabel(layer) {
|
|
6
|
+
switch (layer) {
|
|
7
|
+
case "retrievability":
|
|
8
|
+
return "Retrievability";
|
|
9
|
+
case "citability":
|
|
10
|
+
return "Citability";
|
|
11
|
+
case "absorbability":
|
|
12
|
+
return "Absorbability";
|
|
13
|
+
case "entity_legitimacy":
|
|
14
|
+
return "Entity legitimacy";
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
function layerOneLineDescription(layer) {
|
|
18
|
+
switch (layer) {
|
|
19
|
+
case "retrievability":
|
|
20
|
+
return "Can the engine find the page at all? Robots, sitemap, internal links, machine-readable surfaces.";
|
|
21
|
+
case "citability":
|
|
22
|
+
return "Once retrieved, does it look worth citing? Structure, schema, evidence density, scannability.";
|
|
23
|
+
case "absorbability":
|
|
24
|
+
return "Does the answer actually use this content? Cite-ready evidence, mirrors, llms.txt.";
|
|
25
|
+
case "entity_legitimacy":
|
|
26
|
+
return "Does the entity exist strongly enough to be selected at all? Aexeo surfaces this layer; it does not fix it.";
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// src/admin/PillarView.tsx
|
|
31
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
4
32
|
var PLUGIN_ID = "aexeo-emdash";
|
|
5
33
|
var API_BASE = "/_emdash/api";
|
|
6
|
-
function
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const [
|
|
11
|
-
|
|
34
|
+
function PillarView({
|
|
35
|
+
layer,
|
|
36
|
+
extraSlot
|
|
37
|
+
}) {
|
|
38
|
+
const [state, setState] = useState({
|
|
39
|
+
loading: true,
|
|
40
|
+
error: null,
|
|
41
|
+
payload: null
|
|
42
|
+
});
|
|
43
|
+
const [refreshing, setRefreshing] = useState(false);
|
|
12
44
|
const [toast, setToast] = useState(null);
|
|
13
|
-
const
|
|
45
|
+
const load = useCallback(async () => {
|
|
46
|
+
setState((s) => ({ ...s, loading: true, error: null }));
|
|
47
|
+
try {
|
|
48
|
+
const res = await fetch(`${API_BASE}/plugins/${PLUGIN_ID}/data`, {
|
|
49
|
+
method: "POST",
|
|
50
|
+
headers: csrfHeaders(),
|
|
51
|
+
body: "{}"
|
|
52
|
+
});
|
|
53
|
+
const body = await res.json();
|
|
54
|
+
const payload2 = unwrap(body, res);
|
|
55
|
+
setState({ loading: false, error: null, payload: payload2 });
|
|
56
|
+
} catch (err) {
|
|
57
|
+
setState({
|
|
58
|
+
loading: false,
|
|
59
|
+
error: err instanceof Error ? err.message : String(err),
|
|
60
|
+
payload: null
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}, []);
|
|
64
|
+
const refresh = useCallback(async () => {
|
|
65
|
+
setRefreshing(true);
|
|
66
|
+
setToast(null);
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(`${API_BASE}/plugins/${PLUGIN_ID}/refresh`, {
|
|
69
|
+
method: "POST",
|
|
70
|
+
headers: csrfHeaders(),
|
|
71
|
+
body: "{}"
|
|
72
|
+
});
|
|
73
|
+
const body = await res.json();
|
|
74
|
+
const data = unwrap(body, res);
|
|
75
|
+
setState({ loading: false, error: null, payload: data.payload });
|
|
76
|
+
setToast(`Refreshed ${data.payload.totals.routes} routes`);
|
|
77
|
+
} catch (err) {
|
|
78
|
+
setToast(
|
|
79
|
+
`Refresh failed: ${err instanceof Error ? err.message : String(err)}`
|
|
80
|
+
);
|
|
81
|
+
} finally {
|
|
82
|
+
setRefreshing(false);
|
|
83
|
+
}
|
|
84
|
+
}, []);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
void load();
|
|
87
|
+
}, [load]);
|
|
88
|
+
if (state.loading && state.payload === null) {
|
|
89
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-4 text-sm text-kumo-subtle", children: [
|
|
90
|
+
"Loading ",
|
|
91
|
+
layerHumanLabel(layer),
|
|
92
|
+
" findings\u2026"
|
|
93
|
+
] });
|
|
94
|
+
}
|
|
95
|
+
if (state.error !== null) {
|
|
96
|
+
return /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
|
|
97
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: layerHumanLabel(layer) }),
|
|
98
|
+
/* @__PURE__ */ jsxs("p", { className: "mt-2 rounded border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-700", children: [
|
|
99
|
+
"Failed to load: ",
|
|
100
|
+
state.error
|
|
101
|
+
] }),
|
|
102
|
+
/* @__PURE__ */ jsx(
|
|
103
|
+
"button",
|
|
104
|
+
{
|
|
105
|
+
type: "button",
|
|
106
|
+
onClick: () => void load(),
|
|
107
|
+
className: "mt-3 rounded border border-kumo-line px-3 py-1.5 text-sm hover:bg-kumo-tint",
|
|
108
|
+
children: "Retry"
|
|
109
|
+
}
|
|
110
|
+
)
|
|
111
|
+
] });
|
|
112
|
+
}
|
|
113
|
+
const payload = state.payload;
|
|
114
|
+
if (payload === null) {
|
|
115
|
+
return /* @__PURE__ */ jsx("div", { className: "p-4 text-sm text-kumo-subtle", children: "No data." });
|
|
116
|
+
}
|
|
117
|
+
const breakdown = payload.layerBreakdown.find((b) => b.layer === layer);
|
|
118
|
+
const findings = payload.findings.filter(
|
|
119
|
+
(f) => (f.layers?.primary ?? "citability") === layer
|
|
120
|
+
);
|
|
121
|
+
const sitewide = payload.sitewideFindings.filter(
|
|
122
|
+
(f) => (f.layers?.primary ?? "citability") === layer
|
|
123
|
+
);
|
|
124
|
+
const routesByPath = /* @__PURE__ */ new Map();
|
|
125
|
+
for (const route of payload.routes) {
|
|
126
|
+
routesByPath.set(route.route, route);
|
|
127
|
+
}
|
|
128
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-4 p-4", children: [
|
|
129
|
+
/* @__PURE__ */ jsxs("header", { className: "flex items-start justify-between gap-4", children: [
|
|
130
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
131
|
+
/* @__PURE__ */ jsx("h1", { className: "text-xl font-semibold", children: layerHumanLabel(layer) }),
|
|
132
|
+
/* @__PURE__ */ jsx("p", { className: "mt-1 text-sm text-kumo-subtle", children: layerOneLineDescription(layer) }),
|
|
133
|
+
/* @__PURE__ */ jsx("p", { className: "mt-2 text-sm", children: breakdown === void 0 || breakdown.total === 0 ? /* @__PURE__ */ jsx("span", { className: "text-kumo-subtle", children: "No findings on this layer." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
134
|
+
/* @__PURE__ */ jsx("strong", { children: breakdown.total }),
|
|
135
|
+
" findings \u2014",
|
|
136
|
+
" ",
|
|
137
|
+
breakdown.errors,
|
|
138
|
+
" errors, ",
|
|
139
|
+
breakdown.warnings,
|
|
140
|
+
" warnings."
|
|
141
|
+
] }) })
|
|
142
|
+
] }),
|
|
143
|
+
/* @__PURE__ */ jsx(
|
|
144
|
+
"button",
|
|
145
|
+
{
|
|
146
|
+
type: "button",
|
|
147
|
+
onClick: () => void refresh(),
|
|
148
|
+
disabled: refreshing,
|
|
149
|
+
className: "rounded bg-kumo-brand px-3 py-1.5 text-sm font-medium text-white hover:bg-kumo-brand/90 disabled:opacity-50",
|
|
150
|
+
children: refreshing ? "Refreshing\u2026" : "Refresh"
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
] }),
|
|
154
|
+
toast !== null && /* @__PURE__ */ jsx("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
|
|
155
|
+
extraSlot,
|
|
156
|
+
sitewide.length > 0 && /* @__PURE__ */ jsxs("section", { className: "rounded border border-kumo-line p-3", children: [
|
|
157
|
+
/* @__PURE__ */ jsx("h2", { className: "text-sm font-medium", children: "Sitewide findings" }),
|
|
158
|
+
/* @__PURE__ */ jsx("ul", { className: "mt-2 space-y-1 text-sm", children: sitewide.map((finding, i) => /* @__PURE__ */ jsxs("li", { className: "flex items-start gap-2", children: [
|
|
159
|
+
/* @__PURE__ */ jsx(SeverityBadge, { severity: finding.severity }),
|
|
160
|
+
/* @__PURE__ */ jsx("code", { className: "font-mono text-xs", children: finding.rule_id }),
|
|
161
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1", children: finding.message }),
|
|
162
|
+
finding.layers?.secondaries.length ? /* @__PURE__ */ jsx(SecondariesChips, { layers: finding.layers.secondaries }) : null
|
|
163
|
+
] }, i)) })
|
|
164
|
+
] }),
|
|
165
|
+
findings.length === 0 ? sitewide.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-kumo-subtle", children: "All clean on this layer." }) : null : /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded border border-kumo-line", children: /* @__PURE__ */ jsxs("table", { className: "w-full text-left text-sm", children: [
|
|
166
|
+
/* @__PURE__ */ jsx("thead", { className: "bg-kumo-tint", children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
167
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Route" }),
|
|
168
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Rule" }),
|
|
169
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Severity" }),
|
|
170
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Message" }),
|
|
171
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Also affects" })
|
|
172
|
+
] }) }),
|
|
173
|
+
/* @__PURE__ */ jsx("tbody", { children: findings.map((finding, i) => {
|
|
174
|
+
const routeInfo = routesByPath.get(finding.route);
|
|
175
|
+
return /* @__PURE__ */ jsxs("tr", { className: "border-t border-kumo-line", children: [
|
|
176
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx(RouteLinks, { finding, info: routeInfo }) }),
|
|
177
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx("code", { className: "rounded bg-kumo-tint px-1.5 py-0.5 font-mono text-xs", children: finding.rule_id }) }),
|
|
178
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx(SeverityBadge, { severity: finding.severity }) }),
|
|
179
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: finding.message }),
|
|
180
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 align-top", children: finding.layers?.secondaries.length ? /* @__PURE__ */ jsx(SecondariesChips, { layers: finding.layers.secondaries }) : /* @__PURE__ */ jsx("span", { className: "text-xs text-kumo-subtle", children: "\u2014" }) })
|
|
181
|
+
] }, i);
|
|
182
|
+
}) })
|
|
183
|
+
] }) })
|
|
184
|
+
] });
|
|
185
|
+
}
|
|
186
|
+
function RouteLinks({
|
|
187
|
+
finding,
|
|
188
|
+
info
|
|
189
|
+
}) {
|
|
190
|
+
if (info === void 0) {
|
|
191
|
+
return /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: finding.route });
|
|
192
|
+
}
|
|
193
|
+
return /* @__PURE__ */ jsxs("span", { className: "space-x-2", children: [
|
|
194
|
+
info.editUrl !== "" ? /* @__PURE__ */ jsx(
|
|
195
|
+
"a",
|
|
196
|
+
{
|
|
197
|
+
href: info.editUrl,
|
|
198
|
+
className: "font-mono text-xs text-kumo-link hover:underline",
|
|
199
|
+
children: finding.route
|
|
200
|
+
}
|
|
201
|
+
) : /* @__PURE__ */ jsx("span", { className: "font-mono text-xs", children: finding.route }),
|
|
202
|
+
info.publishedUrl !== "" && /* @__PURE__ */ jsx(
|
|
203
|
+
"a",
|
|
204
|
+
{
|
|
205
|
+
href: info.publishedUrl,
|
|
206
|
+
target: "_blank",
|
|
207
|
+
rel: "noopener noreferrer",
|
|
208
|
+
className: "text-xs text-kumo-link hover:underline",
|
|
209
|
+
children: "live \u2197"
|
|
210
|
+
}
|
|
211
|
+
),
|
|
212
|
+
info.status !== "" && info.status !== "published" && /* @__PURE__ */ jsx("span", { className: "text-xs text-kumo-subtle", children: info.status })
|
|
213
|
+
] });
|
|
214
|
+
}
|
|
215
|
+
function SecondariesChips({ layers }) {
|
|
216
|
+
return /* @__PURE__ */ jsx("span", { className: "space-x-1", children: layers.map((layer) => /* @__PURE__ */ jsx(
|
|
217
|
+
"span",
|
|
218
|
+
{
|
|
219
|
+
className: "inline-block rounded border border-kumo-line bg-kumo-tint px-1.5 py-0.5 text-xs text-kumo-subtle",
|
|
220
|
+
title: layerOneLineDescription(layer),
|
|
221
|
+
children: layerHumanLabel(layer).toLowerCase()
|
|
222
|
+
},
|
|
223
|
+
layer
|
|
224
|
+
)) });
|
|
225
|
+
}
|
|
226
|
+
function SeverityBadge({ severity }) {
|
|
227
|
+
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";
|
|
228
|
+
return /* @__PURE__ */ jsx(
|
|
229
|
+
"span",
|
|
230
|
+
{
|
|
231
|
+
className: `inline-block rounded border px-1.5 py-0.5 text-xs font-medium ${classes}`,
|
|
232
|
+
children: severity
|
|
233
|
+
}
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
function csrfHeaders() {
|
|
237
|
+
return {
|
|
238
|
+
"Content-Type": "application/json",
|
|
239
|
+
"X-EmDash-Request": "1"
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
function unwrap(body, res) {
|
|
243
|
+
if (body.error !== void 0) {
|
|
244
|
+
throw new Error(`${body.error.code}: ${body.error.message}`);
|
|
245
|
+
}
|
|
246
|
+
if (body.data === void 0) {
|
|
247
|
+
throw new Error(`Empty response (HTTP ${res.status})`);
|
|
248
|
+
}
|
|
249
|
+
return body.data;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// src/admin/Absorbability.tsx
|
|
253
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
254
|
+
function Absorbability() {
|
|
255
|
+
return /* @__PURE__ */ jsx2(PillarView, { layer: "absorbability" });
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/admin/Citability.tsx
|
|
259
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
260
|
+
function Citability() {
|
|
261
|
+
return /* @__PURE__ */ jsx3(PillarView, { layer: "citability" });
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// src/admin/EntityPresence.tsx
|
|
265
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useState as useState2 } from "react";
|
|
266
|
+
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
267
|
+
var PLUGIN_ID2 = "aexeo-emdash";
|
|
268
|
+
var API_BASE2 = "/_emdash/api";
|
|
269
|
+
var SOURCE_LABELS = {
|
|
270
|
+
wikipedia: "Wikipedia",
|
|
271
|
+
wikidata: "Wikidata",
|
|
272
|
+
github: "GitHub",
|
|
273
|
+
rdap: "Domain registration",
|
|
274
|
+
common_crawl: "Common Crawl"
|
|
275
|
+
};
|
|
276
|
+
var SOURCE_ORDER = [
|
|
277
|
+
"wikipedia",
|
|
278
|
+
"wikidata",
|
|
279
|
+
"github",
|
|
280
|
+
"rdap",
|
|
281
|
+
"common_crawl"
|
|
282
|
+
];
|
|
283
|
+
function EntityPresence() {
|
|
284
|
+
const [data, setData] = useState2(null);
|
|
285
|
+
const [loadError, setLoadError] = useState2(null);
|
|
286
|
+
const [busy, setBusy] = useState2(null);
|
|
287
|
+
const load = useCallback2(async () => {
|
|
288
|
+
setLoadError(null);
|
|
289
|
+
try {
|
|
290
|
+
const res = await callPresenceRoute("data");
|
|
291
|
+
setData(res);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
setLoadError(error instanceof Error ? error.message : String(error));
|
|
294
|
+
}
|
|
295
|
+
}, []);
|
|
296
|
+
const refresh = useCallback2(async () => {
|
|
297
|
+
setBusy("refresh");
|
|
298
|
+
setLoadError(null);
|
|
299
|
+
try {
|
|
300
|
+
const res = await callPresenceRoute("refresh");
|
|
301
|
+
setData(res);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
setLoadError(error instanceof Error ? error.message : String(error));
|
|
304
|
+
} finally {
|
|
305
|
+
setBusy(null);
|
|
306
|
+
}
|
|
307
|
+
}, []);
|
|
308
|
+
useEffect2(() => {
|
|
309
|
+
void load();
|
|
310
|
+
}, [load]);
|
|
311
|
+
if (loadError !== null) {
|
|
312
|
+
return /* @__PURE__ */ jsxs2("div", { className: "rounded border border-red-300 bg-red-50 p-3 text-sm text-red-900", children: [
|
|
313
|
+
"Failed to load presence data: ",
|
|
314
|
+
loadError
|
|
315
|
+
] });
|
|
316
|
+
}
|
|
317
|
+
if (data === null) {
|
|
318
|
+
return /* @__PURE__ */ jsx4("div", { className: "text-sm text-kumo-subtle", children: "Loading presence data\u2026" });
|
|
319
|
+
}
|
|
320
|
+
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." });
|
|
322
|
+
}
|
|
323
|
+
if (data.state === "no_organization") {
|
|
324
|
+
return /* @__PURE__ */ jsxs2("div", { className: "rounded border border-kumo-line bg-kumo-canvas p-3 text-sm", children: [
|
|
325
|
+
"The manifest exists but has no organization. Add an",
|
|
326
|
+
" ",
|
|
327
|
+
/* @__PURE__ */ jsx4("code", { children: "organization" }),
|
|
328
|
+
" entry with at least a ",
|
|
329
|
+
/* @__PURE__ */ jsx4("code", { children: "name" }),
|
|
330
|
+
" ",
|
|
331
|
+
"and ideally a ",
|
|
332
|
+
/* @__PURE__ */ jsx4("code", { children: "website" }),
|
|
333
|
+
", then refresh."
|
|
334
|
+
] });
|
|
335
|
+
}
|
|
336
|
+
return /* @__PURE__ */ jsxs2("div", { className: "space-y-3", children: [
|
|
337
|
+
/* @__PURE__ */ jsxs2("header", { className: "flex items-baseline justify-between gap-3", children: [
|
|
338
|
+
/* @__PURE__ */ jsxs2("div", { children: [
|
|
339
|
+
/* @__PURE__ */ jsx4("h3", { className: "text-sm font-medium", children: "Public web presence" }),
|
|
340
|
+
/* @__PURE__ */ jsxs2("p", { className: "mt-1 text-xs text-kumo-subtle", children: [
|
|
341
|
+
"What the open web shows about",
|
|
342
|
+
" ",
|
|
343
|
+
/* @__PURE__ */ jsx4("strong", { children: data.entityName ?? "this entity" }),
|
|
344
|
+
". Aexeo does not score this layer \u2014 it surfaces it. Click through each row to verify."
|
|
345
|
+
] })
|
|
346
|
+
] }),
|
|
347
|
+
/* @__PURE__ */ jsx4(
|
|
348
|
+
"button",
|
|
349
|
+
{
|
|
350
|
+
type: "button",
|
|
351
|
+
onClick: () => void refresh(),
|
|
352
|
+
disabled: busy !== null,
|
|
353
|
+
className: "rounded border border-kumo-line px-3 py-1 text-xs hover:bg-kumo-canvas disabled:opacity-50",
|
|
354
|
+
children: busy === "refresh" ? "Checking\u2026" : "Refresh"
|
|
355
|
+
}
|
|
356
|
+
)
|
|
357
|
+
] }),
|
|
358
|
+
data.state === "empty" && /* @__PURE__ */ jsxs2("div", { className: "rounded border border-kumo-line bg-kumo-canvas p-3 text-sm", children: [
|
|
359
|
+
"No checks have been run yet for",
|
|
360
|
+
" ",
|
|
361
|
+
/* @__PURE__ */ jsx4("strong", { children: data.entityName }),
|
|
362
|
+
". Hit Refresh to query the five sources."
|
|
363
|
+
] }),
|
|
364
|
+
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: [
|
|
365
|
+
"Cached results are ",
|
|
366
|
+
formatAge(data.ageMinutes),
|
|
367
|
+
" old. Hit Refresh to re-check."
|
|
368
|
+
] }),
|
|
369
|
+
data.state === "fresh" && data.ageMinutes !== null && /* @__PURE__ */ jsxs2("div", { className: "text-xs text-kumo-subtle", children: [
|
|
370
|
+
"Last checked ",
|
|
371
|
+
formatAge(data.ageMinutes),
|
|
372
|
+
" ago."
|
|
373
|
+
] }),
|
|
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)) })
|
|
375
|
+
] });
|
|
376
|
+
}
|
|
377
|
+
function SourceCard({ result }) {
|
|
378
|
+
const label = SOURCE_LABELS[result.source] ?? result.source;
|
|
379
|
+
const tone = toneFor(result.status);
|
|
380
|
+
return /* @__PURE__ */ jsx4(
|
|
381
|
+
"li",
|
|
382
|
+
{
|
|
383
|
+
className: `rounded border p-3 ${tone.border} ${tone.bg} text-sm`,
|
|
384
|
+
children: /* @__PURE__ */ jsxs2("div", { className: "flex items-start justify-between gap-3", children: [
|
|
385
|
+
/* @__PURE__ */ jsxs2("div", { className: "min-w-0 flex-1", children: [
|
|
386
|
+
/* @__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) })
|
|
390
|
+
] }),
|
|
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 })
|
|
394
|
+
] }),
|
|
395
|
+
result.url !== void 0 && /* @__PURE__ */ jsx4(
|
|
396
|
+
"a",
|
|
397
|
+
{
|
|
398
|
+
href: result.url,
|
|
399
|
+
target: "_blank",
|
|
400
|
+
rel: "noreferrer noopener",
|
|
401
|
+
className: "shrink-0 self-center text-xs underline hover:no-underline",
|
|
402
|
+
children: "Open \u2197"
|
|
403
|
+
}
|
|
404
|
+
)
|
|
405
|
+
] })
|
|
406
|
+
}
|
|
407
|
+
);
|
|
408
|
+
}
|
|
409
|
+
function toneFor(status) {
|
|
410
|
+
switch (status) {
|
|
411
|
+
case "found":
|
|
412
|
+
return {
|
|
413
|
+
border: "border-emerald-200",
|
|
414
|
+
bg: "bg-emerald-50",
|
|
415
|
+
icon: "text-emerald-700",
|
|
416
|
+
statusText: "text-emerald-700",
|
|
417
|
+
symbol: "\u2713"
|
|
418
|
+
};
|
|
419
|
+
case "not_found":
|
|
420
|
+
return {
|
|
421
|
+
border: "border-kumo-line",
|
|
422
|
+
bg: "bg-kumo-canvas",
|
|
423
|
+
icon: "text-kumo-subtle",
|
|
424
|
+
statusText: "text-kumo-subtle",
|
|
425
|
+
symbol: "\xB7"
|
|
426
|
+
};
|
|
427
|
+
case "unreachable":
|
|
428
|
+
return {
|
|
429
|
+
border: "border-amber-200",
|
|
430
|
+
bg: "bg-amber-50",
|
|
431
|
+
icon: "text-amber-800",
|
|
432
|
+
statusText: "text-amber-800",
|
|
433
|
+
symbol: "!"
|
|
434
|
+
};
|
|
435
|
+
case "skipped":
|
|
436
|
+
return {
|
|
437
|
+
border: "border-kumo-line",
|
|
438
|
+
bg: "bg-kumo-canvas",
|
|
439
|
+
icon: "text-kumo-subtle",
|
|
440
|
+
statusText: "text-kumo-subtle",
|
|
441
|
+
symbol: "\u2014"
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
function statusLabel(status) {
|
|
446
|
+
switch (status) {
|
|
447
|
+
case "found":
|
|
448
|
+
return "found";
|
|
449
|
+
case "not_found":
|
|
450
|
+
return "no record";
|
|
451
|
+
case "unreachable":
|
|
452
|
+
return "couldn't reach";
|
|
453
|
+
case "skipped":
|
|
454
|
+
return "skipped";
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
function orderResults(results) {
|
|
458
|
+
const known = SOURCE_ORDER.map(
|
|
459
|
+
(name) => results.find((r) => r.source === name) ?? null
|
|
460
|
+
).filter((r) => r !== null);
|
|
461
|
+
const unknown = results.filter(
|
|
462
|
+
(r) => !SOURCE_ORDER.includes(r.source)
|
|
463
|
+
);
|
|
464
|
+
return [...known, ...unknown];
|
|
465
|
+
}
|
|
466
|
+
function formatAge(minutes) {
|
|
467
|
+
if (minutes < 60) return `${minutes} min`;
|
|
468
|
+
const hours = Math.floor(minutes / 60);
|
|
469
|
+
if (hours < 24) {
|
|
470
|
+
const remMin = minutes % 60;
|
|
471
|
+
return remMin === 0 ? `${hours}h` : `${hours}h ${remMin}m`;
|
|
472
|
+
}
|
|
473
|
+
const days = Math.floor(hours / 24);
|
|
474
|
+
return `${days}d`;
|
|
475
|
+
}
|
|
476
|
+
async function callPresenceRoute(kind) {
|
|
477
|
+
const res = await fetch(`${API_BASE2}/plugins/${PLUGIN_ID2}/presence`, {
|
|
478
|
+
method: "POST",
|
|
479
|
+
headers: { "Content-Type": "application/json" },
|
|
480
|
+
body: JSON.stringify({ kind })
|
|
481
|
+
});
|
|
482
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
483
|
+
const body = await res.json();
|
|
484
|
+
if ("error" in body) {
|
|
485
|
+
throw new Error(body.error.message ?? "presence route returned error");
|
|
486
|
+
}
|
|
487
|
+
return body.data;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/admin/Facts.tsx
|
|
491
|
+
import { useCallback as useCallback3, useEffect as useEffect3, useState as useState3 } from "react";
|
|
492
|
+
import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
493
|
+
var PLUGIN_ID3 = "aexeo-emdash";
|
|
494
|
+
var API_BASE3 = "/_emdash/api";
|
|
495
|
+
function Facts() {
|
|
496
|
+
const [data, setData] = useState3(null);
|
|
497
|
+
const [loadError, setLoadError] = useState3(null);
|
|
498
|
+
const [draft, setDraft] = useState3("");
|
|
499
|
+
const [validation, setValidation] = useState3(null);
|
|
500
|
+
const [busy, setBusy] = useState3(null);
|
|
501
|
+
const [toast, setToast] = useState3(null);
|
|
502
|
+
const loadCurrent = useCallback3(async () => {
|
|
14
503
|
setLoadError(null);
|
|
15
504
|
try {
|
|
16
505
|
const res = await callRoute("data", {});
|
|
@@ -23,10 +512,10 @@ function Facts() {
|
|
|
23
512
|
setLoadError(err instanceof Error ? err.message : String(err));
|
|
24
513
|
}
|
|
25
514
|
}, []);
|
|
26
|
-
|
|
515
|
+
useEffect3(() => {
|
|
27
516
|
void loadCurrent();
|
|
28
517
|
}, [loadCurrent]);
|
|
29
|
-
const onCopyPrompt =
|
|
518
|
+
const onCopyPrompt = useCallback3(async () => {
|
|
30
519
|
setBusy("prompt");
|
|
31
520
|
setToast(null);
|
|
32
521
|
try {
|
|
@@ -43,7 +532,7 @@ function Facts() {
|
|
|
43
532
|
setBusy(null);
|
|
44
533
|
}
|
|
45
534
|
}, []);
|
|
46
|
-
const onValidate =
|
|
535
|
+
const onValidate = useCallback3(async () => {
|
|
47
536
|
setBusy("validate");
|
|
48
537
|
setToast(null);
|
|
49
538
|
setValidation(null);
|
|
@@ -60,7 +549,7 @@ function Facts() {
|
|
|
60
549
|
setBusy(null);
|
|
61
550
|
}
|
|
62
551
|
}, [draft]);
|
|
63
|
-
const onSave =
|
|
552
|
+
const onSave = useCallback3(async () => {
|
|
64
553
|
setBusy("save");
|
|
65
554
|
setToast(null);
|
|
66
555
|
try {
|
|
@@ -76,15 +565,15 @@ function Facts() {
|
|
|
76
565
|
}
|
|
77
566
|
}, [draft, loadCurrent]);
|
|
78
567
|
const validationOk = validation !== null && validation.validation.valid && validation.validation.errors.length === 0 && validation.assessment.mismatches.filter((m) => m.severity === "error").length === 0;
|
|
79
|
-
return /* @__PURE__ */
|
|
80
|
-
/* @__PURE__ */
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
568
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-6 p-4", children: [
|
|
569
|
+
/* @__PURE__ */ jsxs3("header", { children: [
|
|
570
|
+
/* @__PURE__ */ jsx5("h1", { className: "text-xl font-semibold", children: "Truth manifest" }),
|
|
571
|
+
/* @__PURE__ */ jsxs3("p", { className: "mt-1 text-sm text-kumo-subtle", children: [
|
|
83
572
|
"Author a ",
|
|
84
|
-
/* @__PURE__ */
|
|
573
|
+
/* @__PURE__ */ jsx5("code", { children: "facts.json" }),
|
|
85
574
|
" using your LLM of choice. The plugin frames the question, validates the answer, and stores the result. Read",
|
|
86
575
|
" ",
|
|
87
|
-
/* @__PURE__ */
|
|
576
|
+
/* @__PURE__ */ jsx5(
|
|
88
577
|
"a",
|
|
89
578
|
{
|
|
90
579
|
href: "https://github.com/schiste/Aexeo/blob/main/docs/facts-manifest.md",
|
|
@@ -98,18 +587,18 @@ function Facts() {
|
|
|
98
587
|
"for the philosophy behind this flow."
|
|
99
588
|
] })
|
|
100
589
|
] }),
|
|
101
|
-
loadError !== null && /* @__PURE__ */
|
|
590
|
+
loadError !== null && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-700", children: [
|
|
102
591
|
"Failed to load manifest state: ",
|
|
103
592
|
loadError
|
|
104
593
|
] }),
|
|
105
|
-
/* @__PURE__ */
|
|
106
|
-
/* @__PURE__ */
|
|
107
|
-
/* @__PURE__ */
|
|
594
|
+
/* @__PURE__ */ jsxs3("section", { className: "rounded border border-kumo-line p-3", children: [
|
|
595
|
+
/* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "Status" }),
|
|
596
|
+
/* @__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." })
|
|
108
597
|
] }),
|
|
109
|
-
/* @__PURE__ */
|
|
110
|
-
/* @__PURE__ */
|
|
111
|
-
/* @__PURE__ */
|
|
112
|
-
/* @__PURE__ */
|
|
598
|
+
/* @__PURE__ */ jsxs3("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
|
|
599
|
+
/* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "1. Generate authoring prompt" }),
|
|
600
|
+
/* @__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." }),
|
|
601
|
+
/* @__PURE__ */ jsx5(
|
|
113
602
|
"button",
|
|
114
603
|
{
|
|
115
604
|
type: "button",
|
|
@@ -120,9 +609,9 @@ function Facts() {
|
|
|
120
609
|
}
|
|
121
610
|
)
|
|
122
611
|
] }),
|
|
123
|
-
/* @__PURE__ */
|
|
124
|
-
/* @__PURE__ */
|
|
125
|
-
/* @__PURE__ */
|
|
612
|
+
/* @__PURE__ */ jsxs3("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
|
|
613
|
+
/* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "2. Paste & validate" }),
|
|
614
|
+
/* @__PURE__ */ jsx5(
|
|
126
615
|
"textarea",
|
|
127
616
|
{
|
|
128
617
|
value: draft,
|
|
@@ -133,8 +622,8 @@ function Facts() {
|
|
|
133
622
|
className: "w-full rounded border border-kumo-line bg-kumo-tint p-2 font-mono text-xs"
|
|
134
623
|
}
|
|
135
624
|
),
|
|
136
|
-
/* @__PURE__ */
|
|
137
|
-
/* @__PURE__ */
|
|
625
|
+
/* @__PURE__ */ jsxs3("div", { className: "flex gap-2", children: [
|
|
626
|
+
/* @__PURE__ */ jsx5(
|
|
138
627
|
"button",
|
|
139
628
|
{
|
|
140
629
|
type: "button",
|
|
@@ -144,7 +633,7 @@ function Facts() {
|
|
|
144
633
|
children: busy === "validate" ? "Validating\u2026" : "Validate"
|
|
145
634
|
}
|
|
146
635
|
),
|
|
147
|
-
/* @__PURE__ */
|
|
636
|
+
/* @__PURE__ */ jsx5(
|
|
148
637
|
"button",
|
|
149
638
|
{
|
|
150
639
|
type: "button",
|
|
@@ -157,8 +646,8 @@ function Facts() {
|
|
|
157
646
|
)
|
|
158
647
|
] })
|
|
159
648
|
] }),
|
|
160
|
-
toast !== null && /* @__PURE__ */
|
|
161
|
-
validation !== null && /* @__PURE__ */
|
|
649
|
+
toast !== null && /* @__PURE__ */ jsx5("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
|
|
650
|
+
validation !== null && /* @__PURE__ */ jsx5(ValidationReport, { result: validation })
|
|
162
651
|
] });
|
|
163
652
|
}
|
|
164
653
|
function ValidationReport({
|
|
@@ -170,13 +659,13 @@ function ValidationReport({
|
|
|
170
659
|
const warnMismatches = result.assessment.mismatches.filter(
|
|
171
660
|
(m) => m.severity === "warning"
|
|
172
661
|
);
|
|
173
|
-
return /* @__PURE__ */
|
|
174
|
-
/* @__PURE__ */
|
|
175
|
-
/* @__PURE__ */
|
|
176
|
-
/* @__PURE__ */
|
|
662
|
+
return /* @__PURE__ */ jsxs3("section", { className: "space-y-3 rounded border border-kumo-line p-3", children: [
|
|
663
|
+
/* @__PURE__ */ jsx5("h2", { className: "text-sm font-medium", children: "Validation result" }),
|
|
664
|
+
/* @__PURE__ */ jsxs3("div", { className: "text-sm", children: [
|
|
665
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
177
666
|
"Shape:",
|
|
178
667
|
" ",
|
|
179
|
-
/* @__PURE__ */
|
|
668
|
+
/* @__PURE__ */ jsx5("strong", { children: result.validation.valid ? "valid" : "invalid" }),
|
|
180
669
|
" ",
|
|
181
670
|
"\xB7 org",
|
|
182
671
|
" ",
|
|
@@ -192,14 +681,14 @@ function ValidationReport({
|
|
|
192
681
|
result.validation.forbidden_term_count,
|
|
193
682
|
" forbidden terms"
|
|
194
683
|
] }),
|
|
195
|
-
/* @__PURE__ */
|
|
684
|
+
/* @__PURE__ */ jsxs3("div", { children: [
|
|
196
685
|
"Score: ",
|
|
197
|
-
/* @__PURE__ */
|
|
686
|
+
/* @__PURE__ */ jsx5("strong", { children: result.assessment.score }),
|
|
198
687
|
"/",
|
|
199
688
|
result.assessment.score_ceiling,
|
|
200
689
|
" \xB7 source =",
|
|
201
690
|
" ",
|
|
202
|
-
/* @__PURE__ */
|
|
691
|
+
/* @__PURE__ */ jsx5("code", { children: result.assessment.structured_truth_source }),
|
|
203
692
|
" \xB7",
|
|
204
693
|
" ",
|
|
205
694
|
result.assessment.pages_analyzed,
|
|
@@ -209,23 +698,23 @@ function ValidationReport({
|
|
|
209
698
|
" with schema.org"
|
|
210
699
|
] })
|
|
211
700
|
] }),
|
|
212
|
-
result.validation.errors.length > 0 && /* @__PURE__ */
|
|
213
|
-
/* @__PURE__ */
|
|
214
|
-
/* @__PURE__ */
|
|
701
|
+
result.validation.errors.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-red-500/40 bg-red-500/10 p-2 text-sm", children: [
|
|
702
|
+
/* @__PURE__ */ jsx5("strong", { children: "Schema errors:" }),
|
|
703
|
+
/* @__PURE__ */ jsx5("ul", { className: "mt-1 list-disc pl-5", children: result.validation.errors.map((e, i) => /* @__PURE__ */ jsx5("li", { children: e }, i)) })
|
|
215
704
|
] }),
|
|
216
|
-
result.validation.warnings.length > 0 && /* @__PURE__ */
|
|
217
|
-
/* @__PURE__ */
|
|
218
|
-
/* @__PURE__ */
|
|
705
|
+
result.validation.warnings.length > 0 && /* @__PURE__ */ jsxs3("div", { className: "rounded border border-yellow-500/40 bg-yellow-500/10 p-2 text-sm", children: [
|
|
706
|
+
/* @__PURE__ */ jsx5("strong", { children: "Schema warnings:" }),
|
|
707
|
+
/* @__PURE__ */ jsx5("ul", { className: "mt-1 list-disc pl-5", children: result.validation.warnings.map((w, i) => /* @__PURE__ */ jsx5("li", { children: w }, i)) })
|
|
219
708
|
] }),
|
|
220
|
-
errMismatches.length > 0 && /* @__PURE__ */
|
|
221
|
-
/* @__PURE__ */
|
|
222
|
-
/* @__PURE__ */
|
|
709
|
+
errMismatches.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: "Mismatches with site (errors):" }),
|
|
711
|
+
/* @__PURE__ */ jsx5(MismatchList, { items: errMismatches })
|
|
223
712
|
] }),
|
|
224
|
-
warnMismatches.length > 0 && /* @__PURE__ */
|
|
225
|
-
/* @__PURE__ */
|
|
226
|
-
/* @__PURE__ */
|
|
713
|
+
warnMismatches.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: "Mismatches with site (warnings):" }),
|
|
715
|
+
/* @__PURE__ */ jsx5(MismatchList, { items: warnMismatches })
|
|
227
716
|
] }),
|
|
228
|
-
result.validation.errors.length === 0 && result.assessment.mismatches.length === 0 && /* @__PURE__ */
|
|
717
|
+
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: [
|
|
229
718
|
"\u2713 Manifest is valid and agrees with on-page schema.org. Click",
|
|
230
719
|
" ",
|
|
231
720
|
"Save to persist."
|
|
@@ -235,18 +724,18 @@ function ValidationReport({
|
|
|
235
724
|
function MismatchList({
|
|
236
725
|
items
|
|
237
726
|
}) {
|
|
238
|
-
return /* @__PURE__ */
|
|
239
|
-
/* @__PURE__ */
|
|
727
|
+
return /* @__PURE__ */ jsx5("ul", { className: "mt-1 list-disc pl-5", children: items.map((m, i) => /* @__PURE__ */ jsxs3("li", { children: [
|
|
728
|
+
/* @__PURE__ */ jsx5("code", { className: "text-xs", children: m.route }),
|
|
240
729
|
" \xB7 ",
|
|
241
730
|
m.field,
|
|
242
731
|
": expected",
|
|
243
732
|
" ",
|
|
244
|
-
/* @__PURE__ */
|
|
733
|
+
/* @__PURE__ */ jsx5("code", { className: "text-xs", children: m.expected }),
|
|
245
734
|
", observed",
|
|
246
735
|
" ",
|
|
247
|
-
/* @__PURE__ */
|
|
736
|
+
/* @__PURE__ */ jsx5("code", { className: "text-xs", children: m.observed }),
|
|
248
737
|
" ",
|
|
249
|
-
/* @__PURE__ */
|
|
738
|
+
/* @__PURE__ */ jsxs3("span", { className: "text-xs text-kumo-subtle", children: [
|
|
250
739
|
"(",
|
|
251
740
|
m.source,
|
|
252
741
|
")"
|
|
@@ -254,7 +743,7 @@ function MismatchList({
|
|
|
254
743
|
] }, i)) });
|
|
255
744
|
}
|
|
256
745
|
async function callRoute(kind, extra) {
|
|
257
|
-
const res = await fetch(`${
|
|
746
|
+
const res = await fetch(`${API_BASE3}/plugins/${PLUGIN_ID3}/facts`, {
|
|
258
747
|
method: "POST",
|
|
259
748
|
headers: {
|
|
260
749
|
"Content-Type": "application/json",
|
|
@@ -272,29 +761,48 @@ async function callRoute(kind, extra) {
|
|
|
272
761
|
return body.data;
|
|
273
762
|
}
|
|
274
763
|
|
|
764
|
+
// src/admin/EntityLegitimacy.tsx
|
|
765
|
+
import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
766
|
+
function EntityLegitimacy() {
|
|
767
|
+
return /* @__PURE__ */ jsx6(
|
|
768
|
+
PillarView,
|
|
769
|
+
{
|
|
770
|
+
layer: "entity_legitimacy",
|
|
771
|
+
extraSlot: /* @__PURE__ */ jsxs4("div", { className: "space-y-3", children: [
|
|
772
|
+
/* @__PURE__ */ jsxs4("section", { className: "rounded border border-kumo-line p-3", children: [
|
|
773
|
+
/* @__PURE__ */ jsx6("h2", { className: "text-sm font-medium", children: "Truth manifest" }),
|
|
774
|
+
/* @__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." }),
|
|
775
|
+
/* @__PURE__ */ jsx6("div", { className: "mt-3", children: /* @__PURE__ */ jsx6(Facts, {}) })
|
|
776
|
+
] }),
|
|
777
|
+
/* @__PURE__ */ jsx6("section", { className: "rounded border border-kumo-line p-3", children: /* @__PURE__ */ jsx6(EntityPresence, {}) })
|
|
778
|
+
] })
|
|
779
|
+
}
|
|
780
|
+
);
|
|
781
|
+
}
|
|
782
|
+
|
|
275
783
|
// src/admin/Findings.tsx
|
|
276
|
-
import { useCallback as
|
|
277
|
-
import { Fragment, jsx as
|
|
278
|
-
var
|
|
279
|
-
var
|
|
784
|
+
import { useCallback as useCallback4, useEffect as useEffect4, useState as useState4 } from "react";
|
|
785
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
786
|
+
var PLUGIN_ID4 = "aexeo-emdash";
|
|
787
|
+
var API_BASE4 = "/_emdash/api";
|
|
280
788
|
function Findings() {
|
|
281
|
-
const [state, setState] =
|
|
789
|
+
const [state, setState] = useState4({
|
|
282
790
|
loading: true,
|
|
283
791
|
error: null,
|
|
284
792
|
payload: null
|
|
285
793
|
});
|
|
286
|
-
const [refreshing, setRefreshing] =
|
|
287
|
-
const [toast, setToast] =
|
|
288
|
-
const load =
|
|
794
|
+
const [refreshing, setRefreshing] = useState4(false);
|
|
795
|
+
const [toast, setToast] = useState4(null);
|
|
796
|
+
const load = useCallback4(async () => {
|
|
289
797
|
setState((s) => ({ ...s, loading: true, error: null }));
|
|
290
798
|
try {
|
|
291
|
-
const res = await fetch(`${
|
|
799
|
+
const res = await fetch(`${API_BASE4}/plugins/${PLUGIN_ID4}/data`, {
|
|
292
800
|
method: "POST",
|
|
293
|
-
headers:
|
|
801
|
+
headers: csrfHeaders2(),
|
|
294
802
|
body: "{}"
|
|
295
803
|
});
|
|
296
804
|
const body = await res.json();
|
|
297
|
-
const payload2 =
|
|
805
|
+
const payload2 = unwrap2(body, res);
|
|
298
806
|
setState({ loading: false, error: null, payload: payload2 });
|
|
299
807
|
} catch (err) {
|
|
300
808
|
setState({
|
|
@@ -304,17 +812,17 @@ function Findings() {
|
|
|
304
812
|
});
|
|
305
813
|
}
|
|
306
814
|
}, []);
|
|
307
|
-
const refresh =
|
|
815
|
+
const refresh = useCallback4(async () => {
|
|
308
816
|
setRefreshing(true);
|
|
309
817
|
setToast(null);
|
|
310
818
|
try {
|
|
311
|
-
const res = await fetch(`${
|
|
819
|
+
const res = await fetch(`${API_BASE4}/plugins/${PLUGIN_ID4}/refresh`, {
|
|
312
820
|
method: "POST",
|
|
313
|
-
headers:
|
|
821
|
+
headers: csrfHeaders2(),
|
|
314
822
|
body: "{}"
|
|
315
823
|
});
|
|
316
824
|
const body = await res.json();
|
|
317
|
-
const data =
|
|
825
|
+
const data = unwrap2(body, res);
|
|
318
826
|
setState({ loading: false, error: null, payload: data.payload });
|
|
319
827
|
if (data.summary) {
|
|
320
828
|
const { documentsScanned, routesUpdated, totalFindings, errors } = data.summary;
|
|
@@ -334,20 +842,20 @@ function Findings() {
|
|
|
334
842
|
setRefreshing(false);
|
|
335
843
|
}
|
|
336
844
|
}, []);
|
|
337
|
-
|
|
845
|
+
useEffect4(() => {
|
|
338
846
|
void load();
|
|
339
847
|
}, [load]);
|
|
340
848
|
if (state.loading && state.payload === null) {
|
|
341
|
-
return /* @__PURE__ */
|
|
849
|
+
return /* @__PURE__ */ jsx7("div", { className: "p-4 text-sm text-kumo-subtle", children: "Loading findings\u2026" });
|
|
342
850
|
}
|
|
343
851
|
if (state.error !== null) {
|
|
344
|
-
return /* @__PURE__ */
|
|
345
|
-
/* @__PURE__ */
|
|
346
|
-
/* @__PURE__ */
|
|
852
|
+
return /* @__PURE__ */ jsxs5("div", { className: "p-4", children: [
|
|
853
|
+
/* @__PURE__ */ jsx7("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
|
|
854
|
+
/* @__PURE__ */ jsxs5("p", { className: "mt-2 rounded border border-red-500/40 bg-red-500/10 p-3 text-sm text-red-700", children: [
|
|
347
855
|
"Failed to load: ",
|
|
348
856
|
state.error
|
|
349
857
|
] }),
|
|
350
|
-
/* @__PURE__ */
|
|
858
|
+
/* @__PURE__ */ jsx7(
|
|
351
859
|
"button",
|
|
352
860
|
{
|
|
353
861
|
type: "button",
|
|
@@ -360,17 +868,17 @@ function Findings() {
|
|
|
360
868
|
}
|
|
361
869
|
const payload = state.payload;
|
|
362
870
|
if (payload === null) {
|
|
363
|
-
return /* @__PURE__ */
|
|
871
|
+
return /* @__PURE__ */ jsx7("div", { className: "p-4 text-sm text-kumo-subtle", children: "No data." });
|
|
364
872
|
}
|
|
365
873
|
const routesByPath = /* @__PURE__ */ new Map();
|
|
366
874
|
for (const route of payload.routes) {
|
|
367
875
|
routesByPath.set(route.route, route);
|
|
368
876
|
}
|
|
369
|
-
return /* @__PURE__ */
|
|
370
|
-
/* @__PURE__ */
|
|
371
|
-
/* @__PURE__ */
|
|
372
|
-
/* @__PURE__ */
|
|
373
|
-
/* @__PURE__ */
|
|
877
|
+
return /* @__PURE__ */ jsxs5("div", { className: "space-y-4 p-4", children: [
|
|
878
|
+
/* @__PURE__ */ jsxs5("header", { className: "flex items-center justify-between gap-4", children: [
|
|
879
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
880
|
+
/* @__PURE__ */ jsx7("h1", { className: "text-xl font-semibold", children: "SEO findings" }),
|
|
881
|
+
/* @__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: [
|
|
374
882
|
payload.totals.findings,
|
|
375
883
|
" findings across ",
|
|
376
884
|
payload.totals.routes,
|
|
@@ -382,7 +890,7 @@ function Findings() {
|
|
|
382
890
|
" warnings."
|
|
383
891
|
] }) })
|
|
384
892
|
] }),
|
|
385
|
-
/* @__PURE__ */
|
|
893
|
+
/* @__PURE__ */ jsx7(
|
|
386
894
|
"button",
|
|
387
895
|
{
|
|
388
896
|
type: "button",
|
|
@@ -393,51 +901,51 @@ function Findings() {
|
|
|
393
901
|
}
|
|
394
902
|
)
|
|
395
903
|
] }),
|
|
396
|
-
toast !== null && /* @__PURE__ */
|
|
397
|
-
payload.sitewideFindings.length > 0 && /* @__PURE__ */
|
|
398
|
-
/* @__PURE__ */
|
|
399
|
-
/* @__PURE__ */
|
|
400
|
-
/* @__PURE__ */
|
|
401
|
-
/* @__PURE__ */
|
|
402
|
-
/* @__PURE__ */
|
|
904
|
+
toast !== null && /* @__PURE__ */ jsx7("div", { className: "rounded border border-kumo-line bg-kumo-tint p-3 text-sm", children: toast }),
|
|
905
|
+
payload.sitewideFindings.length > 0 && /* @__PURE__ */ jsxs5("section", { className: "rounded border border-kumo-line p-3", children: [
|
|
906
|
+
/* @__PURE__ */ jsx7("h2", { className: "text-sm font-medium", children: "Sitewide" }),
|
|
907
|
+
/* @__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: [
|
|
908
|
+
/* @__PURE__ */ jsx7(SeverityBadge2, { severity: finding.severity }),
|
|
909
|
+
/* @__PURE__ */ jsx7("code", { className: "font-mono text-xs", children: finding.rule_id }),
|
|
910
|
+
/* @__PURE__ */ jsx7("span", { className: "flex-1", children: finding.message })
|
|
403
911
|
] }, i)) })
|
|
404
912
|
] }),
|
|
405
|
-
payload.findings.length === 0 ? /* @__PURE__ */
|
|
406
|
-
/* @__PURE__ */
|
|
407
|
-
/* @__PURE__ */
|
|
408
|
-
/* @__PURE__ */
|
|
409
|
-
/* @__PURE__ */
|
|
410
|
-
/* @__PURE__ */
|
|
913
|
+
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: [
|
|
914
|
+
/* @__PURE__ */ jsx7("thead", { className: "bg-kumo-tint", children: /* @__PURE__ */ jsxs5("tr", { children: [
|
|
915
|
+
/* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Route" }),
|
|
916
|
+
/* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Rule" }),
|
|
917
|
+
/* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Severity" }),
|
|
918
|
+
/* @__PURE__ */ jsx7("th", { className: "px-3 py-2 font-medium text-kumo-subtle", children: "Message" })
|
|
411
919
|
] }) }),
|
|
412
|
-
/* @__PURE__ */
|
|
920
|
+
/* @__PURE__ */ jsx7("tbody", { children: payload.findings.map((finding, i) => {
|
|
413
921
|
const routeInfo = routesByPath.get(finding.route);
|
|
414
|
-
return /* @__PURE__ */
|
|
415
|
-
/* @__PURE__ */
|
|
416
|
-
/* @__PURE__ */
|
|
417
|
-
/* @__PURE__ */
|
|
418
|
-
/* @__PURE__ */
|
|
922
|
+
return /* @__PURE__ */ jsxs5("tr", { className: "border-t border-kumo-line", children: [
|
|
923
|
+
/* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx7(RouteLinks2, { finding, info: routeInfo }) }),
|
|
924
|
+
/* @__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 }) }),
|
|
925
|
+
/* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: /* @__PURE__ */ jsx7(SeverityBadge2, { severity: finding.severity }) }),
|
|
926
|
+
/* @__PURE__ */ jsx7("td", { className: "px-3 py-2 align-top", children: finding.message })
|
|
419
927
|
] }, i);
|
|
420
928
|
}) })
|
|
421
929
|
] }) })
|
|
422
930
|
] });
|
|
423
931
|
}
|
|
424
|
-
function
|
|
932
|
+
function RouteLinks2({
|
|
425
933
|
finding,
|
|
426
934
|
info
|
|
427
935
|
}) {
|
|
428
936
|
if (info === void 0) {
|
|
429
|
-
return /* @__PURE__ */
|
|
937
|
+
return /* @__PURE__ */ jsx7("span", { className: "font-mono text-xs", children: finding.route });
|
|
430
938
|
}
|
|
431
|
-
return /* @__PURE__ */
|
|
432
|
-
info.editUrl !== "" ? /* @__PURE__ */
|
|
939
|
+
return /* @__PURE__ */ jsxs5("span", { className: "space-x-2", children: [
|
|
940
|
+
info.editUrl !== "" ? /* @__PURE__ */ jsx7(
|
|
433
941
|
"a",
|
|
434
942
|
{
|
|
435
943
|
href: info.editUrl,
|
|
436
944
|
className: "font-mono text-xs text-kumo-link hover:underline",
|
|
437
945
|
children: finding.route
|
|
438
946
|
}
|
|
439
|
-
) : /* @__PURE__ */
|
|
440
|
-
info.publishedUrl !== "" && /* @__PURE__ */
|
|
947
|
+
) : /* @__PURE__ */ jsx7("span", { className: "font-mono text-xs", children: finding.route }),
|
|
948
|
+
info.publishedUrl !== "" && /* @__PURE__ */ jsx7(
|
|
441
949
|
"a",
|
|
442
950
|
{
|
|
443
951
|
href: info.publishedUrl,
|
|
@@ -447,12 +955,12 @@ function RouteLinks({
|
|
|
447
955
|
children: "live \u2197"
|
|
448
956
|
}
|
|
449
957
|
),
|
|
450
|
-
info.status !== "" && info.status !== "published" && /* @__PURE__ */
|
|
958
|
+
info.status !== "" && info.status !== "published" && /* @__PURE__ */ jsx7("span", { className: "text-xs text-kumo-subtle", children: info.status })
|
|
451
959
|
] });
|
|
452
960
|
}
|
|
453
|
-
function
|
|
961
|
+
function SeverityBadge2({ severity }) {
|
|
454
962
|
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";
|
|
455
|
-
return /* @__PURE__ */
|
|
963
|
+
return /* @__PURE__ */ jsx7(
|
|
456
964
|
"span",
|
|
457
965
|
{
|
|
458
966
|
className: `inline-block rounded border px-1.5 py-0.5 text-xs font-medium ${classes}`,
|
|
@@ -460,7 +968,7 @@ function SeverityBadge({ severity }) {
|
|
|
460
968
|
}
|
|
461
969
|
);
|
|
462
970
|
}
|
|
463
|
-
function
|
|
971
|
+
function csrfHeaders2() {
|
|
464
972
|
return {
|
|
465
973
|
"Content-Type": "application/json",
|
|
466
974
|
// emdash's apiFetch wrapper sets this on every mutation;
|
|
@@ -469,7 +977,7 @@ function csrfHeaders() {
|
|
|
469
977
|
"X-EmDash-Request": "1"
|
|
470
978
|
};
|
|
471
979
|
}
|
|
472
|
-
function
|
|
980
|
+
function unwrap2(body, res) {
|
|
473
981
|
if (body.error !== void 0) {
|
|
474
982
|
throw new Error(`${body.error.code}: ${body.error.message}`);
|
|
475
983
|
}
|
|
@@ -479,12 +987,25 @@ function unwrap(body, res) {
|
|
|
479
987
|
return body.data;
|
|
480
988
|
}
|
|
481
989
|
|
|
990
|
+
// src/admin/Retrievability.tsx
|
|
991
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
992
|
+
function Retrievability() {
|
|
993
|
+
return /* @__PURE__ */ jsx8(PillarView, { layer: "retrievability" });
|
|
994
|
+
}
|
|
995
|
+
|
|
482
996
|
// src/admin.tsx
|
|
483
997
|
var pages = {
|
|
998
|
+
// Four pillar pages — the canonical organization going forward.
|
|
999
|
+
"/retrievability": Retrievability,
|
|
1000
|
+
"/citability": Citability,
|
|
1001
|
+
"/absorbability": Absorbability,
|
|
1002
|
+
"/entity-legitimacy": EntityLegitimacy,
|
|
1003
|
+
// /findings stays as a cross-pillar flat view for users who want
|
|
1004
|
+
// every finding in one list. Not removed because it's still useful
|
|
1005
|
+
// for triage — "show me everything that's wrong" is a real workflow.
|
|
484
1006
|
"/findings": Findings,
|
|
485
|
-
// /facts
|
|
486
|
-
//
|
|
487
|
-
// the React adminEntry. Same mechanism as /findings.
|
|
1007
|
+
// /facts kept as an alias so old bookmarks don't 404. Renders the
|
|
1008
|
+
// same Facts component the EntityLegitimacy page composes.
|
|
488
1009
|
"/facts": Facts
|
|
489
1010
|
};
|
|
490
1011
|
export {
|