@relvehq/agent-ready 0.3.0 → 0.4.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.
Files changed (29) hide show
  1. package/README.md +24 -3
  2. package/SETUP.md +354 -354
  3. package/dist/core/report.d.ts +9 -3
  4. package/dist/core/report.js +30 -10
  5. package/dist/core/version.d.ts +1 -0
  6. package/dist/core/version.js +8 -0
  7. package/dist/index.d.ts +2 -1
  8. package/dist/index.js +5 -1
  9. package/dist/refine/check.d.ts +3 -1
  10. package/dist/refine/check.js +43 -0
  11. package/dist/refine/remote.d.ts +3 -2
  12. package/dist/refine/remote.js +3 -2
  13. package/dist/wp/relve-agent-ready/includes/class-relve-ar-admin.php +560 -550
  14. package/dist/wp/relve-agent-ready/includes/class-relve-ar-converter.php +762 -762
  15. package/dist/wp/relve-agent-ready/includes/class-relve-ar-llms.php +192 -192
  16. package/dist/wp/relve-agent-ready/includes/class-relve-ar-markdown-builder.php +455 -455
  17. package/dist/wp/relve-agent-ready/includes/class-relve-ar-negotiation.php +334 -334
  18. package/dist/wp/relve-agent-ready/includes/class-relve-ar-refiner.php +894 -894
  19. package/dist/wp/relve-agent-ready/includes/class-relve-ar-reporter.php +147 -0
  20. package/dist/wp/relve-agent-ready/includes/class-relve-ar-response.php +226 -226
  21. package/dist/wp/relve-agent-ready/includes/class-relve-ar-router.php +422 -421
  22. package/dist/wp/relve-agent-ready/includes/class-relve-ar-settings.php +210 -201
  23. package/dist/wp/relve-agent-ready/includes/class-relve-ar-store.php +583 -583
  24. package/dist/wp/relve-agent-ready/includes/index.php +2 -2
  25. package/dist/wp/relve-agent-ready/index.php +2 -2
  26. package/dist/wp/relve-agent-ready/readme.txt +119 -108
  27. package/dist/wp/relve-agent-ready/relve-agent-ready.php +82 -81
  28. package/dist/wp/relve-agent-ready/uninstall.php +35 -35
  29. package/package.json +1 -1
@@ -1,9 +1,11 @@
1
1
  import type { HitEvent } from "./config";
2
+ /** Relve's ingest URL, used when AGENT_READY_ENDPOINT is not set. */
3
+ export declare const DEFAULT_HITS_ENDPOINT = "https://relvehq.com/api/agent-ready/v1/hits";
2
4
  export interface ReporterOptions {
3
5
  /** The venture's dashboard key. */
4
6
  key: string;
5
- /** Ingest URL that receives { key, event }. */
6
- endpoint: string;
7
+ /** Ingest URL that receives { key, client, event }. Default: Relve's. */
8
+ endpoint?: string;
7
9
  /** Give up after this long. Default 2000 ms. */
8
10
  timeoutMs?: number;
9
11
  /** Injected for tests. */
@@ -11,5 +13,9 @@ export interface ReporterOptions {
11
13
  }
12
14
  /** An `onHit` that sends each event to the dashboard. */
13
15
  export declare function reporter(opts: ReporterOptions): (event: HitEvent) => Promise<void>;
14
- /** A reporter from env (AGENT_READY_KEY + AGENT_READY_ENDPOINT), or null when either is missing. */
16
+ /**
17
+ * A reporter from env, or null when AGENT_READY_KEY is missing.
18
+ * AGENT_READY_ENDPOINT is optional (Relve's by default); when set it must be
19
+ * http(s), else null.
20
+ */
15
21
  export declare function reporterFromEnv(env: Record<string, string | undefined>): ((event: HitEvent) => Promise<void>) | null;
@@ -2,28 +2,42 @@
2
2
  // Measure, the easy way: send every agent visit to a dashboard with one key
3
3
  // (changes/agent-ready-engine, "easy setup"). Replaces writing an `onHit`.
4
4
  //
5
- // AGENT_READY_KEY=ar_live_xxx (the venture's key)
6
- // AGENT_READY_ENDPOINT=https://.../hits (the dashboard's ingest URL)
5
+ // AGENT_READY_KEY=ar_live_yoursite (your key: ar_ + 3-64 of A-Z a-z 0-9 _ -)
6
+ // AGENT_READY_ENDPOINT=https://.../hits (optional: another dashboard)
7
7
  //
8
- // `reporter()` returns an `onHit` that POSTs { key, event } as JSON, with a
9
- // short timeout and keepalive. Fire-and-forget like every `onHit`: it never
10
- // throws and the response never waits for it.
8
+ // With only AGENT_READY_KEY set, visits go to Relve's dashboard
9
+ // (DEFAULT_HITS_ENDPOINT, changes/agent-ready-telemetry). Nothing is sent
10
+ // unless the key is set: reporting is opt-in.
11
+ //
12
+ // What one report holds: the key, the package version and the HitEvent
13
+ // (time, host, path, how the Markdown was asked for and where it came from,
14
+ // status, tokens, bytes, the visitor's user agent, duration). Never the
15
+ // Markdown, never the visitor's IP.
16
+ //
17
+ // `reporter()` returns an `onHit` that POSTs { key, client, event } as JSON,
18
+ // with a short timeout and keepalive. Fire-and-forget like every `onHit`: it
19
+ // never throws and the response never waits for it.
11
20
  //
12
21
  // EDGE-SAFE. No Node APIs.
13
22
  Object.defineProperty(exports, "__esModule", { value: true });
23
+ exports.DEFAULT_HITS_ENDPOINT = void 0;
14
24
  exports.reporter = reporter;
15
25
  exports.reporterFromEnv = reporterFromEnv;
26
+ const version_1 = require("./version");
27
+ /** Relve's ingest URL, used when AGENT_READY_ENDPOINT is not set. */
28
+ exports.DEFAULT_HITS_ENDPOINT = "https://relvehq.com/api/agent-ready/v1/hits";
16
29
  /** An `onHit` that sends each event to the dashboard. */
17
30
  function reporter(opts) {
18
31
  const f = opts.fetch ?? fetch;
32
+ const endpoint = opts.endpoint ?? exports.DEFAULT_HITS_ENDPOINT;
19
33
  return async (event) => {
20
34
  const ctl = new AbortController();
21
35
  const timer = setTimeout(() => ctl.abort(), opts.timeoutMs ?? 2000);
22
36
  try {
23
- await f(opts.endpoint, {
37
+ await f(endpoint, {
24
38
  method: "POST",
25
39
  headers: { "content-type": "application/json", authorization: `Bearer ${opts.key}` },
26
- body: JSON.stringify({ key: opts.key, event }),
40
+ body: JSON.stringify({ key: opts.key, client: `npm/${version_1.PACKAGE_VERSION}`, event }),
27
41
  keepalive: true,
28
42
  signal: ctl.signal,
29
43
  });
@@ -36,11 +50,17 @@ function reporter(opts) {
36
50
  }
37
51
  };
38
52
  }
39
- /** A reporter from env (AGENT_READY_KEY + AGENT_READY_ENDPOINT), or null when either is missing. */
53
+ /**
54
+ * A reporter from env, or null when AGENT_READY_KEY is missing.
55
+ * AGENT_READY_ENDPOINT is optional (Relve's by default); when set it must be
56
+ * http(s), else null.
57
+ */
40
58
  function reporterFromEnv(env) {
41
59
  const key = env.AGENT_READY_KEY?.trim();
42
60
  const endpoint = env.AGENT_READY_ENDPOINT?.trim();
43
- if (!key || !endpoint || !/^https?:\/\//.test(endpoint))
61
+ if (!key)
62
+ return null;
63
+ if (endpoint && !/^https?:\/\//.test(endpoint))
44
64
  return null;
45
- return reporter({ key, endpoint });
65
+ return reporter({ key, endpoint: endpoint || undefined });
46
66
  }
@@ -0,0 +1 @@
1
+ export declare const PACKAGE_VERSION = "0.4.0";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ // The package version, in one place: the refine user agent and the visit
3
+ // reporter both send it, so Relve can tell which release a venture runs
4
+ // (changes/agent-ready-telemetry). Keep in step with package.json.
5
+ // EDGE-SAFE.
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PACKAGE_VERSION = void 0;
8
+ exports.PACKAGE_VERSION = "0.4.0";
package/dist/index.d.ts CHANGED
@@ -6,7 +6,8 @@ export { buildLlmsTxt, type BuildLlmsOptions } from "./core/llms";
6
6
  export { byteLength, etagFor, ifNoneMatchHits, markdownResponse, MARKDOWN_CONTENT_TYPE, type RespondOptions } from "./core/respond";
7
7
  export { COMMON_PRIVATE_PATHS, createAgentReady, enabledFromEnv, siteFromEnv, type EasyOptions, type Env } from "./core/easy";
8
8
  export { entriesFromUrls, humanize, parseSitemap, sitemapEntries, type ParsedSitemap, type SitemapEntriesOptions } from "./core/sitemap";
9
- export { reporter, reporterFromEnv, type ReporterOptions } from "./core/report";
9
+ export { DEFAULT_HITS_ENDPOINT, reporter, reporterFromEnv, type ReporterOptions } from "./core/report";
10
+ export { PACKAGE_VERSION } from "./core/version";
10
11
  export { ANSWER_BOT_TOKENS, classifyAgent, isAnswerBot, type Bot, type BotKind } from "./proof/bots";
11
12
  export { filterHits, memoryHitStore, teeHits, type HitQuery, type HitStore } from "./proof/hits";
12
13
  export { formatSummary, summarize, type Count, type HitSummary } from "./proof/stats";
package/dist/index.js CHANGED
@@ -8,7 +8,8 @@
8
8
  // @relvehq/agent-ready/next/route Next.js route handler
9
9
  // and the Next.js middleware adapter lives at @relvehq/agent-ready/next.
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.formatAudit = exports.blockedBots = exports.auditSite = exports.renderDashboard = exports.summarize = exports.formatSummary = exports.teeHits = exports.memoryHitStore = exports.filterHits = exports.isAnswerBot = exports.classifyAgent = exports.ANSWER_BOT_TOKENS = exports.reporterFromEnv = exports.reporter = exports.sitemapEntries = exports.parseSitemap = exports.humanize = exports.entriesFromUrls = exports.siteFromEnv = exports.enabledFromEnv = exports.createAgentReady = exports.COMMON_PRIVATE_PATHS = exports.MARKDOWN_CONTENT_TYPE = exports.markdownResponse = exports.ifNoneMatchHits = exports.etagFor = exports.byteLength = exports.buildLlmsTxt = exports.jsonLdFacts = exports.hasFrontMatter = exports.frontMatter = exports.estimateTokens = exports.enrich = exports.wantsMarkdown = exports.stripMdSuffix = exports.normalizePath = exports.mdUrlPath = exports.isExcluded = exports.isEnabled = exports.emitHit = exports.defineAgentReady = exports.VIA_HEADER = exports.DEFAULT_NEGOTIATED_CACHE_CONTROL = exports.DEFAULT_INTERNAL_PREFIX = exports.DEFAULT_INTERNAL_HEADER = exports.DEFAULT_CACHE_CONTROL = exports.ALWAYS_EXCLUDE = exports.parseAccept = exports.chooseFormat = void 0;
11
+ exports.blockedBots = exports.auditSite = exports.renderDashboard = exports.summarize = exports.formatSummary = exports.teeHits = exports.memoryHitStore = exports.filterHits = exports.isAnswerBot = exports.classifyAgent = exports.ANSWER_BOT_TOKENS = exports.PACKAGE_VERSION = exports.reporterFromEnv = exports.reporter = exports.DEFAULT_HITS_ENDPOINT = exports.sitemapEntries = exports.parseSitemap = exports.humanize = exports.entriesFromUrls = exports.siteFromEnv = exports.enabledFromEnv = exports.createAgentReady = exports.COMMON_PRIVATE_PATHS = exports.MARKDOWN_CONTENT_TYPE = exports.markdownResponse = exports.ifNoneMatchHits = exports.etagFor = exports.byteLength = exports.buildLlmsTxt = exports.jsonLdFacts = exports.hasFrontMatter = exports.frontMatter = exports.estimateTokens = exports.enrich = exports.wantsMarkdown = exports.stripMdSuffix = exports.normalizePath = exports.mdUrlPath = exports.isExcluded = exports.isEnabled = exports.emitHit = exports.defineAgentReady = exports.VIA_HEADER = exports.DEFAULT_NEGOTIATED_CACHE_CONTROL = exports.DEFAULT_INTERNAL_PREFIX = exports.DEFAULT_INTERNAL_HEADER = exports.DEFAULT_CACHE_CONTROL = exports.ALWAYS_EXCLUDE = exports.parseAccept = exports.chooseFormat = void 0;
12
+ exports.formatAudit = void 0;
12
13
  var accept_1 = require("./core/accept");
13
14
  Object.defineProperty(exports, "chooseFormat", { enumerable: true, get: function () { return accept_1.chooseFormat; } });
14
15
  Object.defineProperty(exports, "parseAccept", { enumerable: true, get: function () { return accept_1.parseAccept; } });
@@ -54,8 +55,11 @@ Object.defineProperty(exports, "humanize", { enumerable: true, get: function ()
54
55
  Object.defineProperty(exports, "parseSitemap", { enumerable: true, get: function () { return sitemap_1.parseSitemap; } });
55
56
  Object.defineProperty(exports, "sitemapEntries", { enumerable: true, get: function () { return sitemap_1.sitemapEntries; } });
56
57
  var report_1 = require("./core/report");
58
+ Object.defineProperty(exports, "DEFAULT_HITS_ENDPOINT", { enumerable: true, get: function () { return report_1.DEFAULT_HITS_ENDPOINT; } });
57
59
  Object.defineProperty(exports, "reporter", { enumerable: true, get: function () { return report_1.reporter; } });
58
60
  Object.defineProperty(exports, "reporterFromEnv", { enumerable: true, get: function () { return report_1.reporterFromEnv; } });
61
+ var version_1 = require("./core/version");
62
+ Object.defineProperty(exports, "PACKAGE_VERSION", { enumerable: true, get: function () { return version_1.PACKAGE_VERSION; } });
59
63
  // Proof: who reads, how much, and how agent-ready a site is.
60
64
  var bots_1 = require("./proof/bots");
61
65
  Object.defineProperty(exports, "ANSWER_BOT_TOKENS", { enumerable: true, get: function () { return bots_1.ANSWER_BOT_TOKENS; } });
@@ -1,6 +1,6 @@
1
1
  import type { PageInput } from "./types";
2
2
  import type { PromptSettings } from "./prompts";
3
- export type IssueKind = "number" | "url" | "frontmatter" | "hash" | "section" | "h1" | "html" | "placeholder" | "tokens" | "empty";
3
+ export type IssueKind = "number" | "url" | "frontmatter" | "hash" | "section" | "h1" | "html" | "placeholder" | "tokens" | "empty" | "plan";
4
4
  export interface CheckIssue {
5
5
  kind: IssueKind;
6
6
  detail: string;
@@ -15,3 +15,5 @@ export interface CheckOptions {
15
15
  countTokens?: (text: string) => number;
16
16
  }
17
17
  export declare function checkDoc(doc: string, input: PageInput, settings: PromptSettings, opts?: CheckOptions): CheckResult;
18
+ /** First-column names of the tables under "## Pricing" / "## Plans" headings. */
19
+ export declare function planNames(prose: string): string[];
@@ -12,6 +12,9 @@
12
12
  // h1 not exactly one H1
13
13
  // html HTML tags in the document
14
14
  // placeholder a {{PLACEHOLDER}} or <Template field> left in
15
+ // plan a plan named in a "## Pricing" / "## Plans" table that the
16
+ // input never names (e.g. a made-up "Basic" built from the
17
+ // prices of other products shown on the page; 2026-10-29)
15
18
  // tokens over the prompt's token budget
16
19
  // empty no real body
17
20
  //
@@ -20,6 +23,7 @@
20
23
  // EDGE-SAFE (pure). It cannot catch a reworded claim; people still read.
21
24
  Object.defineProperty(exports, "__esModule", { value: true });
22
25
  exports.checkDoc = checkDoc;
26
+ exports.planNames = planNames;
23
27
  const enrich_1 = require("../core/enrich");
24
28
  const URL_RE = /https?:\/\/[^\s<>()[\]|"'`]+/g;
25
29
  const NUM_RE = /\d+(?:[.,]\d+)*/g;
@@ -100,8 +104,47 @@ function checkDoc(doc, input, settings, opts = {}) {
100
104
  seen.add(c);
101
105
  add("number", n);
102
106
  }
107
+ // Plans: every plan a Pricing / Plans table names must be named in the
108
+ // input. The number check alone passes a plan stitched together from
109
+ // prices that are on the page but belong to something else.
110
+ for (const name of planNames(prose)) {
111
+ if (!namedIn(haystack, name))
112
+ add("plan", name);
113
+ }
103
114
  return { ok: issues.length === 0, issues, tokens };
104
115
  }
116
+ /** First-column names of the tables under "## Pricing" / "## Plans" headings. */
117
+ function planNames(prose) {
118
+ const names = [];
119
+ for (const section of prose.split(/^(?=##\s)/m)) {
120
+ const heading = /^##\s+(.+)$/m.exec(section);
121
+ if (!heading || !/^(pricing|plans)\b/i.test(heading[1].trim()))
122
+ continue;
123
+ let header = true;
124
+ for (const line of section.split("\n")) {
125
+ if (!line.trim().startsWith("|")) {
126
+ header = true; // a new table starts with its own header row
127
+ continue;
128
+ }
129
+ if (/^\|[\s:|-]+\|?\s*$/.test(line.trim()))
130
+ continue; // separator row
131
+ if (header) {
132
+ header = false;
133
+ continue;
134
+ }
135
+ const cell = line.trim().replace(/^\|/, "").split("|")[0] ?? "";
136
+ const name = cell.replace(/[*_`]/g, "").replace(/\s+/g, " ").trim();
137
+ if (name)
138
+ names.push(name);
139
+ }
140
+ }
141
+ return names;
142
+ }
143
+ /** The name appears in the text as a whole word or phrase, ignoring case and spacing. */
144
+ function namedIn(text, name) {
145
+ const words = name.split(" ").map(escapeRe).join("\\s+");
146
+ return new RegExp(`(?<![A-Za-z0-9])${words}(?![A-Za-z0-9])`, "i").test(text);
147
+ }
105
148
  /** "1,400" = "1400", "0.10" = "0.1", "05" = "5". */
106
149
  function canonNum(s) {
107
150
  const plain = s.replace(/,(?=\d{3}\b)/g, "");
@@ -1,7 +1,8 @@
1
- export declare const PACKAGE_VERSION = "0.3.0";
1
+ import { PACKAGE_VERSION } from "../core/version";
2
+ export { PACKAGE_VERSION };
2
3
  export declare const DEFAULT_REFINE_ENDPOINT = "https://relvehq.com/api/agent-ready/v1/refine";
3
4
  export declare const REFINE_MODELS: readonly ["gpt-4o", "gpt-4o-mini", "gpt-4.1", "gpt-4.1-mini"];
4
- export declare const USER_AGENT = "agent-ready/0.3.0 (+https://relvehq.com/agent-ready)";
5
+ export declare const USER_AGENT = "agent-ready/0.4.0 (+https://relvehq.com/agent-ready)";
5
6
  export type RemoteStatus = "ok" | "unchanged" | "rejected" | "error" | "skipped";
6
7
  export interface RemoteItem {
7
8
  path: string;
@@ -52,10 +52,11 @@ exports.savedFingerprint = savedFingerprint;
52
52
  exports.refineRemote = refineRemote;
53
53
  exports.stopMessage = stopMessage;
54
54
  const file_store_1 = require("./file-store");
55
- exports.PACKAGE_VERSION = "0.3.0";
55
+ const version_1 = require("../core/version");
56
+ Object.defineProperty(exports, "PACKAGE_VERSION", { enumerable: true, get: function () { return version_1.PACKAGE_VERSION; } });
56
57
  exports.DEFAULT_REFINE_ENDPOINT = "https://relvehq.com/api/agent-ready/v1/refine";
57
58
  exports.REFINE_MODELS = ["gpt-4o", "gpt-4o-mini", "gpt-4.1", "gpt-4.1-mini"];
58
- exports.USER_AGENT = `agent-ready/${exports.PACKAGE_VERSION} (+https://relvehq.com/agent-ready)`;
59
+ exports.USER_AGENT = `agent-ready/${version_1.PACKAGE_VERSION} (+https://relvehq.com/agent-ready)`;
59
60
  /** Errors that mean every later call would fail the same way: the run stops. */
60
61
  const FATAL = new Set(["openai_auth", "openai_quota", "missing_key"]);
61
62
  /** The saved JSON's fingerprint, else one built from a local run's sourceHash, else null. */