seo 0.2.6 → 0.2.8
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/README.md +1 -1
- package/dist/cli.js +2 -2
- package/dist/{dist-PRmi6cXV.js → dist-B8eKKp3B.js} +66 -66
- package/dist/dist-B8eKKp3B.js.map +1 -0
- package/dist/{dist-Xkhuyn70.js → dist-DkWLBABR.js} +1 -1
- package/dist/index.d.ts +41 -9
- package/dist/index.js +122 -39
- package/dist/index.js.map +1 -1
- package/dist/mcp.js +122 -39
- package/dist/mcp.js.map +1 -1
- package/dist/{package-B9-D646K.js → package-BDez60C3.js} +2 -2
- package/dist/{package-B9-D646K.js.map → package-BDez60C3.js.map} +1 -1
- package/package.json +2 -3
- package/dist/dist-PRmi6cXV.js.map +0 -1
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire as __seoCreateRequire } from 'node:module'; const require = __seoCreateRequire(import.meta.url);
|
|
3
|
-
import{$ as e,$t as t,A as n,At as r,B as i,Bt as a,C as o,Ct as s,D as c,Dt as l,E as u,Et as d,F as f,Ft as p,G as m,Gt as ee,H as h,Ht as te,I as ne,It as re,J as ie,Jt as ae,K as g,Kt as oe,L as se,Lt as ce,M as le,Mt as ue,N as de,Nt as fe,O as pe,Ot as me,P as he,Pt as ge,Q as _e,Qt as ve,R as ye,Rt as be,S as xe,St as Se,T as Ce,Tt as we,U as Te,Ut as Ee,V as De,Vt as Oe,W as ke,Wt as Ae,X as je,Xt as Me,Y as Ne,Yt as Pe,Z as Fe,Zt as Ie,_ as Le,_n as _,_t as Re,a as ze,an as Be,at as Ve,b as He,bt as Ue,c as We,cn as Ge,ct as Ke,d as qe,dn as Je,dt as Ye,en as Xe,et as Ze,f as Qe,fn as $e,ft as et,g as tt,gn as nt,gt as rt,h as it,hn as at,ht as ot,i as st,in as ct,it as lt,j as ut,jt as dt,k as ft,kt as pt,l as mt,ln as ht,lt as gt,m as _t,mn as vt,mt as yt,nn as bt,nt as xt,on as St,ot as Ct,p as wt,pn as Tt,pt as Et,q as Dt,qt as Ot,r as kt,rn as At,rt as jt,sn as Mt,st as Nt,t as Pt,tn as Ft,tt as It,u as Lt,un as Rt,ut as zt,v as Bt,vn as Vt,vt as Ht,w as Ut,wt as Wt,x as Gt,xt as Kt,y as qt,yn as Jt,yt as Yt,z as Xt,zt as Zt}from"./dist-PRmi6cXV.js";import{constants as Qt,copyFileSync as $t,existsSync as v,mkdirSync as en,readFileSync as tn,readdirSync as nn,realpathSync as rn,renameSync as an,rmSync as on,statSync as sn,writeFileSync as cn}from"node:fs";import{homedir as ln}from"node:os";import{basename as un,dirname as y,isAbsolute as dn,join as b,posix as fn,relative as pn,resolve as mn,win32 as hn}from"node:path";import{randomUUID as gn}from"node:crypto";import{spawn as _n,spawnSync as vn}from"node:child_process";import{fileURLToPath as yn}from"node:url";import{isDeepStrictEqual as bn,stripVTControlCharacters as xn}from"node:util";import{lstat as Sn,mkdir as Cn,mkdtemp as wn,readFile as Tn,readdir as En,rename as Dn,rm as On,writeFile as kn}from"node:fs/promises";import{defineCommand as x,runCommand as An,runMain as jn}from"citty";import{cancel as Mn,confirm as Nn,intro as Pn,isCancel as Fn,log as In,multiselect as Ln,note as S,outro as Rn,password as zn,select as Bn,text as Vn}from"@clack/prompts";import Hn from"picocolors";import Un from"string-width";import Wn from"cli-table3";import{applyEdits as Gn,modify as Kn,parse as qn,printParseErrorCode as Jn}from"jsonc-parser";import Yn from"update-notifier";const C={summary:`workflow.site.generated_at.summary.attribution.confidence.classification.updates_matched.known_confounders.page_segment_status.page_segment_eligible_rows.page_segment_returned_rows.page_segment_limited_rows.page_segment_result_limit.page_segment_source_row_limit.page_segment_source_possibly_truncated.page_segment_warnings.query_segment_status.query_segment_eligible_rows.query_segment_returned_rows.query_segment_limited_rows.query_segment_result_limit.query_segment_source_row_limit.query_segment_source_possibly_truncated.query_segment_warnings.device_segment_status.device_segment_eligible_rows.device_segment_returned_rows.device_segment_limited_rows.device_segment_result_limit.device_segment_source_row_limit.device_segment_source_possibly_truncated.device_segment_warnings.country_segment_status.country_segment_eligible_rows.country_segment_returned_rows.country_segment_limited_rows.country_segment_result_limit.country_segment_source_row_limit.country_segment_source_possibly_truncated.country_segment_warnings`.split(`.`),steps:[`rank`,`tool`,`status`,`summary`],actions:[`rank`,`title`,`confidence`,`action`],findings:[`dimension`,`data_status`,`eligible_rows`,`returned_rows`,`limited_rows`,`result_limit`,`unmatched_rows`,`summary`,`winner_key`,`winner_click_delta`,`winner_impression_delta`,`winner_position_delta`,`loser_key`,`loser_click_delta`,`loser_impression_delta`,`loser_position_delta`],templates:[`rank`,`direction`,`template`,`confidence`,`url_count`,`click_delta`,`impression_delta`,`movement_share`,`movement_share_scope`,`confidence_scope`,`eligible_rows`,`returned_rows`,`limited_rows`,`result_limit`,`source_possibly_truncated`,`common_terms`,`sample_urls`,`summary`],evidence:[`rank`,`evidence`],confounders:[`rank`,`source`,`title`,`date`,`scope`,`target`,`description`],segment:[`rank`,`dimension`,`data_status`,`evidence_scope`,`key`,`before_clicks`,`after_clicks`,`click_delta`,`before_impressions`,`after_impressions`,`impression_delta`,`before_position`,`after_position`,`position_delta`],unmatchedSegment:[`rank`,`dimension`,`data_status`,`key`,`retained_in`,`clicks`,`impressions`,`position`,`reason`]};function Xn(e,t){return[...e.output.segments[t].winners,...e.output.segments[t].losers].map((n,r)=>({rank:r+1,dimension:t,data_status:e.output.segments[t].dataStatus,evidence_scope:n.evidenceScope,key:n.key,before_clicks:n.beforeClicks,after_clicks:n.afterClicks,click_delta:n.clickDelta,before_impressions:n.beforeImpressions,after_impressions:n.afterImpressions,impression_delta:n.impressionDelta,before_position:n.beforePosition,after_position:n.afterPosition,position_delta:n.positionDelta}))}function Zn(e,t){return e.output.segments[t].unmatchedSegments.map((n,r)=>({rank:r+1,dimension:t,data_status:e.output.segments[t].dataStatus,key:n.key,retained_in:n.retainedIn,clicks:n.clicks,impressions:n.impressions,position:n.position,reason:n.reason}))}function Qn(e){return[{filename:`postmortem-summary.csv`,headers:[...C.summary],rows:[{workflow:e.workflow,site:e.site,generated_at:e.generatedAt,summary:e.summary,attribution:e.output.update.attribution,confidence:e.output.update.confidence,classification:e.output.update.classification,updates_matched:e.output.update.overlappingUpdates.length,known_confounders:e.output.update.confounders.length,page_segment_status:e.output.segments.page.dataStatus,page_segment_eligible_rows:e.output.segments.page.coverage.eligibleRows,page_segment_returned_rows:e.output.segments.page.coverage.returnedRows,page_segment_limited_rows:e.output.segments.page.coverage.limitedRows,page_segment_result_limit:e.output.segments.page.coverage.resultLimit,page_segment_source_row_limit:e.output.segments.page.coverage.sourceRowLimit,page_segment_source_possibly_truncated:e.output.segments.page.coverage.sourcePossiblyTruncated,page_segment_warnings:e.output.segments.page.warnings.join(`; `),query_segment_status:e.output.segments.query.dataStatus,query_segment_eligible_rows:e.output.segments.query.coverage.eligibleRows,query_segment_returned_rows:e.output.segments.query.coverage.returnedRows,query_segment_limited_rows:e.output.segments.query.coverage.limitedRows,query_segment_result_limit:e.output.segments.query.coverage.resultLimit,query_segment_source_row_limit:e.output.segments.query.coverage.sourceRowLimit,query_segment_source_possibly_truncated:e.output.segments.query.coverage.sourcePossiblyTruncated,query_segment_warnings:e.output.segments.query.warnings.join(`; `),device_segment_status:e.output.segments.device.dataStatus,device_segment_eligible_rows:e.output.segments.device.coverage.eligibleRows,device_segment_returned_rows:e.output.segments.device.coverage.returnedRows,device_segment_limited_rows:e.output.segments.device.coverage.limitedRows,device_segment_result_limit:e.output.segments.device.coverage.resultLimit,device_segment_source_row_limit:e.output.segments.device.coverage.sourceRowLimit,device_segment_source_possibly_truncated:e.output.segments.device.coverage.sourcePossiblyTruncated,device_segment_warnings:e.output.segments.device.warnings.join(`; `),country_segment_status:e.output.segments.country.dataStatus,country_segment_eligible_rows:e.output.segments.country.coverage.eligibleRows,country_segment_returned_rows:e.output.segments.country.coverage.returnedRows,country_segment_limited_rows:e.output.segments.country.coverage.limitedRows,country_segment_result_limit:e.output.segments.country.coverage.resultLimit,country_segment_source_row_limit:e.output.segments.country.coverage.sourceRowLimit,country_segment_source_possibly_truncated:e.output.segments.country.coverage.sourcePossiblyTruncated,country_segment_warnings:e.output.segments.country.warnings.join(`; `)}]},{filename:`workflow-steps.csv`,headers:[...C.steps],rows:e.steps.map((e,t)=>({rank:t+1,tool:e.tool,status:e.status,summary:e.summary}))},{filename:`workflow-actions.csv`,headers:[...C.actions],rows:e.actions.map((e,t)=>({rank:t+1,title:e.title,confidence:e.confidence,action:e.action}))},{filename:`postmortem-findings.csv`,headers:[...C.findings],rows:e.output.insights.map(e=>({dimension:e.dimension,data_status:e.dataStatus,eligible_rows:e.coverage.eligibleRows,returned_rows:e.coverage.returnedRows,limited_rows:e.coverage.limitedRows,result_limit:e.coverage.resultLimit,unmatched_rows:e.unmatchedRows,summary:e.summary,winner_key:e.winner?.key,winner_click_delta:e.winner?.clickDelta,winner_impression_delta:e.winner?.impressionDelta,winner_position_delta:e.winner?.positionDelta,loser_key:e.loser?.key,loser_click_delta:e.loser?.clickDelta,loser_impression_delta:e.loser?.impressionDelta,loser_position_delta:e.loser?.positionDelta}))},{filename:`postmortem-template-movement.csv`,headers:[...C.templates],rows:e.output.templateMovement.map((e,t)=>({rank:t+1,direction:e.direction,template:e.signature,confidence:e.confidence,url_count:e.urlCount,click_delta:e.clickDelta,impression_delta:e.impressionDelta,movement_share:e.movementShare,movement_share_scope:e.movementShareScope,confidence_scope:e.confidenceScope,eligible_rows:e.segmentCoverage.eligibleRows,returned_rows:e.segmentCoverage.returnedRows,limited_rows:e.segmentCoverage.limitedRows,result_limit:e.segmentCoverage.resultLimit,source_possibly_truncated:e.segmentCoverage.sourcePossiblyTruncated,common_terms:e.commonTerms.join(`; `),sample_urls:e.sampleUrls.join(`; `),summary:e.summary}))},{filename:`postmortem-update-evidence.csv`,headers:[...C.evidence],rows:e.output.update.evidence.map((e,t)=>({rank:t+1,evidence:e}))},{filename:`postmortem-confounders.csv`,headers:[...C.confounders],rows:e.output.update.confounders.map((e,t)=>({rank:t+1,source:e.source,title:e.title,date:e.date,scope:e.scope,target:e.target,description:e.description}))},...[`page`,`query`,`device`,`country`].map(t=>({filename:`postmortem-segment-${t}.csv`,headers:[...C.segment],rows:Xn(e,t)})),...[`page`,`query`,`device`,`country`].map(t=>({filename:`postmortem-segment-${t}-unmatched.csv`,headers:[...C.unmatchedSegment],rows:Zn(e,t)}))]}function $n(e){try{let t=new URL(e);return t.protocol!==`http:`&&t.protocol!==`https:`?void 0:t.hostname.toLowerCase().replace(/\.$/,``)||void 0}catch{return}}function er(e){if(!e.startsWith(`sc-domain:`))return;let t=e.slice(10).trim().toLowerCase();if(!(!t||/[/:]/.test(t)))return t.replace(/\.$/,``)||void 0}function tr(e,t){let n=er(e);return n?t===n||t.endsWith(`.${n}`)?`domain`:void 0:$n(e)===t?`hostname`:void 0}function nr(e,t){return t.flatMap(t=>{let n=t.stream.webStreamData?.defaultUri;if(!n)return[];let r=$n(n);if(!r)return[];let i=tr(e,r);return i?[{...t,defaultUri:n,hostname:r,match:i}]:[]})}function rr(e,t){let n=e.stream.displayName??e.defaultUri,r=e.match===`domain`?`is inside`:`matches`;return`Matched Google Analytics web stream ${n} (${e.defaultUri}): its hostname ${r} ${t}.`}function ir(e){let t=e-Date.now();if(t<=0)return`expired`;let n=Math.round(t/6e4);if(n<60)return`in ${n}m`;let r=Math.floor(n/60),i=n%60;return i?`in ${r}h ${i}m`:`in ${r}h`}function w(e,t){return{type:`boolean`,default:!0,description:e,negativeDescription:t}}function T(e){return typeof e==`string`?e:void 0}function E(e){let t=T(e.project),n=T(e.client);if(t&&n&&t!==n)throw Error(`Use either --project or --client, not both.`);return t??n}function D(e){return typeof e==`boolean`?e:void 0}function ar(e){let t=T(e.rendering);if(t!==void 0&&t!==`auto`&&t!==`on`&&t!==`off`)throw new _(`INVALID_INPUT`,`--rendering must be auto, on, or off.`);if(D(e.js)===!0&&t&&t!==`on`)throw new _(`INVALID_INPUT`,`Use either --js or --rendering on, not both with different modes.`);return t??(D(e.js)?`on`:`auto`)}function or(e,t){let n=D(e[t]);if(n===!1)return!0;if(n===!0)return!1;let r=D(e[sr(t)]);if(r===!1)return!0;if(r===!0)return!1;if(D(e[`no-${t}`])===!0||D(e[`no${cr(t)}`])===!0)return!0}function sr(e){return e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function cr(e){let t=sr(e);return t?`${t[0]?.toUpperCase()}${t.slice(1)}`:``}function O(e){if(typeof e==`number`)return e;if(typeof e!=`string`||!e.trim())return;let t=Number(e);return Number.isFinite(t)?t:void 0}function k(e,t){if(e===void 0||e===``)return;let n=O(e);if(n===void 0)throw new _(`INVALID_INPUT`,`${t} must be a number.`);return n}function A(e){if(typeof e!=`string`)return;let t=e.split(`,`).map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}function j(e){return A(e)??[]}function lr(e){let t={concurrency:O(e[`fetch-concurrency`]),intervalCap:O(e[`fetch-interval-cap`]),intervalMs:O(e[`fetch-interval-ms`])};return Object.values(t).some(e=>e!==void 0)?t:void 0}function ur(e){let t={concurrency:k(e[`fetch-concurrency`],`--fetch-concurrency`),intervalCap:k(e[`fetch-interval-cap`],`--fetch-interval-cap`),intervalMs:k(e[`fetch-interval-ms`],`--fetch-interval-ms`)};return Object.values(t).some(e=>e!==void 0)?t:void 0}function M(e){return e.json===!0}async function dr(e,t){let n=T(e),r=T(t);if(n&&r)throw Error(`Use either --body or --body-file, not both.`);if(!n&&!r)return;let i=n??await Tn(r??``,`utf8`),a=JSON.parse(i);if(!a||typeof a!=`object`||Array.isArray(a))throw Error(`JSON body must be an object.`);return a}function fr(e){if(typeof e==`number`)return Number.isFinite(e)?Math.round(e):void 0;if(!e)return;let t=Number.parseInt(e,10);return Number.isFinite(t)?t:void 0}function pr(e={}){let t=e.env??process.env,n=fr(e.columns)??fr(e.streamColumns)??fr(t.COLUMNS)??80;return Math.min(200,Math.max(40,n))}function N(e={}){let t=e.env??process.env,n=e.isTTY??!!process.stdout.isTTY,r=e.color??!!(n&&t.NO_COLOR===void 0);return{columns:pr({...e,env:t,streamColumns:e.streamColumns??process.stdout.columns}),colors:Hn.createColors(r),hasColor:r,isInteractive:n&&!t.CI}}function P(e){return Un(xn(e))}function mr(e,t){let n=[],r=``;for(let i of e)r&&P(`${r}${i}`)>t?(n.push(r),r=i):r+=i;return r&&n.push(r),n}function hr(e,t){if(!e)return[``];let n=e.trim().split(/\s+/u),r=[],i=``;for(let e of n){let n=P(e)>t?mr(e,t):[e];for(let e of n)i?P(`${i} ${e}`)<=t?i+=` ${e}`:(r.push(i),i=e):i=e}return i&&r.push(i),r.length>0?r:[``]}function F(e,t){let n=Math.max(1,t);return e.replaceAll(`\r
|
|
3
|
+
import{$ as e,$t as t,A as n,At as r,B as i,Bt as a,C as o,Ct as s,D as c,Dt as l,E as u,Et as d,F as f,Ft as p,G as m,Gt as ee,H as h,Ht as te,I as ne,It as re,J as ie,Jt as ae,K as g,Kt as oe,L as se,Lt as ce,M as le,Mt as ue,N as de,Nt as fe,O as pe,Ot as me,P as he,Pt as ge,Q as _e,Qt as ve,R as ye,Rt as be,S as xe,St as Se,T as Ce,Tt as we,U as Te,Ut as Ee,V as De,Vt as Oe,W as ke,Wt as Ae,X as je,Xt as Me,Y as Ne,Yt as Pe,Z as Fe,Zt as Ie,_ as Le,_n as _,_t as Re,a as ze,an as Be,at as Ve,b as He,bt as Ue,c as We,cn as Ge,ct as Ke,d as qe,dn as Je,dt as Ye,en as Xe,et as Ze,f as Qe,fn as $e,ft as et,g as tt,gn as nt,gt as rt,h as it,hn as at,ht as ot,i as st,in as ct,it as lt,j as ut,jt as dt,k as ft,kt as pt,l as mt,ln as ht,lt as gt,m as _t,mn as vt,mt as yt,nn as bt,nt as xt,on as St,ot as Ct,p as wt,pn as Tt,pt as Et,q as Dt,qt as Ot,r as kt,rn as At,rt as jt,sn as Mt,st as Nt,t as Pt,tn as Ft,tt as It,u as Lt,un as Rt,ut as zt,v as Bt,vn as Vt,vt as Ht,w as Ut,wt as Wt,x as Gt,xt as Kt,y as qt,yn as Jt,yt as Yt,z as Xt,zt as Zt}from"./dist-B8eKKp3B.js";import{constants as Qt,copyFileSync as $t,existsSync as v,mkdirSync as en,readFileSync as tn,readdirSync as nn,realpathSync as rn,renameSync as an,rmSync as on,statSync as sn,writeFileSync as cn}from"node:fs";import{homedir as ln}from"node:os";import{basename as un,dirname as y,isAbsolute as dn,join as b,posix as fn,relative as pn,resolve as mn,win32 as hn}from"node:path";import{randomUUID as gn}from"node:crypto";import{spawn as _n,spawnSync as vn}from"node:child_process";import{fileURLToPath as yn}from"node:url";import{isDeepStrictEqual as bn,stripVTControlCharacters as xn}from"node:util";import{lstat as Sn,mkdir as Cn,mkdtemp as wn,readFile as Tn,readdir as En,rename as Dn,rm as On,writeFile as kn}from"node:fs/promises";import{defineCommand as x,runCommand as An,runMain as jn}from"citty";import{cancel as Mn,confirm as Nn,intro as Pn,isCancel as Fn,log as In,multiselect as Ln,note as S,outro as Rn,password as zn,select as Bn,text as Vn}from"@clack/prompts";import Hn from"picocolors";import Un from"string-width";import Wn from"cli-table3";import{applyEdits as Gn,modify as Kn,parse as qn,printParseErrorCode as Jn}from"jsonc-parser";import Yn from"update-notifier";const C={summary:`workflow.site.generated_at.summary.attribution.confidence.classification.updates_matched.known_confounders.page_segment_status.page_segment_eligible_rows.page_segment_returned_rows.page_segment_limited_rows.page_segment_result_limit.page_segment_source_row_limit.page_segment_source_possibly_truncated.page_segment_warnings.query_segment_status.query_segment_eligible_rows.query_segment_returned_rows.query_segment_limited_rows.query_segment_result_limit.query_segment_source_row_limit.query_segment_source_possibly_truncated.query_segment_warnings.device_segment_status.device_segment_eligible_rows.device_segment_returned_rows.device_segment_limited_rows.device_segment_result_limit.device_segment_source_row_limit.device_segment_source_possibly_truncated.device_segment_warnings.country_segment_status.country_segment_eligible_rows.country_segment_returned_rows.country_segment_limited_rows.country_segment_result_limit.country_segment_source_row_limit.country_segment_source_possibly_truncated.country_segment_warnings`.split(`.`),steps:[`rank`,`tool`,`status`,`summary`],actions:[`rank`,`title`,`confidence`,`action`],findings:[`dimension`,`data_status`,`eligible_rows`,`returned_rows`,`limited_rows`,`result_limit`,`unmatched_rows`,`summary`,`winner_key`,`winner_click_delta`,`winner_impression_delta`,`winner_position_delta`,`loser_key`,`loser_click_delta`,`loser_impression_delta`,`loser_position_delta`],templates:[`rank`,`direction`,`template`,`confidence`,`url_count`,`click_delta`,`impression_delta`,`movement_share`,`movement_share_scope`,`confidence_scope`,`eligible_rows`,`returned_rows`,`limited_rows`,`result_limit`,`source_possibly_truncated`,`common_terms`,`sample_urls`,`summary`],evidence:[`rank`,`evidence`],confounders:[`rank`,`source`,`title`,`date`,`scope`,`target`,`description`],segment:[`rank`,`dimension`,`data_status`,`evidence_scope`,`key`,`before_clicks`,`after_clicks`,`click_delta`,`before_impressions`,`after_impressions`,`impression_delta`,`before_position`,`after_position`,`position_delta`],unmatchedSegment:[`rank`,`dimension`,`data_status`,`key`,`retained_in`,`clicks`,`impressions`,`position`,`reason`]};function Xn(e,t){return[...e.output.segments[t].winners,...e.output.segments[t].losers].map((n,r)=>({rank:r+1,dimension:t,data_status:e.output.segments[t].dataStatus,evidence_scope:n.evidenceScope,key:n.key,before_clicks:n.beforeClicks,after_clicks:n.afterClicks,click_delta:n.clickDelta,before_impressions:n.beforeImpressions,after_impressions:n.afterImpressions,impression_delta:n.impressionDelta,before_position:n.beforePosition,after_position:n.afterPosition,position_delta:n.positionDelta}))}function Zn(e,t){return e.output.segments[t].unmatchedSegments.map((n,r)=>({rank:r+1,dimension:t,data_status:e.output.segments[t].dataStatus,key:n.key,retained_in:n.retainedIn,clicks:n.clicks,impressions:n.impressions,position:n.position,reason:n.reason}))}function Qn(e){return[{filename:`postmortem-summary.csv`,headers:[...C.summary],rows:[{workflow:e.workflow,site:e.site,generated_at:e.generatedAt,summary:e.summary,attribution:e.output.update.attribution,confidence:e.output.update.confidence,classification:e.output.update.classification,updates_matched:e.output.update.overlappingUpdates.length,known_confounders:e.output.update.confounders.length,page_segment_status:e.output.segments.page.dataStatus,page_segment_eligible_rows:e.output.segments.page.coverage.eligibleRows,page_segment_returned_rows:e.output.segments.page.coverage.returnedRows,page_segment_limited_rows:e.output.segments.page.coverage.limitedRows,page_segment_result_limit:e.output.segments.page.coverage.resultLimit,page_segment_source_row_limit:e.output.segments.page.coverage.sourceRowLimit,page_segment_source_possibly_truncated:e.output.segments.page.coverage.sourcePossiblyTruncated,page_segment_warnings:e.output.segments.page.warnings.join(`; `),query_segment_status:e.output.segments.query.dataStatus,query_segment_eligible_rows:e.output.segments.query.coverage.eligibleRows,query_segment_returned_rows:e.output.segments.query.coverage.returnedRows,query_segment_limited_rows:e.output.segments.query.coverage.limitedRows,query_segment_result_limit:e.output.segments.query.coverage.resultLimit,query_segment_source_row_limit:e.output.segments.query.coverage.sourceRowLimit,query_segment_source_possibly_truncated:e.output.segments.query.coverage.sourcePossiblyTruncated,query_segment_warnings:e.output.segments.query.warnings.join(`; `),device_segment_status:e.output.segments.device.dataStatus,device_segment_eligible_rows:e.output.segments.device.coverage.eligibleRows,device_segment_returned_rows:e.output.segments.device.coverage.returnedRows,device_segment_limited_rows:e.output.segments.device.coverage.limitedRows,device_segment_result_limit:e.output.segments.device.coverage.resultLimit,device_segment_source_row_limit:e.output.segments.device.coverage.sourceRowLimit,device_segment_source_possibly_truncated:e.output.segments.device.coverage.sourcePossiblyTruncated,device_segment_warnings:e.output.segments.device.warnings.join(`; `),country_segment_status:e.output.segments.country.dataStatus,country_segment_eligible_rows:e.output.segments.country.coverage.eligibleRows,country_segment_returned_rows:e.output.segments.country.coverage.returnedRows,country_segment_limited_rows:e.output.segments.country.coverage.limitedRows,country_segment_result_limit:e.output.segments.country.coverage.resultLimit,country_segment_source_row_limit:e.output.segments.country.coverage.sourceRowLimit,country_segment_source_possibly_truncated:e.output.segments.country.coverage.sourcePossiblyTruncated,country_segment_warnings:e.output.segments.country.warnings.join(`; `)}]},{filename:`workflow-steps.csv`,headers:[...C.steps],rows:e.steps.map((e,t)=>({rank:t+1,tool:e.tool,status:e.status,summary:e.summary}))},{filename:`workflow-actions.csv`,headers:[...C.actions],rows:e.actions.map((e,t)=>({rank:t+1,title:e.title,confidence:e.confidence,action:e.action}))},{filename:`postmortem-findings.csv`,headers:[...C.findings],rows:e.output.insights.map(e=>({dimension:e.dimension,data_status:e.dataStatus,eligible_rows:e.coverage.eligibleRows,returned_rows:e.coverage.returnedRows,limited_rows:e.coverage.limitedRows,result_limit:e.coverage.resultLimit,unmatched_rows:e.unmatchedRows,summary:e.summary,winner_key:e.winner?.key,winner_click_delta:e.winner?.clickDelta,winner_impression_delta:e.winner?.impressionDelta,winner_position_delta:e.winner?.positionDelta,loser_key:e.loser?.key,loser_click_delta:e.loser?.clickDelta,loser_impression_delta:e.loser?.impressionDelta,loser_position_delta:e.loser?.positionDelta}))},{filename:`postmortem-template-movement.csv`,headers:[...C.templates],rows:e.output.templateMovement.map((e,t)=>({rank:t+1,direction:e.direction,template:e.signature,confidence:e.confidence,url_count:e.urlCount,click_delta:e.clickDelta,impression_delta:e.impressionDelta,movement_share:e.movementShare,movement_share_scope:e.movementShareScope,confidence_scope:e.confidenceScope,eligible_rows:e.segmentCoverage.eligibleRows,returned_rows:e.segmentCoverage.returnedRows,limited_rows:e.segmentCoverage.limitedRows,result_limit:e.segmentCoverage.resultLimit,source_possibly_truncated:e.segmentCoverage.sourcePossiblyTruncated,common_terms:e.commonTerms.join(`; `),sample_urls:e.sampleUrls.join(`; `),summary:e.summary}))},{filename:`postmortem-update-evidence.csv`,headers:[...C.evidence],rows:e.output.update.evidence.map((e,t)=>({rank:t+1,evidence:e}))},{filename:`postmortem-confounders.csv`,headers:[...C.confounders],rows:e.output.update.confounders.map((e,t)=>({rank:t+1,source:e.source,title:e.title,date:e.date,scope:e.scope,target:e.target,description:e.description}))},...[`page`,`query`,`device`,`country`].map(t=>({filename:`postmortem-segment-${t}.csv`,headers:[...C.segment],rows:Xn(e,t)})),...[`page`,`query`,`device`,`country`].map(t=>({filename:`postmortem-segment-${t}-unmatched.csv`,headers:[...C.unmatchedSegment],rows:Zn(e,t)}))]}function $n(e){try{let t=new URL(e);return t.protocol!==`http:`&&t.protocol!==`https:`?void 0:t.hostname.toLowerCase().replace(/\.$/,``)||void 0}catch{return}}function er(e){if(!e.startsWith(`sc-domain:`))return;let t=e.slice(10).trim().toLowerCase();if(!(!t||/[/:]/.test(t)))return t.replace(/\.$/,``)||void 0}function tr(e,t){let n=er(e);return n?t===n||t.endsWith(`.${n}`)?`domain`:void 0:$n(e)===t?`hostname`:void 0}function nr(e,t){return t.flatMap(t=>{let n=t.stream.webStreamData?.defaultUri;if(!n)return[];let r=$n(n);if(!r)return[];let i=tr(e,r);return i?[{...t,defaultUri:n,hostname:r,match:i}]:[]})}function rr(e,t){let n=e.stream.displayName??e.defaultUri,r=e.match===`domain`?`is inside`:`matches`;return`Matched Google Analytics web stream ${n} (${e.defaultUri}): its hostname ${r} ${t}.`}function ir(e){let t=e-Date.now();if(t<=0)return`expired`;let n=Math.round(t/6e4);if(n<60)return`in ${n}m`;let r=Math.floor(n/60),i=n%60;return i?`in ${r}h ${i}m`:`in ${r}h`}function w(e,t){return{type:`boolean`,default:!0,description:e,negativeDescription:t}}function T(e){return typeof e==`string`?e:void 0}function E(e){let t=T(e.project),n=T(e.client);if(t&&n&&t!==n)throw Error(`Use either --project or --client, not both.`);return t??n}function D(e){return typeof e==`boolean`?e:void 0}function ar(e){let t=T(e.rendering);if(t!==void 0&&t!==`auto`&&t!==`on`&&t!==`off`)throw new _(`INVALID_INPUT`,`--rendering must be auto, on, or off.`);if(D(e.js)===!0&&t&&t!==`on`)throw new _(`INVALID_INPUT`,`Use either --js or --rendering on, not both with different modes.`);return t??(D(e.js)?`on`:`auto`)}function or(e,t){let n=D(e[t]);if(n===!1)return!0;if(n===!0)return!1;let r=D(e[sr(t)]);if(r===!1)return!0;if(r===!0)return!1;if(D(e[`no-${t}`])===!0||D(e[`no${cr(t)}`])===!0)return!0}function sr(e){return e.replace(/-([a-z])/g,(e,t)=>t.toUpperCase())}function cr(e){let t=sr(e);return t?`${t[0]?.toUpperCase()}${t.slice(1)}`:``}function O(e){if(typeof e==`number`)return e;if(typeof e!=`string`||!e.trim())return;let t=Number(e);return Number.isFinite(t)?t:void 0}function k(e,t){if(e===void 0||e===``)return;let n=O(e);if(n===void 0)throw new _(`INVALID_INPUT`,`${t} must be a number.`);return n}function A(e){if(typeof e!=`string`)return;let t=e.split(`,`).map(e=>e.trim()).filter(Boolean);return t.length?t:void 0}function j(e){return A(e)??[]}function lr(e){let t={concurrency:O(e[`fetch-concurrency`]),intervalCap:O(e[`fetch-interval-cap`]),intervalMs:O(e[`fetch-interval-ms`])};return Object.values(t).some(e=>e!==void 0)?t:void 0}function ur(e){let t={concurrency:k(e[`fetch-concurrency`],`--fetch-concurrency`),intervalCap:k(e[`fetch-interval-cap`],`--fetch-interval-cap`),intervalMs:k(e[`fetch-interval-ms`],`--fetch-interval-ms`)};return Object.values(t).some(e=>e!==void 0)?t:void 0}function M(e){return e.json===!0}async function dr(e,t){let n=T(e),r=T(t);if(n&&r)throw Error(`Use either --body or --body-file, not both.`);if(!n&&!r)return;let i=n??await Tn(r??``,`utf8`),a=JSON.parse(i);if(!a||typeof a!=`object`||Array.isArray(a))throw Error(`JSON body must be an object.`);return a}function fr(e){if(typeof e==`number`)return Number.isFinite(e)?Math.round(e):void 0;if(!e)return;let t=Number.parseInt(e,10);return Number.isFinite(t)?t:void 0}function pr(e={}){let t=e.env??process.env,n=fr(e.columns)??fr(e.streamColumns)??fr(t.COLUMNS)??80;return Math.min(200,Math.max(40,n))}function N(e={}){let t=e.env??process.env,n=e.isTTY??!!process.stdout.isTTY,r=e.color??!!(n&&t.NO_COLOR===void 0);return{columns:pr({...e,env:t,streamColumns:e.streamColumns??process.stdout.columns}),colors:Hn.createColors(r),hasColor:r,isInteractive:n&&!t.CI}}function P(e){return Un(xn(e))}function mr(e,t){let n=[],r=``;for(let i of e)r&&P(`${r}${i}`)>t?(n.push(r),r=i):r+=i;return r&&n.push(r),n}function hr(e,t){if(!e)return[``];let n=e.trim().split(/\s+/u),r=[],i=``;for(let e of n){let n=P(e)>t?mr(e,t):[e];for(let e of n)i?P(`${i} ${e}`)<=t?i+=` ${e}`:(r.push(i),i=e):i=e}return i&&r.push(i),r.length>0?r:[``]}function F(e,t){let n=Math.max(1,t);return e.replaceAll(`\r
|
|
4
4
|
`,`
|
|
5
5
|
`).split(`
|
|
6
6
|
`).flatMap(e=>hr(e,n))}function gr(e,t){if(P(e)<=t)return e;let n=Math.max(1,t-P(`...`)),r=``;for(let t of e){if(P(`${r}${t}`)>n)break;r+=t}return`${r}...`}const _r={top:``,"top-mid":``,"top-left":``,"top-right":``,bottom:``,"bottom-mid":``,"bottom-left":``,"bottom-right":``,left:``,"left-mid":``,mid:``,"mid-mid":``,right:``,"right-mid":``,middle:``};function vr(e){return e===void 0?``:String(e)}function yr(e,t){return e.map((e,n)=>{let r=t.map(e=>vr(e[n]));return Math.min(42,Math.max(P(e),...r.map(P),4))})}function br(e,t,n){return e.length===0||e.length>4?!1:yr(e,t).reduce((e,t)=>e+t+2,0)<=n.columns}function xr(e,t,n){let r=yr(e,t).map(e=>e+2),i=new Wn({chars:_r,colWidths:r,head:e.map(e=>n.colors.bold(e)),style:{border:[],head:[],"padding-left":0,"padding-right":2},wordWrap:!1});for(let n of t)i.push(e.map((e,t)=>F(vr(n[t]),Math.max(1,(r[t]??3)-2)).join(`
|
|
@@ -69,7 +69,7 @@ Control comparison
|
|
|
69
69
|
`),R([[`Control`,e.control.change.title],[`Adjusted clicks`,e.control.adjusted.clickDelta===null?`n/a`:U(e.control.adjusted.clickDelta)],[`Adjusted click %`,e.control.adjusted.clickPctPoints===null?`n/a`:`${e.control.adjusted.clickPctPoints.toFixed(1)} pts`],[`Note`,e.control.note]])),Y(`Warnings`,e.warnings),Y(`Caveats`,e.caveats)}const ro=x({meta:{name:`tests`,description:`Create and report local SEO tests from Search Console and Google Analytics data`},subCommands:{list:x({meta:{name:`list`,description:`List saved SEO tests`},args:{site:{type:`string`,description:`GSC property URL.`},client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name.`},limit:{type:`string`,description:`Maximum tests to list. Defaults to 20.`},json:{type:`boolean`,default:!1,description:`Print machine-readable JSON.`}},run:async({args:e})=>{let t=M(e),n=E(e),r=It({site:(n||T(e.site)?await H({client:n,site:T(e.site),options:{json:t}}):void 0)?.site,limit:O(e.limit)});if(t){L({tests:r});return}z([`ID`,`Date`,`Scope`,`Target`,`Title`],r.map(e=>[e.id,e.changedAt,e.scope,e.target,e.title]))}}),create:x({meta:{name:`create`,description:`Create a local SEO test`},args:{site:{type:`string`,description:`GSC property URL.`},client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name.`},scope:{type:`string`,default:`page`,description:`Change scope: site, page, query, or group.`},target:{type:`string`,required:!0,description:`Changed URL, query, group pattern, or site marker.`},title:{type:`string`,required:!0,description:`Plain-English name for the test.`},description:{type:`string`,description:`Optional note about what changed.`},date:{type:`string`,description:`Change date in YYYY-MM-DD. Defaults to today.`},json:{type:`boolean`,default:!1,description:`Print machine-readable JSON.`}},run:async({args:e})=>{let t=M(e),n=await H({client:E(e),site:T(e.site),options:{json:t}}),r=xt({site:n.site,scope:Xa(e.scope),target:T(e.target)??``,title:T(e.title)??``,description:T(e.description),changedAt:T(e.date)??Ya()});if(t){L(r);return}R([[`ID`,r.id],[`Date`,r.changedAt],[`Project`,n.client?.name??n.site],[`Scope`,r.scope],[`Target`,r.target],[`Title`,r.title]])}}),report:x({meta:{name:`report`,description:`Report an SEO test with equal finalized before/after windows`},args:{id:{type:`string`,description:`Saved SEO test id.`},site:{type:`string`,description:`GSC property URL.`},client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name.`},scope:{type:`string`,description:`Ad-hoc change scope: site, page, query, or group.`},target:{type:`string`,description:`Ad-hoc changed URL, query, group pattern, or site marker.`},title:{type:`string`,description:`Ad-hoc test title.`},date:{type:`string`,description:`Ad-hoc change date in YYYY-MM-DD.`},property:{type:`string`,description:`Google Analytics property ID.`},"control-scope":{type:`string`,description:`Control scope: site, page, query, or group.`},"control-target":{type:`string`,description:`Control URL, query, group pattern, or site marker.`},"control-title":{type:`string`,description:`Plain-English name for the control group.`},before:{type:`string`,description:`Days before the change date. Defaults to 28.`},after:{type:`string`,description:`Days after the change date. Defaults to 28.`},refresh:{type:`boolean`,default:!1,description:`Bypass the local Search Console and Google Analytics cache.`},json:{type:`boolean`,default:!1,description:`Print machine-readable JSON.`}},run:async({args:e})=>{let t=M(e),n=T(e.id),r=!n||E(e)||T(e.site)?await H({client:E(e),site:T(e.site),options:{json:t,refresh:D(e.refresh)}}):void 0,i=await Dt({id:n,site:n?void 0:r?.site,scope:n?void 0:Za(e.scope),target:n?void 0:T(e.target),title:T(e.title),changedAt:n?void 0:T(e.date),googleAnalyticsPropertyId:T(e.property)??r?.client?.analytics.google?.propertyId,controlScope:Za(e[`control-scope`]),controlTarget:T(e[`control-target`]),controlTitle:T(e[`control-title`]),beforeDays:k(e.before,`--before`),afterDays:k(e.after,`--after`),refresh:D(e.refresh)});if(t){L(i);return}no(i)}})}});function io(e){if(!e)return;let t=Date.now();return e=>{let n=((Date.now()-t)/1e3).toFixed(1);process.stderr.write(`[seo ${n}s] ${e}\n`)}}const ao={site:{type:`string`,description:`GSC property URL, for example sc-domain:example.com.`},client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name.`}},oo={...X([`includeBrand`,`verifyContent`,`verifyLimit`,`js`,`fetchConcurrency`,`fetchIntervalCap`,`fetchIntervalMs`,`refresh`]),json:{type:`boolean`,default:!1,description:`Print machine-readable JSON.`}};function so(e){return{includeBrand:D(e[`include-brand`]),verifyContent:D(e[`verify-content`]),verifyLimit:O(e[`verify-limit`])??3,js:D(e.js)?!0:void 0,rate:lr(e),refresh:D(e.refresh)}}function co(e){return{client:E(e),site:T(e.site),refresh:D(e.refresh)}}const{json:lo,...uo}=oo,fo=uo,po={client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name. Defaults to the configured default.`},site:{type:`string`,description:`GSC property URL/id when not using a saved project.`}};function mo(e){return{type:`string`,description:`Output folder. Defaults to ./seo-export/<project>-${e}-YYYY-MM-DD.`}}function ho(e){return e.toLowerCase().replace(/^sc-domain:/,``).replace(/^https?:\/\//,``).replace(/[^a-z0-9._-]+/g,`-`).replace(/^-+|-+$/g,``)}function go(e){let t=new Date().toISOString().slice(0,10),n=ho(e.clientId??e.site);return mn(process.cwd(),`seo-export`,`${n}-${e.report}-${t}`)}async function _o(e,t){await Cn(e,{recursive:!0});let n=[];for(let r of t){let t=mn(e,r.filename);await kn(t,l(r.rows,r.headers),`utf8`),n.push(t)}return n}function vo(e,t){process.stdout.write(`Wrote ${gt(t.length,`CSV file`)} to ${e}\n`);for(let e of t)process.stdout.write(`- ${e}\n`)}const yo=x({meta:{name:`diagnose`,description:`Export diagnosis tables: priorities, anomalies, movement, decay, cannibalisation, striking-distance, and quick wins.`},args:{...po,out:mo(`diagnose`),days:{type:`string`,description:`GSC lookback window. Defaults to 90.`},recent:{type:`string`,description:`Recent anomaly window in days.`},limit:{type:`string`,description:`Maximum rows per movement/opportunity table.`},"include-brand":{type:`boolean`,default:!1,description:`Include branded queries in opportunity reports.`},"verify-content":{type:`boolean`,default:!1,description:`Verify top opportunities against page title, meta, and content.`},"verify-limit":{type:`string`,description:`Maximum opportunity URLs to verify.`},js:{type:`boolean`,default:!1,description:`Force JavaScript rendering for verified pages.`},"fetch-concurrency":{type:`string`,description:`Maximum concurrent page fetches per host. Defaults to 4.`},"fetch-interval-cap":{type:`string`,description:`Maximum page fetches per interval per host. Defaults to 4.`},"fetch-interval-ms":{type:`string`,description:`Fetch rate interval in milliseconds. Defaults to 1000.`},refresh:{type:`boolean`,default:!1,description:`Bypass local cache and fetch fresh data.`}},run:async({args:e})=>{let t=await H({client:E(e),site:T(e.site)}),n=await Fe({site:t.site,days:O(e.days),recentDays:O(e.recent),limit:O(e.limit),brandTerms:t.client?.brandTerms,includeBrand:D(e[`include-brand`]),verifyContent:D(e[`verify-content`]),verifyLimit:O(e[`verify-limit`]),js:D(e.js)?!0:`auto`,rate:lr(e),refresh:D(e.refresh),progress:io(!0)}),r=T(e.out)??go({report:`diagnose`,clientId:t.client?.id,site:t.site});vo(r,await _o(r,s(n)))}}),bo=`.seo-okf.json`,xo=`${JSON.stringify({generator:`seo`,format:`okf`,version:1})}\n`;function So(e,t){let n=mn(e,t),r=pn(mn(e),n);if(!r||r.startsWith(`..`)||dn(r))throw new _(`INVALID_INPUT`,`Unsafe OKF file path: ${t}`);return n}async function Co(e,t){for(let n of t){let t=So(e,n.path);await Cn(y(t),{recursive:!0}),await kn(t,n.content)}await kn(b(e,bo),xo)}async function wo(e){let t=[];async function n(e,r=``){let i=await En(e,{withFileTypes:!0});for(let a of i){let i=r?`${r}/${a.name}`:a.name,o=b(e,a.name);a.isDirectory()?await n(o,i):a.isFile()&&a.name.endsWith(`.md`)&&t.push({path:i,content:await Tn(o,`utf8`)})}}return await n(e),t.sort((e,t)=>e.path<t.path?-1:+(e.path>t.path))}async function To(e){try{let t=await Sn(e);if(t.isSymbolicLink()||!t.isDirectory())throw new _(`INVALID_INPUT`,`OKF output must be a real directory: ${e}`);if(!(await En(e)).length)return!0;try{if(await Tn(b(e,bo),`utf8`)===xo)return!0}catch{}throw new _(`INVALID_INPUT`,`Refusing to replace non-empty unmanaged directory: ${e}`)}catch(e){if(e.code===`ENOENT`)return!1;throw e}}async function Eo(e,t){if(!yt(t).valid)throw new _(`INVALID_INPUT`,`Generated bundle did not pass seo OKF checks and was not written.`);let n=mn(e),r=y(n);await Cn(r,{recursive:!0});let i=await To(n),a=await wn(b(r,`.${un(n)}-staging-`)),o=b(r,`.${un(n)}-backup-${gn()}`),s=!1;try{await Co(a,t);let e=yt(await wo(a));if(!e.valid)throw new _(`INTERNAL_ERROR`,`Staged OKF files failed validation after writing.`);return i&&(await Dn(n,o),s=!0),await Dn(a,n),s&&await On(o,{recursive:!0,force:!0}),e}catch(e){throw await On(a,{recursive:!0,force:!0}),s&&(await On(n,{recursive:!0,force:!0}),await Dn(o,n)),e}}async function Do(e,t){if(!e){process.stdout.write(t);return}await Cn(y(e),{recursive:!0}),await kn(e,t),process.stdout.write(`Wrote ${e}\n`)}function Oo(e){let t=T(e)??`okf`;if([`okf`,`markdown`,`json`].includes(t))return t;throw Error(`Format must be one of: okf, markdown, json.`)}function ko(e){return{reportId:e.id,url:e.config.url,generatedAt:e.generatedAt,crawl:{summary:e.summary,caveats:e.caveats,warnings:e.warnings,pages:e.pages.map(e=>({url:e.finalUrl,title:e.title,metaDescription:e.metaDescription,status:e.status,indexable:e.indexable,wordCount:e.wordCount,schemaTypes:e.schemaTypes,sameAs:e.schemaSameAs,internalInlinks:e.internalInlinkCount,contentSample:e.contentSample}))},aiReadiness:Zt(e),entityReadiness:a(e),llmsTxt:ce(e)}}function Ao(e){let t=ko(e);return`${[`# Site Knowledge Export`,``,`Source: ${e.config.url}`,`Crawl report: ${e.id}`,`Generated: ${t.generatedAt}`,``,`## Summary`,``,`- Documents: ${e.summary.totalPages}${e.requestEvidenceStatus===`available`?` from ${e.requests.length} URL requests`:e.requestEvidenceStatus===`partial`?` from ${e.requests.length} observed URL requests (request evidence is partial)`:` (request evidence unavailable for this legacy report)`}`,`- Indexable pages: ${e.summary.indexablePages}`,`- Crawl findings: ${e.issues.length} (${e.summary.highIssues} high, ${e.summary.mediumIssues} medium, ${e.summary.lowIssues} low)`,`- AI-search evidence: ${t.aiReadiness.dataStatus} (${t.aiReadiness.assessment})`,`- Entity evidence: ${t.entityReadiness.dataStatus} (${t.entityReadiness.assessment})`,``,`## Top AI Readiness Actions`,``,...t.aiReadiness.topActions.length?t.aiReadiness.topActions.map(e=>`- ${e.title}: ${e.action}`):[`- No AI-search technical actions in this crawl.`],``,`## Entity Signals`,``,`- sameAs profiles: ${t.entityReadiness.entities.sameAs.length}`,`- Social profiles: ${t.entityReadiness.entities.socialProfiles.length}`,`- Authors: ${t.entityReadiness.entities.authors.length}`,``,`## Important Pages`,``,...e.pages.filter(e=>e.indexable&&e.status<400).slice(0,100).map(e=>`- [${e.title??e.finalUrl}](${e.finalUrl}) - ${e.metaDescription??e.contentSample??`No summary available.`}`),``,`# Citations`,``,`- [Crawl start URL](${e.config.url})`,``].join(`
|
|
70
70
|
`)}\n`}const jo=x({meta:{name:`knowledge`,description:`Export site knowledge from a saved crawl as OKF, Markdown, or JSON`},args:{"report-id":{type:`string`,description:`Saved crawl report id to export.`},site:{type:`string`,description:`GSC property URL for selecting the latest saved crawl.`},client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name.`},format:{type:`string`,description:`Output format: okf, markdown, or json. Defaults to okf.`},output:{type:`string`,description:`Output directory for OKF, or output file for Markdown/JSON.`},"max-concepts":{type:`string`,description:`Maximum OKF concept files. Defaults to 500.`},json:{type:`boolean`,default:!1,description:`Print command metadata as JSON.`}},run:async({args:e})=>{let t=M(e),n=Oo(e.format),r=n===`okf`?Et(k(e[`max-concepts`],`--max-concepts`)):void 0,i=await ei(e,{json:t}),a=T(e.output);if(n===`okf`){let e=Ye(i,{maxConcepts:r}),o=a??`./okf`,s=await Eo(o,e.files);if(t){L({format:n,output:o,bundle:e,validation:s});return}process.stdout.write(`Wrote OKF bundle to ${o}\n\n`),R([[`Files`,String(e.files.length)],[`Concepts`,String(e.conceptCount)],[`Valid`,s.valid?`yes`:`no`]]);return}if(n===`json`){await Do(a,`${JSON.stringify(ko(i),null,2)}\n`);return}await Do(a,Ao(i))}}),Mo=x({meta:{name:`monthly`,description:`Export monthly report tables plus the underlying diagnosis detail CSVs.`},args:{...po,out:mo(`monthly`),month:{type:`string`,description:`Report month as YYYY-MM. Defaults to the latest month with final GSC data.`},...X([`limit`],{limit:{description:`Maximum rows per diagnostic section. Defaults to 10.`}}),...fo},run:async({args:e})=>{let t=await H({client:E(e),site:T(e.site),options:{refresh:D(e.refresh)}}),n=await le({site:t.site,month:T(e.month),limit:O(e.limit),brandTerms:t.client?.brandTerms,...so(e),progress:io(!0)}),r=T(e.out)??go({report:`monthly`,clientId:t.client?.id,site:t.site});vo(r,await _o(r,Wt(n)))}}),No=x({meta:{name:`narrative`,description:`Export report narrative tables plus the underlying diagnosis detail CSVs.`},args:{...po,out:mo(`narrative`),...X([`days`,`recentDays`],{days:{description:`Diagnosis window length in days. Defaults to 90.`}}),"start-date":{type:`string`,description:`Optional report start date as YYYY-MM-DD.`},"end-date":{type:`string`,description:`Optional report end date as YYYY-MM-DD.`},...X([`limit`],{limit:{description:`Maximum rows per diagnostic section. Defaults to 10.`}}),"change-limit":{type:`string`,description:`Maximum saved changes to measure. Defaults to 5.`},...fo},run:async({args:e})=>{let t=await H({client:E(e),site:T(e.site),options:{refresh:D(e.refresh)}}),n=await de({site:t.site,days:O(e.days),recentDays:O(e.recent),startDate:T(e[`start-date`]),endDate:T(e[`end-date`]),limit:O(e.limit),changeLimit:O(e[`change-limit`]),brandTerms:t.client?.brandTerms,...so(e),progress:io(!0)}),r=T(e.out)??go({report:`narrative`,clientId:t.client?.id,site:t.site});vo(r,await _o(r,Wt(n)))}});function Po(e){return f({days:k(e.days,`--days`),sitemaps:A(e.sitemap),maxSitemapUrls:k(e[`max-sitemap-urls`],`--max-sitemap-urls`),templateLimit:k(e.limit,`--limit`),minimumTemplateUrls:k(e[`minimum-template-urls`],`--minimum-template-urls`),minimumTemplateShare:k(e[`minimum-template-share`],`--minimum-template-share`),minimumTemplateImpressions:k(e[`minimum-template-impressions`],`--minimum-template-impressions`),crawlSamples:k(e[`crawl-samples`],`--crawl-samples`),inspectSamples:k(e[`inspect-samples`],`--inspect-samples`),brandTerms:A(e[`brand-terms`]),includeBrand:D(e[`include-brand`]),js:D(e.js)?!0:`auto`,refresh:D(e.refresh),rate:ur(e)})}const Fo=x({meta:{name:`pseo`,description:`Export pSEO audit tables: templates, demand patterns, top queries, sample coverage, crawl samples, and inspection samples.`},args:{...po,out:mo(`pseo`),days:{type:`string`,description:`GSC lookback window. Defaults to 28.`},limit:{type:`string`,description:`Maximum pSEO templates to export.`},sitemap:{type:`string`,description:`Comma-separated sitemap URLs. Can be passed once.`},"crawl-samples":{type:`string`,description:`Number of representative URLs to fetch per template. Defaults to 0.`},"inspect-samples":{type:`string`,description:`Number of representative URLs to inspect in GSC per template. Defaults to 0.`},"max-sitemap-urls":{type:`string`,description:`Maximum discovered URLs per sitemap. Defaults to 50000.`},"minimum-template-urls":{type:`string`,description:`Minimum repeated URLs required for a template. Defaults to 3.`},"minimum-template-share":{type:`string`,description:`Minimum share of discovered URLs from 0 to 1. Defaults to 0.`},"minimum-template-impressions":{type:`string`,description:`Minimum retained page impressions for a template. Defaults to 0.`},"brand-terms":{type:`string`,description:`Comma-separated brand terms to exclude from query evidence.`},"include-brand":{type:`boolean`,default:!1,description:`Include branded queries in pSEO demand analysis.`},js:{type:`boolean`,default:!1,description:`Force JavaScript rendering for crawled samples.`},"fetch-concurrency":{type:`string`,description:`Maximum concurrent page fetches per host. Defaults to 4.`},"fetch-interval-cap":{type:`string`,description:`Maximum page fetches per interval per host. Defaults to 4.`},"fetch-interval-ms":{type:`string`,description:`Fetch rate interval in milliseconds. Defaults to 1000.`},refresh:{type:`boolean`,default:!1,description:`Bypass local cache and fetch fresh data.`}},run:async({args:e})=>{let t=Po(e),n=await H({client:E(e),site:T(e.site)}),r=await ne({site:n.site,...t,brandTerms:t.brandTerms??n.client?.brandTerms,progress:io(!0)}),i=T(e.out)??go({report:`pseo`,clientId:n.client?.id,site:n.site});vo(i,await _o(i,we(r)))}}),Io=x({meta:{name:`refresh-priorities`,description:`Export the ranked SEO priority queue, score breakdowns, grouped findings, and diagnosis detail CSVs.`},args:{...po,out:mo(`refresh-priorities`),...X([`days`,`recentDays`,`limit`,`includeBrand`,`refresh`],{days:{description:`Diagnosis window length in days. Defaults to 90.`},limit:{description:`Maximum queue items to export. Defaults to 25.`}}),"google-analytics-property":{type:`string`,description:`Google Analytics property ID to use for analytics value. Defaults from the selected project.`},"verify-content":w(`Verify top opportunities against page title, meta, and content. Defaults to true.`,`Skip page content verification.`),"verify-limit":{type:`string`,description:`Maximum opportunity URLs to verify. Defaults to 5.`}},run:async({args:e})=>{let t=await H({client:E(e),site:T(e.site),options:{refresh:D(e.refresh)}}),n=await c({site:t.site,days:O(e.days),recentDays:O(e.recent),limit:O(e.limit),brandTerms:t.client?.brandTerms,includeBrand:D(e[`include-brand`]),googleAnalyticsPropertyId:T(e[`google-analytics-property`])??t.client?.analytics.google?.propertyId,verifyContent:D(e[`verify-content`]),verifyLimit:O(e[`verify-limit`]),refresh:D(e.refresh)}),r=T(e.out)??go({report:`refresh-priorities`,clientId:t.client?.id,site:t.site});vo(r,await _o(r,d(n)))}}),Lo=x({meta:{name:`export`,description:`Export full report data to CSV files`},subCommands:{diagnose:yo,knowledge:jo,narrative:No,monthly:Mo,"update-postmortem":x({meta:{name:`update-postmortem`,description:`Export update postmortem attribution, findings, template movement, and segment movers.`},args:{...po,out:mo(`update-postmortem`),...X([`days`,`recentDays`,`limit`,`includeBrand`,`refresh`],{days:{description:`Diagnosis window length in days. Defaults to 90.`},limit:{description:`Maximum winners/losers per segment. Defaults to 20.`}}),"known-change":{type:`string`,description:`Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.`},"ignore-change-log":{type:`boolean`,default:!1,description:`Do not use saved change-log entries as confounders.`}},run:async({args:e})=>{let t=await H({client:E(e),site:T(e.site),options:{refresh:D(e.refresh)}}),n=await Ce({site:t.site,days:O(e.days),recentDays:O(e.recent),limit:O(e.limit),brandTerms:t.client?.brandTerms,includeBrand:D(e[`include-brand`]),knownConfounders:T(e[`known-change`])?[T(e[`known-change`])??``]:void 0,includeChangeLog:!D(e[`ignore-change-log`]),refresh:D(e.refresh)}),r=T(e.out)??go({report:`update-postmortem`,clientId:t.client?.id,site:t.site});vo(r,await _o(r,Qn(n)))}}),"refresh-priorities":Io,pseo:Fo}}),Ro=x({...oa,meta:{name:`init`,description:"Legacy alias for `seo start`."}});async function zo(e,t){if(!e){process.stdout.write(t);return}await Cn(y(e),{recursive:!0}),await kn(e,t),process.stdout.write(`Wrote ${e}\n`)}const Bo={"report-id":{type:`string`,description:`Saved crawl report id to use.`},site:{type:`string`,description:`GSC property URL for selecting the latest saved crawl.`},client:{type:`string`,description:`Legacy alias for --project.`},project:{type:`string`,description:`Saved project id or name.`},json:{type:`boolean`,default:!1,description:`Print machine-readable JSON.`}},Vo=x({meta:{name:`llms`,description:`Inspect or generate optional llms.txt from saved crawl data`},subCommands:{audit:x({meta:{name:`audit`,description:`Inspect optional llms.txt presence from a saved crawl`},args:Bo,run:async({args:e})=>{let t=M(e),n=ce(await ei(e,{json:t}));if(t){L(n);return}process.stdout.write(`llms.txt audit for ${n.url}\n\n`),R([[`SEO impact`,n.googleSearchImpact],[`Optional`,n.optional?`yes`:`no`],[`Found`,n.exists?`yes`:`no`],[`URL`,n.llmsTxtUrl],[`Status`,n.status?String(n.status):`-`]]),process.stdout.write(`\n${n.headline}\n`),n.issues.length&&(process.stdout.write(`
|
|
71
71
|
Issues
|
|
72
|
-
`),z([`Severity`,`Issue`,`Action`],n.issues.map(e=>[e.severity,e.title,K(e.action,96)]))),Y(`Recommended pages`,n.recommendedPages.slice(0,10).map(e=>`${e.section}: ${e.url}`))}}),generate:x({meta:{name:`generate`,description:`Generate an llms.txt draft from a saved crawl`},args:{...Bo,output:{type:`string`,description:`Write llms.txt to this path instead of stdout.`},"max-urls":{type:`string`,description:`Maximum URLs to include. Defaults to 250.`},"token-budget":{type:`string`,description:`Approximate token budget. Defaults to 12000.`},exclude:{type:`string`,description:`Comma-separated URL patterns to exclude.`},title:{type:`string`,description:`Override the llms.txt title.`},description:{type:`string`,description:`Override the llms.txt description.`}},run:async({args:e})=>{let t=M(e),n=be(await ei(e,{json:t}),{maxUrls:O(e[`max-urls`]),tokenBudget:O(e[`token-budget`]),exclude:A(e.exclude),title:T(e.title),description:T(e.description)});if(t){L(n);return}await zo(T(e.output),n.content),T(e.output)&&R([[`URLs`,String(n.includedUrls)],[`Estimated tokens`,String(n.estimatedTokens)]])}})}}),Ho=[{client:`claude-desktop`,flag:`claude-desktop`},{client:`claude-code`,flag:`claude-code`},{client:`codex`,flag:`codex`},{client:`cursor`,flag:`cursor`}];function Uo(e,t){return D(e.all)?t:Ho.filter(({flag:t})=>D(e[t])).map(({client:e})=>e)}const Wo=x({meta:{name:`mcp`,description:`MCP server helpers`},subCommands:{serve:x({meta:{name:`serve`,description:`Run the SEO MCP server`},args:{test:{type:`boolean`,default:!1,description:`Start in test mode`}},run:async({args:e})=>{let{startMcpServer:t}=await import(`./dist-
|
|
72
|
+
`),z([`Severity`,`Issue`,`Action`],n.issues.map(e=>[e.severity,e.title,K(e.action,96)]))),Y(`Recommended pages`,n.recommendedPages.slice(0,10).map(e=>`${e.section}: ${e.url}`))}}),generate:x({meta:{name:`generate`,description:`Generate an llms.txt draft from a saved crawl`},args:{...Bo,output:{type:`string`,description:`Write llms.txt to this path instead of stdout.`},"max-urls":{type:`string`,description:`Maximum URLs to include. Defaults to 250.`},"token-budget":{type:`string`,description:`Approximate token budget. Defaults to 12000.`},exclude:{type:`string`,description:`Comma-separated URL patterns to exclude.`},title:{type:`string`,description:`Override the llms.txt title.`},description:{type:`string`,description:`Override the llms.txt description.`}},run:async({args:e})=>{let t=M(e),n=be(await ei(e,{json:t}),{maxUrls:O(e[`max-urls`]),tokenBudget:O(e[`token-budget`]),exclude:A(e.exclude),title:T(e.title),description:T(e.description)});if(t){L(n);return}await zo(T(e.output),n.content),T(e.output)&&R([[`URLs`,String(n.includedUrls)],[`Estimated tokens`,String(n.estimatedTokens)]])}})}}),Ho=[{client:`claude-desktop`,flag:`claude-desktop`},{client:`claude-code`,flag:`claude-code`},{client:`codex`,flag:`codex`},{client:`cursor`,flag:`cursor`}];function Uo(e,t){return D(e.all)?t:Ho.filter(({flag:t})=>D(e[t])).map(({client:e})=>e)}const Wo=x({meta:{name:`mcp`,description:`MCP server helpers`},subCommands:{serve:x({meta:{name:`serve`,description:`Run the SEO MCP server`},args:{test:{type:`boolean`,default:!1,description:`Start in test mode`}},run:async({args:e})=>{let{startMcpServer:t}=await import(`./dist-DkWLBABR.js`);await t({test:D(e.test)})}}),install:x({meta:{name:`install`,description:`Install or remove SEO MCP config for local clients`},args:{uninstall:{type:`boolean`,default:!1,description:`Remove the SEO MCP config instead of adding it`},reinstall:{type:`boolean`,default:!1,description:`Rewrite an existing managed SEO MCP config`},"claude-desktop":{type:`boolean`,default:!1,description:`Update Claude Desktop`},"claude-code":{type:`boolean`,default:!1,description:`Update Claude Code`},codex:{type:`boolean`,default:!1,description:`Update Codex CLI, app, and IDE extension`},cursor:{type:`boolean`,default:!1,description:`Update Cursor`},all:{type:`boolean`,default:!1,description:`Update every detected MCP client`},json:{type:`boolean`,default:!1,description:`Print structured JSON output`}},run:async({args:e})=>{if(D(e.uninstall)&&D(e.reinstall))throw new _(`INVALID_INPUT`,`Use either --uninstall or --reinstall, not both.`);let t=Si(),n=Ti({targets:t}),r=M(e),i=Uo(e,n.map(e=>e.client));if(i.length===0){if(!I({json:r}))throw new _(`INVALID_INPUT`,`Choose an MCP client with --claude-desktop, --claude-code, --codex, --cursor, or --all.`);let a=n.length>0?n:t;i=B(await Ln({message:e.uninstall?`Remove seo from which MCP clients?`:`Install seo into which MCP clients?`,options:a.map(e=>({value:e.client,label:e.label,hint:e.path})),initialValues:n.map(e=>e.client),required:!0}))}let a=i.filter(e=>!t.some(t=>t.client===e));if(a.length>0)throw new _(`INVALID_INPUT`,`MCP setup is not supported for ${a.join(`, `)} on ${process.platform}.`);let o=t.filter(e=>i.includes(e.client)).map(t=>D(e.uninstall)?Wi(t):Ui(t,{reinstall:D(e.reinstall)}));if(r){L({operation:D(e.uninstall)?`uninstall`:`install`,results:o});return}for(let e of o)process.stdout.write(`${e.changed?`updated`:`skipped`} ${e.client} · ${e.path}\n`)}})}}),Go=x({meta:{name:`crawl-diff`,description:`Crawl a site and diff technical/page changes vs last run`},args:{url:{type:`string`,required:!0,description:`Start URL to crawl.`},site:{type:`string`,description:`Optional GSC property to associate with the crawl.`},limit:{type:`string`,description:`Maximum pages to crawl. Defaults to 50.`},json:{type:`boolean`,default:!1,description:`Print machine-readable JSON.`},refresh:{type:`boolean`,default:!1,description:`Bypass local HTTP cache.`},js:{type:`boolean`,default:!1,description:`Force JavaScript rendering when Playwright is installed.`}},run:async({args:e})=>{let t=await m({startUrl:T(e.url)??``,site:T(e.site),limit:O(e.limit),refresh:D(e.refresh),js:D(e.js)?!0:`auto`});if(M(e)){L(t);return}if(R([[`Run`,t.run.id],[`Start URL`,t.run.startUrl],[`Crawled`,String(t.summary.crawled)],[`Previous run`,t.previousRun?.id??`none`],[`Added`,String(t.summary.added)],[`Removed`,String(t.summary.removed)],[`Changed`,String(t.summary.changed)],[`New errors`,String(t.summary.newErrors)],[`Indexability flips`,String(t.summary.indexabilityFlips)],[`High-priority actions`,String(t.summary.highPriorityRecommendations)]]),t.recommendations.length&&(process.stdout.write(`
|
|
73
73
|
Recommended actions
|
|
74
74
|
`),z([`Severity`,`Category`,`URL`,`Action`],t.recommendations.slice(0,10).map(e=>[e.severity,e.category,K(e.url,56),K(e.action,72)])),J(`Top crawl actions`,t.recommendations.map(e=>({label:e.category,context:`${e.severity}, ${K(e.url,96)}`,action:e.action})))),t.items.length&&(process.stdout.write(`
|
|
75
75
|
Changed URLs
|