@cmo-so/cli 0.12.16 → 0.12.17
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/dist/cmo.mjs +34 -10
- package/package.json +1 -1
package/dist/cmo.mjs
CHANGED
|
@@ -34705,30 +34705,54 @@ async function techAudit(site, o2 = {}) {
|
|
|
34705
34705
|
...urls.length > crawl.length ? { note: `Crawled the first ${crawl.length} of ${urls.length} sitemap addresses (limit up to 200).` } : {}
|
|
34706
34706
|
};
|
|
34707
34707
|
}
|
|
34708
|
-
async function
|
|
34709
|
-
const key = globalThis.process?.env?.PAGESPEED_API_KEY;
|
|
34708
|
+
async function pageSpeedRun(url, key) {
|
|
34710
34709
|
const q4 = new URLSearchParams({ url, strategy: "mobile", category: "performance" });
|
|
34711
34710
|
if (key) q4.set("key", key);
|
|
34712
34711
|
const r = await fetch(`https://www.googleapis.com/pagespeedonline/v5/runPagespeed?${q4}`, {
|
|
34713
34712
|
signal: AbortSignal.timeout(9e4)
|
|
34714
34713
|
}).catch(() => null);
|
|
34715
|
-
if (!r || !r.ok)
|
|
34716
|
-
return {
|
|
34717
|
-
error: `PageSpeed Insights didn't answer (${r?.status ?? "timeout"})${r?.status === 429 && !key ? ": the server needs a PAGESPEED_API_KEY (Google Cloud, free)" : ""}.`
|
|
34718
|
-
};
|
|
34714
|
+
if (!r || !r.ok) return { status: r?.status ?? 0 };
|
|
34719
34715
|
const j2 = await r.json();
|
|
34720
34716
|
const f2 = j2.loadingExperience?.metrics ?? {};
|
|
34721
34717
|
const a3 = j2.lighthouseResult?.audits ?? {};
|
|
34722
34718
|
const field = !!f2.LARGEST_CONTENTFUL_PAINT_MS;
|
|
34723
34719
|
return {
|
|
34724
|
-
|
|
34720
|
+
status: 200,
|
|
34721
|
+
field,
|
|
34725
34722
|
score: Math.round((j2.lighthouseResult?.categories?.performance?.score ?? 0) * 100),
|
|
34726
|
-
lcp_ms: field ? f2.LARGEST_CONTENTFUL_PAINT_MS?.percentile : Math.round(a3["largest-contentful-paint"]?.numericValue ?? 0),
|
|
34723
|
+
lcp_ms: field ? f2.LARGEST_CONTENTFUL_PAINT_MS?.percentile ?? 0 : Math.round(a3["largest-contentful-paint"]?.numericValue ?? 0),
|
|
34727
34724
|
cls: field ? (f2.CUMULATIVE_LAYOUT_SHIFT_SCORE?.percentile ?? 0) / 100 : Number((a3["cumulative-layout-shift"]?.numericValue ?? 0).toFixed(3)),
|
|
34728
34725
|
inp_ms: f2.INTERACTION_TO_NEXT_PAINT?.percentile ?? null,
|
|
34729
34726
|
tbt_ms: Math.round(a3["total-blocking-time"]?.numericValue ?? 0)
|
|
34730
34727
|
};
|
|
34731
34728
|
}
|
|
34729
|
+
async function pageSpeed(url) {
|
|
34730
|
+
const key = globalThis.process?.env?.PAGESPEED_API_KEY;
|
|
34731
|
+
const runs = await Promise.all(
|
|
34732
|
+
[1, 2, 3].map((n2) => pageSpeedRun(`${url}${url.includes("?") ? "&" : "?"}cmo-speed=${Date.now()}-${n2}`, key))
|
|
34733
|
+
);
|
|
34734
|
+
const ok2 = runs.filter((r) => r.status === 200 && "lcp_ms" in r);
|
|
34735
|
+
if (!ok2.length) {
|
|
34736
|
+
const status = runs[0]?.status ?? 0;
|
|
34737
|
+
return {
|
|
34738
|
+
error: `PageSpeed Insights didn't answer (${status || "timeout"})${status === 429 && !key ? ": the server needs a PAGESPEED_API_KEY (Google Cloud, free)" : ""}.`
|
|
34739
|
+
};
|
|
34740
|
+
}
|
|
34741
|
+
const median = (xs) => {
|
|
34742
|
+
const s = [...xs].sort((a3, b2) => a3 - b2);
|
|
34743
|
+
return s[Math.floor((s.length - 1) / 2)];
|
|
34744
|
+
};
|
|
34745
|
+
const field = ok2.some((r) => r.field);
|
|
34746
|
+
return {
|
|
34747
|
+
source: field ? "real visitors (Chrome UX Report, 28 days)" : `lab test, median of ${ok2.length} runs (no real-visitor data yet)`,
|
|
34748
|
+
score: median(ok2.map((r) => r.score)),
|
|
34749
|
+
lcp_ms: median(ok2.map((r) => r.lcp_ms)),
|
|
34750
|
+
cls: median(ok2.map((r) => r.cls)),
|
|
34751
|
+
inp_ms: ok2.find((r) => r.inp_ms != null)?.inp_ms ?? null,
|
|
34752
|
+
tbt_ms: median(ok2.map((r) => r.tbt_ms)),
|
|
34753
|
+
runs: ok2.map((r) => ({ score: r.score, lcp_ms: r.lcp_ms }))
|
|
34754
|
+
};
|
|
34755
|
+
}
|
|
34732
34756
|
var STOP = new Set(
|
|
34733
34757
|
"the a an and or of to in for on with by at from is are be your our you we it this that how what why best guide near vs and/or my me us".split(
|
|
34734
34758
|
" "
|
|
@@ -37711,7 +37735,7 @@ function withRelated(blocks, heading2, links2) {
|
|
|
37711
37735
|
var seoTechTools = [
|
|
37712
37736
|
tool({
|
|
37713
37737
|
name: "wp_seo_tech_audit",
|
|
37714
|
-
description: "Technical SEO check of the connected site, like a crawler: robots.txt (sitemap line, Google or AI crawlers blocked), the sitemap and every page it lists (status, redirects, noindex in the sitemap, canonicals pointing elsewhere, H1 count, missing or duplicate titles and descriptions, long titles, pictures without alt text, broken structured data, thin pages), broken and redirected internal links, generic link words, llms.txt; speed: true adds Core Web Vitals for the homepage (PageSpeed Insights). Findings ranked p0\u2026p4 with the fix and a tool when one can do it. Read-only. Internal-link layout: wp_internal_links_plan.",
|
|
37738
|
+
description: "Technical SEO check of the connected site, like a crawler: robots.txt (sitemap line, Google or AI crawlers blocked), the sitemap and every page it lists (status, redirects, noindex in the sitemap, canonicals pointing elsewhere, H1 count, missing or duplicate titles and descriptions, long titles, pictures without alt text, broken structured data, thin pages), broken and redirected internal links, generic link words, llms.txt; speed: true adds Core Web Vitals for the homepage (PageSpeed Insights: real visitors when Google has them, else the median of three lab runs). Findings ranked p0\u2026p4 with the fix and a tool when one can do it. Read-only. Internal-link layout: wp_internal_links_plan.",
|
|
37715
37739
|
parameters: {
|
|
37716
37740
|
type: "object",
|
|
37717
37741
|
properties: {
|
|
@@ -41359,7 +41383,7 @@ var program = new Command();
|
|
|
41359
41383
|
// package.json
|
|
41360
41384
|
var package_default = {
|
|
41361
41385
|
name: "@cmo-so/cli",
|
|
41362
|
-
version: "0.12.
|
|
41386
|
+
version: "0.12.17",
|
|
41363
41387
|
description: "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
41364
41388
|
type: "module",
|
|
41365
41389
|
license: "MIT",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cmo-so/cli",
|
|
3
|
-
"version": "0.12.
|
|
3
|
+
"version": "0.12.17",
|
|
4
4
|
"description": "CMO.so on the command line: your websites, ideas, blog posts, LinkedIn queue and results, plus a local MCP server for Claude Desktop, Cursor and other MCP clients.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|