@rubytech/create-realagent-code 0.1.116 → 0.1.118

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.
Files changed (90) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/neo4j/schema.cypher +104 -0
  3. package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
  4. package/payload/platform/plugins/admin/PLUGIN.md +1 -0
  5. package/payload/platform/plugins/aeo/.claude-plugin/plugin.json +17 -0
  6. package/payload/platform/plugins/aeo/PLUGIN.md +81 -0
  7. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts +2 -0
  8. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.d.ts.map +1 -0
  9. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js +121 -0
  10. package/payload/platform/plugins/aeo/mcp/dist/__tests__/audit-heuristics.test.js.map +1 -0
  11. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts +2 -0
  12. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.d.ts.map +1 -0
  13. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js +129 -0
  14. package/payload/platform/plugins/aeo/mcp/dist/__tests__/schema-mapping.test.js.map +1 -0
  15. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts +2 -0
  16. package/payload/platform/plugins/aeo/mcp/dist/index.d.ts.map +1 -0
  17. package/payload/platform/plugins/aeo/mcp/dist/index.js +171 -0
  18. package/payload/platform/plugins/aeo/mcp/dist/index.js.map +1 -0
  19. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts +27 -0
  20. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.d.ts.map +1 -0
  21. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js +274 -0
  22. package/payload/platform/plugins/aeo/mcp/dist/lib/audit-heuristics.js.map +1 -0
  23. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts +5 -0
  24. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.d.ts.map +1 -0
  25. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js +38 -0
  26. package/payload/platform/plugins/aeo/mcp/dist/lib/neo4j.js.map +1 -0
  27. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts +48 -0
  28. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.d.ts.map +1 -0
  29. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js +254 -0
  30. package/payload/platform/plugins/aeo/mcp/dist/lib/schema-mapping.js.map +1 -0
  31. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts +25 -0
  32. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.d.ts.map +1 -0
  33. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js +78 -0
  34. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-audit-page.js.map +1 -0
  35. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts +18 -0
  36. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.d.ts.map +1 -0
  37. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js +56 -0
  38. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-emit-jsonld.js.map +1 -0
  39. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts +37 -0
  40. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.d.ts.map +1 -0
  41. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js +94 -0
  42. package/payload/platform/plugins/aeo/mcp/dist/tools/aeo-write-llms-txt.js.map +1 -0
  43. package/payload/platform/plugins/aeo/mcp/package.json +22 -0
  44. package/payload/platform/plugins/aeo/mcp/vitest.config.ts +9 -0
  45. package/payload/platform/plugins/aeo/skills/structured-answer/SKILL.md +53 -0
  46. package/payload/platform/plugins/docs/PLUGIN.md +1 -0
  47. package/payload/platform/plugins/docs/references/admin-session.md +1 -1
  48. package/payload/platform/plugins/docs/references/aeo.md +87 -0
  49. package/payload/platform/plugins/docs/references/deployment.md +1 -1
  50. package/payload/platform/plugins/email/PLUGIN.md +6 -0
  51. package/payload/platform/plugins/email/skills/email-composition/SKILL.md +180 -0
  52. package/payload/platform/plugins/memory/mcp/dist/index.js +5 -0
  53. package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
  54. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts +2 -0
  55. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.d.ts.map +1 -0
  56. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js +62 -0
  57. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/label-origin-gate.test.js.map +1 -0
  58. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts +2 -0
  59. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.d.ts.map +1 -0
  60. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js +62 -0
  61. package/payload/platform/plugins/memory/mcp/dist/lib/__tests__/schema-cypher-drift.test.js.map +1 -0
  62. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts +18 -0
  63. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.d.ts.map +1 -0
  64. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js +29 -0
  65. package/payload/platform/plugins/memory/mcp/dist/lib/label-origin-gate.js.map +1 -0
  66. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js +2 -0
  67. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-update-emit.test.js.map +1 -1
  68. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js +1 -1
  69. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-write-emit.test.js.map +1 -1
  70. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts +3 -0
  71. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.d.ts.map +1 -1
  72. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js +9 -1
  73. package/payload/platform/plugins/memory/mcp/dist/tools/memory-update.js.map +1 -1
  74. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.d.ts.map +1 -1
  75. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js +8 -0
  76. package/payload/platform/plugins/memory/mcp/dist/tools/memory-write.js.map +1 -1
  77. package/payload/platform/plugins/memory/mcp/vitest.config.ts +4 -0
  78. package/payload/platform/plugins/memory/references/schema-base.md +5 -1
  79. package/payload/platform/scripts/smoke-boot-services.sh +30 -2
  80. package/payload/platform/templates/specialists/agents/signal-detector.md +1 -1
  81. package/payload/server/public/assets/{admin-DloKrK2i.js → admin-D6IfAzYY.js} +1 -1
  82. package/payload/server/public/assets/{data-NMvGx6jm.js → data-BGbQyufe.js} +1 -1
  83. package/payload/server/public/assets/{graph-CN60KyTy.js → graph-D-1lRTeL.js} +1 -1
  84. package/payload/server/public/assets/{graph-labels-h39S93Xo.js → graph-labels-BRXJHNYE.js} +1 -1
  85. package/payload/server/public/assets/{page-B0iMmY6t.js → page-B4oirCvn.js} +1 -1
  86. package/payload/server/public/assets/{page-CFRU-BdJ.js → page-FmJ7PIYx.js} +1 -1
  87. package/payload/server/public/data.html +3 -3
  88. package/payload/server/public/graph.html +3 -3
  89. package/payload/server/public/index.html +4 -4
  90. package/payload/server/server.js +14 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rubytech/create-realagent-code",
3
- "version": "0.1.116",
3
+ "version": "0.1.118",
4
4
  "description": "Install Real Agent — Built for agents. By agents.",
5
5
  "bin": {
6
6
  "create-realagent-code": "./dist/index.js"
@@ -1100,3 +1100,107 @@ FOR (h:CloudflareHostname) REQUIRE (h.accountId, h.hostnameValue) IS UNIQUE;
1100
1100
 
1101
1101
  CREATE INDEX cloudflare_hostname_account IF NOT EXISTS
1102
1102
  FOR (h:CloudflareHostname) ON (h.accountId);
1103
+
1104
+ // ----------------------------------------------------------
1105
+ // Estate-agent ontology (Task 358) — Listing-centric model
1106
+ // documented at platform/plugins/memory/references/schema-estate-agent.md.
1107
+ //
1108
+ // These declarations exist primarily so the memory-write validator's
1109
+ // parseLabelsFromSchemaCypher() registers each label on a fresh deploy
1110
+ // where no node of the label has yet landed — without them, the first
1111
+ // :Listing write from the listing-curator agent is rejected as "unknown
1112
+ // label" against an empty db.labels() set.
1113
+ //
1114
+ // Idempotency contracts mirror schema-estate-agent.md:
1115
+ // :Listing / :Viewing / :Offer — (accountId, sourceSystem, sourceId)
1116
+ // :Property — (accountId, slug)
1117
+ // :ImageObject — (accountId, listingSlug, url) for the
1118
+ // estate-agent variant, (accountId, name,
1119
+ // contentUrl) for the brand-asset variant.
1120
+ // Because the two writers use different
1121
+ // natural keys, only an accountId index is
1122
+ // declared at the schema level — uniqueness
1123
+ // is enforced at write time by the curator
1124
+ // / brand-asset writer's MERGE clause.
1125
+ // ----------------------------------------------------------
1126
+
1127
+ CREATE CONSTRAINT listing_account_source_unique IF NOT EXISTS
1128
+ FOR (l:Listing) REQUIRE (l.accountId, l.sourceSystem, l.sourceId) IS UNIQUE;
1129
+
1130
+ CREATE INDEX listing_account IF NOT EXISTS
1131
+ FOR (l:Listing) ON (l.accountId);
1132
+
1133
+ CREATE INDEX listing_status IF NOT EXISTS
1134
+ FOR (l:Listing) ON (l.status);
1135
+
1136
+ CREATE INDEX listing_type IF NOT EXISTS
1137
+ FOR (l:Listing) ON (l.listingType);
1138
+
1139
+ CREATE VECTOR INDEX listing_embedding IF NOT EXISTS
1140
+ FOR (l:Listing) ON (l.embedding)
1141
+ OPTIONS {
1142
+ indexConfig: {
1143
+ `vector.dimensions`: 768,
1144
+ `vector.similarity_function`: 'cosine'
1145
+ }
1146
+ };
1147
+
1148
+ CREATE CONSTRAINT property_account_slug_unique IF NOT EXISTS
1149
+ FOR (p:Property) REQUIRE (p.accountId, p.slug) IS UNIQUE;
1150
+
1151
+ CREATE INDEX property_account IF NOT EXISTS
1152
+ FOR (p:Property) ON (p.accountId);
1153
+
1154
+ CREATE CONSTRAINT viewing_account_source_unique IF NOT EXISTS
1155
+ FOR (v:Viewing) REQUIRE (v.accountId, v.sourceSystem, v.sourceId) IS UNIQUE;
1156
+
1157
+ CREATE INDEX viewing_account IF NOT EXISTS
1158
+ FOR (v:Viewing) ON (v.accountId);
1159
+
1160
+ CREATE CONSTRAINT offer_account_source_unique IF NOT EXISTS
1161
+ FOR (o:Offer) REQUIRE (o.accountId, o.sourceSystem, o.sourceId) IS UNIQUE;
1162
+
1163
+ CREATE INDEX offer_account IF NOT EXISTS
1164
+ FOR (o:Offer) ON (o.accountId);
1165
+
1166
+ CREATE INDEX image_object_account IF NOT EXISTS
1167
+ FOR (i:ImageObject) ON (i.accountId);
1168
+
1169
+ // :PostalAddress (schema:PostalAddress) — shared address nodes documented in
1170
+ // schema-base.md. Address rows are deliberately accountId-free (one address
1171
+ // can be shared across customers / orders / listings); writers MERGE on the
1172
+ // formatted address triple. Declared here so a fresh deploy registers the
1173
+ // label before the first :PostalAddress write lands.
1174
+ CREATE INDEX postal_address_postcode IF NOT EXISTS
1175
+ FOR (a:PostalAddress) ON (a.postalCode);
1176
+
1177
+ // ----------------------------------------------------------
1178
+ // AEOAudit — Answer Engine Optimisation audit history (Task 354).
1179
+ // Written by the aeo plugin's aeo-audit-page tool when invoked
1180
+ // with persist=true. Append-only audit trail; each invocation
1181
+ // produces a new node. Linked via
1182
+ // (KnowledgeDocument)-[:HAS_AEO_AUDIT]->(AEOAudit) when the audit
1183
+ // targets a stored document, otherwise standalone keyed on
1184
+ // (accountId, target, runAt).
1185
+ //
1186
+ // Properties: accountId, auditId (uuid), target (url or
1187
+ // '(inline html)'), score (0-100), heuristicsJson (serialized
1188
+ // per-heuristic result), runAt, createdByAgent, createdBySession,
1189
+ // createdAt.
1190
+ //
1191
+ // Monitor-related labels (:AEOPrompt, :AEOCheck, :AEOCitation) are
1192
+ // intentionally NOT declared in v1 — the multi-engine monitor is
1193
+ // filed as a follow-up task and the schema will land with it.
1194
+ // ----------------------------------------------------------
1195
+
1196
+ CREATE CONSTRAINT aeo_audit_id_unique IF NOT EXISTS
1197
+ FOR (a:AEOAudit) REQUIRE a.auditId IS UNIQUE;
1198
+
1199
+ CREATE INDEX aeo_audit_account IF NOT EXISTS
1200
+ FOR (a:AEOAudit) ON (a.accountId);
1201
+
1202
+ CREATE INDEX aeo_audit_target IF NOT EXISTS
1203
+ FOR (a:AEOAudit) ON (a.target);
1204
+
1205
+ CREATE INDEX aeo_audit_run_at IF NOT EXISTS
1206
+ FOR (a:AEOAudit) ON (a.runAt);
@@ -9,6 +9,11 @@
9
9
  "source": "./admin",
10
10
  "version": "0.1.0"
11
11
  },
12
+ {
13
+ "name": "aeo",
14
+ "source": "./aeo",
15
+ "version": "0.1.0"
16
+ },
12
17
  {
13
18
  "name": "business-assistant",
14
19
  "source": "./business-assistant",
@@ -1,5 +1,6 @@
1
1
  ---
2
2
  name: admin
3
+ surface: platform
3
4
  description: "Platform administration plugin. Provides system-status, public-hostname (deterministic Cloudflare public-URL resolver, single call returning the operator's canonical hostname so agents never guess property names on :CloudflareHostname nodes), brand-settings, account-manage, account-update, admin-add, admin-remove, admin-list, admin-update-pin, agent-list, agent-config-read, logs-read, plugin-read, skill-load (one-call resolve+read for SKILL.md by skill name, the canonical primitive for loading a named skill; plugin-read remains the reader for references/* and PLUGIN.md), store-skill (deterministic write counterpart to plugin-read; persists operator-authored skills as plugin files under the active account), session-reset, session-resume, file-attach, wifi, action-approval tools (action-pending, action-approve, action-reject, action-edit), and session-retrospective-mark-complete (the deterministic sentinel the session-end Stop hook reads via JSONL grep to release the retrospective gate; admin calls it once per session after running the three-pass retrospective) for managing the Maxy platform."
4
5
  tools:
5
6
  - name: system-status
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "aeo",
3
+ "description": "Answer Engine Optimisation. Emits schema.org JSON-LD for typed graph entities, generates llms.txt + llms-full.txt for the site, and audits pages against eight AEO heuristics with one rewrite suggestion per fail. Writes :AEOAudit history nodes when audits are persisted.",
4
+ "version": "0.1.0",
5
+ "author": {
6
+ "name": "Rubytech LLC"
7
+ },
8
+ "mcpServers": {
9
+ "aeo": {
10
+ "type": "stdio",
11
+ "command": "node",
12
+ "args": [
13
+ "${CLAUDE_PLUGIN_ROOT}/mcp/dist/index.js"
14
+ ]
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: aeo
3
+ description: "Answer Engine Optimisation. Emits schema.org JSON-LD for typed graph entities, generates llms.txt + llms-full.txt for the site, and audits pages against eight AEO heuristics with one rewrite suggestion per fail. Writes :AEOAudit history nodes when audits are persisted."
4
+ tools:
5
+ - name: aeo-emit-jsonld
6
+ publicAllowlist: false
7
+ adminAllowlist: true
8
+ - name: aeo-write-llms-txt
9
+ publicAllowlist: false
10
+ adminAllowlist: true
11
+ - name: aeo-audit-page
12
+ publicAllowlist: false
13
+ adminAllowlist: true
14
+ skills:
15
+ - skills/structured-answer/SKILL.md
16
+ always: false
17
+ embed: false
18
+ metadata: {"platform":{}}
19
+ mcp:
20
+ command: node
21
+ args:
22
+ - ${PLATFORM_ROOT}/lib/mcp-spawn-tee/dist/index.js
23
+ - ${PLATFORM_ROOT}/plugins/aeo/mcp/dist/index.js
24
+ env:
25
+ MCP_SPAWN_TEE_NAME: aeo
26
+ LOG_DIR: ${LOG_DIR}
27
+ PLATFORM_ROOT: ${PLATFORM_ROOT}
28
+ ACCOUNT_ID: ${ACCOUNT_ID}
29
+ SESSION_ID: ${SESSION_ID}
30
+ AGENT_SLUG: ${AGENT_SLUG}
31
+ mcp-manifest: auto
32
+ ---
33
+
34
+ # AEO (Answer Engine Optimisation)
35
+
36
+ This plugin makes the platform's content legible to answer engines — Claude, ChatGPT, Perplexity, Google AI Overviews, Bing Copilot. Classical SEO ranks links; AEO shapes the page so the answer-engine extractor lifts the right answer.
37
+
38
+ ## The three surfaces
39
+
40
+ 1. **JSON-LD** (`aeo-emit-jsonld`). Every typed graph entity that backs a page can be projected to a `<script type="application/ld+json">` block. The mapper covers `Organization`, `LocalBusiness`, `Person`, `Service`, `Product`, `Article`, `FAQPage`, `RealEstateListing`, `Event`. Other labels fall through to `schema:Thing` and are flagged as a doc gap.
41
+
42
+ 2. **llms.txt** (`aeo-write-llms-txt`). The site emits `/llms.txt` (index of pages, one link per line) and `/llms-full.txt` (concatenated full text). Format follows the current draft at `https://llmstxt.org/`. Source is `KnowledgeDocument` nodes with a `url` property. Pages without a `url` are skipped and counted in the response.
43
+
44
+ 3. **Audit** (`aeo-audit-page`). Run the eight-heuristic scorecard against a URL or raw HTML. Each heuristic returns pass / warn / fail with one rewrite suggestion per fail. Score is `100 * (passes + 0.5 * warns) / 8`. Pass `persist: true` with a `targetKnowledgeDocumentId` to record an `:AEOAudit` node linked back to the document.
45
+
46
+ ## The eight heuristics
47
+
48
+ | Heuristic | Pass | Warn | Fail |
49
+ |---|---|---|---|
50
+ | `h1-present` | one `<h1>` | more than one | none |
51
+ | `jsonld-present` | one or more JSON-LD blocks, all parse | some parse | none, or all unparseable |
52
+ | `structured-answer` | first `<p>` after `<h1>` is ≤280 chars | first `<p>` is over 280 chars | no `<p>` after `<h1>` |
53
+ | `faq-section` | `FAQPage` JSON-LD on page | FAQ text but no JSON-LD | nothing FAQ-like |
54
+ | `meta-description` | 80–160 chars | present but outside range | absent |
55
+ | `canonical-url` | `<link rel="canonical">` present | — | absent |
56
+ | `og-tags` | `og:title` and `og:description` both set | — | one or both missing |
57
+ | `heading-hierarchy` | no level skips | — | h1→h3 or similar jump |
58
+
59
+ `structured-answer` is the highest-impact: answer engines lift the structured-answer span verbatim. A page can fail every other heuristic and still get cited if the first paragraph cleanly answers the question.
60
+
61
+ ## Persistence model
62
+
63
+ The plugin only writes `:AEOAudit` nodes (when `persist: true`). It does not own the entities it reads — `KnowledgeDocument`, `Organization`, `Person`, etc. belong to the memory plugin. Edges written:
64
+
65
+ - `(:KnowledgeDocument)-[:HAS_AEO_AUDIT]->(:AEOAudit)`
66
+
67
+ The audit nodes carry `accountId`, `target` (URL or `(inline html)`), `score`, `heuristicsJson` (full result), `runAt`, `createdByAgent`, `createdBySession`. They form an append-only audit history; aggregate trend queries (score-over-time) walk this set.
68
+
69
+ ## What this plugin does not do
70
+
71
+ - No LLM API calls. There is no monitor in v1. The "is my brand cited when a customer asks Claude / ChatGPT / Perplexity / Gemini" question depends on multi-engine answer harvesting that runs differently under maxy-code's no-API-key architecture, and is filed as a follow-up task.
72
+ - No automatic emission. `aeo-emit-jsonld` returns a script block; wiring it into the platform's page render path is per-renderer work, also filed as a follow-up.
73
+ - No publish-hook regeneration of `llms.txt`. The tool runs on demand. Hooking it into the publish event is a follow-up.
74
+ - No prose authoring. AEO audits structure; it does not rewrite content. Writer-craft owns voice.
75
+
76
+ ## See also
77
+
78
+ - User guide: `platform/plugins/docs/references/aeo.md`
79
+ - Structured-answer template: `platform/plugins/aeo/skills/structured-answer/SKILL.md`
80
+ - Schema declaration: `platform/neo4j/schema.cypher` (search `AEOAudit`)
81
+ - Schema reference: `platform/plugins/memory/schema-base.md` (search `AEOAudit`)
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=audit-heuristics.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-heuristics.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/audit-heuristics.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,121 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { auditHtml } from "../lib/audit-heuristics.js";
3
+ function pick(result, name) {
4
+ const r = result.heuristics.find((h) => h.name === name);
5
+ if (!r)
6
+ throw new Error(`heuristic ${name} not found`);
7
+ return r;
8
+ }
9
+ const GOOD_PAGE = `<!doctype html>
10
+ <html><head>
11
+ <title>How much does a boiler service cost? — Acme</title>
12
+ <meta name="description" content="A standard boiler service in Brighton costs £85 to £120, takes about one hour, and includes a written safety report.">
13
+ <link rel="canonical" href="https://acme.test/boiler-service-cost">
14
+ <meta property="og:title" content="How much does a boiler service cost?">
15
+ <meta property="og:description" content="A standard boiler service in Brighton costs £85 to £120, takes about one hour, and includes a written safety report.">
16
+ <script type="application/ld+json">{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"Cost?","acceptedAnswer":{"@type":"Answer","text":"£85–£120."}}]}</script>
17
+ </head><body>
18
+ <h1>How much does a boiler service cost?</h1>
19
+ <p>A standard boiler service in Brighton costs £85 to £120 and takes about one hour.</p>
20
+ <h2>What's included</h2>
21
+ <p>Safety checks, flue gas analysis, pressure adjustment, written report.</p>
22
+ <h2>Frequently asked questions</h2>
23
+ <p>Common questions are answered above.</p>
24
+ </body></html>`;
25
+ const BAD_PAGE = `<!doctype html>
26
+ <html><head><title>Acme</title></head>
27
+ <body>
28
+ <div>Some words.</div>
29
+ </body></html>`;
30
+ describe("auditHtml — golden good page", () => {
31
+ const result = auditHtml(GOOD_PAGE);
32
+ it("scores 100", () => {
33
+ expect(result.score).toBe(100);
34
+ });
35
+ it("passes every heuristic", () => {
36
+ for (const h of result.heuristics) {
37
+ expect(h.status, `${h.name}: ${h.detail}`).toBe("pass");
38
+ }
39
+ });
40
+ });
41
+ describe("auditHtml — bad page exercises every fail path", () => {
42
+ const result = auditHtml(BAD_PAGE);
43
+ it("scores 0 or near-zero", () => {
44
+ expect(result.score).toBeLessThanOrEqual(10);
45
+ });
46
+ it("fails h1-present", () => {
47
+ expect(pick(result, "h1-present").status).toBe("fail");
48
+ });
49
+ it("fails jsonld-present", () => {
50
+ expect(pick(result, "jsonld-present").status).toBe("fail");
51
+ });
52
+ it("fails meta-description", () => {
53
+ expect(pick(result, "meta-description").status).toBe("fail");
54
+ });
55
+ it("fails canonical-url", () => {
56
+ expect(pick(result, "canonical-url").status).toBe("fail");
57
+ });
58
+ it("fails og-tags with both missing", () => {
59
+ const r = pick(result, "og-tags");
60
+ expect(r.status).toBe("fail");
61
+ expect(r.detail).toContain("og:title");
62
+ expect(r.detail).toContain("og:description");
63
+ });
64
+ it("emits a rewrite suggestion for every failure", () => {
65
+ for (const h of result.heuristics) {
66
+ if (h.status === "fail") {
67
+ expect(h.suggestion, `${h.name} missing suggestion`).toBeTruthy();
68
+ }
69
+ }
70
+ });
71
+ });
72
+ describe("auditHtml — warn paths", () => {
73
+ it("warns when first <p> after <h1> exceeds 280 chars", () => {
74
+ const long = "X".repeat(300);
75
+ const html = `<html><head>
76
+ <title>t</title>
77
+ <meta name="description" content="${"d".repeat(120)}">
78
+ <link rel="canonical" href="https://a.test">
79
+ <meta property="og:title" content="t">
80
+ <meta property="og:description" content="t">
81
+ <script type="application/ld+json">{"@type":"FAQPage"}</script>
82
+ </head><body>
83
+ <h1>Topic</h1><p>${long}</p>
84
+ <h2>More</h2><p>x</p>
85
+ </body></html>`;
86
+ const result = auditHtml(html);
87
+ expect(pick(result, "structured-answer").status).toBe("warn");
88
+ });
89
+ it("warns when meta-description length is outside 80–160", () => {
90
+ const html = `<html><head>
91
+ <title>t</title>
92
+ <meta name="description" content="too short">
93
+ <link rel="canonical" href="https://a.test">
94
+ <meta property="og:title" content="t">
95
+ <meta property="og:description" content="t">
96
+ <script type="application/ld+json">{"@type":"FAQPage"}</script>
97
+ </head><body>
98
+ <h1>Topic</h1><p>short answer</p>
99
+ </body></html>`;
100
+ expect(pick(auditHtml(html), "meta-description").status).toBe("warn");
101
+ });
102
+ it("warns when there are multiple <h1> elements", () => {
103
+ const html = `<html><body><h1>A</h1><h1>B</h1><p>x</p></body></html>`;
104
+ expect(pick(auditHtml(html), "h1-present").status).toBe("warn");
105
+ });
106
+ it("fails heading-hierarchy on h1→h3 skip", () => {
107
+ const html = `<html><body><h1>A</h1><p>x</p><h3>Skipped</h3></body></html>`;
108
+ const r = pick(auditHtml(html), "heading-hierarchy");
109
+ expect(r.status).toBe("fail");
110
+ expect(r.detail).toContain("h1");
111
+ expect(r.detail).toContain("h3");
112
+ });
113
+ it("warns on unparseable JSON-LD when other blocks parse", () => {
114
+ const html = `<html><head>
115
+ <script type="application/ld+json">{"@type":"FAQPage"}</script>
116
+ <script type="application/ld+json">not json</script>
117
+ </head><body><h1>T</h1><p>a</p></body></html>`;
118
+ expect(pick(auditHtml(html), "jsonld-present").status).toBe("warn");
119
+ });
120
+ });
121
+ //# sourceMappingURL=audit-heuristics.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-heuristics.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-heuristics.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=schema-mapping.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-mapping.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/schema-mapping.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,129 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { buildJsonLd, renderJsonLdScript, resolveSchemaType, MissingPropertyError, } from "../lib/schema-mapping.js";
3
+ describe("resolveSchemaType", () => {
4
+ it("maps known graph labels to schema.org types", () => {
5
+ expect(resolveSchemaType("LocalBusiness")).toBe("LocalBusiness");
6
+ expect(resolveSchemaType("Organization")).toBe("Organization");
7
+ expect(resolveSchemaType("Person")).toBe("Person");
8
+ expect(resolveSchemaType("Service")).toBe("Service");
9
+ expect(resolveSchemaType("Product")).toBe("Product");
10
+ expect(resolveSchemaType("CreativeWork")).toBe("Article");
11
+ expect(resolveSchemaType("Article")).toBe("Article");
12
+ expect(resolveSchemaType("FAQPage")).toBe("FAQPage");
13
+ expect(resolveSchemaType("Listing")).toBe("RealEstateListing");
14
+ expect(resolveSchemaType("RealEstateListing")).toBe("RealEstateListing");
15
+ expect(resolveSchemaType("Event")).toBe("Event");
16
+ });
17
+ it("falls back to Thing for unknown labels", () => {
18
+ expect(resolveSchemaType("UnknownLabel")).toBe("Thing");
19
+ });
20
+ });
21
+ describe("buildJsonLd", () => {
22
+ it("renders an Organization with required name", () => {
23
+ const obj = buildJsonLd({
24
+ label: "Organization",
25
+ properties: { name: "Acme", website: "https://acme.test" },
26
+ });
27
+ expect(obj["@context"]).toBe("https://schema.org");
28
+ expect(obj["@type"]).toBe("Organization");
29
+ expect(obj.name).toBe("Acme");
30
+ expect(obj.url).toBe("https://acme.test");
31
+ });
32
+ it("renders a LocalBusiness with nested PostalAddress", () => {
33
+ const obj = buildJsonLd({
34
+ label: "LocalBusiness",
35
+ elementId: "4:abc:1",
36
+ properties: {
37
+ name: "Acme Plumbing",
38
+ streetAddress: "1 High St",
39
+ addressLocality: "Brighton",
40
+ postalCode: "BN1 1AA",
41
+ },
42
+ });
43
+ expect(obj["@id"]).toBe("4:abc:1");
44
+ expect(obj.address).toEqual({
45
+ "@type": "PostalAddress",
46
+ streetAddress: "1 High St",
47
+ addressLocality: "Brighton",
48
+ postalCode: "BN1 1AA",
49
+ });
50
+ });
51
+ it("renders a Person and synthesises name from givenName + familyName", () => {
52
+ const obj = buildJsonLd({
53
+ label: "Person",
54
+ properties: {
55
+ givenName: "Joel",
56
+ familyName: "Smalley",
57
+ email: "j@example.com",
58
+ },
59
+ });
60
+ expect(obj["@type"]).toBe("Person");
61
+ expect(obj.name).toBe("Joel Smalley");
62
+ expect(obj.email).toBe("j@example.com");
63
+ });
64
+ it("renders a Service with an Offer when price is set", () => {
65
+ const obj = buildJsonLd({
66
+ label: "Service",
67
+ properties: { name: "Boiler service", price: 120, priceCurrency: "GBP" },
68
+ });
69
+ expect(obj.offers).toEqual({
70
+ "@type": "Offer",
71
+ price: 120,
72
+ priceCurrency: "GBP",
73
+ });
74
+ });
75
+ it("renders an Article remapping title→headline and abstract→description", () => {
76
+ const obj = buildJsonLd({
77
+ label: "Article",
78
+ properties: { title: "How boilers work", abstract: "Short summary" },
79
+ });
80
+ expect(obj.headline).toBe("How boilers work");
81
+ expect(obj.description).toBe("Short summary");
82
+ });
83
+ it("renders an FAQPage with mainEntity Question/Answer pairs", () => {
84
+ const obj = buildJsonLd({
85
+ label: "FAQPage",
86
+ properties: {
87
+ name: "Boiler FAQ",
88
+ questions: [
89
+ { name: "How long does it take?", acceptedAnswer: "About an hour." },
90
+ { name: "Do you charge call-out?", acceptedAnswer: "No." },
91
+ ],
92
+ },
93
+ });
94
+ expect(Array.isArray(obj.mainEntity)).toBe(true);
95
+ const main = obj.mainEntity;
96
+ expect(main).toHaveLength(2);
97
+ });
98
+ it("renders an Event with required name + startDate", () => {
99
+ const obj = buildJsonLd({
100
+ label: "Event",
101
+ properties: { name: "Open day", startDate: "2026-06-01T10:00:00Z" },
102
+ });
103
+ expect(obj.startDate).toBe("2026-06-01T10:00:00Z");
104
+ });
105
+ it("throws MissingPropertyError when required property is absent", () => {
106
+ expect(() => buildJsonLd({ label: "Event", properties: { name: "Open day" } })).toThrow(MissingPropertyError);
107
+ });
108
+ it("renders unknown labels as schema:Thing without throwing", () => {
109
+ const obj = buildJsonLd({
110
+ label: "Mystery",
111
+ properties: { name: "Anonymous", description: "Unknown" },
112
+ });
113
+ expect(obj["@type"]).toBe("Thing");
114
+ expect(obj.name).toBe("Anonymous");
115
+ });
116
+ });
117
+ describe("renderJsonLdScript", () => {
118
+ it("wraps the JSON in a script block", () => {
119
+ const obj = buildJsonLd({
120
+ label: "Organization",
121
+ properties: { name: "Acme" },
122
+ });
123
+ const block = renderJsonLdScript(obj);
124
+ expect(block).toMatch(/^<script type="application\/ld\+json">/);
125
+ expect(block).toMatch(/<\/script>$/);
126
+ expect(block).toContain('"Acme"');
127
+ });
128
+ });
129
+ //# sourceMappingURL=schema-mapping.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-mapping.test.js","sourceRoot":"","sources":["../../src/__tests__/schema-mapping.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,GACrB,MAAM,0BAA0B,CAAC;AAElC,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,iBAAiB,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACjE,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC/D,MAAM,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC1D,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QAC/D,MAAM,CAAC,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACzE,MAAM,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC1D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACpD,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,EAAE;SAC3D,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QACnD,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC9B,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,eAAe;YACtB,SAAS,EAAE,SAAS;YACpB,UAAU,EAAE;gBACV,IAAI,EAAE,eAAe;gBACrB,aAAa,EAAE,WAAW;gBAC1B,eAAe,EAAE,UAAU;gBAC3B,UAAU,EAAE,SAAS;aACtB;SACF,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC;YAC1B,OAAO,EAAE,eAAe;YACxB,aAAa,EAAE,WAAW;YAC1B,eAAe,EAAE,UAAU;YAC3B,UAAU,EAAE,SAAS;SACtB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mEAAmE,EAAE,GAAG,EAAE;QAC3E,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,QAAQ;YACf,UAAU,EAAE;gBACV,SAAS,EAAE,MAAM;gBACjB,UAAU,EAAE,SAAS;gBACrB,KAAK,EAAE,eAAe;aACvB;SACF,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACtC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,GAAG,EAAE;QAC3D,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,GAAG,EAAE,aAAa,EAAE,KAAK,EAAE;SACzE,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACzB,OAAO,EAAE,OAAO;YAChB,KAAK,EAAE,GAAG;YACV,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE,KAAK,EAAE,kBAAkB,EAAE,QAAQ,EAAE,eAAe,EAAE;SACrE,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;QAC9C,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,0DAA0D,EAAE,GAAG,EAAE;QAClE,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE;gBACV,IAAI,EAAE,YAAY;gBAClB,SAAS,EAAE;oBACT,EAAE,IAAI,EAAE,wBAAwB,EAAE,cAAc,EAAE,gBAAgB,EAAE;oBACpE,EAAE,IAAI,EAAE,yBAAyB,EAAE,cAAc,EAAE,KAAK,EAAE;iBAC3D;aACF;SACF,CAAC,CAAC;QACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,MAAM,IAAI,GAAG,GAAG,CAAC,UAAuB,CAAC;QACzC,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,OAAO;YACd,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,sBAAsB,EAAE;SACpE,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,GAAG,EAAE,CACV,WAAW,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAClE,CAAC,OAAO,CAAC,oBAAoB,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,SAAS;YAChB,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE;SAC1D,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IAClC,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,GAAG,GAAG,WAAW,CAAC;YACtB,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE;SAC7B,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,kBAAkB,CAAC,GAAG,CAAC,CAAC;QACtC,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC;QAChE,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;QACrC,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}