seo 0.3.0-beta.2 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":["compareText","normalizedPath","statusLabel","readConfig","credentialSourceLabel","connectCommand","statusCommand","reportCommand","disconnectCommand","readConfig","truncate","shellArg","truncate","quote","urlListArgs","crawlUrlArg","crawlModeArg","parseUrlList","truncate","formatNumber","today","changeScope","slug","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","doctorCommand","truncate","connectCommand","statusCommand","disconnectCommand","connectCommand","statusCommand","disconnectCommand","listCommand","describeCommand","installCommand","runCommand","listCommand","runCommand","truncate","truncate","doctorCommand"],"sources":["../packages/core/dist/export/report-html.js","../packages/core/dist/export/update-postmortem.js","../packages/core/dist/ga4/matching.js","../packages/core/dist/gsc/local-export.js","../packages/core/dist/gsc/local-export-reconcile.js","../packages/core/dist/utils/time.js","../packages/cli/src/args.ts","../packages/cli/src/presentation/context.ts","../packages/cli/src/presentation/render.ts","../packages/cli/src/presentation/report.ts","../packages/cli/src/presentation/views.ts","../packages/cli/src/utils.ts","../packages/cli/src/selection.ts","../packages/cli/src/commands/analytics/clicky/index.ts","../packages/cli/src/commands/analytics/google/properties.ts","../packages/cli/src/commands/output.ts","../packages/cli/src/commands/analytics/google/report.ts","../packages/cli/src/commands/analytics/google/index.ts","../packages/cli/src/commands/analytics/index.ts","../packages/cli/src/commands/google-login.ts","../packages/cli/src/commands/auth.ts","../packages/cli/src/commands/cache.ts","../packages/cli/src/commands/shared.ts","../packages/cli/src/commands/setup/project-target.ts","../packages/cli/src/commands/mcp-clients.ts","../packages/cli/src/commands/mcp-config.ts","../packages/cli/src/commands/skill-install.ts","../packages/cli/src/commands/setup/prompts.ts","../packages/cli/src/commands/setup/flow.ts","../packages/cli/src/commands/setup/index.ts","../packages/cli/src/commands/clients/brand.ts","../packages/cli/src/commands/clients/profiles/output.ts","../packages/cli/src/commands/clients/profiles/add.ts","../packages/cli/src/commands/clients/profiles/default.ts","../packages/cli/src/commands/clients/profiles/delete.ts","../packages/cli/src/commands/clients/profiles/list.ts","../packages/cli/src/commands/clients/profiles/show.ts","../packages/cli/src/commands/clients/profiles.ts","../packages/cli/src/commands/clients/index.ts","../packages/cli/src/commands/content.ts","../packages/cli/src/commands/core-commands.ts","../packages/cli/src/json-output.ts","../packages/cli/src/presentation/crawl-report.ts","../packages/cli/src/commands/analytics/connection.ts","../packages/cli/src/commands/crawl.ts","../packages/cli/src/commands/crawl-reports.ts","../packages/cli/src/commands/data.ts","../packages/cli/src/commands/report-options.ts","../packages/cli/src/commands/diagnosis-reports.ts","../packages/cli/src/commands/experiments/change-log.ts","../packages/cli/src/commands/experiments/content-groups.ts","../packages/cli/src/commands/experiments/tests.ts","../packages/cli/src/progress.ts","../packages/cli/src/commands/export/shared.ts","../packages/cli/src/commands/export/diagnose.ts","../packages/cli/src/commands/export/refresh-priorities.ts","../packages/cli/src/commands/export/update-postmortem.ts","../packages/cli/src/commands/export/index.ts","../packages/cli/src/commands/init.ts","../packages/cli/src/commands/logs.ts","../packages/cli/src/commands/mcp.ts","../packages/cli/src/commands/monitoring/crawl-diff.ts","../packages/cli/src/commands/monitoring/args.ts","../packages/cli/src/commands/workflows/output.ts","../packages/cli/src/commands/monitoring/output.ts","../packages/cli/src/commands/monitoring/index.ts","../packages/cli/src/commands/monitoring/index-coverage.ts","../packages/cli/src/commands/monitoring/index-watch.ts","../packages/cli/src/commands/monitoring/link-recover.ts","../packages/cli/src/commands/monitoring/redirect-trace.ts","../packages/cli/src/commands/opportunities/ai-referrals.ts","../packages/cli/src/commands/opportunities/cannibal.ts","../packages/cli/src/commands/opportunities/ctr.ts","../packages/cli/src/commands/opportunities/decaying.ts","../packages/cli/src/commands/opportunities/internal-links.ts","../packages/cli/src/commands/opportunities/page-opportunities.ts","../packages/cli/src/commands/opportunities/query-cluster.ts","../packages/cli/src/commands/opportunities/quick-wins.ts","../packages/cli/src/commands/opportunities/second-page.ts","../packages/cli/src/commands/page-audit.ts","../packages/cli/src/commands/performance.ts","../packages/cli/src/commands/product/diagnose.ts","../packages/cli/src/commands/product/doctor.ts","../packages/cli/src/commands/product/segment-impact.ts","../packages/cli/src/commands/product/striking-distance.ts","../packages/cli/src/commands/providers/shared.ts","../packages/cli/src/commands/providers/ahrefs.ts","../packages/cli/src/commands/providers/dataforseo.ts","../packages/cli/src/commands/providers/extensions.ts","../packages/cli/src/commands/providers/index.ts","../packages/cli/src/commands/report-catalog.ts","../packages/cli/src/commands/rules.ts","../packages/cli/src/commands/schedule.ts","../packages/cli/src/commands/skill-paths.ts","../packages/cli/src/commands/skills-eval.ts","../packages/cli/src/commands/skills.ts","../packages/cli/src/commands/system.ts","../packages/cli/src/commands/telemetry.ts","../packages/cli/src/commands/workflows/crawl-queue.ts","../packages/cli/src/commands/report-html.ts","../packages/cli/src/commands/workflows/main-report-json.ts","../packages/cli/src/commands/workflows/url-report-output.ts","../packages/cli/src/commands/workflows/url-report-evidence.ts","../packages/cli/src/commands/workflows/diagnose-property.ts","../packages/cli/src/commands/workflows/refresh-priorities.ts","../packages/cli/src/commands/workflows/technical-watch.ts","../packages/cli/src/commands/workflows/update-postmortem.ts","../packages/cli/src/error-feedback.ts","../packages/cli/src/renames.ts","../packages/cli/src/self-update.ts","../packages/cli/src/index.ts"],"sourcesContent":["function escapeHtml(value) {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;');\n}\nfunction safeHttpUrl(value) {\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? url.toString()\n : undefined;\n }\n catch {\n return undefined;\n }\n}\nfunction siteMarkup(site) {\n const safeUrl = safeHttpUrl(site);\n const label = escapeHtml(site);\n return safeUrl\n ? `<a href=\"${escapeHtml(safeUrl)}\" rel=\"noreferrer\">${label}</a>`\n : label;\n}\nfunction list(items) {\n if (items.length === 0)\n return '<p class=\"empty\">No items to report.</p>';\n return `<ul>${items.map((item) => `<li>${escapeHtml(item)}</li>`).join('')}</ul>`;\n}\nfunction reportSections(report) {\n return report.sections\n .map((section) => `<section class=\"panel\">\n <h2>${escapeHtml(section.title)}</h2>\n ${list(section.bullets)}\n </section>`)\n .join('');\n}\nfunction additionalSections(sections) {\n return sections\n .map((section) => `<section class=\"panel\">\n <h2>${escapeHtml(section.title)}</h2>\n ${section.summary ? `<p>${escapeHtml(section.summary)}</p>` : ''}\n ${list(section.items)}\n </section>`)\n .join('');\n}\nfunction priorities(report) {\n if (report.priorities.length === 0) {\n return '<p class=\"empty\">No evidence-backed priorities were found.</p>';\n }\n return `<ol class=\"priorities\">${report.priorities\n .map((priority) => `<li>\n <div class=\"priority-heading\">\n <strong>${escapeHtml(priority.title)}</strong>\n <span class=\"confidence\">${escapeHtml(priority.confidence)} confidence</span>\n </div>\n <p>${escapeHtml(priority.action)}</p>\n </li>`)\n .join('')}</ol>`;\n}\nfunction analystEvidence(report) {\n const skipped = report.diagnosis.skippedSections ?? [];\n const attempts = report.changeMeasurementAttempts;\n return `<section class=\"panel analyst-only\">\n <h2>Evidence coverage</h2>\n <dl class=\"facts\">\n <div><dt>Data status</dt><dd>${escapeHtml(report.dataStatus)}</dd></div>\n <div><dt>Generated</dt><dd>${escapeHtml(report.generatedAt)}</dd></div>\n <div><dt>Saved changes checked</dt><dd>${attempts.length}</dd></div>\n <div><dt>Unavailable sections</dt><dd>${skipped.length}</dd></div>\n </dl>\n ${skipped.length\n ? `<h3>Unavailable sections</h3>${list(skipped.map((section) => 'reason' in section && typeof section.reason === 'string'\n ? `${section.section}: ${section.reason}`\n : section.section))}`\n : ''}\n </section>`;\n}\nconst styles = `\n :root { color-scheme: light; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; color: #17211b; background: #f2f4ef; }\n * { box-sizing: border-box; }\n body { margin: 0; line-height: 1.55; }\n a { color: inherit; text-decoration-color: #ff5b35; text-underline-offset: 0.18em; }\n main { width: min(980px, calc(100% - 32px)); margin: 32px auto 64px; }\n header { padding: clamp(28px, 6vw, 64px); color: #f9fbf7; background: #17211b; border-radius: 20px; }\n .eyebrow { margin: 0 0 12px; color: #ff7958; font-size: 0.78rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; }\n h1 { max-width: 760px; margin: 0; font-size: clamp(2rem, 5vw, 4rem); line-height: 1.02; letter-spacing: -0.04em; }\n header .headline { max-width: 760px; margin: 24px 0 0; font-size: clamp(1.05rem, 2vw, 1.3rem); color: #d9e1d9; }\n .meta { display: flex; flex-wrap: wrap; gap: 10px 22px; margin-top: 28px; color: #b9c5ba; font-size: 0.9rem; }\n .status { display: inline-flex; width: fit-content; margin-top: 22px; padding: 6px 10px; border: 1px solid #4f6153; border-radius: 999px; font-size: 0.8rem; font-weight: 700; text-transform: capitalize; }\n .panel { margin-top: 20px; padding: clamp(22px, 4vw, 38px); background: #fff; border: 1px solid #dfe4dc; border-radius: 16px; box-shadow: 0 8px 30px rgba(23, 33, 27, 0.05); }\n h2 { margin: 0 0 16px; font-size: clamp(1.25rem, 3vw, 1.65rem); letter-spacing: -0.02em; }\n h3 { margin: 26px 0 10px; font-size: 1rem; }\n p { margin: 0 0 14px; }\n ul, ol { margin: 0; padding-left: 1.25rem; }\n li + li { margin-top: 10px; }\n .priorities { list-style: none; padding: 0; counter-reset: priority; }\n .priorities > li { counter-increment: priority; padding: 18px 0 18px 52px; position: relative; border-top: 1px solid #e6eae4; }\n .priorities > li:first-child { border-top: 0; padding-top: 4px; }\n .priorities > li::before { content: counter(priority); position: absolute; left: 0; top: 16px; display: grid; width: 34px; height: 34px; place-items: center; border-radius: 50%; color: #17211b; background: #ff7958; font-weight: 800; }\n .priorities > li:first-child::before { top: 2px; }\n .priority-heading { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 20px; }\n .confidence { color: #647067; font-size: 0.82rem; text-transform: capitalize; }\n .priorities p { margin: 8px 0 0; color: #3e4941; }\n .facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin: 0; }\n .facts div { padding: 14px; background: #f5f7f3; border-radius: 10px; }\n dt { color: #647067; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; }\n dd { margin: 4px 0 0; font-weight: 700; }\n details summary { cursor: pointer; font-weight: 750; }\n details ul { margin-top: 14px; }\n .empty { color: #647067; font-style: italic; }\n footer { margin-top: 26px; color: #647067; font-size: 0.8rem; text-align: center; }\n @media print { :root { background: #fff; } main { width: 100%; margin: 0; } header, .panel { break-inside: avoid; box-shadow: none; } header { border-radius: 0; } }\n`;\nexport function renderReportHtml(input) {\n const report = input.report;\n const view = input.view ?? 'client';\n const title = input.title ?? 'SEO report';\n const evidenceNotesOpen = report.dataStatus !== 'complete' ? ' open' : '';\n const analyst = view === 'analyst' ? analystEvidence(report) : '';\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"robots\" content=\"noindex,nofollow\">\n <title>${escapeHtml(title)}: ${escapeHtml(report.site)}</title>\n <style>${styles}</style>\n</head>\n<body>\n <main>\n <header>\n <p class=\"eyebrow\">${escapeHtml(title)}</p>\n <h1>${siteMarkup(report.site)}</h1>\n <p class=\"headline\">${escapeHtml(report.headline)}</p>\n <div class=\"meta\">\n <span>${escapeHtml(report.period.startDate)} to ${escapeHtml(report.period.endDate)}</span>\n <span>Generated ${escapeHtml(report.generatedAt.slice(0, 10))}</span>\n <span>${escapeHtml(view)} view</span>\n </div>\n <span class=\"status\">${escapeHtml(report.dataStatus)} data</span>\n </header>\n\n <section class=\"panel\">\n <h2>Priorities</h2>\n ${priorities(report)}\n </section>\n\n ${reportSections(report)}\n ${additionalSections(input.additionalSections ?? [])}\n ${analyst}\n\n <section class=\"panel\">\n <details${evidenceNotesOpen}>\n <summary>Evidence notes and limitations</summary>\n ${list(report.caveats)}\n </details>\n </section>\n\n <footer>Generated locally from observed report evidence.</footer>\n </main>\n</body>\n</html>`;\n}\n//# sourceMappingURL=report-html.js.map","const HEADERS = {\n summary: [\n 'workflow',\n 'site',\n 'generated_at',\n 'summary',\n 'attribution',\n 'confidence',\n 'classification',\n 'updates_matched',\n 'known_confounders',\n 'page_segment_status',\n 'page_segment_eligible_rows',\n 'page_segment_returned_rows',\n 'page_segment_limited_rows',\n 'page_segment_result_limit',\n 'page_segment_source_row_limit',\n 'page_segment_source_possibly_truncated',\n 'page_segment_warnings',\n 'query_segment_status',\n 'query_segment_eligible_rows',\n 'query_segment_returned_rows',\n 'query_segment_limited_rows',\n 'query_segment_result_limit',\n 'query_segment_source_row_limit',\n 'query_segment_source_possibly_truncated',\n 'query_segment_warnings',\n 'device_segment_status',\n 'device_segment_eligible_rows',\n 'device_segment_returned_rows',\n 'device_segment_limited_rows',\n 'device_segment_result_limit',\n 'device_segment_source_row_limit',\n 'device_segment_source_possibly_truncated',\n 'device_segment_warnings',\n 'country_segment_status',\n 'country_segment_eligible_rows',\n 'country_segment_returned_rows',\n 'country_segment_limited_rows',\n 'country_segment_result_limit',\n 'country_segment_source_row_limit',\n 'country_segment_source_possibly_truncated',\n 'country_segment_warnings',\n ],\n steps: ['rank', 'tool', 'status', 'summary'],\n actions: ['rank', 'title', 'confidence', 'action'],\n findings: [\n 'dimension',\n 'data_status',\n 'eligible_rows',\n 'returned_rows',\n 'limited_rows',\n 'result_limit',\n 'unmatched_rows',\n 'summary',\n 'winner_key',\n 'winner_click_delta',\n 'winner_impression_delta',\n 'winner_position_delta',\n 'loser_key',\n 'loser_click_delta',\n 'loser_impression_delta',\n 'loser_position_delta',\n ],\n templates: [\n 'rank',\n 'direction',\n 'template',\n 'confidence',\n 'url_count',\n 'click_delta',\n 'impression_delta',\n 'movement_share',\n 'movement_share_scope',\n 'confidence_scope',\n 'eligible_rows',\n 'returned_rows',\n 'limited_rows',\n 'result_limit',\n 'source_possibly_truncated',\n 'common_terms',\n 'sample_urls',\n 'summary',\n ],\n evidence: ['rank', 'evidence'],\n confounders: [\n 'rank',\n 'source',\n 'title',\n 'date',\n 'scope',\n 'target',\n 'description',\n ],\n segment: [\n 'rank',\n 'dimension',\n 'data_status',\n 'evidence_scope',\n 'key',\n 'before_clicks',\n 'after_clicks',\n 'click_delta',\n 'before_impressions',\n 'after_impressions',\n 'impression_delta',\n 'before_position',\n 'after_position',\n 'position_delta',\n ],\n unmatchedSegment: [\n 'rank',\n 'dimension',\n 'data_status',\n 'key',\n 'retained_in',\n 'clicks',\n 'impressions',\n 'position',\n 'reason',\n ],\n};\nfunction postmortemSegmentRows(report, dimension) {\n return [\n ...report.output.segments[dimension].winners,\n ...report.output.segments[dimension].losers,\n ].map((item, index) => ({\n rank: index + 1,\n dimension,\n data_status: report.output.segments[dimension].dataStatus,\n evidence_scope: item.evidenceScope,\n key: item.key,\n before_clicks: item.beforeClicks,\n after_clicks: item.afterClicks,\n click_delta: item.clickDelta,\n before_impressions: item.beforeImpressions,\n after_impressions: item.afterImpressions,\n impression_delta: item.impressionDelta,\n before_position: item.beforePosition,\n after_position: item.afterPosition,\n position_delta: item.positionDelta,\n }));\n}\nfunction postmortemUnmatchedSegmentRows(report, dimension) {\n return report.output.segments[dimension].unmatchedSegments.map((item, index) => ({\n rank: index + 1,\n dimension,\n data_status: report.output.segments[dimension].dataStatus,\n key: item.key,\n retained_in: item.retainedIn,\n clicks: item.clicks,\n impressions: item.impressions,\n position: item.position,\n reason: item.reason,\n }));\n}\nexport function updatePostmortemCsvFiles(report) {\n return [\n {\n filename: 'postmortem-summary.csv',\n headers: [...HEADERS.summary],\n rows: [\n {\n workflow: report.workflow,\n site: report.site,\n generated_at: report.generatedAt,\n summary: report.summary,\n attribution: report.output.update.attribution,\n confidence: report.output.update.confidence,\n classification: report.output.update.classification,\n updates_matched: report.output.update.overlappingUpdates.length,\n known_confounders: report.output.update.confounders.length,\n page_segment_status: report.output.segments.page.dataStatus,\n page_segment_eligible_rows: report.output.segments.page.coverage.eligibleRows,\n page_segment_returned_rows: report.output.segments.page.coverage.returnedRows,\n page_segment_limited_rows: report.output.segments.page.coverage.limitedRows,\n page_segment_result_limit: report.output.segments.page.coverage.resultLimit,\n page_segment_source_row_limit: report.output.segments.page.coverage.sourceRowLimit,\n page_segment_source_possibly_truncated: report.output.segments.page.coverage.sourcePossiblyTruncated,\n page_segment_warnings: report.output.segments.page.warnings.join('; '),\n query_segment_status: report.output.segments.query.dataStatus,\n query_segment_eligible_rows: report.output.segments.query.coverage.eligibleRows,\n query_segment_returned_rows: report.output.segments.query.coverage.returnedRows,\n query_segment_limited_rows: report.output.segments.query.coverage.limitedRows,\n query_segment_result_limit: report.output.segments.query.coverage.resultLimit,\n query_segment_source_row_limit: report.output.segments.query.coverage.sourceRowLimit,\n query_segment_source_possibly_truncated: report.output.segments.query.coverage.sourcePossiblyTruncated,\n query_segment_warnings: report.output.segments.query.warnings.join('; '),\n device_segment_status: report.output.segments.device.dataStatus,\n device_segment_eligible_rows: report.output.segments.device.coverage.eligibleRows,\n device_segment_returned_rows: report.output.segments.device.coverage.returnedRows,\n device_segment_limited_rows: report.output.segments.device.coverage.limitedRows,\n device_segment_result_limit: report.output.segments.device.coverage.resultLimit,\n device_segment_source_row_limit: report.output.segments.device.coverage.sourceRowLimit,\n device_segment_source_possibly_truncated: report.output.segments.device.coverage.sourcePossiblyTruncated,\n device_segment_warnings: report.output.segments.device.warnings.join('; '),\n country_segment_status: report.output.segments.country.dataStatus,\n country_segment_eligible_rows: report.output.segments.country.coverage.eligibleRows,\n country_segment_returned_rows: report.output.segments.country.coverage.returnedRows,\n country_segment_limited_rows: report.output.segments.country.coverage.limitedRows,\n country_segment_result_limit: report.output.segments.country.coverage.resultLimit,\n country_segment_source_row_limit: report.output.segments.country.coverage.sourceRowLimit,\n country_segment_source_possibly_truncated: report.output.segments.country.coverage.sourcePossiblyTruncated,\n country_segment_warnings: report.output.segments.country.warnings.join('; '),\n },\n ],\n },\n {\n filename: 'workflow-steps.csv',\n headers: [...HEADERS.steps],\n rows: report.steps.map((step, index) => ({\n rank: index + 1,\n tool: step.tool,\n status: step.status,\n summary: step.summary,\n })),\n },\n {\n filename: 'workflow-actions.csv',\n headers: [...HEADERS.actions],\n rows: report.actions.map((action, index) => ({\n rank: index + 1,\n title: action.title,\n confidence: action.confidence,\n action: action.action,\n })),\n },\n {\n filename: 'postmortem-findings.csv',\n headers: [...HEADERS.findings],\n rows: report.output.insights.map((item) => ({\n dimension: item.dimension,\n data_status: item.dataStatus,\n eligible_rows: item.coverage.eligibleRows,\n returned_rows: item.coverage.returnedRows,\n limited_rows: item.coverage.limitedRows,\n result_limit: item.coverage.resultLimit,\n unmatched_rows: item.unmatchedRows,\n summary: item.summary,\n winner_key: item.winner?.key,\n winner_click_delta: item.winner?.clickDelta,\n winner_impression_delta: item.winner?.impressionDelta,\n winner_position_delta: item.winner?.positionDelta,\n loser_key: item.loser?.key,\n loser_click_delta: item.loser?.clickDelta,\n loser_impression_delta: item.loser?.impressionDelta,\n loser_position_delta: item.loser?.positionDelta,\n })),\n },\n {\n filename: 'postmortem-template-movement.csv',\n headers: [...HEADERS.templates],\n rows: report.output.templateMovement.map((item, index) => ({\n rank: index + 1,\n direction: item.direction,\n template: item.signature,\n confidence: item.confidence,\n url_count: item.urlCount,\n click_delta: item.clickDelta,\n impression_delta: item.impressionDelta,\n movement_share: item.movementShare,\n movement_share_scope: item.movementShareScope,\n confidence_scope: item.confidenceScope,\n eligible_rows: item.segmentCoverage.eligibleRows,\n returned_rows: item.segmentCoverage.returnedRows,\n limited_rows: item.segmentCoverage.limitedRows,\n result_limit: item.segmentCoverage.resultLimit,\n source_possibly_truncated: item.segmentCoverage.sourcePossiblyTruncated,\n common_terms: item.commonTerms.join('; '),\n sample_urls: item.sampleUrls.join('; '),\n summary: item.summary,\n })),\n },\n {\n filename: 'postmortem-update-evidence.csv',\n headers: [...HEADERS.evidence],\n rows: report.output.update.evidence.map((evidence, index) => ({\n rank: index + 1,\n evidence,\n })),\n },\n {\n filename: 'postmortem-confounders.csv',\n headers: [...HEADERS.confounders],\n rows: report.output.update.confounders.map((item, index) => ({\n rank: index + 1,\n source: item.source,\n title: item.title,\n date: item.date,\n scope: item.scope,\n target: item.target,\n description: item.description,\n })),\n },\n ...['page', 'query', 'device', 'country'].map((dimension) => ({\n filename: `postmortem-segment-${dimension}.csv`,\n headers: [...HEADERS.segment],\n rows: postmortemSegmentRows(report, dimension),\n })),\n ...['page', 'query', 'device', 'country'].map((dimension) => ({\n filename: `postmortem-segment-${dimension}-unmatched.csv`,\n headers: [...HEADERS.unmatchedSegment],\n rows: postmortemUnmatchedSegmentRows(report, dimension),\n })),\n ];\n}\n//# sourceMappingURL=update-postmortem.js.map","function hostnameFromUrl(value) {\n try {\n const url = new URL(value);\n if (url.protocol !== 'http:' && url.protocol !== 'https:')\n return undefined;\n return url.hostname.toLowerCase().replace(/\\.$/, '') || undefined;\n }\n catch {\n return undefined;\n }\n}\nfunction domainFromProperty(value) {\n if (!value.startsWith('sc-domain:'))\n return undefined;\n const domain = value.slice('sc-domain:'.length).trim().toLowerCase();\n if (!domain || /[/:]/.test(domain))\n return undefined;\n return domain.replace(/\\.$/, '') || undefined;\n}\nfunction matchForSite(site, streamHostname) {\n const domain = domainFromProperty(site);\n if (domain) {\n return streamHostname === domain || streamHostname.endsWith(`.${domain}`)\n ? 'domain'\n : undefined;\n }\n return hostnameFromUrl(site) === streamHostname ? 'hostname' : undefined;\n}\nexport function matchGa4WebStreams(site, candidates) {\n return candidates.flatMap((candidate) => {\n const defaultUri = candidate.stream.webStreamData?.defaultUri;\n if (!defaultUri)\n return [];\n const hostname = hostnameFromUrl(defaultUri);\n if (!hostname)\n return [];\n const match = matchForSite(site, hostname);\n if (!match)\n return [];\n return [{ ...candidate, defaultUri, hostname, match }];\n });\n}\nexport function ga4MatchReason(match, site) {\n const stream = match.stream.displayName ?? match.defaultUri;\n const location = match.match === 'domain' ? 'is inside' : 'matches';\n return `Matched Google Analytics web stream ${stream} (${match.defaultUri}): its hostname ${location} ${site}.`;\n}\n//# sourceMappingURL=matching.js.map","import { createHash } from 'node:crypto';\nimport { readdir, stat } from 'node:fs/promises';\nimport { extname, join, resolve } from 'node:path';\nimport { SeoError } from '../errors.js';\nimport { csvRecords, DEFAULT_IMPORT_STREAM_BYTES, importFile, } from '../imports/records.js';\nexport const DEFAULT_SEARCH_CONSOLE_EXPORT_ROW_LIMIT = 5_000;\nexport const MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT = 100_000;\nexport const MAX_SEARCH_CONSOLE_EXPORT_FILES = 20;\nconst IMPORT_LABEL = 'Search Console export';\nconst QUERY_TABLE_HEADERS = new Set(['top queries', 'query', 'queries']);\nconst PAGE_TABLE_HEADERS = new Set(['top pages', 'page', 'pages', 'url']);\nconst CLICKS_ALIASES = ['clicks', 'url clicks'];\nconst IMPRESSIONS_ALIASES = ['impressions'];\nconst CTR_ALIASES = ['ctr', 'url ctr', 'site ctr'];\nconst POSITION_ALIASES = [\n 'position',\n 'average position',\n 'avg position',\n 'avg. position',\n];\nconst CAVEATS = [\n 'Query and page tables are separate aggregates from a Search Console export; no query-to-page mapping exists and none was created.',\n 'Search Console exports are partial: anonymised queries are withheld and export row caps apply, so missing rows are not zeros.',\n];\nfunction exportRowLimit(value) {\n const result = value ?? DEFAULT_SEARCH_CONSOLE_EXPORT_ROW_LIMIT;\n if (!Number.isSafeInteger(result) ||\n result < 1 ||\n result > MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT) {\n throw new SeoError('INVALID_INPUT', `Search Console export row limit must be between 1 and ${MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT}.`);\n }\n return result;\n}\nasync function exportCsvPaths(input) {\n const path = resolve(input);\n const target = await stat(path).catch(() => undefined);\n if (!target) {\n throw new SeoError('INVALID_INPUT', `Search Console export path was not found: ${path}`);\n }\n if (target.isFile())\n return [path];\n if (!target.isDirectory()) {\n throw new SeoError('INVALID_INPUT', `Search Console export path must be a CSV file or a directory: ${path}`);\n }\n const entries = await readdir(path, { withFileTypes: true });\n const files = entries\n .filter((entry) => {\n if (!entry.isFile())\n return false;\n const extension = extname(entry.name).toLowerCase();\n return extension === '.csv' || extension === '.tsv';\n })\n .map((entry) => join(path, entry.name))\n .sort(compareText);\n if (files.length === 0) {\n throw new SeoError('INVALID_INPUT', `Search Console export directory contains no CSV files: ${path}`);\n }\n if (files.length > MAX_SEARCH_CONSOLE_EXPORT_FILES) {\n throw new SeoError('INVALID_INPUT', `Search Console export directories can contain at most ${MAX_SEARCH_CONSOLE_EXPORT_FILES} CSV files.`);\n }\n return files;\n}\nfunction normalizedHeader(value) {\n return value\n .replace(/^\\uFEFF/u, '')\n .trim()\n .toLowerCase();\n}\nfunction metricIndex(headers, aliases) {\n for (const alias of aliases) {\n const index = headers.indexOf(alias);\n if (index > 0)\n return index;\n }\n return null;\n}\nfunction countValue(cell) {\n const trimmed = (cell ?? '').trim();\n if (!trimmed)\n return null;\n if (!/^\\d+(?:,\\d{3})*$/u.test(trimmed))\n return null;\n const parsed = Number(trimmed.replaceAll(',', ''));\n return Number.isSafeInteger(parsed) ? parsed : null;\n}\nfunction ctrValue(cell) {\n const trimmed = (cell ?? '').trim();\n if (!trimmed)\n return null;\n if (trimmed.endsWith('%')) {\n const parsed = Number(trimmed.slice(0, -1).trim());\n if (!Number.isFinite(parsed))\n return null;\n const fraction = parsed / 100;\n return fraction >= 0 && fraction <= 1 ? fraction : null;\n }\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : null;\n}\nfunction positionValue(cell) {\n const trimmed = (cell ?? '').trim();\n if (!trimmed)\n return null;\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\nfunction absoluteHttpUrl(value) {\n let parsed;\n try {\n parsed = new URL(value);\n }\n catch {\n return null;\n }\n return parsed.protocol === 'http:' || parsed.protocol === 'https:'\n ? value\n : null;\n}\nfunction compareText(left, right) {\n return left < right ? -1 : left > right ? 1 : 0;\n}\nfunction keepImportedRow(candidate, existing) {\n if (candidate.impressions !== existing.impressions) {\n return candidate.impressions > existing.impressions;\n }\n return candidate.clicks > existing.clicks;\n}\nfunction compareQueryRows(left, right) {\n return (right.clicks - left.clicks ||\n right.impressions - left.impressions ||\n compareText(left.query, right.query));\n}\nfunction comparePageRows(left, right) {\n return (right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n compareText(left.url, right.url));\n}\nfunction tableOutput(state, compare, rowLimit) {\n const sorted = [...state.byKey.values()].sort(compare);\n const capped = state.capped || sorted.length > rowLimit;\n return {\n rows: sorted.slice(0, rowLimit),\n totalRows: sorted.length,\n capped,\n };\n}\nexport async function loadSearchConsoleExport(input) {\n const rowLimit = exportRowLimit(input.rowLimit);\n const paths = await exportCsvPaths(input.path);\n const files = [];\n const warnings = [];\n const queryState = {\n byKey: new Map(),\n suppliedRows: 0,\n capped: false,\n };\n const pageState = {\n byKey: new Map(),\n suppliedRows: 0,\n capped: false,\n };\n for (const path of paths) {\n const file = await importFile({\n file: path,\n format: 'csv',\n label: IMPORT_LABEL,\n });\n const hash = createHash('sha256');\n const progress = { bytesRead: 0, hash };\n const records = csvRecords({\n path: file.path,\n byteLimit: DEFAULT_IMPORT_STREAM_BYTES,\n progress,\n label: IMPORT_LABEL,\n });\n const first = await records.next();\n const rawHeaders = Array.isArray(first.value) ? first.value : [];\n const headers = rawHeaders.map((value, index) => (index === 0 ? value.replace(/^\\uFEFF/u, '') : value).trim());\n const normalizedHeaders = headers.map(normalizedHeader);\n const firstHeader = normalizedHeaders[0] ?? '';\n const table = QUERY_TABLE_HEADERS.has(firstHeader)\n ? 'queries'\n : PAGE_TABLE_HEADERS.has(firstHeader)\n ? 'pages'\n : 'unrecognized';\n const headerReason = table === 'unrecognized'\n ? headers.length === 0\n ? 'The file has no header row.'\n : `The first header \"${headers[0]}\" is not a recognized Search Console query or page column.`\n : undefined;\n const clicksIndex = metricIndex(normalizedHeaders, CLICKS_ALIASES);\n const impressionsIndex = metricIndex(normalizedHeaders, IMPRESSIONS_ALIASES);\n const ctrIndex = metricIndex(normalizedHeaders, CTR_ALIASES);\n const positionIndex = metricIndex(normalizedHeaders, POSITION_ALIASES);\n const missingRequiredFields = [\n ...(clicksIndex === null ? ['Clicks'] : []),\n ...(impressionsIndex === null ? ['Impressions'] : []),\n ];\n const reason = headerReason ??\n (missingRequiredFields.length\n ? `The recognized ${table} table is missing required ${missingRequiredFields.join(' and ')} columns.`\n : undefined);\n const usable = table !== 'unrecognized' && reason === undefined;\n let fileRows = 0;\n let suppliedRows = 0;\n let validRows = 0;\n let invalidRows = 0;\n let duplicateRows = 0;\n const tableState = table === 'queries' ? queryState : pageState;\n for await (const values of records) {\n fileRows += 1;\n if (!usable)\n continue;\n if (tableState.suppliedRows >= rowLimit)\n continue;\n suppliedRows += 1;\n tableState.suppliedRows += 1;\n if (values.length !== headers.length) {\n invalidRows += 1;\n continue;\n }\n const clicks = countValue(values[clicksIndex ?? -1]);\n const impressions = countValue(values[impressionsIndex ?? -1]);\n if (clicks === null || impressions === null) {\n invalidRows += 1;\n continue;\n }\n const ctrCell = ctrIndex === null ? '' : (values[ctrIndex] ?? '').trim();\n const positionCell = positionIndex === null ? '' : (values[positionIndex] ?? '').trim();\n const ctr = ctrIndex === null ? null : ctrValue(ctrCell);\n const position = positionIndex === null ? null : positionValue(positionCell);\n if ((ctrCell && ctr === null) || (positionCell && position === null)) {\n invalidRows += 1;\n continue;\n }\n const metrics = {\n clicks,\n impressions,\n ctr,\n position,\n };\n const key = (values[0] ?? '').trim();\n if (table === 'queries') {\n if (!key) {\n invalidRows += 1;\n continue;\n }\n const existing = queryState.byKey.get(key);\n if (existing) {\n duplicateRows += 1;\n if (keepImportedRow(metrics, existing)) {\n queryState.byKey.set(key, { query: key, ...metrics });\n }\n continue;\n }\n validRows += 1;\n queryState.byKey.set(key, { query: key, ...metrics });\n continue;\n }\n const url = absoluteHttpUrl(key);\n if (!url) {\n invalidRows += 1;\n continue;\n }\n const existing = pageState.byKey.get(url);\n if (existing) {\n duplicateRows += 1;\n if (keepImportedRow(metrics, existing)) {\n pageState.byKey.set(url, { url, ...metrics });\n }\n continue;\n }\n validRows += 1;\n pageState.byKey.set(url, { url, ...metrics });\n }\n const capped = usable && fileRows > suppliedRows;\n if (capped) {\n if (table === 'queries')\n queryState.capped = true;\n else\n pageState.capped = true;\n warnings.push(`Only ${suppliedRows} of ${fileRows} rows in ${file.path} were processed within the shared ${table} row limit of ${rowLimit}.`);\n }\n if (reason) {\n warnings.push(`Skipped ${file.path}: ${reason ?? 'the file was not recognized.'}`);\n }\n if (invalidRows > 0) {\n warnings.push(`${invalidRows} row${invalidRows === 1 ? '' : 's'} in ${file.path} ${invalidRows === 1 ? 'was' : 'were'} invalid and skipped.`);\n }\n files.push({\n path: file.path,\n table,\n sha256: hash.digest('hex'),\n fileBytes: file.fileBytes,\n bytesRead: progress.bytesRead,\n encoding: progress.encoding ?? 'utf-8',\n delimiter: progress.delimiter ?? null,\n includedFields: [...headers].sort(compareText),\n fileRows,\n suppliedRows,\n validRows,\n invalidRows,\n duplicateRows,\n capped,\n rowLimit,\n ...(reason === undefined ? {} : { reason }),\n });\n }\n if (files.every((file) => file.table === 'unrecognized')) {\n warnings.push('No file matched the Search Console query or page table headers, so no rows were imported.');\n }\n return {\n source: 'search-console-export',\n exportedAt: input.exportedAt?.toISOString() ?? null,\n importedAt: (input.now ?? new Date()).toISOString(),\n files,\n queries: tableOutput(queryState, compareQueryRows, rowLimit),\n pages: tableOutput(pageState, comparePageRows, rowLimit),\n warnings,\n caveats: [\n ...CAVEATS,\n input.exportedAt\n ? 'exportedAt was supplied by the caller and is not verified from the file; importedAt records when the local files were loaded.'\n : 'The export time is unavailable unless supplied separately; importedAt records when the local files were loaded, not when Search Console produced them.',\n ],\n };\n}\n//# sourceMappingURL=local-export.js.map","import { SeoError } from '../errors.js';\nexport const DEFAULT_UNREACHED_PAGE_LIMIT = 100;\nfunction unreachedLimit(value) {\n const result = value ?? DEFAULT_UNREACHED_PAGE_LIMIT;\n if (!Number.isSafeInteger(result) || result < 1) {\n throw new SeoError('INVALID_INPUT', 'Unreached-page limit must be a positive integer.');\n }\n return result;\n}\nfunction normalizedPath(value) {\n let parsed;\n try {\n parsed = new URL(value);\n }\n catch {\n return null;\n }\n const pathname = parsed.pathname !== '/' && parsed.pathname.endsWith('/')\n ? parsed.pathname.slice(0, -1)\n : parsed.pathname;\n return `${pathname}${parsed.search}`;\n}\nfunction compareText(left, right) {\n return left < right ? -1 : left > right ? 1 : 0;\n}\nfunction compareUnreached(left, right) {\n return (right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n compareText(left.url, right.url));\n}\nexport function reconcileExportPagesWithCrawl(input) {\n const limit = unreachedLimit(input.limit);\n const crawledPaths = new Set();\n for (const url of input.crawledUrls) {\n const path = normalizedPath(url);\n if (path !== null)\n crawledPaths.add(path);\n }\n const origins = new Set();\n let matchedPages = 0;\n const unreached = [];\n for (const page of input.pages) {\n let parsed;\n try {\n parsed = new URL(page.url);\n }\n catch {\n continue;\n }\n origins.add(parsed.origin);\n const path = normalizedPath(page.url);\n if (path !== null && crawledPaths.has(path))\n matchedPages += 1;\n else\n unreached.push(page);\n }\n unreached.sort(compareUnreached);\n const exportOrigins = [...origins].sort(compareText);\n return {\n joinBasis: 'path',\n crawlOrigin: input.crawlOrigin,\n exportOrigins,\n originMismatch: exportOrigins.some((origin) => origin !== input.crawlOrigin),\n matchedPages,\n unreachedPages: unreached.slice(0, limit),\n unreachedCount: unreached.length,\n capped: unreached.length > limit,\n };\n}\n//# sourceMappingURL=local-export-reconcile.js.map","export function parseOlderThan(input) {\n if (!input) {\n return undefined;\n }\n const match = input.trim().match(/^(\\d+)([smhdw])$/i);\n if (!match) {\n throw new Error(`Invalid duration \"${input}\". Use values like 7d, 12h, 30m.`);\n }\n const valuePart = match[1];\n const unitPart = match[2];\n if (!valuePart || !unitPart) {\n throw new Error(`Invalid duration \"${input}\".`);\n }\n const value = Number.parseInt(valuePart, 10);\n const unit = unitPart.toLowerCase();\n const multipliers = {\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n };\n const multiplier = multipliers[unit];\n if (!multiplier) {\n throw new Error(`Unsupported duration unit in \"${input}\".`);\n }\n return value * multiplier;\n}\nexport function formatRelativeExpiry(expiresAt) {\n const delta = expiresAt - Date.now();\n if (delta <= 0) {\n return 'expired';\n }\n const minutes = Math.round(delta / 60_000);\n if (minutes < 60) {\n return `in ${minutes}m`;\n }\n const hours = Math.floor(minutes / 60);\n const remMinutes = minutes % 60;\n return remMinutes ? `in ${hours}h ${remMinutes}m` : `in ${hours}h`;\n}\nexport function isoDate(daysAgo = 0) {\n const date = new Date();\n date.setUTCDate(date.getUTCDate() - daysAgo);\n return date.toISOString().slice(0, 10);\n}\n//# sourceMappingURL=time.js.map","import { readFile } from 'node:fs/promises'\nimport { type JavaScriptRenderingMode, SeoError } from '@seo/core'\nimport type { BooleanArgDef } from 'citty'\n\nexport function defaultTrueBooleanArg(\n description: string,\n negativeDescription: string,\n): BooleanArgDef {\n return {\n type: 'boolean',\n default: true,\n description,\n negativeDescription,\n }\n}\n\nexport function stringArg(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nexport function projectArg(args: Record<string, unknown>): string | undefined {\n const project = stringArg(args.project)\n const client = stringArg(args.client)\n if (project && client && project !== client) {\n throw new Error('Use either --project or --client, not both.')\n }\n return project ?? client\n}\n\nexport function booleanArg(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\n}\n\n/**\n * `--js` remains an alias for `--rendering on` while callers move to the\n * explicit modes. A mode is returned even when neither flag was supplied so\n * commands can pass it straight to the core API.\n */\nexport function renderingModeArg(\n args: Record<string, unknown>,\n): JavaScriptRenderingMode {\n const rendering = stringArg(args.rendering)\n if (\n rendering !== undefined &&\n rendering !== 'auto' &&\n rendering !== 'on' &&\n rendering !== 'off'\n ) {\n throw new SeoError('INVALID_INPUT', '--rendering must be auto, on, or off.')\n }\n if (booleanArg(args.js) === true && rendering && rendering !== 'on') {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --js or --rendering on, not both with different modes.',\n )\n }\n return rendering ?? (booleanArg(args.js) ? 'on' : 'auto')\n}\n\nexport function negatedBooleanArg(\n args: Record<string, unknown>,\n name: string,\n): boolean | undefined {\n const positive = booleanArg(args[name])\n if (positive === false) return true\n if (positive === true) return false\n const camelPositive = booleanArg(args[toCamelCase(name)])\n if (camelPositive === false) return true\n if (camelPositive === true) return false\n const explicitNo = booleanArg(args[`no-${name}`])\n if (explicitNo === true) return true\n const camelNo = booleanArg(args[`no${toPascalCase(name)}`])\n if (camelNo === true) return true\n return undefined\n}\n\nfunction toCamelCase(value: string): string {\n return value.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase())\n}\n\nfunction toPascalCase(value: string): string {\n const camel = toCamelCase(value)\n return camel ? `${camel[0]?.toUpperCase()}${camel.slice(1)}` : ''\n}\n\nexport function numberArg(value: unknown): number | undefined {\n if (typeof value === 'number') return value\n if (typeof value !== 'string' || !value.trim()) return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nexport function strictNumberArg(\n value: unknown,\n label: string,\n): number | undefined {\n if (value === undefined || value === '') return undefined\n const parsed = numberArg(value)\n if (parsed === undefined)\n throw new SeoError('INVALID_INPUT', `${label} must be a number.`)\n return parsed\n}\n\nexport function csvArg(value: unknown): string[] | undefined {\n if (typeof value !== 'string') return undefined\n const items = value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean)\n return items.length ? items : undefined\n}\n\nexport function listArg(value: unknown): string[] {\n return csvArg(value) ?? []\n}\n\nexport function fetchRateArg(args: Record<string, unknown>):\n | {\n concurrency?: number\n intervalCap?: number\n intervalMs?: number\n }\n | undefined {\n const rate = {\n concurrency: numberArg(args['fetch-concurrency']),\n intervalCap: numberArg(args['fetch-interval-cap']),\n intervalMs: numberArg(args['fetch-interval-ms']),\n }\n return Object.values(rate).some((value) => value !== undefined)\n ? rate\n : undefined\n}\n\nexport function strictFetchRateArg(args: Record<string, unknown>):\n | {\n concurrency?: number\n intervalCap?: number\n intervalMs?: number\n }\n | undefined {\n const rate = {\n concurrency: strictNumberArg(\n args['fetch-concurrency'],\n '--fetch-concurrency',\n ),\n intervalCap: strictNumberArg(\n args['fetch-interval-cap'],\n '--fetch-interval-cap',\n ),\n intervalMs: strictNumberArg(\n args['fetch-interval-ms'],\n '--fetch-interval-ms',\n ),\n }\n return Object.values(rate).some((value) => value !== undefined)\n ? rate\n : undefined\n}\n\nexport function jsonFlag(args: Record<string, unknown>): boolean {\n return args.json === true\n}\n\nexport async function jsonBodyArg(\n value: unknown,\n fileValue: unknown,\n): Promise<Record<string, unknown> | undefined> {\n const inline = stringArg(value)\n const file = stringArg(fileValue)\n if (inline && file) {\n throw new Error('Use either --body or --body-file, not both.')\n }\n if (!inline && !file) return undefined\n const source = inline ?? (await readFile(file ?? '', 'utf8'))\n const parsed = JSON.parse(source) as unknown\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('JSON body must be an object.')\n }\n return parsed as Record<string, unknown>\n}\n","import { stripVTControlCharacters } from 'node:util'\nimport pc from 'picocolors'\nimport stringWidth from 'string-width'\n\nconst DEFAULT_COLUMNS = 80\nconst MIN_COLUMNS = 40\nconst MAX_COLUMNS = 200\n\nexport type TerminalContext = {\n columns: number\n colors: ReturnType<typeof pc.createColors>\n hasColor: boolean\n isInteractive: boolean\n}\n\nexport type TerminalContextOptions = {\n columns?: number\n color?: boolean\n env?: NodeJS.ProcessEnv\n isTTY?: boolean\n streamColumns?: number\n}\n\nfunction parsedColumns(value: number | string | undefined): number | undefined {\n if (typeof value === 'number') {\n return Number.isFinite(value) ? Math.round(value) : undefined\n }\n if (!value) return undefined\n const parsed = Number.parseInt(value, 10)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nexport function resolveTerminalColumns(\n options: TerminalContextOptions = {},\n): number {\n const env = options.env ?? process.env\n const requested =\n parsedColumns(options.columns) ??\n parsedColumns(options.streamColumns) ??\n parsedColumns(env.COLUMNS) ??\n DEFAULT_COLUMNS\n return Math.min(MAX_COLUMNS, Math.max(MIN_COLUMNS, requested))\n}\n\nexport function createTerminalContext(\n options: TerminalContextOptions = {},\n): TerminalContext {\n const env = options.env ?? process.env\n const isTTY = options.isTTY ?? Boolean(process.stdout.isTTY)\n const hasColor = options.color ?? Boolean(isTTY && env.NO_COLOR === undefined)\n return {\n columns: resolveTerminalColumns({\n ...options,\n env,\n streamColumns: options.streamColumns ?? process.stdout.columns,\n }),\n colors: pc.createColors(hasColor),\n hasColor,\n isInteractive: isTTY && !env.CI,\n }\n}\n\nexport function visibleWidth(value: string): number {\n return stringWidth(stripVTControlCharacters(value))\n}\n\nfunction splitToken(token: string, width: number): string[] {\n const chunks: string[] = []\n let chunk = ''\n for (const character of token) {\n if (chunk && visibleWidth(`${chunk}${character}`) > width) {\n chunks.push(chunk)\n chunk = character\n } else {\n chunk += character\n }\n }\n if (chunk) chunks.push(chunk)\n return chunks\n}\n\nfunction wrapLine(value: string, width: number): string[] {\n if (!value) return ['']\n const words = value.trim().split(/\\s+/u)\n const lines: string[] = []\n let line = ''\n\n for (const word of words) {\n const pieces = visibleWidth(word) > width ? splitToken(word, width) : [word]\n for (const piece of pieces) {\n if (!line) {\n line = piece\n } else if (visibleWidth(`${line} ${piece}`) <= width) {\n line += ` ${piece}`\n } else {\n lines.push(line)\n line = piece\n }\n }\n }\n if (line) lines.push(line)\n return lines.length > 0 ? lines : ['']\n}\n\nexport function wrapText(value: string, width: number): string[] {\n const safeWidth = Math.max(1, width)\n return value\n .replaceAll('\\r\\n', '\\n')\n .split('\\n')\n .flatMap((line) => wrapLine(line, safeWidth))\n}\n\nexport function truncateText(value: string, width: number): string {\n if (visibleWidth(value) <= width) return value\n const suffix = '...'\n const available = Math.max(1, width - visibleWidth(suffix))\n let result = ''\n for (const character of value) {\n if (visibleWidth(`${result}${character}`) > available) break\n result += character\n }\n return `${result}${suffix}`\n}\n","import Table from 'cli-table3'\nimport {\n type TerminalContext,\n truncateText,\n visibleWidth,\n wrapText,\n} from './context.js'\n\nexport type TerminalCell = string | number\nexport type TerminalRow = TerminalCell[]\n\ntype TableOptions = {\n layout?: 'auto' | 'records' | 'table'\n rowNumbers?: boolean\n}\n\ntype Callout = {\n body?: string\n command?: string\n title: string\n}\n\nconst borderlessChars = {\n top: '',\n 'top-mid': '',\n 'top-left': '',\n 'top-right': '',\n bottom: '',\n 'bottom-mid': '',\n 'bottom-left': '',\n 'bottom-right': '',\n left: '',\n 'left-mid': '',\n mid: '',\n 'mid-mid': '',\n right: '',\n 'right-mid': '',\n middle: '',\n}\n\nfunction stringCell(value: TerminalCell | undefined): string {\n return value === undefined ? '' : String(value)\n}\n\nfunction naturalColumnWidths(head: string[], rows: TerminalRow[]): number[] {\n return head.map((label, column) => {\n const values = rows.map((row) => stringCell(row[column]))\n return Math.min(\n 42,\n Math.max(visibleWidth(label), ...values.map(visibleWidth), 4),\n )\n })\n}\n\nfunction canRenderTable(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n): boolean {\n if (head.length === 0 || head.length > 4) return false\n const numericColumns = head.map((_, column) =>\n rows.every((row) =>\n /^-?(?:\\d+(?:\\.\\d+)?|\\d+(?:\\.\\d+)?%)$/u.test(\n stringCell(row[column]).trim(),\n ),\n ),\n )\n if (!numericColumns.some(Boolean)) return false\n const widths = naturalColumnWidths(head, rows)\n const tableWidth = widths.reduce((total, width) => total + width + 2, 0)\n return tableWidth <= context.columns\n}\n\nfunction styledValue(\n label: string,\n value: string,\n context: TerminalContext,\n): string {\n if (!/(?:status|state|assessment|data|allowed)/iu.test(label)) return value\n const normalized = value.trim().toLowerCase()\n if (['pass', 'passed', 'completed', 'allowed', 'yes'].includes(normalized)) {\n return context.colors.green(value)\n }\n if (['warn', 'warning', 'review', 'partial'].includes(normalized)) {\n return context.colors.yellow(value)\n }\n if (['fail', 'failed', 'blocked', 'no'].includes(normalized)) {\n return context.colors.red(value)\n }\n if (['unknown', 'unavailable'].includes(normalized)) {\n return context.colors.blue(value)\n }\n return value\n}\n\nfunction renderDenseTable(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n): string {\n const widths = naturalColumnWidths(head, rows).map((width) => width + 2)\n const table = new Table({\n chars: borderlessChars,\n colWidths: widths,\n head: head.map((label) => context.colors.bold(label)),\n style: {\n border: [],\n head: [],\n 'padding-left': 0,\n 'padding-right': 2,\n },\n wordWrap: false,\n })\n for (const row of rows) {\n table.push(\n head.map((label, column) =>\n wrapText(\n styledValue(label, stringCell(row[column]), context),\n Math.max(1, (widths[column] ?? 3) - 2),\n ).join('\\n'),\n ),\n )\n }\n return table.toString()\n}\n\nfunction renderRecordValue(\n label: string,\n value: string,\n labelWidth: number,\n context: TerminalContext,\n): string[] {\n const gap = 2\n const valueWidth = context.columns - labelWidth - gap\n if (valueWidth < 24) {\n return [\n context.colors.dim(label),\n ...wrapText(value, context.columns - 2).map((line) => ` ${line}`),\n ]\n }\n const wrapped = wrapText(value, valueWidth)\n return wrapped.map((line, index) => {\n const prefix =\n index === 0 ? label.padEnd(labelWidth) : ''.padEnd(labelWidth)\n return `${context.colors.dim(prefix)}${' '.repeat(gap)}${line}`\n })\n}\n\nexport function renderRecords(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n options: { rowNumbers?: boolean } = {},\n): string {\n const labelWidth = Math.min(\n 28,\n Math.max(...head.map((label) => visibleWidth(label)), 0),\n )\n const showNumbers = options.rowNumbers ?? false\n const digits = String(rows.length).length\n const blocks = rows.map((row, index) => {\n const lines: string[] = []\n if (showNumbers) {\n lines.push(context.colors.bold(String(index + 1).padStart(digits, '0')))\n }\n for (const [column, label] of head.entries()) {\n lines.push(\n ...renderRecordValue(\n label,\n styledValue(label, stringCell(row[column]), context),\n labelWidth,\n context,\n ),\n )\n }\n return lines.join('\\n')\n })\n return blocks.join('\\n\\n')\n}\n\nexport function renderTable(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n options: TableOptions = {},\n): string {\n if (rows.length === 0) return context.colors.dim('No results.')\n const useTable =\n options.layout === 'table' ||\n (options.layout !== 'records' && canRenderTable(head, rows, context))\n return useTable\n ? renderDenseTable(head, rows, context)\n : renderRecords(head, rows, context, options)\n}\n\nexport function renderKeyValues(\n rows: Array<[string, string]>,\n context: TerminalContext,\n): string {\n if (rows.length === 0) return ''\n const labelWidth = Math.min(\n 28,\n Math.max(...rows.map(([label]) => visibleWidth(label))),\n )\n return rows\n .flatMap(([label, value]) => {\n const lines = renderRecordValue(label, value, labelWidth, context)\n if (lines.length > 0) {\n const first = lines[0] ?? ''\n lines[0] = first.replace(label, context.colors.bold(label))\n }\n return lines\n })\n .join('\\n')\n}\n\nexport function renderCallout(\n callout: Callout,\n context: TerminalContext,\n): string {\n const lines = [context.colors.bold(callout.title)]\n if (callout.body) lines.push(...wrapText(callout.body, context.columns))\n if (callout.command) {\n lines.push(\n context.colors.cyan(truncateText(callout.command, context.columns)),\n )\n }\n return lines.join('\\n')\n}\n","import { type TerminalContext, wrapText } from './context.js'\n\nexport type SemanticStatus =\n | 'pass'\n | 'warning'\n | 'fail'\n | 'unknown'\n | 'info'\n | 'notApplicable'\n\nexport type SemanticDiagnostic = {\n status: SemanticStatus\n title: string\n explanation: string\n fix?: string\n evidence?: string[]\n}\n\nexport type SemanticReportSection = {\n title: string\n diagnostics: SemanticDiagnostic[]\n}\n\nexport type SemanticReportView = {\n title: string\n target?: string\n status: SemanticStatus\n summary: string\n metrics?: Array<{\n label: string\n value: string | number\n status?: SemanticStatus\n }>\n sections: SemanticReportSection[]\n notes?: string[]\n}\n\nfunction statusStyle(status: SemanticStatus, context: TerminalContext) {\n if (status === 'pass') return context.colors.green\n if (status === 'warning') return context.colors.yellow\n if (status === 'fail') return context.colors.red\n if (status === 'unknown') return context.colors.blue\n if (status === 'info') return context.colors.cyan\n return context.colors.dim\n}\n\nfunction statusLabel(status: SemanticStatus): string {\n if (status === 'warning') return 'WARN'\n if (status === 'notApplicable') return 'N/A'\n return status.toUpperCase()\n}\n\nfunction indent(value: string, spaces: number, width: number): string[] {\n const prefix = ' '.repeat(spaces)\n return wrapText(value, Math.max(1, width - spaces)).map(\n (line) => `${prefix}${line}`,\n )\n}\n\nfunction renderDiagnostic(\n diagnostic: SemanticDiagnostic,\n context: TerminalContext,\n): string {\n const style = statusStyle(diagnostic.status, context)\n const label = style(`[${statusLabel(diagnostic.status)}]`.padEnd(10))\n const titleWidth = Math.max(1, context.columns - 10)\n const titles = wrapText(diagnostic.title, titleWidth)\n const lines = titles.map(\n (line, index) =>\n `${index === 0 ? label : ' '.repeat(10)}${context.colors.bold(line)}`,\n )\n lines.push(...indent(diagnostic.explanation, 10, context.columns))\n for (const item of diagnostic.evidence ?? []) {\n const wrapped = wrapText(item, Math.max(1, context.columns - 20))\n lines.push(\n ...wrapped.map(\n (line, index) =>\n `${' '.repeat(10)}${index === 0 ? `${context.colors.dim('Evidence')} ` : ' '}${line}`,\n ),\n )\n }\n if (diagnostic.fix) {\n const wrapped = wrapText(diagnostic.fix, Math.max(1, context.columns - 15))\n lines.push(\n ...wrapped.map(\n (line, index) =>\n `${' '.repeat(10)}${index === 0 ? `${context.colors.cyan(context.colors.bold('Fix'))} ` : ' '}${line}`,\n ),\n )\n }\n return lines.join('\\n')\n}\n\nfunction renderMetrics(\n metrics: NonNullable<SemanticReportView['metrics']>,\n context: TerminalContext,\n): string {\n const line = metrics\n .map((metric) => {\n const value = String(metric.value)\n const rendered = metric.status\n ? statusStyle(metric.status, context)(value)\n : context.colors.bold(value)\n return `${metric.label} ${rendered}`\n })\n .join(context.colors.dim(' · '))\n return wrapText(line, context.columns).join('\\n')\n}\n\nexport function renderSemanticReport(\n report: SemanticReportView,\n context: TerminalContext,\n): string {\n const style = statusStyle(report.status, context)\n const output = [context.colors.bold(report.title)]\n if (report.target) output.push(context.colors.dim(report.target))\n output.push('')\n output.push(\n `${style(statusLabel(report.status))} ${wrapText(report.summary, Math.max(1, context.columns - 6)).join('\\n ')}`,\n )\n if (report.metrics?.length)\n output.push(renderMetrics(report.metrics, context))\n\n for (const section of report.sections.filter(\n (item) => item.diagnostics.length > 0,\n )) {\n output.push('', context.colors.bold(section.title))\n output.push(\n section.diagnostics\n .map((diagnostic) => renderDiagnostic(diagnostic, context))\n .join('\\n\\n'),\n )\n }\n\n if (report.notes?.length) {\n output.push('', context.colors.bold('Notes'))\n for (const note of report.notes) {\n const lines = wrapText(note, Math.max(1, context.columns - 2))\n output.push(\n ...lines.map((line, index) => `${index === 0 ? '- ' : ' '}${line}`),\n )\n }\n }\n return output.join('\\n')\n}\n","import { type TerminalContext, visibleWidth, wrapText } from './context.js'\n\nexport type CheckView = {\n detail: string\n fix?: string\n label: string\n status: 'pass' | 'warn' | 'fail'\n}\n\nexport type CatalogItemView = {\n category: string\n id: string\n name: string\n}\n\nexport type SummaryItemView = {\n description?: string\n meta?: string[]\n title: string\n}\n\nexport type ParameterView = {\n description?: string\n name: string\n required: boolean\n type: string\n}\n\nfunction plural(count: number, singular: string, multiple = `${singular}s`) {\n return count === 1 ? singular : multiple\n}\n\nfunction indented(value: string, indent: number, width: number): string[] {\n const prefix = ' '.repeat(indent)\n return wrapText(value, Math.max(1, width - indent)).map(\n (line) => `${prefix}${line}`,\n )\n}\n\nexport function renderHeading(\n title: string,\n context: TerminalContext,\n summary?: string,\n): string {\n return [\n context.colors.bold(title),\n ...(summary ? wrapText(summary, context.columns) : []),\n ].join('\\n')\n}\n\nexport function renderChecks(\n checks: CheckView[],\n context: TerminalContext,\n): string {\n const styles = {\n pass: context.colors.green,\n warn: context.colors.yellow,\n fail: context.colors.red,\n }\n return checks\n .map((check) => {\n const status = styles[check.status](check.status.toUpperCase().padEnd(4))\n const lines = [`${status} ${context.colors.bold(check.label)}`]\n lines.push(...indented(check.detail, 6, context.columns))\n if (check.fix) {\n const fixLines = wrapText(check.fix, Math.max(1, context.columns - 11))\n lines.push(\n ...fixLines.map(\n (line, index) =>\n `${' '.repeat(6)}${index === 0 ? `${context.colors.bold('Fix')} ` : ' '}${line}`,\n ),\n )\n }\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\nexport function checkSummary(checks: CheckView[]): string {\n const passed = checks.filter((check) => check.status === 'pass').length\n const warnings = checks.filter((check) => check.status === 'warn').length\n const failed = checks.filter((check) => check.status === 'fail').length\n return `${passed} ${plural(passed, 'check')} passed, ${warnings} ${plural(warnings, 'warning')}, ${failed} failed.`\n}\n\nfunction renderCatalogItem(\n item: CatalogItemView,\n idWidth: number,\n context: TerminalContext,\n): string {\n const gap = 2\n const nameWidth = context.columns - idWidth - gap - 2\n if (nameWidth < 24 || visibleWidth(item.id) > idWidth) {\n return [\n ...indented(item.id, 2, context.columns).map((line) =>\n context.colors.cyan(line),\n ),\n ...indented(item.name, 4, context.columns),\n ].join('\\n')\n }\n const names = wrapText(item.name, nameWidth)\n return names\n .map((name, index) => {\n const id = index === 0 ? item.id.padEnd(idWidth) : ''.padEnd(idWidth)\n return ` ${context.colors.cyan(id)}${' '.repeat(gap)}${name}`\n })\n .join('\\n')\n}\n\nfunction categoryLabel(category: string): string {\n const value = category.replaceAll('-', ' ')\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n\nexport function renderCatalog(\n items: CatalogItemView[],\n context: TerminalContext,\n options: {\n categoryLabels?: Record<string, string>\n noun: string\n },\n): string {\n const groups = new Map<string, CatalogItemView[]>()\n for (const item of items) {\n const group = groups.get(item.category) ?? []\n group.push(item)\n groups.set(item.category, group)\n }\n const intro = `${items.length} ${plural(items.length, options.noun)} across ${groups.size} ${plural(groups.size, 'category', 'categories')}.`\n const idWidth = Math.min(\n 30,\n Math.max(...items.map((item) => visibleWidth(item.id)), 0),\n )\n const labelledCategories = Object.keys(options.categoryLabels ?? {}).filter(\n (category) => groups.has(category),\n )\n const remainingCategories = [...groups.keys()].filter(\n (category) => !labelledCategories.includes(category),\n )\n const sections = [...labelledCategories, ...remainingCategories].map(\n (category) => {\n const entries = groups.get(category) ?? []\n const label =\n options.categoryLabels?.[category] ?? categoryLabel(category)\n return [\n context.colors.bold(`${label} (${entries.length})`),\n ...entries.map((item) => renderCatalogItem(item, idWidth, context)),\n ].join('\\n')\n },\n )\n return [intro, ...sections].join('\\n\\n')\n}\n\nexport function renderSummaryList(\n items: SummaryItemView[],\n context: TerminalContext,\n options: { empty: string },\n): string {\n if (items.length === 0) return context.colors.dim(options.empty)\n\n return items\n .map((item) => {\n const lines = [context.colors.bold(item.title)]\n if (item.description) {\n lines.push(...indented(item.description, 2, context.columns))\n }\n const meta = item.meta?.filter(Boolean).join(' · ')\n if (meta) {\n lines.push(\n ...indented(meta, 2, context.columns).map((line) =>\n context.colors.dim(line),\n ),\n )\n }\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\nexport function renderSection(\n title: string,\n paragraphs: readonly string[],\n context: TerminalContext,\n): string {\n const body = paragraphs\n .filter((paragraph) => paragraph.trim().length > 0)\n .flatMap((paragraph) => wrapText(paragraph, context.columns))\n return [context.colors.bold(title), ...body].join('\\n')\n}\n\nexport function renderBulletSection(\n title: string,\n items: readonly string[],\n context: TerminalContext,\n): string {\n const body = items.flatMap((item) => {\n const wrapped = wrapText(item, Math.max(1, context.columns - 2))\n return wrapped.map((line, index) => `${index === 0 ? '- ' : ' '}${line}`)\n })\n return [context.colors.bold(title), ...body].join('\\n')\n}\n\nexport function renderParameters(\n parameters: ParameterView[],\n context: TerminalContext,\n): string {\n if (parameters.length === 0) {\n return context.colors.dim('No parameters.')\n }\n\n return renderSummaryList(\n parameters.map((parameter) => ({\n title: parameter.name,\n description: parameter.description,\n meta: [parameter.type, parameter.required ? 'required' : 'optional'],\n })),\n context,\n { empty: 'No parameters.' },\n )\n}\n","import { createTerminalContext } from './presentation/context.js'\nimport {\n renderCallout,\n renderKeyValues,\n renderTable,\n} from './presentation/render.js'\nimport {\n renderSemanticReport,\n type SemanticReportView,\n} from './presentation/report.js'\nimport {\n type CatalogItemView,\n type CheckView,\n type ParameterView,\n renderBulletSection,\n renderCatalog,\n renderChecks,\n renderHeading,\n renderParameters,\n renderSection,\n renderSummaryList,\n type SummaryItemView,\n} from './presentation/views.js'\n\nexport function canPrompt(options: { json?: boolean } = {}): boolean {\n return Boolean(\n !options.json &&\n process.stdin.isTTY &&\n process.stdout.isTTY &&\n !process.env.CI,\n )\n}\n\nexport function printJson(data: unknown): void {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`)\n}\n\nexport function printKeyValue(rows: Array<[string, string]>): void {\n const output = renderKeyValues(rows, createTerminalContext())\n if (output) process.stdout.write(`${output}\\n`)\n}\n\nexport function printTable(\n head: string[],\n rows: Array<Array<string | number>>,\n): void {\n process.stdout.write(`${renderTable(head, rows, createTerminalContext())}\\n`)\n}\n\nexport function printCallout(callout: {\n body?: string\n command?: string\n title: string\n}): void {\n process.stdout.write(`${renderCallout(callout, createTerminalContext())}\\n`)\n}\n\nexport function printHeading(title: string, summary?: string): void {\n process.stdout.write(\n `${renderHeading(title, createTerminalContext(), summary)}\\n`,\n )\n}\n\nexport function printChecks(checks: CheckView[]): void {\n process.stdout.write(`${renderChecks(checks, createTerminalContext())}\\n`)\n}\n\nexport function printSemanticReport(report: SemanticReportView): void {\n process.stdout.write(\n `${renderSemanticReport(report, createTerminalContext())}\\n`,\n )\n}\n\nexport function printCatalog(\n items: CatalogItemView[],\n options: {\n categoryLabels?: Record<string, string>\n noun: string\n },\n): void {\n process.stdout.write(\n `${renderCatalog(items, createTerminalContext(), options)}\\n`,\n )\n}\n\nexport function printSummaryList(\n items: SummaryItemView[],\n options: { empty: string },\n): void {\n process.stdout.write(\n `${renderSummaryList(items, createTerminalContext(), options)}\\n`,\n )\n}\n\nexport function printSection(title: string, ...paragraphs: string[]): void {\n process.stdout.write(\n `${renderSection(title, paragraphs, createTerminalContext())}\\n`,\n )\n}\n\nexport function printBulletSection(\n title: string,\n items: readonly string[],\n): void {\n process.stdout.write(\n `${renderBulletSection(title, items, createTerminalContext())}\\n`,\n )\n}\n\nexport function printParameters(parameters: ParameterView[]): void {\n process.stdout.write(\n `${renderParameters(parameters, createTerminalContext())}\\n`,\n )\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport function maybeExitCancelled<T>(value: T | symbol): T {\n if (typeof value === 'symbol') {\n process.exit(1)\n }\n return value\n}\n","import { type Option, select, text } from '@clack/prompts'\nimport {\n type ClientProfile,\n ga4PropertyIdFromName,\n getClient,\n listClients,\n listGa4AccountSummaries,\n listSites,\n readConfig,\n SeoError,\n selectGoogleAccounts,\n} from '@seo/core'\nimport { canPrompt, maybeExitCancelled } from './utils.js'\n\ntype ResolveOptions = {\n allowDefault?: boolean\n json?: boolean\n refresh?: boolean\n account?: string\n}\n\ntype SiteChoice = {\n siteUrl: string\n permissionLevel?: string\n}\n\ntype GoogleAnalyticsPropertyChoice = {\n property: string\n displayName: string\n account: string\n}\n\nexport type ClientSelection = {\n client?: ClientProfile\n site: string\n}\n\nfunction selectClientGoogleAccounts(client: ClientProfile | undefined): void {\n selectGoogleAccounts(client?.googleAccounts)\n}\n\nfunction includesQuery(values: string[], query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized) return true\n return values.some((value) => value.toLowerCase().includes(normalized))\n}\n\nasync function chooseFromSearch<T>(input: {\n message: string\n searchMessage: string\n emptyMessage: string\n choices: T[]\n label: (choice: T) => string\n hint?: (choice: T) => string | undefined\n searchValues: (choice: T) => string[]\n}): Promise<T> {\n let visible = input.choices\n\n if (input.choices.length > 8) {\n const query = maybeExitCancelled(\n await text({\n message: input.searchMessage,\n placeholder: 'Type part of the name or URL, or leave blank',\n }),\n )\n visible = input.choices.filter((choice) =>\n includesQuery(input.searchValues(choice), query),\n )\n\n if (!visible.length) {\n throw new SeoError('INVALID_INPUT', input.emptyMessage)\n }\n }\n\n return maybeExitCancelled(\n await select({\n message: input.message,\n options: visible.map((choice) => {\n const hint = input.hint?.(choice)\n return {\n value: choice,\n label: input.label(choice),\n ...(hint ? { hint } : {}),\n }\n }) as Option<T>[],\n }),\n )\n}\n\nexport async function resolveSite(input: {\n site?: string\n options?: ResolveOptions\n}): Promise<string> {\n if (input.site) return input.site\n\n const config = readConfig()\n const defaultSiteKnown =\n Boolean(config.defaultSite) &&\n (config.clients.some((client) => client.siteUrl === config.defaultSite) ||\n config.sites.some((site) => site.siteUrl === config.defaultSite))\n if (\n input.options?.allowDefault !== false &&\n config.defaultSite &&\n defaultSiteKnown\n ) {\n selectClientGoogleAccounts(\n config.clients.find(\n (client) => client.isDefault && client.siteUrl === config.defaultSite,\n ),\n )\n return config.defaultSite\n }\n\n if (input.options?.json || !canPrompt()) {\n throw new SeoError(\n 'INVALID_INPUT',\n config.defaultSite\n ? `Saved default site ${config.defaultSite} does not match any saved project. Pass --site or --project, or run \\`seo start\\` to save a new default.`\n : 'No site selected. Pass --site, use --project on supported commands, or run `seo start` in a terminal.',\n )\n }\n\n const sites = await listSites(input.options?.refresh, input.options?.account)\n if (!sites.length) {\n throw new SeoError(\n 'PROPERTY_NOT_FOUND',\n 'No Search Console properties found for this Google login.',\n )\n }\n if (sites.length === 1) {\n return sites[0]?.siteUrl ?? ''\n }\n\n const choice = await chooseFromSearch<SiteChoice>({\n message: 'Choose a Search Console property',\n searchMessage: 'Search Search Console properties',\n emptyMessage: 'No Search Console properties matched that search.',\n choices: sites,\n label: (site) => site.siteUrl,\n hint: (site) => site.permissionLevel,\n searchValues: (site) => [site.siteUrl, site.permissionLevel ?? ''],\n })\n\n return choice.siteUrl\n}\n\nexport async function resolveClientSelection(input: {\n client?: string\n project?: string\n site?: string\n options?: ResolveOptions\n}): Promise<ClientSelection> {\n if (input.client && input.project && input.client !== input.project) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --project or --client, not both.',\n )\n }\n const project = input.project ?? input.client\n if (project) {\n const client = getClient(project)\n if (!client) {\n throw new SeoError('INVALID_INPUT', `Project not found: ${project}`)\n }\n selectClientGoogleAccounts(client)\n return { client, site: client.siteUrl }\n }\n\n const defaultClient = getClient()\n if (!input.site && defaultClient) {\n selectClientGoogleAccounts(defaultClient)\n return { client: defaultClient, site: defaultClient.siteUrl }\n }\n\n return {\n site: await resolveSite({ site: input.site, options: input.options }),\n }\n}\n\nexport async function resolveClient(input: {\n client?: string\n project?: string\n options?: ResolveOptions\n}): Promise<ClientProfile | undefined> {\n if (input.client && input.project && input.client !== input.project) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --project or --client, not both.',\n )\n }\n const project = input.project ?? input.client\n if (project) {\n const client = getClient(project)\n if (!client) {\n throw new SeoError('INVALID_INPUT', `Project not found: ${project}`)\n }\n selectClientGoogleAccounts(client)\n return client\n }\n\n const clients = listClients()\n if (!clients.length) return undefined\n const defaultClient = getClient()\n if (defaultClient) {\n selectClientGoogleAccounts(defaultClient)\n return defaultClient\n }\n\n if (input.options?.json || !canPrompt()) return undefined\n\n const selected = await chooseFromSearch<ClientProfile>({\n message: 'Choose a project',\n searchMessage: 'Search projects',\n emptyMessage: 'No projects matched that search.',\n choices: clients,\n label: (client) => client.name,\n hint: (client) => client.siteUrl,\n searchValues: (client) => [client.id, client.name, client.siteUrl],\n })\n selectClientGoogleAccounts(selected)\n return selected\n}\n\nexport async function resolveGoogleAnalyticsProperty(input: {\n property?: string\n options?: ResolveOptions\n}): Promise<string> {\n if (input.property) return input.property\n\n const config = readConfig()\n if (config.analytics.google.defaultPropertyId) {\n return config.analytics.google.defaultPropertyId\n }\n\n if (input.options?.json || !canPrompt()) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'No Google Analytics property selected. Pass --property or run this command in a terminal to choose one.',\n )\n }\n\n const accountSummaries = await listGa4AccountSummaries(input.options?.account)\n const choices = accountSummaries.flatMap((account) =>\n account.propertySummaries.map((property) => ({\n property: ga4PropertyIdFromName(property.property),\n displayName: property.displayName ?? property.property,\n account: account.displayName ?? account.account,\n })),\n )\n\n if (!choices.length) {\n throw new SeoError(\n 'PROPERTY_NOT_FOUND',\n 'No Google Analytics properties found for this Google login.',\n )\n }\n if (choices.length === 1) {\n return choices[0]?.property ?? ''\n }\n\n const choice = await chooseFromSearch<GoogleAnalyticsPropertyChoice>({\n message: 'Choose a Google Analytics property',\n searchMessage: 'Search Google Analytics properties',\n emptyMessage: 'No Google Analytics properties matched that search.',\n choices,\n label: (property) => `${property.displayName} (${property.property})`,\n hint: (property) => property.account,\n searchValues: (property) => [\n property.property,\n property.displayName,\n property.account,\n ],\n })\n\n return choice.property\n}\n","import { confirm, intro, note, outro, password, text } from '@clack/prompts'\nimport {\n analyticsConnection,\n CLICKY_SITEKEY_ENV,\n deleteClickySiteKey,\n deleteProviderExtensionCredentials,\n inspectProviderPackage,\n installProviderPackage,\n loadInstalledProviderExtensions,\n type RegisteredProviderExtension,\n readClickySiteKey,\n readProviderExtensionCredentials,\n removeClientAnalyticsConnection,\n runProviderExtensionAction,\n SeoError,\n setClientAnalyticsConnection,\n verifyAnalyticsProvider,\n writeClickySiteKey,\n writeProviderExtensionAccount,\n writeProviderExtensionCredentials,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../../args.js'\nimport { resolveClient } from '../../../selection.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n printTable,\n} from '../../../utils.js'\n\nconst CLICKY_PROVIDER_PACKAGE = '@seoskill/clicky-provider'\n\nfunction credentialSourceLabel(source: string | undefined): string {\n if (source === 'keychain') return 'system keychain'\n if (source === 'file') return 'private local file'\n if (source === 'provider-store') return 'provider credential store'\n return source ?? 'missing'\n}\n\nasync function clickyProvider(input: {\n json?: boolean\n}): Promise<RegisteredProviderExtension> {\n let loaded = await loadInstalledProviderExtensions()\n const installed = loaded.registry.get('clicky')\n if (installed) return installed\n const failure = loaded.failures.find((item) => item.id === 'clicky')\n if (failure) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n `The Clicky provider package could not load: ${failure.message}`,\n )\n }\n const interactive = canPrompt({ json: input.json })\n if (!interactive) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n `Clicky is now an optional provider package. Run \\`seo providers install ${CLICKY_PROVIDER_PACKAGE} --yes\\`, then run this command again.`,\n )\n }\n let release: Awaited<ReturnType<typeof inspectProviderPackage>>\n try {\n release = await inspectProviderPackage(CLICKY_PROVIDER_PACKAGE)\n } catch (error) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n error instanceof Error ? error.message : String(error),\n )\n }\n note(\n [\n `${release.package}@${release.version}`,\n `Publisher: ${release.publisher ?? 'not supplied by npm'}`,\n `Repository: ${release.repository ?? 'not supplied by npm'}`,\n `Integrity: ${release.integrity}`,\n ].join('\\n'),\n 'Clicky package',\n )\n note(\n 'This package can read files, use the network, and run with the same local permissions as seo.',\n 'Local permissions',\n )\n const approved = maybeExitCancelled(\n await confirm({\n message: 'Install the Clicky provider package?',\n initialValue: true,\n }),\n )\n if (!approved) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider package is required for this command.',\n )\n }\n await installProviderPackage(release)\n loaded = await loadInstalledProviderExtensions()\n const provider = loaded.registry.get('clicky')\n if (!provider) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider package was installed but could not load. Run `seo providers doctor`.',\n )\n }\n return provider\n}\n\nasync function resolveClickySiteId(input: {\n siteId?: string\n project?: string\n json?: boolean\n}): Promise<string> {\n if (input.siteId) return input.siteId\n const client = await resolveClient({\n client: input.project,\n options: { json: input.json },\n })\n const connection = analyticsConnection(client)\n if (connection?.provider === 'clicky') return connection.siteId\n if (\n connection?.provider === 'extension' &&\n connection.providerId === 'clicky' &&\n connection.account.siteId\n ) {\n return connection.account.siteId\n }\n throw new SeoError(\n 'INVALID_INPUT',\n 'No Clicky site is selected. Pass --site-id or use a project connected to Clicky.',\n )\n}\n\nasync function savedCredentials(\n provider: RegisteredProviderExtension,\n siteId: string,\n): Promise<{ siteKey?: string; source?: string }> {\n const legacy = await readClickySiteKey(siteId)\n if (legacy) return { siteKey: legacy.siteKey, source: legacy.source }\n try {\n const credentials = await readProviderExtensionCredentials({\n providerId: 'clicky',\n account: { siteId },\n fields: provider.connection.fields,\n })\n return credentials.sitekey\n ? { siteKey: credentials.sitekey, source: 'provider-store' }\n : {}\n } catch {\n return {}\n }\n}\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save a Clicky sitekey',\n },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const provider = await clickyProvider({ json })\n const interactive = canPrompt({ json })\n const requestedProject = projectArg(args)\n const project = requestedProject\n ? await resolveClient({ project: requestedProject, options: { json } })\n : undefined\n if (interactive) intro('Connect Clicky')\n const currentConnection = analyticsConnection(project)\n const currentSiteId =\n currentConnection?.provider === 'clicky'\n ? currentConnection.siteId\n : currentConnection?.provider === 'extension' &&\n currentConnection.providerId === 'clicky'\n ? currentConnection.account.siteId\n : undefined\n const siteId =\n stringArg(args['site-id']) ??\n currentSiteId ??\n (interactive\n ? maybeExitCancelled(\n await text({\n message: 'Clicky site ID',\n validate: (value) =>\n /^\\d{1,30}$/u.test(value?.trim() ?? '')\n ? undefined\n : 'Enter the numeric site ID from Clicky',\n }),\n )\n : undefined)\n if (!siteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass --site-id when the selected project is not already connected to Clicky.',\n )\n }\n const existing = await savedCredentials(provider, siteId)\n const siteKey =\n existing.siteKey ??\n (interactive\n ? maybeExitCancelled(\n await password({\n message: 'Clicky sitekey',\n validate: (value) =>\n /^[A-Za-z0-9]{12,64}$/u.test(value?.trim() ?? '')\n ? undefined\n : 'Enter the sitekey from Clicky',\n }),\n )\n : undefined)\n if (!siteKey) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run this command in a terminal or set ${CLICKY_SITEKEY_ENV}.`,\n )\n }\n await verifyAnalyticsProvider({\n providerId: 'clicky',\n account: { siteId },\n credentials: { sitekey: siteKey },\n })\n const source =\n existing.source ?? (await writeClickySiteKey(siteId, siteKey))\n await writeProviderExtensionCredentials({\n providerId: 'clicky',\n account: { siteId },\n credentials: { sitekey: siteKey },\n })\n writeProviderExtensionAccount('clicky', { siteId })\n const savedProject = project\n ? setClientAnalyticsConnection(project.id, {\n provider: 'extension',\n providerId: 'clicky',\n account: { siteId },\n })\n : undefined\n const result = {\n siteId,\n connected: true,\n credentialSource: source,\n project: savedProject\n ? { id: savedProject.id, name: savedProject.name }\n : undefined,\n }\n if (json) {\n printJson(result)\n return\n }\n const message = savedProject\n ? `Connection verified and attached to ${savedProject.name}. Saved in the ${credentialSourceLabel(source)}.`\n : `Connection verified. Saved in the ${credentialSourceLabel(source)}.`\n if (interactive) outro(message)\n else process.stdout.write(`${message}\\n`)\n },\n})\n\nconst statusCommand = defineCommand({\n meta: { name: 'status', description: 'Show the local Clicky connection' },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n check: {\n type: 'boolean',\n default: false,\n description: 'Verify the saved sitekey with Clicky.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const provider = await clickyProvider({ json })\n const siteId = await resolveClickySiteId({\n siteId: stringArg(args['site-id']),\n project: projectArg(args),\n json,\n })\n const credential = await savedCredentials(provider, siteId)\n const check = booleanArg(args.check)\n if (check && credential.siteKey) {\n await verifyAnalyticsProvider({\n providerId: 'clicky',\n account: { siteId },\n credentials: { sitekey: credential.siteKey },\n })\n }\n const result = {\n siteId,\n connected: Boolean(credential.siteKey),\n credentialSource: credential.source,\n liveCheck: check\n ? credential.siteKey\n ? ('passed' as const)\n : ('unavailable' as const)\n : ('not-requested' as const),\n }\n if (json) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Site ID', siteId],\n ['Connected', result.connected ? 'yes' : 'no'],\n ['Credential', credentialSourceLabel(result.credentialSource)],\n ['Live check', result.liveCheck],\n ])\n },\n})\n\nconst reportCommand = defineCommand({\n meta: {\n name: 'report',\n description: 'Run a bounded Clicky analytics report',\n },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n type: {\n type: 'string',\n default: 'pages-entrance',\n description: 'Clicky report type. Defaults to pages-entrance.',\n },\n 'start-date': {\n type: 'string',\n required: true,\n description: 'First site calendar date in YYYY-MM-DD format.',\n },\n 'end-date': {\n type: 'string',\n required: true,\n description: 'Last site calendar date in YYYY-MM-DD format.',\n },\n limit: {\n type: 'string',\n default: '100',\n description: 'Maximum retained rows. Defaults to 100 and caps at 5000.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local Clicky cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const provider = await clickyProvider({ json })\n const siteId = await resolveClickySiteId({\n siteId: stringArg(args['site-id']),\n project: projectArg(args),\n json,\n })\n const credential = await savedCredentials(provider, siteId)\n const action = await runProviderExtensionAction({\n providerId: 'clicky',\n actionId: 'report',\n account: { siteId },\n ...(credential.siteKey\n ? { credentials: { sitekey: credential.siteKey } }\n : {}),\n params: {\n type: stringArg(args.type) ?? 'pages-entrance',\n startDate: stringArg(args['start-date']) ?? '',\n endDate: stringArg(args['end-date']) ?? '',\n limit: numberArg(args.limit) ?? 100,\n },\n refresh: booleanArg(args.refresh),\n })\n if (!action.data || typeof action.data !== 'object') {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider returned an invalid report.',\n )\n }\n const result = {\n ...(action.data as Record<string, unknown>),\n cache: action.cache,\n } as {\n siteId: string\n type: string\n rows: Array<Record<string, unknown>>\n returnedRows: number\n cache: string\n }\n if (json) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Site ID', result.siteId],\n ['Report', result.type],\n ['Rows', String(result.returnedRows)],\n ['Cache', result.cache],\n ])\n printTable(\n ['Value', 'Title', 'URL'],\n result.rows\n .slice(0, 25)\n .map((row) => [\n String(row.value ?? ''),\n String(row.title ?? ''),\n String(row.url ?? ''),\n ]),\n )\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: { name: 'disconnect', description: 'Remove a saved Clicky sitekey' },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n await clickyProvider({ json })\n const siteId = await resolveClickySiteId({\n siteId: stringArg(args['site-id']),\n project: projectArg(args),\n json,\n })\n await deleteClickySiteKey(siteId)\n await deleteProviderExtensionCredentials({\n providerId: 'clicky',\n account: { siteId },\n })\n const environmentCredential = Boolean(process.env[CLICKY_SITEKEY_ENV])\n const result = {\n siteId,\n savedCredentialRemoved: true,\n environmentCredential: environmentCredential ? 'active' : 'missing',\n }\n if (json) printJson(result)\n else\n process.stdout.write(\n environmentCredential\n ? `Saved sitekey removed. ${CLICKY_SITEKEY_ENV} is still active.\\n`\n : 'Clicky is disconnected for this site.\\n',\n )\n },\n})\n\nconst detachCommand = defineCommand({\n meta: {\n name: 'detach',\n description: 'Remove Clicky from one project without deleting its sitekey',\n },\n args: {\n project: {\n type: 'string',\n required: true,\n description: 'Saved project id or name.',\n },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = await resolveClient({\n project: projectArg(args),\n options: { json },\n })\n const selected = analyticsConnection(project)\n const provider =\n selected?.provider === 'extension' && selected.providerId === 'clicky'\n ? ('extension:clicky' as const)\n : selected?.provider === 'clicky'\n ? ('clicky' as const)\n : undefined\n if (!project || !provider) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'The selected project is not attached to Clicky.',\n )\n }\n const updated = removeClientAnalyticsConnection(project.id, provider)\n const result = {\n project: { id: updated.id, name: updated.name },\n detached: true,\n selectedAnalytics: updated.analytics.selected,\n savedSitekey: true,\n }\n if (json) printJson(result)\n else\n process.stdout.write(\n `Clicky detached from ${updated.name}. The saved sitekey was kept.\\n`,\n )\n },\n})\n\nexport const clickyAnalyticsCommand = defineCommand({\n meta: {\n name: 'clicky',\n description: 'Connect Clicky and read bounded analytics reports',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n report: reportCommand,\n detach: detachCommand,\n disconnect: disconnectCommand,\n },\n})\n","import {\n ga4PropertyIdFromName,\n listGa4AccountSummaries,\n readConfig,\n writeConfig,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson, printTable } from '../../../utils.js'\n\nexport const googleAnalyticsPropertiesCommand = defineCommand({\n meta: {\n name: 'properties',\n description: 'List Google Analytics accounts and properties',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n save: {\n type: 'string',\n description:\n 'Save this numeric Google Analytics property ID as the default.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n },\n run: async ({ args }) => {\n const summaries = await listGa4AccountSummaries(stringArg(args.account))\n const rows = summaries.flatMap((account) =>\n account.propertySummaries.map((property) => ({\n account: account.displayName ?? account.account,\n property: ga4PropertyIdFromName(property.property),\n displayName: property.displayName ?? property.property,\n })),\n )\n\n const save = stringArg(args.save)\n if (save) {\n const config = readConfig()\n config.analytics.google.defaultPropertyId = save\n writeConfig(config)\n }\n\n if (jsonFlag(args)) {\n printJson({ accountSummaries: summaries, properties: rows, saved: save })\n return\n }\n if (save) {\n process.stdout.write(`Saved default Google Analytics property ${save}.\\n`)\n }\n printTable(\n ['Property', 'Name', 'Account'],\n rows.map((row) => [row.property, row.displayName, row.account]),\n )\n },\n})\n","import { truncateText } from '../presentation/context.js'\nimport type {\n SemanticDiagnostic,\n SemanticReportView,\n SemanticStatus,\n} from '../presentation/report.js'\nimport { printSemanticReport, printTable } from '../utils.js'\n\nconst HUMAN_ROW_LIMIT = 25\ntype TableRow = Array<string | number>\ntype ActionDetail = {\n label: string\n action: string\n context?: string\n}\n\ntype ReportMetric = {\n label: string\n value: string | number\n status?: SemanticStatus\n}\n\ntype ReportSummary = {\n title: string\n target?: string\n status: SemanticStatus\n summary: string\n metrics?: ReportMetric[]\n diagnostics?: {\n title: string\n items: SemanticDiagnostic[]\n }[]\n notes?: string[]\n}\n\nexport function formatCount(value: number): string {\n return Math.round(value).toLocaleString('en-GB')\n}\n\nexport function formatPosition(value: number): string {\n return value.toFixed(1)\n}\n\nexport function formatPercent(value: number): string {\n return `${(value * 100).toFixed(1)}%`\n}\n\nexport function truncate(value: string, maxLength = 72): string {\n return truncateText(value, maxLength)\n}\n\nexport function verificationSummary(report: {\n verification?: { requested: boolean; verified: number; failed: number }\n}): string {\n if (!report.verification?.requested) return 'off'\n return `${report.verification.verified} checked, ${report.verification.failed} failed`\n}\n\nexport function reportSummaryView(summary: ReportSummary): SemanticReportView {\n return {\n title: summary.title,\n target: summary.target,\n status: summary.status,\n summary: summary.summary,\n metrics: summary.metrics,\n sections: (summary.diagnostics ?? []).map((section) => ({\n title: section.title,\n diagnostics: section.items,\n })),\n notes: summary.notes,\n }\n}\n\nexport function printReportSummary(summary: ReportSummary): void {\n printSemanticReport(reportSummaryView(summary))\n}\n\nexport function printLimitedTable(head: string[], rows: TableRow[]): void {\n printTable(head, rows.slice(0, HUMAN_ROW_LIMIT))\n if (rows.length > HUMAN_ROW_LIMIT) {\n process.stdout.write(\n `Showing ${HUMAN_ROW_LIMIT} of ${rows.length}. Use --json for full data.\\n`,\n )\n }\n}\n\nexport function printActionDetails(\n title: string,\n actions: ActionDetail[],\n limit = 5,\n): void {\n const visible = actions\n .filter((item) => item.action.trim().length > 0)\n .slice(0, limit)\n const report = actionDetailsView(title, visible)\n if (!report) return\n\n process.stdout.write('\\n')\n printSemanticReport(report)\n if (actions.length > visible.length) {\n process.stdout.write(\n `Showing ${visible.length} of ${actions.length}. Use --json for full data.\\n`,\n )\n }\n}\n\nexport function actionDetailsView(\n title: string,\n actions: ActionDetail[],\n): SemanticReportView | undefined {\n if (!actions.length) return undefined\n return {\n title,\n status: 'info',\n summary: `${actions.length} ${actions.length === 1 ? 'action' : 'actions'} shown.`,\n sections: [\n {\n title: 'Actions',\n diagnostics: actions.map((item) => ({\n status: 'info',\n title: item.label,\n explanation:\n item.context ?? 'Review the evidence before making changes.',\n fix: item.action,\n })),\n },\n ],\n }\n}\n\nexport function printNextCommand(command: string): void {\n process.stdout.write(`\\nNext: ${command}\\n`)\n}\n\nexport function printNotes(title: string, notes: string[]): void {\n const visible = notes.filter((note) => note.trim().length > 0)\n if (!visible.length) return\n process.stdout.write(`\\n${title}\\n`)\n for (const note of visible) {\n process.stdout.write(`- ${note}\\n`)\n }\n}\n","import {\n ga4RowsToObjects,\n googleAnalyticsPropertyId,\n runGa4Report,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonBodyArg,\n jsonFlag,\n projectArg,\n stringArg,\n} from '../../../args.js'\nimport {\n resolveClient,\n resolveGoogleAnalyticsProperty,\n} from '../../../selection.js'\nimport { printJson, printTable } from '../../../utils.js'\nimport { printReportSummary } from '../../output.js'\n\ntype GoogleAnalyticsPropertySelectionDependencies = {\n resolveClient: typeof resolveClient\n resolveGoogleAnalyticsProperty: typeof resolveGoogleAnalyticsProperty\n}\n\nexport async function resolveGoogleAnalyticsReportProperty(\n input: {\n property?: string\n project?: string\n options?: { json?: boolean; account?: string }\n },\n dependencies: GoogleAnalyticsPropertySelectionDependencies = {\n resolveClient,\n resolveGoogleAnalyticsProperty,\n },\n): Promise<string> {\n if (input.property) {\n return dependencies.resolveGoogleAnalyticsProperty({\n property: input.property,\n options: input.options,\n })\n }\n\n const client = await dependencies.resolveClient({\n client: input.project,\n options: input.options,\n })\n return dependencies.resolveGoogleAnalyticsProperty({\n property: googleAnalyticsPropertyId(client),\n options: input.options,\n })\n}\n\nexport const googleAnalyticsReportCommand = defineCommand({\n meta: {\n name: 'report',\n description: 'Run a Google Analytics report',\n },\n args: {\n property: {\n type: 'string',\n description:\n 'Google Analytics property ID. If omitted in a terminal, choose one.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description:\n 'Saved project id or name with an optional Google Analytics property.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n 'start-date': { type: 'string', default: '28daysAgo' },\n 'end-date': { type: 'string', default: 'yesterday' },\n dimensions: { type: 'string', default: 'landingPage' },\n metrics: { type: 'string', default: 'sessions,totalUsers,eventCount' },\n limit: { type: 'string', default: '25' },\n body: { type: 'string' },\n 'body-file': { type: 'string' },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local Google Analytics cache.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const property = await resolveGoogleAnalyticsReportProperty({\n property: stringArg(args.property),\n project: projectArg(args),\n options: { json, account: stringArg(args.account) },\n })\n const body =\n (await jsonBodyArg(args.body, args['body-file'])) ??\n ({\n dateRanges: [\n {\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n },\n ],\n dimensions: (csvArg(args.dimensions) ?? []).map((name) => ({ name })),\n metrics: (csvArg(args.metrics) ?? []).map((name) => ({ name })),\n limit: stringArg(args.limit),\n } as Record<string, unknown>)\n const result = await runGa4Report(property, body as never, {\n refresh: booleanArg(args.refresh),\n accountEmail: stringArg(args.account),\n })\n if (json) {\n printJson(result)\n return\n }\n const rows = ga4RowsToObjects(result)\n printReportSummary({\n title: 'Google Analytics report',\n target: property,\n status: 'info',\n summary: `${result.rowCount ?? rows.length} rows returned for the requested dimensions and metrics.`,\n metrics: [\n { label: 'Rows', value: result.rowCount ?? rows.length },\n { label: 'Displayed', value: Math.min(rows.length, 25) },\n ],\n })\n if (rows.length) {\n const headings = Object.keys(rows[0] ?? {})\n printTable(\n headings,\n rows\n .slice(0, 25)\n .map((row) => headings.map((heading) => row[heading] ?? '')),\n )\n }\n },\n})\n","import { defineCommand } from 'citty'\nimport { googleAnalyticsPropertiesCommand } from './properties.js'\nimport { googleAnalyticsReportCommand } from './report.js'\n\nexport const googleAnalyticsCommand = defineCommand({\n meta: {\n name: 'google',\n description: 'Read Google Analytics properties and reports',\n },\n subCommands: {\n properties: googleAnalyticsPropertiesCommand,\n report: googleAnalyticsReportCommand,\n },\n})\n","import { defineCommand } from 'citty'\nimport { clickyAnalyticsCommand } from './clicky/index.js'\nimport { googleAnalyticsCommand } from './google/index.js'\n\nexport const analyticsCommand = defineCommand({\n meta: {\n name: 'analytics',\n description: 'Read analytics data from connected providers',\n },\n subCommands: {\n clicky: clickyAnalyticsCommand,\n google: googleAnalyticsCommand,\n },\n})\n","import { note } from '@clack/prompts'\nimport { loginWithLoopback, type StoredTokens } from '@seo/core'\n\nexport function googleLoginGuidance(): string {\n return 'Your browser will open. Choose your Google account and select all permission boxes for read-only access. Keep this terminal open and finish the browser steps within five minutes.'\n}\n\nexport async function loginWithGuidance(): Promise<StoredTokens> {\n note(googleLoginGuidance(), 'Google sign-in')\n return loginWithLoopback()\n}\n","import { intro, note, outro, password, text } from '@clack/prompts'\nimport {\n authStatus,\n deleteTokens,\n formatRelativeExpiry,\n getSeoCliPaths,\n getTokenStorageStatus,\n listGoogleAccounts,\n readTokens,\n refreshAuthToken,\n SeoError,\n setActiveGoogleAccount,\n setTokenStorageMode,\n writeOauthClient,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n} from '../utils.js'\nimport { loginWithGuidance } from './google-login.js'\n\nfunction serviceAccountSource(source?: string): string {\n if (!source) return 'invalid or conflicting configuration'\n if (source === 'environment-json') {\n return 'SEO_GOOGLE_SERVICE_ACCOUNT_JSON'\n }\n if (source === 'environment-file') {\n return 'SEO_GOOGLE_SERVICE_ACCOUNT_FILE'\n }\n return 'GOOGLE_APPLICATION_CREDENTIALS'\n}\n\nfunction tokenStorageLabel(input: {\n configured: 'keychain' | 'file'\n active: 'keychain' | 'file'\n reason?: string\n}): string {\n if (input.active === 'keychain') return 'system keychain'\n return input.configured === 'keychain'\n ? 'private file fallback'\n : 'private file'\n}\n\nfunction oauthClientLabel(source: 'shared' | 'byo'): string {\n return source === 'shared' ? 'SEO Skill app' : 'Local OAuth config'\n}\n\nfunction oauthIdentityRows(input: {\n accountEmail: string\n clientSource: 'shared' | 'byo'\n expiresAt: number\n scope: string\n}): Array<[string, string]> {\n const rows: Array<[string, string]> = [['Account', input.accountEmail]]\n const scopes = new Set(input.scope.split(/\\s+/u).filter(Boolean))\n\n if (scopes.has('https://www.googleapis.com/auth/webmasters.readonly')) {\n rows.push(['Search Console', 'Read only'])\n } else {\n rows.push(['Search Console', 'Not granted'])\n }\n if (scopes.has('https://www.googleapis.com/auth/analytics.readonly')) {\n rows.push(['Google Analytics', 'Read only'])\n } else {\n rows.push(['Google Analytics', 'Not granted'])\n }\n rows.push(\n ['OAuth app', oauthClientLabel(input.clientSource)],\n ['Expires', formatRelativeExpiry(input.expiresAt)],\n )\n return rows\n}\n\nexport const authCommand = defineCommand({\n meta: {\n name: 'auth',\n description: 'Authentication commands',\n },\n subCommands: {\n login: defineCommand({\n meta: { name: 'login', description: 'Run Google OAuth flow' },\n run: async () => {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n throw new SeoError(\n 'AUTH_CONFIG_REQUIRED',\n 'A service account is active from the environment. Unset its credential variable before running browser OAuth.',\n )\n }\n const tokens = await loginWithGuidance()\n printKeyValue(\n oauthIdentityRows({\n accountEmail: tokens.account_email,\n clientSource: tokens.client_source,\n expiresAt: tokens.expires_at,\n scope: tokens.scope,\n }),\n )\n },\n }),\n logout: defineCommand({\n meta: { name: 'logout', description: 'Delete a local Google login' },\n args: {\n account: {\n type: 'string',\n description: 'Delete the login for this Google account.',\n },\n all: {\n type: 'boolean',\n default: false,\n description: 'Delete every saved Google login.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n const account = stringArg(args.account)\n if (account && args.all) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --account or --all, not both.',\n )\n }\n const targetAccount = args.all\n ? undefined\n : (account ??\n status.accounts.find((savedAccount) => savedAccount.active)\n ?.accountEmail)\n await deleteTokens(targetAccount)\n if (status.activeMode === 'service-account') {\n process.stdout.write(\n `${args.all ? 'Deleted all local Google logins.' : targetAccount ? `Deleted the local login for ${targetAccount}.` : 'No local Google login was found.'} Service account credentials remain available through the environment.\\n`,\n )\n return\n }\n process.stdout.write(\n `${args.all ? 'Deleted all local Google logins.' : targetAccount ? `Deleted the local login for ${targetAccount}.` : 'No local Google login was found.'}\\nRevoke at https://myaccount.google.com/permissions if you also want Google to forget the grant.\\n`,\n )\n },\n }),\n whoami: defineCommand({\n meta: {\n name: 'whoami',\n description: 'Show the signed-in Google account',\n },\n args: {\n account: {\n type: 'string',\n description: 'Show this saved Google account.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n const result = {\n mode: 'service-account',\n account: status.identity ?? null,\n source: serviceAccountSource(status.serviceAccount.source),\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Account type', 'Service account'],\n ['Account', status.identity ?? 'Invalid configuration'],\n ['Credentials', result.source],\n ['Access', 'Search Console and Google Analytics, read only'],\n ])\n return\n }\n const requestedAccount = stringArg(args.account)\n const tokens = requestedAccount\n ? await readTokens(requestedAccount)\n : status.tokens\n if (requestedAccount && !tokens) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${requestedAccount} is not connected.`,\n )\n }\n if (!tokens) {\n if (jsonFlag(args)) {\n printJson({ mode: 'oauth', account: null })\n return\n }\n process.stdout.write('Not logged in.\\n')\n return\n }\n if (jsonFlag(args)) {\n printJson({\n mode: 'oauth',\n account: tokens.account_email,\n scopes: tokens.scope.split(/\\s+/u).filter(Boolean),\n clientSource: tokens.client_source,\n expiresAt: tokens.expires_at,\n })\n return\n }\n printKeyValue(\n oauthIdentityRows({\n accountEmail: tokens.account_email,\n clientSource: tokens.client_source,\n expiresAt: tokens.expires_at,\n scope: tokens.scope,\n }),\n )\n },\n }),\n status: defineCommand({\n meta: {\n name: 'status',\n description: 'Show local Google auth status',\n },\n args: {\n account: {\n type: 'string',\n description: 'Show status for this saved Google account.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n const requestedAccount = stringArg(args.account)\n const selectedTokens = requestedAccount\n ? await readTokens(requestedAccount)\n : status.tokens\n if (\n requestedAccount &&\n !selectedTokens &&\n status.activeMode !== 'service-account'\n ) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${requestedAccount} is not connected.`,\n )\n }\n const storage =\n status.activeMode === 'oauth'\n ? await getTokenStorageStatus()\n : undefined\n if (jsonFlag(args)) {\n printJson({\n authenticated:\n status.activeMode === 'oauth'\n ? Boolean(selectedTokens)\n : status.serviceAccount.configured,\n mode: status.activeMode,\n identity: status.identity,\n account:\n status.activeMode === 'oauth'\n ? selectedTokens?.account_email\n : undefined,\n scopes:\n status.activeMode === 'oauth' ? selectedTokens?.scope : undefined,\n clientSource:\n status.activeMode === 'oauth'\n ? selectedTokens?.client_source\n : undefined,\n expiresAt:\n status.activeMode === 'oauth'\n ? selectedTokens?.expires_at\n : undefined,\n sharedConfigured: status.sharedConfigured,\n byoConfigured: status.byoConfigured,\n serviceAccount: {\n configured: status.serviceAccount.configured,\n identity: status.serviceAccount.identity,\n source: status.serviceAccount.source,\n error: status.serviceAccount.error,\n },\n accounts: status.accounts,\n ...(storage ? { tokenStorage: storage } : {}),\n })\n return\n }\n if (status.activeMode === 'service-account') {\n const rows: Array<[string, string]> = [\n ['Mode', 'service account'],\n ['Identity', status.identity ?? 'unavailable'],\n ['Source', serviceAccountSource(status.serviceAccount.source)],\n ['Scopes', 'Search Console readonly, Google Analytics readonly'],\n ['Storage', 'credentials stay in the environment'],\n ]\n if (status.serviceAccount.error) {\n rows.push(['Status', status.serviceAccount.error])\n }\n printKeyValue(rows)\n return\n }\n if (!selectedTokens) {\n const authMode = status.serviceAccount.error\n ? status.serviceAccount.error\n : status.sharedConfigured\n ? 'Shared seo app available'\n : status.byoConfigured\n ? 'Local OAuth config available'\n : 'No OAuth client configured'\n process.stdout.write(\n `Not logged in. ${authMode}. Run \\`seo auth login\\` to connect Google.\\n`,\n )\n return\n }\n const tokenStorage = storage ?? (await getTokenStorageStatus())\n printKeyValue([\n ['Account', selectedTokens.account_email],\n ['Connected accounts', String(status.accounts.length)],\n ['Scopes', selectedTokens.scope],\n ['Client', oauthClientLabel(selectedTokens.client_source)],\n ['Expires', formatRelativeExpiry(selectedTokens.expires_at)],\n ['Tokens file', getSeoCliPaths().tokensFile],\n ['Token storage', tokenStorageLabel(tokenStorage)],\n ...(tokenStorage.reason\n ? [['Storage note', tokenStorage.reason] as [string, string]]\n : []),\n [\n 'OAuth mode',\n status.sharedConfigured\n ? 'SEO Skill app available'\n : status.byoConfigured\n ? 'Local OAuth config available'\n : 'missing',\n ],\n ['Revoke at', 'https://myaccount.google.com/permissions'],\n ])\n },\n }),\n storage: defineCommand({\n meta: {\n name: 'storage',\n description: 'Show or change local OAuth token storage',\n },\n args: {\n keychain: {\n type: 'boolean',\n default: false,\n description:\n 'Store OAuth tokens in the system keychain when available.',\n },\n file: {\n type: 'boolean',\n default: false,\n description: 'Store OAuth tokens in the private local file.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (args.keychain && args.file) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Choose either --keychain or --file, not both.',\n )\n }\n const storage =\n args.keychain || args.file\n ? await setTokenStorageMode(args.keychain ? 'keychain' : 'file')\n : await getTokenStorageStatus()\n\n if (jsonFlag(args)) {\n printJson(storage)\n return\n }\n\n printKeyValue([\n ['Configured storage', storage.configured],\n ['Active storage', tokenStorageLabel(storage)],\n ...(storage.reason\n ? [['Note', storage.reason] as [string, string]]\n : []),\n ])\n },\n }),\n refresh: defineCommand({\n meta: {\n name: 'refresh',\n description: 'Refresh the Google OAuth token',\n },\n args: {\n account: {\n type: 'string',\n description: 'Refresh this saved Google account.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n process.stdout.write(\n 'Service accounts request short-lived Google tokens automatically. No local refresh token is stored.\\n',\n )\n return\n }\n const tokens = await refreshAuthToken(stringArg(args.account))\n process.stdout.write(\n `Refreshed. New expiry ${new Date(tokens.expires_at).toISOString()}.\\n`,\n )\n },\n }),\n accounts: defineCommand({\n meta: {\n name: 'accounts',\n description: 'List saved Google accounts',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const accounts = listGoogleAccounts()\n if (jsonFlag(args)) {\n printJson({ accounts })\n return\n }\n if (accounts.length === 0) {\n process.stdout.write('No Google accounts are connected.\\n')\n return\n }\n printKeyValue(\n accounts.map((account) => [\n account.active ? 'Active account' : 'Account',\n account.accountEmail,\n ]),\n )\n },\n }),\n use: defineCommand({\n meta: {\n name: 'use',\n description: 'Select the default Google account',\n },\n args: {\n account: {\n type: 'positional',\n required: true,\n description: 'Saved Google account email.',\n },\n },\n run: ({ args }) => {\n const account = stringArg(args.account)\n if (!account) {\n throw new SeoError('INVALID_INPUT', 'Google account is required.')\n }\n setActiveGoogleAccount(account)\n process.stdout.write(`Default Google account: ${account}\\n`)\n },\n }),\n 'setup-client': defineCommand({\n meta: {\n name: 'setup-client',\n description: 'Save your own Google Desktop OAuth client',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Return a structured error instead of prompting.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'INVALID_INPUT',\n '`seo auth setup-client` needs an interactive terminal. Run it without --json, or set SEO_GOOGLE_CLIENT_ID and SEO_GOOGLE_CLIENT_SECRET.',\n )\n }\n intro('Local Google OAuth client')\n note(\n [\n 'This is the advanced path.',\n 'Most users should use the shared seo Google app.',\n 'Your actual sensitive data is the local refresh token, not the desktop app client secret.',\n ].join('\\n'),\n 'Advanced',\n )\n const clientId = maybeExitCancelled(\n await text({\n message: 'Google Desktop OAuth client ID',\n validate: (value) => (value ? undefined : 'Client ID is required'),\n }),\n )\n const clientSecret = maybeExitCancelled(\n await password({\n message: 'Google Desktop OAuth client secret',\n validate: (value) =>\n value ? undefined : 'Client secret is required',\n }),\n )\n writeOauthClient({ clientId, clientSecret })\n outro(`Saved local OAuth config to ${getSeoCliPaths().oauthClientFile}`)\n },\n }),\n },\n})\n","import { clearCache, getCacheStats, SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { formatBytes, printKeyValue } from '../utils.js'\n\nconst CACHE_PROVIDERS = [\n 'gsc',\n 'google-analytics',\n 'dataforseo',\n 'ahrefs',\n 'clicky',\n 'http',\n] as const\n\nfunction cacheProvider(\n value: unknown,\n): (typeof CACHE_PROVIDERS)[number] | undefined {\n if (value === undefined) return undefined\n if (\n typeof value === 'string' &&\n CACHE_PROVIDERS.includes(value as (typeof CACHE_PROVIDERS)[number])\n ) {\n return value as (typeof CACHE_PROVIDERS)[number]\n }\n throw new SeoError(\n 'INVALID_INPUT',\n `--provider must be one of: ${CACHE_PROVIDERS.join(', ')}.`,\n )\n}\n\nexport const cacheCommand = defineCommand({\n meta: { name: 'cache', description: 'Cache helpers' },\n subCommands: {\n stats: defineCommand({\n meta: {\n name: 'stats',\n description: 'Show local cache size and row counts',\n },\n run: async () => {\n const stats = getCacheStats()\n printKeyValue([\n ['DB', stats.dbPath],\n ['Size', formatBytes(stats.sizeBytes)],\n [\n 'Cached data',\n `${formatBytes(stats.logicalSizeBytes)} of ${formatBytes(stats.maxSizeBytes)} automatic limit`,\n ],\n ['Sites', String(stats.counts.sites ?? 0)],\n ['Search Console', String(stats.counts.gsc_cache ?? 0)],\n [\n 'Google Analytics',\n String(stats.counts.google_analytics_cache ?? 0),\n ],\n ['DataForSEO', String(stats.counts.provider_cache ?? 0)],\n ['Ahrefs', String(stats.counts.ahrefs_cache ?? 0)],\n ['Clicky', String(stats.counts.clicky_cache ?? 0)],\n ['HTTP', String(stats.counts.http_cache ?? 0)],\n ])\n },\n }),\n clear: defineCommand({\n meta: {\n name: 'clear',\n description: 'Clear cached API and HTTP data',\n },\n args: {\n provider: {\n type: 'string',\n description:\n 'Optional cache provider: gsc, google-analytics, dataforseo, ahrefs, clicky, or http',\n },\n },\n run: async ({ args }) => {\n const removed = clearCache(cacheProvider(args.provider))\n process.stdout.write(`Removed ${removed} cached rows.\\n`)\n },\n }),\n },\n})\n","import type {\n PageFetchDiagnostics,\n QueryContentClassification,\n} from '@seo/core'\nimport { resolveClientSelection } from '../selection.js'\n\nexport async function selectedSiteOrThrow(\n input: {\n client?: string\n project?: string\n site?: string\n },\n options: { json?: boolean; refresh?: boolean; account?: string } = {},\n): Promise<string> {\n return (\n await resolveClientSelection({\n client: input.client,\n project: input.project,\n site: input.site,\n options,\n })\n ).site\n}\n\nexport function startUrlForSite(site: string): string | undefined {\n if (site.startsWith('http://') || site.startsWith('https://')) return site\n if (site.startsWith('sc-domain:')) return `https://${site.slice(10)}/`\n return undefined\n}\n\nexport function suggestedClientName(site: string): string {\n return site.replace(/^sc-domain:/, '').replace(/^https?:\\/\\//, '')\n}\n\nexport function slugId(value: string): string {\n return value\n .toLowerCase()\n .replace(/^https?:\\/\\//, '')\n .replace(/^sc-domain:/, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60)\n}\n\nexport function formatFetchDiagnostics(\n diagnostics?: PageFetchDiagnostics,\n): string {\n if (!diagnostics) return '-'\n if (diagnostics.backpressure?.status === 'stopped') {\n return `stopped: ${diagnostics.backpressure.reason ?? 'origin cooldown'}`\n }\n if (diagnostics.backpressure?.status === 'slowed') {\n return `slowed ${diagnostics.backpressure.delayMs}ms`\n }\n if (diagnostics.rendering?.status === 'unavailable') {\n return 'raw HTML; rendering unavailable'\n }\n if (diagnostics.rendering?.status === 'failed') {\n return 'raw HTML; rendering failed'\n }\n if (diagnostics.blocked) return 'blocked'\n if (diagnostics.rendered) return 'rendered'\n if (diagnostics.cache === 'hit') return 'cached'\n if (diagnostics.fetched) return 'fetched'\n return diagnostics.source\n}\n\nexport function formatContentCheck(\n classification?: QueryContentClassification,\n): string {\n if (!classification) return '-'\n if (classification === 'serp-framing') return 'wording gap'\n if (classification === 'content-gap') return 'content gap'\n if (classification === 'technical-check') return 'technical check'\n return 'covered'\n}\n","import { select } from '@clack/prompts'\nimport type { ClientProfile } from '@seo/core'\nimport { maybeExitCancelled } from '../../utils.js'\nimport { slugId } from '../shared.js'\n\nconst CREATE_PROJECT = '__create_project__'\nconst SKIP_PROJECT = '__skip_project__'\n\nexport type SetupProjectTarget =\n | { mode: 'create'; requestedId?: string }\n | { mode: 'update'; client: ClientProfile }\n | { mode: 'skip' }\n\nexport type SetupProjectOption = {\n value: string\n label: string\n hint?: string\n}\n\nexport function setupProjectOptions(\n clients: ClientProfile[],\n): SetupProjectOption[] {\n return [\n {\n value: CREATE_PROJECT,\n label: 'Create a new project',\n hint: 'Save a separate site and its data sources',\n },\n ...clients.map((client) => ({\n value: client.id,\n label: `Update ${client.name}`,\n hint: `${client.id}, ${client.siteUrl}`,\n })),\n {\n value: SKIP_PROJECT,\n label: 'Continue without a project profile',\n hint: 'Pass --site or --url when you run reports',\n },\n ]\n}\n\nexport function nextAvailableProjectId(\n name: string,\n clients: ClientProfile[],\n): string {\n const base = slugId(name)\n if (!base) throw new Error('Project id could not be derived.')\n const ids = new Set(clients.map((client) => client.id.toLowerCase()))\n if (!ids.has(base.toLowerCase())) return base\n let suffix = 2\n while (ids.has(`${base}-${suffix}`.toLowerCase())) suffix += 1\n return `${base}-${suffix}`\n}\n\nexport async function chooseSetupProjectTarget(input: {\n clients: ClientProfile[]\n interactive: boolean\n requestedId?: string\n skipProfile?: boolean\n prompt?: (options: SetupProjectOption[]) => Promise<string | symbol>\n}): Promise<SetupProjectTarget> {\n if (input.skipProfile) return { mode: 'skip' }\n if (input.requestedId) {\n const normalized = input.requestedId.toLowerCase()\n const normalizedId = slugId(input.requestedId).toLowerCase()\n const existing = input.clients.find(\n (client) =>\n client.id.toLowerCase() === normalizedId ||\n client.name.toLowerCase() === normalized,\n )\n return existing\n ? { mode: 'update', client: existing }\n : { mode: 'create', requestedId: input.requestedId }\n }\n if (!input.interactive) return { mode: 'create' }\n\n const options = setupProjectOptions(input.clients)\n const choice = maybeExitCancelled(\n await (input.prompt\n ? input.prompt(options)\n : select({\n message: 'Create a project or update an existing one?',\n options,\n })),\n )\n if (choice === CREATE_PROJECT) return { mode: 'create' }\n if (choice === SKIP_PROJECT) return { mode: 'skip' }\n const client = input.clients.find((item) => item.id === choice)\n if (!client) throw new Error(`Project not found: ${choice}`)\n return { mode: 'update', client }\n}\n","import { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, posix, win32 } from 'node:path'\n\nexport type SupportedClient =\n | 'claude-desktop'\n | 'claude-code'\n | 'codex'\n | 'cursor'\n\ninterface BaseClientTarget {\n client: SupportedClient\n label: string\n path: string\n commandNames: string[]\n detectionPaths: string[]\n}\n\nexport interface JsonClientConfigTarget extends BaseClientTarget {\n kind: 'json'\n includeType?: boolean\n}\n\nexport interface NativeClientConfigTarget extends BaseClientTarget {\n kind: 'native'\n executable: 'codex'\n}\n\nexport type ClientConfigTarget =\n | JsonClientConfigTarget\n | NativeClientConfigTarget\n\nfunction platformConfigRoot(input: {\n home: string\n platform: NodeJS.Platform\n env: NodeJS.ProcessEnv\n}): string {\n const path = input.platform === 'win32' ? win32 : posix\n if (input.platform === 'win32') {\n return input.env.APPDATA ?? path.resolve(input.home, 'AppData/Roaming')\n }\n if (input.platform === 'darwin') {\n return path.resolve(input.home, 'Library/Application Support')\n }\n return input.env.XDG_CONFIG_HOME ?? path.resolve(input.home, '.config')\n}\n\nexport function mcpClientTargets(\n input: {\n home?: string\n platform?: NodeJS.Platform\n env?: NodeJS.ProcessEnv\n } = {},\n): ClientConfigTarget[] {\n const home = input.home ?? homedir()\n const platform = input.platform ?? process.platform\n const env = input.env ?? process.env\n const configRoot = platformConfigRoot({ home, platform, env })\n const path = platform === 'win32' ? win32 : posix\n const targets: ClientConfigTarget[] = []\n\n if (platform === 'darwin' || platform === 'win32') {\n const claudeRoot = path.resolve(configRoot, 'Claude')\n targets.push({\n kind: 'json',\n client: 'claude-desktop',\n label: 'Claude Desktop',\n path: path.resolve(claudeRoot, 'claude_desktop_config.json'),\n commandNames: [],\n detectionPaths:\n platform === 'darwin'\n ? [claudeRoot, '/Applications/Claude.app']\n : [claudeRoot],\n })\n }\n\n targets.push(\n {\n kind: 'json',\n client: 'claude-code',\n label: 'Claude Code',\n path: path.resolve(home, '.claude.json'),\n includeType: true,\n commandNames: ['claude'],\n detectionPaths: [path.resolve(home, '.claude')],\n },\n {\n kind: 'native',\n client: 'codex',\n label: 'Codex',\n path: path.resolve(home, '.codex/config.toml'),\n executable: 'codex',\n commandNames: ['codex'],\n detectionPaths: [path.resolve(home, '.codex')],\n },\n {\n kind: 'json',\n client: 'cursor',\n label: 'Cursor',\n path: path.resolve(home, '.cursor/mcp.json'),\n commandNames: ['cursor', 'cursor-agent'],\n detectionPaths: [\n path.resolve(home, '.cursor'),\n ...(platform === 'darwin' ? ['/Applications/Cursor.app'] : []),\n ],\n },\n )\n\n return targets\n}\n\nexport function resolveMcpClientExecutable(\n command: string,\n input: {\n exists?: (path: string) => boolean\n nodePath?: string\n path?: string\n platform?: NodeJS.Platform\n } = {},\n): string {\n const platform = input.platform ?? process.platform\n const exists = input.exists ?? existsSync\n const nodePath = input.nodePath ?? process.execPath\n const names =\n platform === 'win32'\n ? [`${command}.cmd`, `${command}.exe`, command]\n : [command]\n\n const pathEntries = (input.path ?? process.env.PATH ?? '')\n .split(platform === 'win32' ? ';' : ':')\n .filter(Boolean)\n for (const directory of pathEntries) {\n for (const name of names) {\n const candidate = join(directory, name)\n if (exists(candidate)) return candidate\n }\n }\n\n for (const name of names) {\n const candidate = join(dirname(nodePath), name)\n if (exists(candidate)) return candidate\n }\n return command\n}\n\nfunction commandExists(command: string): boolean {\n return resolveMcpClientExecutable(command) !== command\n}\n\nexport function detectMcpClients(\n input: {\n targets?: ClientConfigTarget[]\n hasCommand?: (command: string) => boolean\n hasPath?: (path: string) => boolean\n } = {},\n): ClientConfigTarget[] {\n const targets = input.targets ?? mcpClientTargets()\n const hasCommand = input.hasCommand ?? commandExists\n const hasPath = input.hasPath ?? existsSync\n return targets.filter((target) => {\n if (target.kind === 'native') {\n return target.commandNames.some(hasCommand)\n }\n return (\n hasPath(target.path) ||\n target.detectionPaths.some(hasPath) ||\n target.commandNames.some(hasCommand)\n )\n })\n}\n","import { spawnSync } from 'node:child_process'\nimport {\n constants,\n copyFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n statSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname } from 'node:path'\nimport { isDeepStrictEqual } from 'node:util'\nimport { getSeoCliPaths, SEO_VERSION } from '@seo/core'\nimport {\n applyEdits,\n modify,\n type ParseError,\n parse,\n printParseErrorCode,\n} from 'jsonc-parser'\nimport type {\n ClientConfigTarget,\n JsonClientConfigTarget,\n NativeClientConfigTarget,\n SupportedClient,\n} from './mcp-clients.js'\nimport { resolveMcpClientExecutable } from './mcp-clients.js'\n\ninterface CommandResult {\n status: number | null\n stdout: string\n stderr: string\n error?: Error\n}\n\ntype CommandRunner = (command: string, args: string[]) => CommandResult\n\nexport interface McpServerCommand {\n command: string\n args: string[]\n}\n\nexport interface McpConfigOptions {\n runCommand?: CommandRunner\n reinstall?: boolean\n serverCommand?: McpServerCommand\n}\n\nconst formattingOptions = {\n insertSpaces: true,\n tabSize: 2,\n eol: '\\n',\n}\n\nfunction timestamp(): string {\n return new Date().toISOString().replace(/[:.]/g, '-')\n}\n\nfunction writeAtomic(path: string, value: string): void {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 })\n const tmp = `${path}.${process.pid}.${Date.now()}.tmp`\n const mode = existsSync(path) ? statSync(path).mode & 0o777 : 0o600\n writeFileSync(tmp, value, { encoding: 'utf8', mode })\n renameSync(tmp, path)\n}\n\nfunction backup(path: string): void {\n const base = `${path}.bak-${timestamp()}`\n let candidate = base\n let suffix = 2\n while (existsSync(candidate)) {\n candidate = `${base}-${suffix}`\n suffix += 1\n }\n copyFileSync(path, candidate, constants.COPYFILE_EXCL)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction readConfig(target: JsonClientConfigTarget): {\n source: string\n config: Record<string, unknown>\n} {\n if (!existsSync(target.path)) return { source: '{}\\n', config: {} }\n\n const source = readFileSync(target.path, 'utf8')\n const errors: ParseError[] = []\n const config = parse(source, errors, { allowTrailingComma: true })\n if (errors.length > 0) {\n const first = errors[0]\n const detail = first\n ? `${printParseErrorCode(first.error)} at offset ${first.offset}`\n : 'unknown parse error'\n throw new Error(`Cannot update ${target.path}: invalid JSONC (${detail}).`)\n }\n if (!isRecord(config)) {\n throw new Error(\n `Cannot update ${target.path}: config root must be an object.`,\n )\n }\n if (config.mcpServers !== undefined && !isRecord(config.mcpServers)) {\n throw new Error(\n `Cannot update ${target.path}: mcpServers must be an object.`,\n )\n }\n return { source, config }\n}\n\nfunction isSeoPackageCommand(args: string[]): boolean {\n return (\n args.includes('mcp') &&\n args.includes('serve') &&\n args.some(\n (item) =>\n item === 'seo' || item.startsWith('seo@') || item === '@seo/cli',\n )\n )\n}\n\nfunction isManagedNodeCommand(\n value: Record<string, unknown>,\n args: string[],\n): boolean {\n if (\n typeof value.command !== 'string' ||\n args.length !== 3 ||\n args[1] !== 'mcp' ||\n args[2] !== 'serve' ||\n !isRecord(value.env)\n ) {\n return false\n }\n return value.env.SEO_MCP_CONFIGURED_BY === 'seo'\n}\n\nfunction managedServer(value: unknown): boolean {\n if (!isRecord(value) || !Array.isArray(value.args)) return false\n const args = value.args.filter(\n (item): item is string => typeof item === 'string',\n )\n return isSeoPackageCommand(args) || isManagedNodeCommand(value, args)\n}\n\nfunction writeConfigEdit(input: {\n target: JsonClientConfigTarget\n source: string\n value: unknown\n}): void {\n const next = applyEdits(\n input.source,\n modify(input.source, ['mcpServers', 'seo'], input.value, {\n formattingOptions,\n }),\n )\n if (existsSync(input.target.path)) backup(input.target.path)\n writeAtomic(input.target.path, next)\n}\n\nfunction defaultCommandRunner(command: string, args: string[]): CommandResult {\n const result = spawnSync(command, args, { encoding: 'utf8' })\n return {\n status: result.status,\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n error: result.error,\n }\n}\n\nfunction isTemporaryNpxPath(path: string): boolean {\n const normalized = path.replaceAll('\\\\', '/').toLowerCase()\n return (\n normalized.includes('/_npx/') ||\n normalized.includes('/.npm/_npx/') ||\n normalized.includes('/.cache/pnpm/dlx/')\n )\n}\n\nfunction installedCliPath(cliPath: string | undefined): string | undefined {\n if (!cliPath || !existsSync(cliPath)) return undefined\n const resolved = realpathSync(cliPath)\n return isTemporaryNpxPath(resolved) ? undefined : resolved\n}\n\nexport function resolveMcpServerCommand(\n input: {\n cliPath?: string\n nodePath?: string\n platform?: NodeJS.Platform\n version?: string\n } = {},\n): McpServerCommand {\n const cliPath = installedCliPath(input.cliPath ?? process.argv[1])\n if (cliPath) {\n return {\n command: input.nodePath ?? process.execPath,\n args: [cliPath, 'mcp', 'serve'],\n }\n }\n\n const packageName = `seo@${input.version ?? SEO_VERSION}`\n if ((input.platform ?? process.platform) === 'win32') {\n return {\n command: 'cmd',\n args: ['/c', 'npx', '-y', packageName, 'mcp', 'serve'],\n }\n }\n return { command: 'npx', args: ['-y', packageName, 'mcp', 'serve'] }\n}\n\nfunction serverConfig(\n includeType = false,\n command = resolveMcpServerCommand(),\n): Record<string, unknown> {\n const paths = getSeoCliPaths()\n const config: Record<string, unknown> = {\n command: command.command,\n args: command.args,\n env: {\n SEO_CONFIG_DIR: paths.configDir,\n SEO_MCP_CONFIGURED_BY: 'seo',\n },\n }\n if (includeType) config.type = 'stdio'\n return config\n}\n\nfunction codexManaged(output: string): boolean {\n return (\n output.includes('SEO_MCP_CONFIGURED_BY') ||\n /args:\\s+-y\\s+(?:seo(?:@\\S+)?|@seo\\/cli)\\s+mcp\\s+serve\\b/.test(output)\n )\n}\n\nfunction codexCommand(\n target: NativeClientConfigTarget,\n operation: 'install' | 'uninstall',\n options: Required<\n Pick<McpConfigOptions, 'runCommand' | 'reinstall' | 'serverCommand'>\n >,\n): { client: SupportedClient; path: string; changed: boolean } {\n const executable = resolveMcpClientExecutable(target.executable)\n const current = options.runCommand(executable, ['mcp', 'get', 'seo'])\n if ((current.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT') {\n throw new Error(\n 'Cannot install SEO MCP for Codex: the `codex` command is not available on PATH. Install Codex CLI or choose another MCP client.',\n )\n }\n const exists = current.status === 0\n if (exists && !codexManaged(current.stdout)) {\n throw new Error(\n `Cannot ${operation} SEO MCP: ${target.path} already has an unmanaged mcp_servers.seo entry.`,\n )\n }\n if (operation === 'install' && exists && !options.reinstall) {\n return { client: target.client, path: target.path, changed: false }\n }\n if (operation === 'uninstall' && !exists) {\n return { client: target.client, path: target.path, changed: false }\n }\n\n if (operation === 'install' && exists) {\n const removed = options.runCommand(executable, ['mcp', 'remove', 'seo'])\n if (removed.error || removed.status !== 0) {\n const detail =\n removed.error?.message ?? removed.stderr.trim() ?? 'unknown error'\n throw new Error(`Cannot reinstall SEO MCP for Codex: ${detail}`)\n }\n }\n\n const paths = getSeoCliPaths()\n const args =\n operation === 'install'\n ? [\n 'mcp',\n 'add',\n 'seo',\n '--env',\n `SEO_CONFIG_DIR=${paths.configDir}`,\n '--env',\n 'SEO_MCP_CONFIGURED_BY=seo',\n '--',\n options.serverCommand.command,\n ...options.serverCommand.args,\n ]\n : ['mcp', 'remove', 'seo']\n const result = options.runCommand(executable, args)\n if (result.error || result.status !== 0) {\n const detail =\n result.error?.message ?? result.stderr.trim() ?? 'unknown error'\n throw new Error(`Cannot ${operation} SEO MCP for Codex: ${detail}`)\n }\n return { client: target.client, path: target.path, changed: true }\n}\n\nexport function installMcpConfig(\n target: ClientConfigTarget,\n options: McpConfigOptions = {},\n): { client: SupportedClient; path: string; changed: boolean } {\n const resolved = {\n runCommand: options.runCommand ?? defaultCommandRunner,\n reinstall: options.reinstall ?? false,\n serverCommand: options.serverCommand ?? resolveMcpServerCommand(),\n }\n if (target.kind === 'native') {\n return codexCommand(target, 'install', resolved)\n }\n\n const { source, config } = readConfig(target)\n const servers = config.mcpServers as Record<string, unknown> | undefined\n const current = servers?.seo\n const desired = serverConfig(target.includeType, resolved.serverCommand)\n if (isDeepStrictEqual(current, desired) && !resolved.reinstall) {\n return { client: target.client, path: target.path, changed: false }\n }\n if (current !== undefined && !managedServer(current)) {\n throw new Error(\n `Cannot install SEO MCP: ${target.path} already has an unmanaged mcpServers.seo entry.`,\n )\n }\n\n writeConfigEdit({ target, source, value: desired })\n return { client: target.client, path: target.path, changed: true }\n}\n\nexport function uninstallMcpConfig(\n target: ClientConfigTarget,\n options: Pick<McpConfigOptions, 'runCommand'> = {},\n): { client: SupportedClient; path: string; changed: boolean } {\n if (target.kind === 'native') {\n return codexCommand(target, 'uninstall', {\n runCommand: options.runCommand ?? defaultCommandRunner,\n reinstall: false,\n serverCommand: resolveMcpServerCommand(),\n })\n }\n if (!existsSync(target.path)) {\n return { client: target.client, path: target.path, changed: false }\n }\n\n const { source, config } = readConfig(target)\n const servers = config.mcpServers as Record<string, unknown> | undefined\n if (servers?.seo === undefined) {\n return { client: target.client, path: target.path, changed: false }\n }\n if (!managedServer(servers.seo)) {\n throw new Error(\n `Cannot uninstall SEO MCP: ${target.path} has an unmanaged mcpServers.seo entry.`,\n )\n }\n\n writeConfigEdit({ target, source, value: undefined })\n return { client: target.client, path: target.path, changed: true }\n}\n","import { spawnSync } from 'node:child_process'\n\nexport type SkillInstallOutcome =\n | { status: 'installed' }\n | { status: 'failed'; error: string }\n\n/**\n * Install the packaged router skill for coding agents through the skills\n * ecosystem. Used by guided setup and by `seo skill install`.\n */\nexport function installSeoSkill(\n options: { quiet?: boolean } = {},\n): SkillInstallOutcome {\n const result = spawnSync('npx', ['-y', 'skills', 'add', 'iannuttall/seo'], {\n stdio: options.quiet ? 'ignore' : 'inherit',\n })\n if (result.error) {\n return { status: 'failed', error: result.error.message }\n }\n if (result.status !== 0) {\n return {\n status: 'failed',\n error: `npx skills add exited with status ${result.status ?? 'unknown'}.`,\n }\n }\n return { status: 'installed' }\n}\n","import {\n confirm,\n multiselect,\n note,\n password,\n select,\n text,\n} from '@clack/prompts'\nimport {\n type AnalyticsConnection,\n analyticsConnectionLabel,\n authStatus,\n type Ga4WebStreamCandidate,\n type Ga4WebStreamMatch,\n ga4MatchReason,\n ga4PropertyIdFromName,\n listGa4AccountSummaries,\n listGa4DataStreams,\n listGoogleAccounts,\n loadProviderExtensions,\n matchGa4WebStreams,\n type RegisteredProviderExtension,\n readClickySiteKey,\n readProviderExtensionCredentials,\n SeoError,\n setActiveGoogleAccount,\n verifyAnalyticsProvider,\n writeOauthClient,\n writeProviderExtensionCredentials,\n} from '@seo/core'\nimport { canPrompt, maybeExitCancelled } from '../../utils.js'\nimport { loginWithGuidance } from '../google-login.js'\nimport { detectMcpClients } from '../mcp-clients.js'\nimport { installMcpConfig } from '../mcp-config.js'\nimport { installSeoSkill } from '../skill-install.js'\n\nexport type SetupAuthStatus =\n | 'connected'\n | 'already-connected'\n | 'service-account'\n | 'skipped'\nexport type SetupAuthResult = {\n status: SetupAuthStatus\n accountEmail?: string\n}\nexport type SetupMcpInstall = {\n client: string\n path: string\n changed: boolean\n error?: string\n}\nexport type SetupGoogleAnalyticsSelection = {\n propertyId: string\n accountEmail?: string\n selection: 'explicit' | 'matched' | 'manual'\n reason: string\n}\nexport type SetupAnalyticsSelection =\n | { provider: 'google'; google: SetupGoogleAnalyticsSelection }\n | {\n provider: 'extension'\n extension: { providerId: string; account: Record<string, string> }\n }\n | { provider: 'none' }\nexport type SetupSkillInstall = {\n status: 'installed' | 'declined' | 'skipped' | 'failed'\n error?: string\n}\n\ntype GoogleAnalyticsPropertyChoice = {\n property: string\n label: string\n account: string\n}\n\ntype GoogleAnalyticsSetupChoice = GoogleAnalyticsPropertyChoice & {\n match?: Ga4WebStreamMatch\n}\n\ntype AuthSetupChoice = 'login' | 'setup' | 'skip'\ntype SavedGoogleAccountChoice =\n | { type: 'account'; accountEmail: string }\n | { type: 'connect' }\n | { type: 'skip' }\ntype AnalyticsSetupChoice =\n | 'keep'\n | 'google'\n | 'remove'\n | 'skip'\n | `extension:${string}`\n\nexport function analyticsSetupOptions(\n current?: AnalyticsConnection,\n installedProviders: readonly RegisteredProviderExtension[] = [],\n): Array<{\n value: AnalyticsSetupChoice\n label: string\n hint?: string\n}> {\n const providers: Array<{\n value: AnalyticsSetupChoice\n label: string\n hint?: string\n }> = [\n {\n value: 'google',\n label: 'Google Analytics',\n hint: 'Use a property available to your Google login',\n },\n ...installedProviders\n .filter(\n (provider) =>\n provider.capabilities.some(\n (capability) => capability.id === 'landing-page-visits',\n ) && provider.id !== 'google',\n )\n .map((provider) => ({\n value: `extension:${provider.id}` as const,\n label: provider.displayName,\n hint: `Installed provider from ${provider.package}`,\n })),\n ]\n if (!current) {\n return [...providers, { value: 'skip', label: 'Skip traffic analytics' }]\n }\n const currentLabel = analyticsConnectionLabel(current)\n return [\n {\n value: 'keep' as const,\n label: `Keep ${currentLabel}`,\n hint: 'Leave this project connection unchanged',\n },\n ...providers,\n { value: 'remove', label: 'Remove traffic analytics' },\n ]\n}\n\nasync function connectAnalyticsExtension(\n provider: RegisteredProviderExtension,\n initialAccount: Readonly<Record<string, string>> = {},\n interactive = true,\n): Promise<Extract<SetupAnalyticsSelection, { provider: 'extension' }>> {\n if (\n !provider.capabilities.some(\n (capability) => capability.id === 'landing-page-visits',\n )\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Provider ${provider.id} does not supply landing-page visits.`,\n )\n }\n const account: Record<string, string> = { ...initialAccount }\n const credentials: Record<string, string> = {}\n for (const field of provider.connection.fields.filter(\n (item) => item.kind === 'account',\n )) {\n if (account[field.id]?.trim()) continue\n if (!interactive) {\n if (field.required !== false) {\n throw new SeoError('INVALID_INPUT', `${field.label} is required.`)\n }\n continue\n }\n const value = maybeExitCancelled(\n await text({\n message: field.label,\n validate: (input) =>\n field.required !== false && !input?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n ).trim()\n if (value) account[field.id] = value\n }\n const normalizedAccount = provider.connection.normalizeAccount\n ? provider.connection.normalizeAccount(account)\n : account\n try {\n Object.assign(\n credentials,\n await readProviderExtensionCredentials({\n providerId: provider.id,\n account: normalizedAccount,\n fields: provider.connection.fields,\n }),\n )\n } catch {\n // Missing values are requested below or reported in non-interactive mode.\n }\n if (provider.id === 'clicky' && !credentials.sitekey) {\n const saved = await readClickySiteKey(normalizedAccount.siteId ?? '')\n if (saved) credentials.sitekey = saved.siteKey\n }\n for (const field of provider.connection.fields.filter(\n (item) => item.kind === 'secret',\n )) {\n const environmentValue = field.envVar\n ? process.env[field.envVar]?.trim()\n : undefined\n if (environmentValue) credentials[field.id] = environmentValue\n if (credentials[field.id]) continue\n if (!interactive) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n field.envVar\n ? `Set ${field.envVar} to connect ${provider.displayName}.`\n : `${field.label} is required to connect ${provider.displayName}.`,\n )\n }\n const value = maybeExitCancelled(\n await password({\n message: field.label,\n validate: (input) =>\n field.required !== false && !input?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n ).trim()\n if (value) credentials[field.id] = value\n }\n if (provider.connection.verificationNotice) {\n note(provider.connection.verificationNotice, 'Connection check')\n }\n await verifyAnalyticsProvider({\n providerId: provider.id,\n account: normalizedAccount,\n credentials,\n })\n if (Object.keys(credentials).length > 0) {\n await writeProviderExtensionCredentials({\n providerId: provider.id,\n account: normalizedAccount,\n credentials,\n })\n }\n return {\n provider: 'extension',\n extension: { providerId: provider.id, account: normalizedAccount },\n }\n}\n\nexport function authSetupOptions(input: {\n sharedConfigured: boolean\n byoConfigured: boolean\n canSkip: boolean\n}): Array<{\n value: AuthSetupChoice\n label: string\n hint?: string\n}> {\n const skipOption = input.canSkip\n ? [{ value: 'skip' as const, label: 'Skip for now' }]\n : []\n const hasOauthClient = input.sharedConfigured || input.byoConfigured\n\n return hasOauthClient\n ? [\n {\n value: 'login',\n label: 'Connect Google',\n hint: 'Opens your browser for read-only Search Console and Google Analytics access',\n },\n ...skipOption,\n ]\n : [\n {\n value: 'setup',\n label: 'Set up Google login for local development',\n hint: 'This source checkout does not include the public app credentials',\n },\n ...skipOption,\n ]\n}\n\nasync function findGoogleAnalyticsWebStreamCandidates(\n properties: GoogleAnalyticsPropertyChoice[],\n accountEmail?: string,\n): Promise<{ candidates: Ga4WebStreamCandidate[]; complete: boolean }> {\n const candidates: Ga4WebStreamCandidate[] = []\n let complete = true\n let nextIndex = 0\n\n async function worker(): Promise<void> {\n while (nextIndex < properties.length) {\n const property = properties[nextIndex]\n nextIndex += 1\n if (!property) continue\n\n try {\n const streams = await listGa4DataStreams(\n property.property,\n accountEmail,\n )\n candidates.push(\n ...streams\n .filter((stream) => stream.webStreamData)\n .map((stream) => ({\n account: property.account,\n property: property.property,\n propertyName: property.label,\n stream,\n })),\n )\n } catch {\n complete = false\n }\n }\n }\n\n await Promise.all(\n Array.from({ length: Math.min(properties.length, 4) }, () => worker()),\n )\n return { candidates, complete }\n}\n\nexport async function maybeConnectAuth(\n args: Record<string, unknown>,\n): Promise<SetupAuthResult> {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n return { status: 'service-account', accountEmail: status.identity }\n }\n const requestedAccount =\n typeof args['search-console-account'] === 'string'\n ? args['search-console-account']\n : undefined\n const connectedAccounts = listGoogleAccounts()\n if (requestedAccount) {\n const selected = connectedAccounts.find(\n (account) =>\n account.accountEmail.toLowerCase() === requestedAccount.toLowerCase(),\n )\n if (!selected) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${requestedAccount} is not connected. Run \\`seo auth login\\` first.`,\n )\n }\n return { status: 'already-connected', accountEmail: selected.accountEmail }\n }\n if (args['skip-auth']) return { status: 'skipped' }\n if (!canPrompt({ json: args.json === true })) {\n if (status.tokens) {\n return {\n status: 'already-connected',\n accountEmail: status.tokens.account_email,\n }\n }\n throw new SeoError(\n 'AUTH_REQUIRED',\n 'Not logged in. Run `seo auth login`, or pass --skip-auth to save a project profile without connecting Google.',\n )\n }\n\n if (connectedAccounts.length > 0) {\n const choice = maybeExitCancelled(\n await select<SavedGoogleAccountChoice>({\n message: 'Google account for Search Console',\n options: [\n ...connectedAccounts.map((account) => ({\n value: {\n type: 'account' as const,\n accountEmail: account.accountEmail,\n },\n label: account.accountEmail,\n hint: account.active ? 'Current default' : undefined,\n })),\n {\n value: { type: 'connect' as const },\n label: 'Connect another Google account',\n },\n ...(typeof args.site === 'string'\n ? [\n {\n value: { type: 'skip' as const },\n label: 'Skip for now',\n },\n ]\n : []),\n ],\n }),\n )\n if (choice.type === 'account') {\n setActiveGoogleAccount(choice.accountEmail)\n return {\n status: 'already-connected',\n accountEmail: choice.accountEmail,\n }\n }\n if (choice.type === 'skip') return { status: 'skipped' }\n if (status.sharedConfigured || status.byoConfigured) {\n const tokens = await loginWithGuidance()\n note(\n `Connected as ${tokens.account_email}. seo has read-only access and cannot change your site.`,\n 'Google connected',\n )\n return { status: 'connected', accountEmail: tokens.account_email }\n }\n }\n\n const choice = maybeExitCancelled(\n await select<AuthSetupChoice>({\n message: 'Connect Google now?',\n options: authSetupOptions({\n sharedConfigured: status.sharedConfigured,\n byoConfigured: status.byoConfigured,\n canSkip: typeof args.site === 'string' && args.site.length > 0,\n }),\n }),\n )\n\n if (choice === 'skip') return { status: 'skipped' }\n if (choice === 'setup') {\n const clientId = maybeExitCancelled(\n await text({\n message: 'Google Desktop OAuth client ID',\n validate: (value) => (value ? undefined : 'Client ID is required'),\n }),\n )\n const clientSecret = maybeExitCancelled(\n await password({\n message: 'Google Desktop OAuth client secret',\n validate: (value) => (value ? undefined : 'Client secret is required'),\n }),\n )\n writeOauthClient({ clientId, clientSecret })\n }\n\n const tokens = await loginWithGuidance()\n note(\n `Connected as ${tokens.account_email}. seo has read-only access and cannot change your site.`,\n 'Google connected',\n )\n return { status: 'connected', accountEmail: tokens.account_email }\n}\n\nexport async function chooseGoogleAnalyticsProperty(input: {\n property?: string\n accountEmail?: string\n site: string\n interactive?: boolean\n}): Promise<SetupGoogleAnalyticsSelection | undefined> {\n if (input.property) {\n return {\n propertyId: input.property,\n accountEmail: input.accountEmail,\n selection: 'explicit',\n reason: 'Set with --google-analytics-property.',\n }\n }\n const interactive = input.interactive ?? canPrompt()\n if (!interactive) return undefined\n\n const summaries = await listGa4AccountSummaries(input.accountEmail).catch(\n () => [],\n )\n const properties: GoogleAnalyticsPropertyChoice[] = summaries.flatMap(\n (account) =>\n account.propertySummaries.map((property) => ({\n property: ga4PropertyIdFromName(property.property),\n label: property.displayName ?? property.property,\n account: account.displayName ?? account.account,\n })),\n )\n if (!properties.length) return undefined\n\n const { candidates, complete: streamsComplete } =\n await findGoogleAnalyticsWebStreamCandidates(properties, input.accountEmail)\n const matches = streamsComplete\n ? matchGa4WebStreams(input.site, candidates)\n : []\n const matchesByProperty = new Map<string, Ga4WebStreamMatch>()\n for (const match of matches) {\n matchesByProperty.set(match.property, match)\n }\n const matchedProperties = [...matchesByProperty.values()]\n\n if (matchedProperties.length === 1) {\n const match = matchedProperties[0]\n if (!match) return undefined\n return {\n propertyId: match.property,\n accountEmail: input.accountEmail,\n selection: 'matched',\n reason: ga4MatchReason(match, input.site),\n }\n }\n\n const choices: GoogleAnalyticsSetupChoice[] = matchedProperties.length\n ? matchedProperties.map((match) => ({\n property: match.property,\n label: match.propertyName,\n account: match.account,\n match,\n }))\n : properties\n\n const choice = maybeExitCancelled(\n await select<GoogleAnalyticsSetupChoice | ''>({\n message: matchedProperties.length\n ? 'Several Google Analytics properties match this site. Which property should seo use?'\n : streamsComplete\n ? 'No Google Analytics web stream clearly matches this site. Attach a property?'\n : 'Some Google Analytics web streams could not be read. Attach a property?',\n options: [\n { value: '', label: 'Skip Google Analytics for now' },\n ...choices.map((property) => ({\n value: property,\n label: `${property.label} (${property.property})`,\n hint: property.match\n ? ga4MatchReason(property.match, input.site)\n : property.account,\n })),\n ],\n }),\n )\n if (!choice) return undefined\n\n return {\n propertyId: choice.property,\n accountEmail: input.accountEmail,\n selection: 'manual',\n reason: choice.match\n ? ga4MatchReason(choice.match, input.site)\n : streamsComplete\n ? `Selected ${choice.label} during setup. Its web stream did not clearly match ${input.site}.`\n : `Selected ${choice.label} during setup. seo could not read every Google Analytics web stream, so it did not guess a match.`,\n }\n}\n\nexport async function chooseAnalyticsForSetup(input: {\n googleProperty?: string\n googleAccount?: string\n clickySiteId?: string\n current?: AnalyticsConnection\n site: string\n interactive?: boolean\n}): Promise<SetupAnalyticsSelection | undefined> {\n if (input.googleProperty && input.clickySiteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass either --google-analytics-property or --clicky-site-id, not both.',\n )\n }\n const interactive = input.interactive ?? canPrompt()\n if (input.clickySiteId) {\n const loaded = await loadProviderExtensions()\n const provider = loaded.registry.get('clicky')\n if (!provider) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider package is not installed. Run `seo providers install @seoskill/clicky-provider`.',\n )\n }\n return connectAnalyticsExtension(\n provider,\n { siteId: input.clickySiteId },\n interactive,\n )\n }\n if (input.googleProperty) {\n const accountEmail = await chooseGoogleAnalyticsAccount({\n requested: input.googleAccount,\n interactive,\n })\n const google = await chooseGoogleAnalyticsProperty({\n property: input.googleProperty,\n accountEmail,\n site: input.site,\n interactive,\n })\n return google ? { provider: 'google', google } : undefined\n }\n if (!interactive) return undefined\n\n const loadedProviders = await loadProviderExtensions()\n\n const choice = maybeExitCancelled(\n await select<AnalyticsSetupChoice>({\n message: 'Traffic analytics',\n options: analyticsSetupOptions(\n input.current,\n loadedProviders.registry.list(),\n ),\n }),\n )\n if (choice === 'keep') return undefined\n if (choice === 'remove') return { provider: 'none' }\n if (choice === 'skip') return undefined\n if (choice.startsWith('extension:')) {\n const id = choice.slice('extension:'.length)\n const provider = loadedProviders.registry.get(id)\n if (!provider) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Provider ${id} is installed but could not be loaded. Run \\`seo providers doctor\\`.`,\n )\n }\n return connectAnalyticsExtension(provider)\n }\n const accountEmail = await chooseGoogleAnalyticsAccount({ interactive })\n const google = await chooseGoogleAnalyticsProperty({\n accountEmail,\n site: input.site,\n interactive,\n })\n if (!google) {\n note(\n 'No Google Analytics property was available for this Google login. You can connect one later.',\n 'Traffic analytics skipped',\n )\n }\n return google ? { provider: 'google', google } : undefined\n}\n\nasync function chooseGoogleAnalyticsAccount(input: {\n requested?: string\n interactive: boolean\n}): Promise<string | undefined> {\n const status = await authStatus()\n if (status.activeMode === 'service-account') return status.identity\n const accounts = listGoogleAccounts()\n if (input.requested) {\n const selected = accounts.find(\n (account) =>\n account.accountEmail.toLowerCase() === input.requested?.toLowerCase(),\n )\n if (!selected) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${input.requested} is not connected. Run \\`seo auth login\\` first.`,\n )\n }\n return selected.accountEmail\n }\n if (!input.interactive) {\n return accounts.find((account) => account.active)?.accountEmail\n }\n if (accounts.length === 0) {\n const tokens = await loginWithGuidance()\n return tokens.account_email\n }\n const choice = maybeExitCancelled(\n await select<SavedGoogleAccountChoice>({\n message: 'Google account for Google Analytics',\n options: [\n ...accounts.map((account) => ({\n value: {\n type: 'account' as const,\n accountEmail: account.accountEmail,\n },\n label: account.accountEmail,\n hint: account.active ? 'Current default' : undefined,\n })),\n {\n value: { type: 'connect' as const },\n label: 'Connect another Google account',\n },\n ],\n }),\n )\n if (choice.type === 'account') return choice.accountEmail\n const tokens = await loginWithGuidance()\n note(\n `Connected as ${tokens.account_email}. seo has read-only access and cannot change your site.`,\n 'Google connected',\n )\n return tokens.account_email\n}\n\nexport async function maybeInstallSkill(\n args: Record<string, unknown>,\n): Promise<SetupSkillInstall> {\n if (args['skip-skill'] || !canPrompt({ json: args.json === true })) {\n return { status: 'skipped' }\n }\n const shouldInstall = maybeExitCancelled(\n await confirm({\n message:\n 'Install the SEO skill so coding agents know how to run reports?',\n initialValue: true,\n }),\n )\n if (!shouldInstall) return { status: 'declined' }\n\n return installSeoSkill()\n}\n\nexport async function maybeInstallMcp(\n args: Record<string, unknown>,\n): Promise<SetupMcpInstall[]> {\n if (args['skip-mcp'] || !canPrompt({ json: args.json === true })) return []\n const detected = detectMcpClients()\n if (detected.length === 0) return []\n const shouldInstall = maybeExitCancelled(\n await confirm({\n message: 'Install seo as an MCP server too?',\n initialValue: true,\n }),\n )\n if (!shouldInstall) return []\n\n const selected = maybeExitCancelled(\n await multiselect({\n message: 'Which MCP clients?',\n options: detected.map((target) => ({\n value: target.client,\n label: target.label,\n hint: target.path,\n })),\n initialValues: detected.map((target) => target.client),\n }),\n )\n\n return detected\n .filter((target) => selected.includes(target.client))\n .map((target) => {\n try {\n return installMcpConfig(target)\n } catch (error) {\n return {\n client: target.client,\n path: target.path,\n changed: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n })\n}\n","import { intro, note, outro, text } from '@clack/prompts'\nimport {\n analyticsConnection,\n analyticsConnectionLabel,\n type ClientProfile,\n deriveBrandTerms,\n ensureSeoCliDirs,\n listClients,\n saveClient,\n updateClient,\n} from '@seo/core'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printCallout,\n printJson,\n printKeyValue,\n} from '../../utils.js'\nimport { slugId, startUrlForSite, suggestedClientName } from '../shared.js'\nimport {\n chooseSetupProjectTarget,\n nextAvailableProjectId,\n} from './project-target.js'\nimport {\n chooseAnalyticsForSetup,\n maybeConnectAuth,\n maybeInstallMcp,\n maybeInstallSkill,\n type SetupAuthStatus,\n type SetupGoogleAnalyticsSelection,\n type SetupMcpInstall,\n type SetupSkillInstall,\n} from './prompts.js'\n\ntype SetupResult = {\n client?: ClientProfile\n site: string\n auth: SetupAuthStatus\n googleAnalytics?: SetupGoogleAnalyticsSelection\n extension?: { providerId: string; account: Record<string, string> }\n mcp: SetupMcpInstall[]\n skill?: SetupSkillInstall\n next: string[]\n}\n\nfunction skillInstallLabel(skill: SetupSkillInstall): string {\n if (skill.status === 'installed') return 'installed'\n if (skill.status === 'failed') return 'install failed'\n return 'not installed'\n}\n\nfunction shellArg(value: string): string {\n if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {\n return value\n }\n return `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n}\n\nfunction printStarAsk(): void {\n process.stdout.write('\\n')\n printCallout({\n title: 'Help other people find SEO Skill',\n body: 'If SEO Skill saved you time, a GitHub star helps other people find it.',\n command: 'https://github.com/iannuttall/seo',\n })\n}\n\nfunction mcpInstallLabel(installs: SetupMcpInstall[]): string {\n const failed = installs.filter((install) => install.error).length\n const installed = installs.length - failed\n if (installs.length === 0) return 'not installed'\n if (failed === 0) return `${installed} installed`\n if (installed === 0) return `${failed} skipped`\n return `${installed} installed, ${failed} skipped`\n}\n\nfunction mcpFailureMessage(installs: SetupMcpInstall[]): string | undefined {\n const failures = installs.filter(\n (install): install is SetupMcpInstall & { error: string } =>\n Boolean(install.error),\n )\n if (failures.length === 0) return undefined\n return failures\n .map((install) => `${install.client}: ${install.error}`)\n .join('\\n')\n}\n\nexport async function runGuidedSetup(\n args: Record<string, unknown>,\n): Promise<void> {\n const json = jsonFlag(args)\n if (!json) intro(process.argv[2] === 'start' ? 'seo start' : 'seo setup')\n\n if (args['dry-run']) {\n const next = [\n 'seo auth login',\n 'seo start',\n 'seo report --project acme',\n 'seo refresh-priorities --project acme --verify-content',\n 'seo technical-watch --project acme',\n ]\n if (json) {\n printJson({ dryRun: true, next })\n } else {\n note(next.join('\\n'), 'This setup will guide you through')\n outro('Dry run complete.')\n }\n return\n }\n\n ensureSeoCliDirs()\n const interactive = canPrompt({ json })\n if (interactive) {\n note(\n 'A project profile remembers one site and its report defaults so future commands stay short.',\n 'Project profiles',\n )\n }\n const clients = listClients()\n const projectTarget = await chooseSetupProjectTarget({\n clients,\n interactive,\n requestedId: stringArg(args.id),\n skipProfile: booleanArg(args['skip-profile']),\n })\n const existingProject =\n projectTarget.mode === 'update' ? projectTarget.client : undefined\n const selectedProjectSite = stringArg(args.site) ?? existingProject?.siteUrl\n const siteInput = {\n site: selectedProjectSite,\n options: {\n allowDefault: projectTarget.mode === 'update',\n json,\n refresh: booleanArg(args.refresh),\n },\n }\n const resolvedNonInteractiveSite = interactive\n ? undefined\n : await resolveSite(siteInput)\n const authSelection = await maybeConnectAuth(\n selectedProjectSite ? { ...args, site: selectedProjectSite } : args,\n )\n const auth = authSelection.status\n const site =\n resolvedNonInteractiveSite ??\n (await resolveSite({\n ...siteInput,\n options: {\n ...siteInput.options,\n account: authSelection.accountEmail,\n },\n }))\n const defaultName = suggestedClientName(site)\n\n if (projectTarget.mode === 'skip') {\n const mcp = await maybeInstallMcp(args)\n const skill = await maybeInstallSkill(args)\n const siteArg = `--site ${shellArg(site)}`\n const next = [\n `seo report ${siteArg}`,\n `seo refresh-priorities ${siteArg} --verify-content`,\n `seo technical-watch ${siteArg}`,\n ]\n const result: SetupResult = { site, auth, mcp, skill, next }\n\n if (json) {\n printJson(result)\n return\n }\n\n printKeyValue([\n ['Project profile', 'not saved'],\n ['GSC property', site],\n ['Auth', auth],\n ['MCP', mcpInstallLabel(mcp)],\n ['SEO skill', skillInstallLabel(skill)],\n ])\n const mcpFailure = mcpFailureMessage(mcp)\n if (mcpFailure) note(mcpFailure, 'MCP setup skipped')\n if (skill.error) note(skill.error, 'SEO skill install failed')\n note(next.join('\\n'), 'Try next')\n outro('Setup complete.')\n printStarAsk()\n return\n }\n\n const name =\n stringArg(args.name) ??\n (interactive\n ? maybeExitCancelled(\n await text({\n message: 'Project name',\n placeholder: existingProject?.name ?? defaultName,\n defaultValue: existingProject?.name ?? defaultName,\n }),\n )\n : (existingProject?.name ?? defaultName))\n const id =\n existingProject?.id ??\n (projectTarget.mode === 'create' && projectTarget.requestedId\n ? slugId(projectTarget.requestedId)\n : nextAvailableProjectId(name, clients))\n const defaultStartUrl =\n existingProject?.startUrl ?? startUrlForSite(site) ?? ''\n const startUrl =\n stringArg(args.url) ??\n (interactive\n ? maybeExitCancelled(\n await text({\n message: 'Website URL to crawl',\n placeholder: defaultStartUrl || 'https://example.com',\n defaultValue: defaultStartUrl,\n }),\n )\n : defaultStartUrl || undefined)\n const watchUrls =\n args.urls === undefined\n ? (existingProject?.watchUrls ?? [])\n : listArg(args.urls)\n const analyticsSelection = await chooseAnalyticsForSetup({\n googleProperty: stringArg(args['google-analytics-property']),\n googleAccount: stringArg(args['google-analytics-account']),\n clickySiteId: stringArg(args['clicky-site-id']),\n current: analyticsConnection(existingProject),\n site,\n interactive,\n })\n const googleAnalytics =\n analyticsSelection?.provider === 'google'\n ? analyticsSelection.google\n : undefined\n const extension =\n analyticsSelection?.provider === 'extension'\n ? analyticsSelection.extension\n : undefined\n const derivedBrandTerms =\n existingProject?.brandTerms ?? deriveBrandTerms({ id, name, siteUrl: site })\n const brandTerms =\n args.brand === undefined ? derivedBrandTerms : listArg(args.brand)\n const technicalWeekday =\n numberArg(args.weekday) ?? existingProject?.technicalWeekday ?? 1\n const isDefault =\n booleanArg(args.default) ?? existingProject?.isDefault ?? true\n\n const analytics =\n analyticsSelection === undefined\n ? undefined\n : analyticsSelection.provider === 'google'\n ? {\n ...existingProject?.analytics,\n selected: 'google' as const,\n google: { propertyId: analyticsSelection.google.propertyId },\n }\n : analyticsSelection.provider === 'extension'\n ? {\n ...existingProject?.analytics,\n selected:\n `extension:${analyticsSelection.extension.providerId}` as const,\n extensions: {\n ...existingProject?.analytics.extensions,\n [analyticsSelection.extension.providerId]: {\n account: analyticsSelection.extension.account,\n },\n },\n }\n : {}\n\n const profile = {\n name,\n siteUrl: site,\n startUrl,\n watchUrls,\n brandTerms,\n analytics,\n googleAccounts: {\n ...existingProject?.googleAccounts,\n ...(authSelection.accountEmail\n ? { searchConsole: authSelection.accountEmail }\n : {}),\n ...(googleAnalytics?.accountEmail\n ? { googleAnalytics: googleAnalytics.accountEmail }\n : {}),\n },\n technicalWeekday,\n isDefault,\n }\n const client = existingProject\n ? updateClient(existingProject.id, profile)\n : saveClient({ id, ...profile })\n const mcp = await maybeInstallMcp(args)\n const skill = await maybeInstallSkill(args)\n const next = [\n `seo report --project ${client.id}`,\n `seo refresh-priorities --project ${client.id} --verify-content`,\n `seo technical-watch --project ${client.id}`,\n ]\n const result: SetupResult = {\n client,\n site,\n auth,\n googleAnalytics,\n extension,\n mcp,\n skill,\n next,\n }\n\n if (json) {\n printJson(result)\n return\n }\n\n const selectedAnalytics = analyticsConnection(client)\n\n printKeyValue([\n ['Project profile', `${client.name} (${client.id})`],\n ['GSC property', client.siteUrl],\n [\n 'Search Console account',\n client.googleAccounts?.searchConsole ?? 'default Google account',\n ],\n ['Crawl URL', client.startUrl ?? 'not set'],\n ['Watch URLs', String(client.watchUrls.length)],\n ['Brand terms', client.brandTerms.join(', ') || 'not set'],\n [\n 'Traffic analytics',\n selectedAnalytics\n ? analyticsConnectionLabel(selectedAnalytics)\n : 'not connected (optional)',\n ],\n ...(googleAnalytics\n ? [\n ['Google Analytics selection', googleAnalytics.reason] as [\n string,\n string,\n ],\n ]\n : []),\n ...(client.googleAccounts?.googleAnalytics\n ? [\n [\n 'Google Analytics account',\n client.googleAccounts.googleAnalytics,\n ] as [string, string],\n ]\n : []),\n ['Auth', auth],\n ['MCP', mcpInstallLabel(mcp)],\n ['SEO skill', skillInstallLabel(skill)],\n ])\n const mcpFailure = mcpFailureMessage(mcp)\n if (mcpFailure) note(mcpFailure, 'MCP setup skipped')\n if (skill.error) note(skill.error, 'SEO skill install failed')\n note(next.join('\\n'), 'Try next')\n outro('Setup complete.')\n printStarAsk()\n}\n","import { defineCommand } from 'citty'\nimport { runGuidedSetup } from './flow.js'\n\nexport const setupCommand = defineCommand({\n meta: {\n name: 'setup',\n description:\n 'Guided setup for auth, one project profile, MCP, and next commands',\n },\n args: {\n id: { type: 'string', description: 'Short stable project id.' },\n name: { type: 'string', description: 'Human project name.' },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n 'search-console-account': {\n type: 'string',\n description: 'Saved Google account email for Search Console.',\n },\n url: { type: 'string', description: 'Default technical crawl start URL.' },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to watch with URL Inspection.',\n },\n 'google-analytics-property': {\n type: 'string',\n description: 'Optional Google Analytics property ID.',\n },\n 'google-analytics-account': {\n type: 'string',\n description: 'Saved Google account email for Google Analytics.',\n },\n 'clicky-site-id': {\n type: 'string',\n description:\n 'Optional Clicky site ID. Set SEO_CLICKY_SITEKEY outside a terminal.',\n },\n brand: {\n type: 'string',\n description: 'Comma-separated branded query terms to exclude by default.',\n },\n weekday: {\n type: 'string',\n description: 'Preferred technical-watch weekday. Defaults to Monday.',\n },\n default: {\n type: 'boolean',\n description: 'Make this the default project.',\n },\n 'skip-profile': {\n type: 'boolean',\n default: false,\n description: 'Do not save a project profile during setup.',\n },\n 'skip-auth': {\n type: 'boolean',\n default: false,\n description: 'Skip Google sign-in during setup.',\n },\n 'skip-mcp': {\n type: 'boolean',\n default: false,\n description: 'Skip MCP install prompts.',\n },\n 'skip-skill': {\n type: 'boolean',\n default: false,\n description: 'Skip the SEO skill install prompt.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Refresh GSC property discovery.',\n },\n 'dry-run': {\n type: 'boolean',\n default: false,\n description: 'Show what setup does without changing files.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => runGuidedSetup(args),\n})\n\nexport const startCommand = defineCommand({\n ...setupCommand,\n meta: {\n name: 'start',\n description:\n 'Start here: connect first-party data, save a profile, and get the first report commands',\n },\n})\n\nexport const clientSetupCommand = defineCommand({\n ...setupCommand,\n meta: {\n name: 'setup',\n description: 'Guided setup for one saved project profile',\n },\n})\n","import { detectBrandTerms, getClient, saveClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\n\nexport const clientBrandCommand = defineCommand({\n meta: {\n name: 'brand',\n description: 'Detect and manage project brand query terms',\n },\n subCommands: {\n detect: defineCommand({\n meta: {\n name: 'detect',\n description:\n 'Suggest branded query terms from GSC navigational queries',\n },\n args: {\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name. Defaults to default.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n days: {\n type: 'string',\n description: 'Detection window length in days. Defaults to 28.',\n },\n limit: {\n type: 'string',\n description: 'Maximum candidate terms. Defaults to 10.',\n },\n 'min-impressions': {\n type: 'string',\n description: 'Minimum query impressions. Defaults to 10.',\n },\n save: {\n type: 'boolean',\n default: false,\n description: 'Save suggested terms to the selected project.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local GSC cache.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const client = getClient(projectArg(args))\n const siteUrl = await resolveSite({\n site: stringArg(args.site) ?? client?.siteUrl,\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const detection = await detectBrandTerms({\n site: siteUrl,\n id: client?.id,\n name: client?.name,\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n refresh: booleanArg(args.refresh),\n })\n const saved =\n booleanArg(args.save) && client\n ? saveClient({\n id: client.id,\n name: client.name,\n siteUrl: client.siteUrl,\n startUrl: client.startUrl,\n watchUrls: client.watchUrls,\n analytics: client.analytics,\n brandTerms: detection.suggestedTerms,\n technicalWeekday: client.technicalWeekday,\n isDefault: client.isDefault,\n })\n : undefined\n\n if (booleanArg(args.save) && !client) {\n throw new Error('Pass --project to save detected brand terms.')\n }\n if (json) {\n printJson({ ...detection, saved })\n return\n }\n\n printKeyValue([\n ['Property', detection.site],\n ['Derived terms', detection.derivedTerms.join(', ')],\n ['Suggested terms', detection.suggestedTerms.join(', ')],\n ['Saved', saved ? saved.id : 'no'],\n ])\n printTable(\n ['Term', 'Score', 'Evidence'],\n detection.candidates.map((candidate) => [\n candidate.term,\n candidate.score,\n candidate.evidence\n .map(\n (item) => `${item.query} (${Math.round(item.clicks)} clicks)`,\n )\n .join(', '),\n ]),\n )\n },\n }),\n },\n})\n","import type { ClientProfile } from '@seo/core'\nimport { printKeyValue, printSummaryList } from '../../../utils.js'\n\nexport function printClientList(clients: ClientProfile[]): void {\n printSummaryList(\n clients.map((client) => ({\n title: `${client.name}${client.isDefault ? ' (default)' : ''}`,\n description: client.siteUrl,\n meta: [\n client.id,\n client.startUrl ? `crawl ${client.startUrl}` : '',\n client.watchUrls.length\n ? `${client.watchUrls.length} watched URL${client.watchUrls.length === 1 ? '' : 's'}`\n : '',\n client.brandTerms.length\n ? `${client.brandTerms.length} brand term${client.brandTerms.length === 1 ? '' : 's'}`\n : '',\n ],\n })),\n { empty: 'No saved projects.' },\n )\n}\n\nexport function printClientProfile(client: ClientProfile): void {\n printKeyValue([\n ['ID', client.id],\n ['Name', client.name],\n ['GSC property', client.siteUrl],\n [\n 'Search Console account',\n client.googleAccounts?.searchConsole ?? 'default Google account',\n ],\n ['Crawl URL', client.startUrl ?? 'not set'],\n ['Watch URLs', client.watchUrls.join(', ') || 'not set'],\n ['Brand terms', client.brandTerms.join(', ') || 'not set'],\n [\n 'Google Analytics property',\n client.analytics.google?.propertyId ?? 'not set',\n ],\n [\n 'Google Analytics account',\n client.googleAccounts?.googleAnalytics ?? 'default Google account',\n ],\n ['Clicky site', client.analytics.clicky?.siteId ?? 'not set'],\n ['Selected analytics', client.analytics.selected ?? 'not set'],\n [\n 'Technical weekday',\n client.technicalWeekday === undefined\n ? 'not set'\n : String(client.technicalWeekday),\n ],\n ['Default', client.isDefault ? 'yes' : 'no'],\n ])\n}\n","import { getClient, SeoError, saveClient, updateClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n stringArg,\n} from '../../../args.js'\nimport { resolveSite } from '../../../selection.js'\nimport { printJson } from '../../../utils.js'\nimport { slugId } from '../../shared.js'\nimport { printClientProfile } from './output.js'\n\nexport const clientAddCommand = defineCommand({\n meta: {\n name: 'add',\n description: 'Create or update a project profile',\n },\n args: {\n id: {\n type: 'string',\n description: 'Short stable project id, for example acme.',\n },\n name: {\n type: 'string',\n description: 'Human project name.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n 'search-console-account': {\n type: 'string',\n description: 'Saved Google account email for Search Console.',\n },\n url: {\n type: 'string',\n description: 'Default technical crawl start URL.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to watch with URL Inspection.',\n },\n 'google-analytics-property': {\n type: 'string',\n description: 'Optional Google Analytics property ID for this project.',\n },\n 'google-analytics-account': {\n type: 'string',\n description: 'Saved Google account email for Google Analytics.',\n },\n 'clicky-site-id': {\n type: 'string',\n description:\n 'Optional legacy Clicky site ID. New connections use seo start.',\n },\n brand: {\n type: 'string',\n description: 'Comma-separated branded query terms to exclude by default.',\n },\n weekday: {\n type: 'string',\n description: 'Preferred technical-watch weekday, 0-7.',\n },\n default: {\n type: 'boolean',\n description: 'Make this the default project.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const requestedId = stringArg(args.id)\n const existing = requestedId\n ? (getClient(requestedId) ?? getClient(slugId(requestedId)))\n : undefined\n const googleAnalyticsProperty = stringArg(args['google-analytics-property'])\n const googleAnalyticsAccount = stringArg(args['google-analytics-account'])\n const searchConsoleAccount = stringArg(args['search-console-account'])\n const clickySiteId = stringArg(args['clicky-site-id'])\n if (googleAnalyticsProperty && clickySiteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass either --google-analytics-property or --clicky-site-id, not both.',\n )\n }\n if (\n googleAnalyticsAccount &&\n !googleAnalyticsProperty &&\n !existing?.analytics.google?.propertyId\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--google-analytics-account needs a Google Analytics property.',\n )\n }\n const siteUrl = await resolveSite({\n site: stringArg(args.site) ?? existing?.siteUrl,\n options: { json, account: searchConsoleAccount },\n })\n const profile = {\n name: stringArg(args.name),\n siteUrl,\n startUrl: stringArg(args.url),\n watchUrls: args.urls === undefined ? undefined : listArg(args.urls),\n brandTerms: args.brand === undefined ? undefined : listArg(args.brand),\n analytics:\n googleAnalyticsProperty || googleAnalyticsAccount\n ? {\n ...existing?.analytics,\n selected: 'google' as const,\n google: {\n propertyId:\n googleAnalyticsProperty ??\n existing?.analytics.google?.propertyId ??\n '',\n },\n }\n : clickySiteId\n ? {\n ...existing?.analytics,\n selected: 'clicky' as const,\n clicky: { siteId: clickySiteId },\n }\n : undefined,\n googleAccounts:\n searchConsoleAccount || googleAnalyticsAccount\n ? {\n ...existing?.googleAccounts,\n ...(searchConsoleAccount\n ? { searchConsole: searchConsoleAccount }\n : {}),\n ...(googleAnalyticsAccount\n ? { googleAnalytics: googleAnalyticsAccount }\n : {}),\n }\n : undefined,\n technicalWeekday: numberArg(args.weekday),\n isDefault: booleanArg(args.default),\n }\n const client = existing\n ? updateClient(existing.id, profile)\n : saveClient({ id: requestedId, ...profile })\n if (json) {\n printJson(client)\n return\n }\n printClientProfile(client)\n },\n})\n","import { setDefaultClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\n\nexport const clientDefaultCommand = defineCommand({\n meta: {\n name: 'default',\n description: 'Set the default project',\n },\n args: {\n id: {\n type: 'string',\n required: true,\n description: 'Project id or name.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const client = setDefaultClient(stringArg(args.id) ?? '')\n if (jsonFlag(args)) {\n printJson(client)\n return\n }\n process.stdout.write(`Default project set to ${client.id}.\\n`)\n },\n})\n","import { deleteClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\n\nexport const clientDeleteCommand = defineCommand({\n meta: {\n name: 'delete',\n description: 'Delete a project profile',\n },\n args: {\n id: {\n type: 'string',\n required: true,\n description: 'Project id or name.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const deleted = deleteClient(id)\n if (jsonFlag(args)) {\n printJson({ id, deleted })\n return\n }\n process.stdout.write(`${deleted ? 'Deleted' : 'Not found'} ${id}.\\n`)\n },\n})\n","import { listClients } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\nimport { printClientList } from './output.js'\n\nexport const clientListCommand = defineCommand({\n meta: {\n name: 'list',\n description: 'List saved project profiles',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const clients = listClients()\n if (jsonFlag(args)) {\n printJson({ clients })\n return\n }\n printClientList(clients)\n },\n})\n","import { getClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\nimport { printClientProfile } from './output.js'\n\nexport const clientShowCommand = defineCommand({\n meta: {\n name: 'show',\n description: 'Show one project profile',\n },\n args: {\n id: {\n type: 'string',\n description: 'Project id or name. Defaults to the default project.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const client = getClient(stringArg(args.id))\n if (!client) throw new Error('Project not found.')\n if (jsonFlag(args)) {\n printJson(client)\n return\n }\n printClientProfile(client)\n },\n})\n","import { clientAddCommand } from './profiles/add.js'\nimport { clientDefaultCommand } from './profiles/default.js'\nimport { clientDeleteCommand } from './profiles/delete.js'\nimport { clientListCommand } from './profiles/list.js'\nimport { clientShowCommand } from './profiles/show.js'\n\nexport const clientProfileCommands = {\n list: clientListCommand,\n add: clientAddCommand,\n show: clientShowCommand,\n default: clientDefaultCommand,\n delete: clientDeleteCommand,\n}\n","import { defineCommand } from 'citty'\nimport { clientSetupCommand } from '../setup/index.js'\nimport { clientBrandCommand } from './brand.js'\nimport { clientProfileCommands } from './profiles.js'\n\nexport const clientCommand = defineCommand({\n meta: {\n name: 'client',\n description: 'Manage saved project profiles',\n },\n subCommands: {\n setup: clientSetupCommand,\n brand: clientBrandCommand,\n ...clientProfileCommands,\n },\n})\n\nexport const projectCommand = defineCommand({\n ...clientCommand,\n meta: {\n name: 'projects',\n description: 'Manage saved project profiles',\n },\n})\n","import { contentOptimizationReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printJson } from '../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from './output.js'\n\nexport const contentCommand = defineCommand({\n meta: {\n name: 'content',\n description: 'Optimize page content from real GSC queries',\n },\n subCommands: {\n optimize: defineCommand({\n meta: {\n name: 'optimize',\n description: 'Build a content optimization report for one URL',\n },\n args: {\n site: { type: 'string' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n url: { type: 'string', required: true },\n days: {\n type: 'string',\n description: 'GSC lookback days. Defaults to 28.',\n },\n limit: {\n type: 'string',\n description: 'Maximum GSC queries to inspect. Defaults to 25.',\n },\n 'min-impressions': {\n type: 'string',\n description: 'Minimum query impressions. Defaults to 10.',\n },\n 'include-brand': {\n type: 'boolean',\n default: false,\n description: 'Include branded queries.',\n },\n 'verify-content': defaultTrueBooleanArg(\n 'Fetch the page for content checks. Defaults to true.',\n 'Skip fetching the page for content checks.',\n ),\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for page extraction.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local GSC and HTTP cache.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await contentOptimizationReport({\n site: selection.site,\n url: stringArg(args.url) ?? '',\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent: booleanArg(args['verify-content']) !== false,\n js: booleanArg(args.js) ? true : 'auto',\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Content optimization',\n target: report.url,\n status: 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Score', value: `${report.summary.score}/100` },\n { label: 'Primary intent', value: report.summary.primaryIntent },\n {\n label: 'Primary query',\n value: report.summary.primaryQuery ?? 'None',\n },\n { label: 'Queries', value: formatCount(report.summary.queries) },\n {\n label: 'Opportunities',\n value: formatCount(report.summary.opportunities),\n },\n {\n label: 'Estimated lift',\n value: formatCount(report.summary.estimatedClickLift),\n },\n ],\n })\n\n printActionDetails(\n 'Top actions',\n report.topActions.map((action) => ({\n label: action.title,\n action: action.action,\n context: action.plainEnglish,\n })),\n )\n\n if (report.brief.sections.length) {\n process.stdout.write('\\nSuggested sections\\n')\n printLimitedTable(\n ['Heading', 'Queries'],\n report.brief.sections.map((section) => [\n truncate(section.heading, 48),\n truncate(section.queries.join(', '), 80),\n ]),\n )\n }\n\n if (report.intentMix.length) {\n process.stdout.write('\\nIntent mix\\n')\n printLimitedTable(\n ['Intent', 'Queries', 'Impressions', 'Clicks'],\n report.intentMix.map((intent) => [\n intent.intent,\n formatCount(intent.queries),\n formatCount(intent.impressions),\n formatCount(intent.clicks),\n ]),\n )\n }\n\n printNotes('Caveats', report.caveats)\n },\n }),\n },\n})\n","import {\n listSites,\n localError,\n localResearchKeys,\n nodeCommandDeps,\n SeoError,\n} from '@seo/core'\nimport {\n type Caller,\n type CommandResult,\n DIMENSIONS,\n type Dimension,\n matchProperty,\n RESEARCH_ACTIONS,\n RESEARCH_PROVIDERS,\n type ResearchAction,\n type ResearchProvider,\n runCompare,\n runLostPages,\n runPage,\n runReport,\n runResearch,\n runRows,\n SECTION_IDS,\n type SectionId,\n} from '@seo/core/commands'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printJson } from '../utils.js'\nimport { selectedSiteOrThrow } from './shared.js'\n\n// The shared commands: the same core code and text as the hosted MCP, with\n// this machine's Google sign-in. Each takes a target, optional dates and\n// progressive detail, nothing more.\n\nconst FLAGS: Record<string, string> = {\n site: '--site',\n url: '--url',\n section: '--section',\n date: '--date',\n pages: '--pages',\n dimensions: '--dimensions',\n detail: '--detail',\n offset: '--offset',\n}\n\nconst quote = (value: string | number) =>\n /^[\\w:/.,<>@#?=&%+-]+$/.test(String(value)) ? String(value) : `\"${value}\"`\n\nexport const cliCall: Caller = (command, args) =>\n [\n `seo ${command}`,\n ...Object.entries(args ?? {})\n .filter(([, value]) => value !== undefined)\n .map(\n ([key, value]) => `${FLAGS[key] ?? `--${key}`} ${quote(value ?? '')}`,\n ),\n ].join(' ')\n\nconst common = {\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n account: { type: 'string', description: 'Saved Google account email.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local cache and fetch fresh data.',\n },\n} as const\n\nconst dates = {\n 'start-date': { type: 'string', description: 'Optional YYYY-MM-DD.' },\n 'end-date': { type: 'string', description: 'Optional YYYY-MM-DD.' },\n} as const\n\nconst detail = {\n detail: {\n type: 'string',\n description: 'summary (default), rows for the next page, or full.',\n },\n offset: { type: 'string', description: 'rows only: the first row.' },\n} as const\n\ntype Args = Record<string, unknown>\n\nfunction detailArg(args: Args) {\n const value = stringArg(args.detail) ?? 'summary'\n if (!['summary', 'rows', 'full'].includes(value)) {\n throw new SeoError('INVALID_INPUT', '--detail is summary, rows or full.')\n }\n return value as 'summary' | 'rows' | 'full'\n}\n\n// A saved project, or the property that covers --site or --url.\nasync function property(args: Args, target?: string): Promise<string> {\n const options = {\n json: jsonFlag(args),\n refresh: booleanArg(args.refresh),\n account: stringArg(args.account),\n }\n if (!target || projectArg(args)) {\n return selectedSiteOrThrow({ client: projectArg(args) }, options)\n }\n const names = (await listSites(options.refresh, options.account)).map(\n (site) => site.siteUrl,\n )\n const found = matchProperty(names, target)\n if (!found) {\n throw new SeoError(\n 'PROPERTY_NOT_FOUND',\n `This Google login has no Search Console property for ${target}. Run \\`seo sites\\` to list the properties it can read.`,\n )\n }\n return found\n}\n\nasync function run(\n args: Args,\n task: (deps: ReturnType<typeof nodeCommandDeps>) => Promise<CommandResult>,\n) {\n try {\n const result = await task(\n nodeCommandDeps({\n call: cliCall,\n account: stringArg(args.account),\n refresh: booleanArg(args.refresh),\n }),\n )\n if (jsonFlag(args)) printJson(result.data)\n else process.stdout.write(`${result.text}\\n`)\n } catch (error) {\n throw localError(error)\n }\n}\n\nexport const reportCommand = defineCommand({\n meta: {\n name: 'report',\n description:\n 'The main Search Console report: overview and every section, then one section on request',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n section: {\n type: 'string',\n description: `Optional. One of ${SECTION_IDS.join(', ')}.`,\n },\n ...dates,\n ...detail,\n ...common,\n },\n run: async ({ args }) => {\n const section = stringArg(args.section)\n if (section && !SECTION_IDS.includes(section as SectionId)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `--section is one of ${SECTION_IDS.join(', ')}.`,\n )\n }\n const site = await property(args, stringArg(args.site))\n await run(args, (deps) =>\n runReport(\n {\n site,\n section: section as SectionId | undefined,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n },\n})\n\nexport const pageCommand = defineCommand({\n meta: {\n name: 'page',\n description:\n 'One URL: live page facts, Google index status and its queries',\n },\n args: {\n url: { type: 'string', description: 'The page URL.', required: true },\n ...dates,\n ...detail,\n ...common,\n },\n run: async ({ args }) => {\n const url = stringArg(args.url) ?? ''\n if (!/^https?:\\/\\/\\S+$/.test(url)) {\n throw new SeoError('INVALID_INPUT', '--url must be a full http(s) URL.')\n }\n const site = await property(args, url)\n await run(args, (deps) =>\n runPage(\n {\n site,\n url,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n },\n})\n\nexport const compareCommand = defineCommand({\n meta: {\n name: 'compare',\n description:\n 'Equal periods before and after a date, with the pages and queries that moved',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n date: {\n type: 'string',\n description: 'YYYY-MM-DD: the first day after the change.',\n required: true,\n },\n pages: {\n type: 'string',\n description: 'Optional URL text, such as /blog/.',\n },\n ...common,\n },\n run: async ({ args }) => {\n const site = await property(args, stringArg(args.site))\n await run(args, (deps) =>\n runCompare(\n {\n site,\n date: stringArg(args.date) ?? '',\n pages: stringArg(args.pages),\n },\n deps,\n ),\n )\n },\n})\n\nexport const indexCommand = defineCommand({\n meta: {\n name: 'index',\n description:\n 'Pages that lost most of their clicks, checked live and with URL Inspection',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n ...dates,\n ...common,\n },\n run: async ({ args }) => {\n const site = await property(args, stringArg(args.site))\n await run(args, (deps) =>\n runLostPages(\n {\n site,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n },\n deps,\n ),\n )\n },\n})\n\nexport const dataCommand = defineCommand({\n meta: {\n name: 'data',\n description:\n 'Raw Search Console rows for any dimensions, beside the previous period',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n dimensions: {\n type: 'string',\n description: `Comma-separated: ${DIMENSIONS.join(', ')}. Default query.`,\n },\n page: {\n type: 'string',\n description: 'Optional: only rows for pages whose URL contains this.',\n },\n query: {\n type: 'string',\n description: 'Optional: only rows for queries that contain this.',\n },\n ...dates,\n ...detail,\n ...common,\n },\n run: async ({ args }) => {\n const dimensions = csvArg(args.dimensions) ?? ['query']\n const unknown = dimensions.filter(\n (dimension) => !DIMENSIONS.includes(dimension as Dimension),\n )\n if (unknown.length) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Unknown dimensions: ${unknown.join(', ')}. Use ${DIMENSIONS.join(', ')}.`,\n )\n }\n const site = await property(args, stringArg(args.site))\n const page = stringArg(args.page)\n const query = stringArg(args.query)\n await run(args, (deps) =>\n runRows(\n {\n site,\n dimensions: dimensions as Dimension[],\n filters: [\n ...(page\n ? [\n {\n dimension: 'page' as const,\n operator: 'contains' as const,\n expression: page,\n },\n ]\n : []),\n ...(query\n ? [\n {\n dimension: 'query' as const,\n operator: 'contains' as const,\n expression: query,\n },\n ]\n : []),\n ],\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n },\n})\n\nexport const researchCommand = defineCommand({\n meta: {\n name: 'research',\n description:\n 'Keyword, SERP, competitor and backlink data from your DataForSEO or Ahrefs key',\n },\n args: {\n action: {\n type: 'positional',\n required: true,\n description: RESEARCH_ACTIONS.join(', '),\n },\n provider: {\n type: 'string',\n description: `${RESEARCH_PROVIDERS.join(', ')}. Default: the first one with a saved key.`,\n },\n keywords: { type: 'string', description: 'Comma-separated keywords.' },\n target: { type: 'string', description: 'Domain or URL.' },\n country: {\n type: 'string',\n description: 'Two-letter country code. Default us.',\n },\n ...detail,\n json: common.json,\n },\n run: async ({ args }) => {\n const action = stringArg(args.action) as ResearchAction\n if (!RESEARCH_ACTIONS.includes(action)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `The action is one of ${RESEARCH_ACTIONS.join(', ')}.`,\n )\n }\n const keys = await localResearchKeys()\n const header: Record<ResearchProvider, string> = {\n dataforseo: 'x-dataforseo-login',\n ahrefs: 'x-ahrefs-key',\n }\n const chosen = stringArg(args.provider)\n const provider = (chosen ??\n RESEARCH_PROVIDERS.find((name) => keys.has(header[name])) ??\n 'dataforseo') as ResearchProvider\n if (!RESEARCH_PROVIDERS.includes(provider)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `--provider is one of ${RESEARCH_PROVIDERS.join(', ')}.`,\n )\n }\n if (!keys.has(header[provider])) {\n throw new SeoError(\n 'AUTH_CONFIG_REQUIRED',\n `No ${provider} key saved. Run \\`seo providers ${provider} connect\\` first.`,\n )\n }\n const keywords = csvArg(args.keywords) ?? []\n const target = stringArg(args.target)\n const country = stringArg(args.country)\n await run(args, () =>\n runResearch(\n {\n provider,\n action,\n keywords,\n target,\n country,\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n keys,\n {\n call: (offset) =>\n cliCall('research', {\n action,\n provider,\n keywords: keywords.join(',') || undefined,\n target,\n country,\n detail: 'rows',\n offset,\n }).replace('--action ', ''),\n },\n ),\n )\n },\n})\n","import { createWriteStream } from 'node:fs'\nimport { mkdir } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport type { Writable } from 'node:stream'\nimport { finished } from 'node:stream/promises'\n\nconst BUFFER_SIZE = 64 * 1024\n\nclass BufferedWriter {\n private buffer = ''\n\n constructor(private readonly stream: Writable) {}\n\n async write(value: string): Promise<void> {\n this.buffer += value\n if (this.buffer.length >= BUFFER_SIZE) await this.flush()\n }\n\n async flush(): Promise<void> {\n if (!this.buffer) return\n const chunk = this.buffer\n this.buffer = ''\n if (!this.stream.write(chunk)) {\n await new Promise<void>((resolve, reject) => {\n const onDrain = () => {\n cleanup()\n resolve()\n }\n const onError = (error: Error) => {\n cleanup()\n reject(error)\n }\n const cleanup = () => {\n this.stream.off('drain', onDrain)\n this.stream.off('error', onError)\n }\n this.stream.once('drain', onDrain)\n this.stream.once('error', onError)\n })\n }\n }\n}\n\nfunction indentation(depth: number): string {\n return ' '.repeat(depth)\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (\n value &&\n typeof value === 'object' &&\n 'toJSON' in value &&\n typeof value.toJSON === 'function'\n ) {\n return value.toJSON()\n }\n return value\n}\n\nasync function writeValue(\n writer: BufferedWriter,\n input: unknown,\n depth: number,\n ancestors: Set<object>,\n arrayItem = false,\n): Promise<boolean> {\n const value = jsonValue(input)\n if (value === null) {\n await writer.write('null')\n return true\n }\n if (typeof value === 'string' || typeof value === 'boolean') {\n await writer.write(JSON.stringify(value))\n return true\n }\n if (typeof value === 'number') {\n await writer.write(Number.isFinite(value) ? String(value) : 'null')\n return true\n }\n if (typeof value === 'bigint') {\n JSON.stringify(value)\n }\n if (\n value === undefined ||\n typeof value === 'function' ||\n typeof value === 'symbol'\n ) {\n if (arrayItem) await writer.write('null')\n return arrayItem\n }\n if (!value || typeof value !== 'object') return false\n if (ancestors.has(value)) {\n throw new TypeError('Converting circular structure to JSON')\n }\n ancestors.add(value)\n try {\n if (Array.isArray(value)) {\n if (value.length === 0) {\n await writer.write('[]')\n return true\n }\n await writer.write('[\\n')\n for (let index = 0; index < value.length; index += 1) {\n if (index > 0) await writer.write(',\\n')\n await writer.write(indentation(depth + 1))\n await writeValue(writer, value[index], depth + 1, ancestors, true)\n }\n await writer.write(`\\n${indentation(depth)}]`)\n return true\n }\n\n const entries = Object.entries(value).filter(([, item]) => {\n const normalized = jsonValue(item)\n return !['undefined', 'function', 'symbol'].includes(typeof normalized)\n })\n if (entries.length === 0) {\n await writer.write('{}')\n return true\n }\n await writer.write('{\\n')\n for (let index = 0; index < entries.length; index += 1) {\n const [key, item] = entries[index] as [string, unknown]\n if (index > 0) await writer.write(',\\n')\n await writer.write(`${indentation(depth + 1)}${JSON.stringify(key)}: `)\n await writeValue(writer, item, depth + 1, ancestors)\n }\n await writer.write(`\\n${indentation(depth)}}`)\n return true\n } finally {\n ancestors.delete(value)\n }\n}\n\nexport async function writeJsonStream(\n stream: Writable,\n value: unknown,\n): Promise<void> {\n const writer = new BufferedWriter(stream)\n const written = await writeValue(writer, value, 0, new Set())\n if (!written) await writer.write('undefined')\n await writer.write('\\n')\n await writer.flush()\n}\n\nexport async function writeJsonOutput(\n path: string | undefined,\n value: unknown,\n): Promise<void> {\n if (!path) {\n await writeJsonStream(process.stdout, value)\n return\n }\n await mkdir(dirname(path), { recursive: true })\n const stream = createWriteStream(path)\n try {\n await writeJsonStream(stream, value)\n stream.end()\n await finished(stream)\n } catch (error) {\n stream.destroy()\n throw error\n }\n process.stdout.write(`Wrote ${path}\\n`)\n}\n","import {\n type CrawlReport,\n explainRule,\n reviewObservations,\n type TopFix,\n topFixes,\n} from '@seo/core'\nimport { printSemanticReport } from '../utils.js'\n\nfunction issueStatus(severity: TopFix['severity']): 'fail' | 'warning' {\n return severity === 'high' ? 'fail' : 'warning'\n}\n\nexport function printCrawlHuman(\n report: CrawlReport,\n fixes: TopFix[] = topFixes(report),\n): void {\n const reviews = reviewObservations(report)\n const status =\n report.status === 'failed' || report.summary.highIssues > 0\n ? 'fail'\n : report.status === 'partial'\n ? 'unknown'\n : report.summary.mediumIssues > 0 || report.summary.lowIssues > 0\n ? 'warning'\n : 'pass'\n const accessDiagnostics = report.access.samples.slice(0, 5).map((sample) => ({\n status: 'fail' as const,\n title: sample.evidence.guidance.summary,\n explanation: `${sample.evidence.provider} returned ${sample.evidence.kind} evidence for the crawler request.`,\n evidence: [sample.url],\n fix: sample.evidence.guidance.recommendedAction,\n }))\n const fixDiagnostics = fixes.slice(0, 10).map((fix) => ({\n status: issueStatus(fix.severity),\n title: `${fix.title} on ${fix.count} ${fix.count === 1 ? 'URL' : 'URLs'}`,\n explanation: explainRule(fix.ruleId)?.whyItMatters ?? fix.whyThisRanks,\n evidence: fix.sampleUrls.slice(0, 5),\n fix: fix.howToFix,\n }))\n const reviewDiagnostics = reviews.slice(0, 10).map((review) => ({\n status: 'warning' as const,\n title: `${review.title} on ${review.count} ${review.count === 1 ? 'URL' : 'URLs'}`,\n explanation:\n explainRule(review.ruleId)?.whyItMatters ?? review.whyThisRanks,\n evidence: review.sampleUrls.slice(0, 5),\n fix: review.howToFix,\n }))\n\n printSemanticReport({\n title:\n report.config.strategy === 'health'\n ? 'Sitemap health pass'\n : 'Site crawl',\n target: report.config.url,\n status,\n summary:\n report.status === 'partial'\n ? `Partial evidence from ${report.summary.totalPages} retained pages. Review the caveats before treating missing findings as an all-clear.`\n : `${report.summary.totalPages} pages retained with ${report.issues.length} findings.`,\n metrics: [\n { label: 'Pages', value: report.summary.totalPages },\n {\n label: 'High',\n value: report.summary.highIssues,\n status: 'fail',\n },\n {\n label: 'Medium',\n value: report.summary.mediumIssues,\n status: 'warning',\n },\n { label: 'Low', value: report.summary.lowIssues, status: 'info' },\n { label: 'Failed fetches', value: report.summary.failedUrls },\n ],\n sections: [\n { title: 'Access diagnostics', diagnostics: accessDiagnostics },\n { title: 'Prioritised fixes', diagnostics: fixDiagnostics },\n {\n title: 'Review before changing anything',\n diagnostics: reviewDiagnostics,\n },\n ...(!accessDiagnostics.length &&\n !fixDiagnostics.length &&\n !reviewDiagnostics.length\n ? [\n {\n title: 'Checks',\n diagnostics: [\n {\n status: 'pass' as const,\n title: 'No prioritised findings were observed',\n explanation:\n 'The evaluated crawl evidence did not produce a prioritised fix or review item.',\n },\n ],\n },\n ]\n : []),\n ],\n notes: [\n `Strategy: ${report.config.strategy}. Data: ${report.status}. Report: ${report.id}.`,\n ...report.warnings,\n ...report.caveats,\n ],\n })\n}\n","import {\n type AnalyticsConnection,\n normalizeClickySiteId,\n SeoError,\n} from '@seo/core'\nimport { stringArg } from '../../args.js'\n\nexport const analyticsConnectionArgs = {\n 'google-analytics-property': {\n type: 'string' as const,\n description:\n 'Google Analytics property ID for landing-page sessions. Defaults from --project when saved.',\n },\n 'clicky-site-id': {\n type: 'string' as const,\n description:\n 'Clicky site ID for landing-page visits. Defaults from --project when saved.',\n },\n}\n\nexport function analyticsConnectionFromArgs(\n args: Record<string, unknown>,\n fallback?: AnalyticsConnection,\n): AnalyticsConnection | undefined {\n const googlePropertyId = stringArg(args['google-analytics-property'])\n const clickySiteId = stringArg(args['clicky-site-id'])\n if (googlePropertyId && clickySiteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass either --google-analytics-property or --clicky-site-id, not both.',\n )\n }\n if (googlePropertyId) {\n return { provider: 'google', propertyId: googlePropertyId }\n }\n if (clickySiteId) {\n return { provider: 'clicky', siteId: normalizeClickySiteId(clickySiteId) }\n }\n return fallback\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport {\n analyticsConnection,\n type CrawlOutputFormat,\n crawlSite,\n renderCrawlCsv,\n renderCrawlHtml,\n renderCrawlJunit,\n renderCrawlMarkdownTickets,\n renderCrawlPagesCsv,\n renderCrawlPretty,\n reviewObservations,\n saveCrawlReport,\n topFixes,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n fetchRateArg,\n jsonFlag,\n negatedBooleanArg,\n numberArg,\n projectArg,\n renderingModeArg,\n stringArg,\n} from '../args.js'\nimport { writeJsonOutput } from '../json-output.js'\nimport { printCrawlHuman } from '../presentation/crawl-report.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printKeyValue } from '../utils.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from './analytics/connection.js'\nimport { startUrlForSite } from './shared.js'\n\ntype Severity = 'low' | 'medium' | 'high'\n\nconst severityRank: Record<Severity, number> = {\n high: 3,\n medium: 2,\n low: 1,\n}\n\nexport const crawlCommand = defineCommand({\n meta: {\n name: 'crawl',\n description: 'Run a fast sitemap health pass or a full technical crawl',\n },\n args: {\n crawlUrl: {\n type: 'positional',\n required: false,\n description: 'Site start URL. Optional with --sitemap-url.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Optional when --project has a saved crawl URL.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL for joining page metrics.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...analyticsConnectionArgs,\n mode: {\n type: 'string',\n description:\n 'Crawl mode: site, page, list, or sitemap. Start with sitemap --health for large sites.',\n },\n health: {\n type: 'boolean',\n default: false,\n description:\n 'Run the uncached sitemap status and redirect pass before a full audit. No page-body analysis.',\n },\n 'sitemap-url': {\n type: 'string',\n description:\n 'Explicit sitemap URL. Selects sitemap mode when --mode is omitted.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs for list mode.',\n },\n 'urls-file': {\n type: 'string',\n description: 'File with one URL per line for list mode.',\n },\n 'max-pages': {\n type: 'string',\n description: 'Maximum pages to crawl, up to 10,000. Defaults to 500.',\n },\n 'max-depth': {\n type: 'string',\n description: 'Maximum click depth, up to 64. Defaults to 16.',\n },\n concurrency: {\n type: 'string',\n description:\n 'Parallel page fetches, up to 16. Defaults to 8, or progressively up to 4 with --health.',\n },\n 'fetch-interval-cap': {\n type: 'string',\n description: 'Maximum page fetches per interval per host.',\n },\n 'fetch-interval-ms': {\n type: 'string',\n description: 'Fetch rate interval in milliseconds.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache and fetch fresh pages.',\n },\n include: {\n type: 'string',\n description: 'Comma-separated URL patterns to include.',\n },\n exclude: {\n type: 'string',\n description: 'Comma-separated URL patterns to exclude.',\n },\n 'no-sitemap': {\n type: 'boolean',\n default: false,\n description: 'Do not seed URLs from sitemap.xml.',\n },\n 'no-robots': {\n type: 'boolean',\n default: false,\n description: 'Do not skip URLs disallowed by robots.txt.',\n },\n 'no-external': {\n type: 'boolean',\n default: false,\n description:\n 'Do not check external links. Reserved for full link checks.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Legacy alias for --rendering on.',\n },\n rendering: {\n type: 'string',\n description:\n 'JavaScript rendering mode: auto, on, or off. Defaults to auto.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON. Alias for --format json.',\n },\n format: {\n type: 'string',\n description:\n 'Output format: pretty, json, csv, html, markdown, or junit. JUnit requires --health.',\n },\n output: {\n type: 'string',\n description: 'Write output to this path instead of stdout.',\n },\n csv: {\n type: 'string',\n description: 'CSV table to render: issues or pages. Defaults to issues.',\n },\n save: {\n type: 'boolean',\n default: false,\n description: 'Save the crawl report locally.',\n },\n severity: {\n type: 'string',\n description: 'Only show top fixes at this severity.',\n },\n 'fail-on': {\n type: 'string',\n description: 'Exit non-zero when issues exist at this severity or above.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const format = crawlFormatArg(args.format, json)\n const output = stringArg(args.output)\n const csv = crawlCsvArg(args.csv)\n const severity = severityArg(args.severity)\n const failOn = severityArg(args['fail-on'])\n const project = projectArg(args)\n const urls = await urlListArgs(args)\n const explicitUrl = crawlUrlArg(args)\n const sitemapUrl = stringArg(args['sitemap-url'])\n const health = booleanArg(args.health)\n const explicitMode = crawlModeArg(args.mode)\n if (format === 'junit' && !health) {\n throw new Error('--format junit requires --health.')\n }\n if ((health || sitemapUrl) && explicitMode && explicitMode !== 'sitemap') {\n throw new Error('--health and --sitemap-url require sitemap mode.')\n }\n if (health && negatedBooleanArg(args, 'sitemap')) {\n throw new Error('--health cannot be combined with --no-sitemap.')\n }\n if ((health || sitemapUrl) && urls.length) {\n throw new Error(\n '--health and --sitemap-url cannot be combined with URL list input.',\n )\n }\n const selection =\n stringArg(args.site) ||\n project ||\n (!explicitUrl && !urls.length && !sitemapUrl)\n ? await resolveClientSelection({\n client: project,\n site: stringArg(args.site),\n options: { json },\n })\n : undefined\n const crawlUrl =\n explicitUrl ??\n selection?.client?.startUrl ??\n (selection?.site ? startUrlForSite(selection.site) : undefined) ??\n (sitemapUrl ? new URL('/', sitemapUrl).toString() : undefined) ??\n urls[0]\n if (!crawlUrl) {\n throw new Error(\n 'No crawl URL selected. Pass a URL, --url, or use --project with a saved crawl URL.',\n )\n }\n\n const report = await crawlSite({\n url: crawlUrl,\n projectId: selection?.client?.id,\n site: selection?.site,\n mode:\n explicitMode ??\n (health || sitemapUrl ? 'sitemap' : urls.length ? 'list' : undefined),\n strategy: health ? 'health' : 'full',\n sitemapUrl,\n urls,\n maxPages: numberArg(args['max-pages']),\n maxDepth: numberArg(args['max-depth']),\n concurrency: numberArg(args.concurrency),\n refresh: booleanArg(args.refresh),\n fetchRate: fetchRateArg({\n ...args,\n 'fetch-concurrency': args.concurrency,\n }),\n include: csvArg(args.include),\n exclude: csvArg(args.exclude),\n googleAnalyticsPropertyId: stringArg(args['google-analytics-property']),\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection?.client),\n ),\n useSitemap: !negatedBooleanArg(args, 'sitemap'),\n respectRobots: !negatedBooleanArg(args, 'robots'),\n checkExternal: !negatedBooleanArg(args, 'external'),\n js: renderingModeArg(args),\n })\n const saved = booleanArg(args.save) ? saveCrawlReport(report) : undefined\n const rankedFixes = topFixes(report, { severity })\n const failedThreshold = failOn\n ? report.issues.some(\n (issue) => severityRank[issue.severity] >= severityRank[failOn],\n )\n : false\n const failedRun = report.status === 'failed'\n\n const payload = {\n ...report,\n topFixes: rankedFixes,\n reviewObservations: reviewObservations(report, { severity }),\n ...(failOn ? { failOn, failedThreshold } : {}),\n ...(saved ? { saved } : {}),\n }\n\n if (format === 'json') {\n await writeJsonOutput(output, payload)\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'csv') {\n await writeOrPrint(\n output,\n csv === 'pages' ? renderCrawlPagesCsv(report) : renderCrawlCsv(report),\n )\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'html') {\n await writeOrPrint(output, renderCrawlHtml(report, rankedFixes))\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'junit') {\n await writeOrPrint(output, renderCrawlJunit(report))\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'markdown') {\n await writeOrPrint(\n output,\n renderCrawlMarkdownTickets(report, rankedFixes),\n )\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (output) {\n await writeOrPrint(output, renderCrawlPretty(report, rankedFixes))\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n printCrawlHuman(report, rankedFixes)\n if (saved || failOn) {\n process.stdout.write('\\nRun metadata\\n')\n printKeyValue([\n ['Saved report', saved?.id ?? 'no'],\n ['Fail threshold', failOn ?? 'off'],\n ])\n }\n if (failedRun || failedThreshold) {\n process.exitCode = 1\n }\n },\n})\n\nfunction crawlModeArg(value: unknown) {\n const mode = stringArg(value)\n if (!mode) return undefined\n if (['site', 'page', 'list', 'sitemap'].includes(mode)) {\n return mode as 'site' | 'page' | 'list' | 'sitemap'\n }\n throw new Error('Mode must be one of: site, page, list, sitemap.')\n}\n\nfunction severityArg(value: unknown): Severity | undefined {\n const severity = stringArg(value)\n if (!severity) return undefined\n if (['low', 'medium', 'high'].includes(severity)) {\n return severity as Severity\n }\n throw new Error('Severity must be one of: low, medium, high.')\n}\n\nfunction crawlUrlArg(args: Record<string, unknown>): string | undefined {\n const positional = stringArg(args.crawlUrl)\n const flag = stringArg(args.url)\n if (positional && flag && positional !== flag) {\n throw new Error('Use either a URL argument or --url, not both.')\n }\n return positional ?? flag\n}\n\nfunction crawlFormatArg(value: unknown, json: boolean): CrawlOutputFormat {\n const format = stringArg(value)\n if (json && format && format !== 'json') {\n throw new Error('Use either --json or --format, not both.')\n }\n if (!format) return json ? 'json' : 'pretty'\n if (['pretty', 'json', 'csv', 'html', 'markdown', 'junit'].includes(format)) {\n return format as CrawlOutputFormat\n }\n throw new Error(\n 'Format must be one of: pretty, json, csv, html, markdown, junit.',\n )\n}\n\nfunction crawlCsvArg(value: unknown): 'issues' | 'pages' {\n const csv = stringArg(value)\n if (!csv) return 'issues'\n if (['issues', 'pages'].includes(csv)) return csv as 'issues' | 'pages'\n throw new Error('CSV table must be one of: issues, pages.')\n}\n\nasync function urlListArgs(args: Record<string, unknown>): Promise<string[]> {\n const urls = csvArg(args.urls) ?? []\n const file = stringArg(args['urls-file'])\n if (file) {\n urls.push(...parseUrlList(await readFile(file, 'utf8')))\n }\n return [...new Set(urls)]\n}\n\nfunction parseUrlList(value: string): string[] {\n return value\n .split(/[\\n,]/)\n .map((item) => item.trim())\n .filter((item) => item && !item.startsWith('#'))\n}\n\nasync function writeOrPrint(path: string | undefined, content: string) {\n if (!path) {\n process.stdout.write(content)\n return\n }\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, content)\n process.stdout.write(`Wrote ${path}\\n`)\n}\n","import {\n type CrawlReport,\n type CrawlReportMeta,\n compareCrawlReports,\n crawlSite,\n deleteCrawlReport,\n latestCrawlReport,\n listCrawlReports,\n loadCrawlReport,\n reviewObservations,\n saveCrawlReport,\n topFixes,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printCrawlHuman } from '../presentation/crawl-report.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printJson, printSummaryList, printTable } from '../utils.js'\nimport {\n printActionDetails,\n printNotes,\n printReportSummary,\n truncate,\n} from './output.js'\n\nasync function reportSiteFilter(args: Record<string, unknown>, json: boolean) {\n const project = projectArg(args)\n const site = stringArg(args.site)\n if (!project && !site) return undefined\n return (\n await resolveClientSelection({\n client: project,\n site,\n options: { json },\n })\n ).site\n}\n\nfunction printReportList(reports: CrawlReportMeta[]): void {\n printSummaryList(\n reports.map((report) => ({\n title: report.id,\n description: report.site ?? report.url,\n meta: [\n report.status,\n `${report.totalPages} page${report.totalPages === 1 ? '' : 's'}`,\n `${report.issueCount} issue${report.issueCount === 1 ? '' : 's'}`,\n report.createdAt,\n ],\n })),\n { empty: 'No saved crawl reports.' },\n )\n}\n\nfunction printReport(report: CrawlReport): void {\n printCrawlHuman(report)\n}\n\nfunction printReportDiff(report: ReturnType<typeof compareCrawlReports>): void {\n printReportSummary({\n title: 'Crawl report comparison',\n target: report.after.url,\n status:\n report.comparability.status !== 'comparable' ||\n report.completeness.status !== 'complete'\n ? 'unknown'\n : report.summary.newStatusErrors > 0 ||\n report.summary.issueGroupsWorse > 0\n ? 'warning'\n : 'pass',\n summary: report.headline,\n metrics: [\n {\n label: 'Before',\n value: `${report.before.id} (${report.before.generatedAt})`,\n },\n {\n label: 'After',\n value: `${report.after.id} (${report.after.generatedAt})`,\n },\n { label: 'Comparability', value: report.comparability.status },\n { label: 'Completeness', value: report.completeness.status },\n {\n label: 'Pages',\n value: `${report.after.summary.totalPages} (${report.summary.pageDelta >= 0 ? '+' : ''}${report.summary.pageDelta})`,\n },\n {\n label: 'Issues',\n value: `${report.after.summary.highIssues + report.after.summary.mediumIssues + report.after.summary.lowIssues} (${report.summary.issueDelta >= 0 ? '+' : ''}${report.summary.issueDelta})`,\n },\n { label: 'New status errors', value: report.summary.newStatusErrors },\n { label: 'Fixed status errors', value: report.summary.fixedStatusErrors },\n { label: 'Issue groups worse', value: report.summary.issueGroupsWorse },\n { label: 'Issue groups better', value: report.summary.issueGroupsBetter },\n { label: 'Changed pages', value: report.summary.changedPages },\n { label: 'Added pages', value: report.summary.addedPages },\n { label: 'Removed pages', value: report.summary.removedPages },\n ],\n })\n\n printActionDetails(\n 'Top actions',\n report.topActions.map((action) => ({\n label: action.title,\n context: action.plainEnglish,\n action: action.action,\n })),\n report.topActions.length,\n )\n\n if (report.pageChanges.length) {\n process.stdout.write('\\nChanged pages\\n')\n printTable(\n ['Kind', 'Changes', 'URL'],\n report.pageChanges\n .slice(0, 15)\n .map((item) => [\n item.kind,\n item.changes.join(', '),\n truncate(item.url, 80),\n ]),\n )\n if (report.pageChanges.length > 15) {\n process.stdout.write(\n `Showing 15 of ${report.pageChanges.length}. Use --json for all changes.\\n`,\n )\n }\n }\n\n if (report.issueChanges.length) {\n process.stdout.write('\\nIssue movement\\n')\n printTable(\n ['Rule', 'Before', 'After', 'Delta'],\n report.issueChanges\n .slice(0, 10)\n .map((item) => [\n item.ruleId,\n String(item.before),\n String(item.after),\n `${item.delta >= 0 ? '+' : ''}${item.delta}`,\n ]),\n )\n }\n\n printNotes('Caveats', report.caveats)\n}\n\nfunction selectReportAliasMeta(\n reports: CrawlReportMeta[],\n input: {\n value: 'latest' | 'previous'\n skipId?: string\n },\n): CrawlReportMeta | undefined {\n if (input.value === 'latest') {\n return reports.find((item) => item.id !== input.skipId)\n }\n\n if (input.skipId) {\n const skippedIndex = reports.findIndex((item) => item.id === input.skipId)\n const older = skippedIndex >= 0 ? reports.slice(skippedIndex + 1) : reports\n return older.find((item) => item.id !== input.skipId)\n }\n\n return reports[1]\n}\n\nfunction resolveReportAlias(input: {\n value: string\n site?: string\n skipId?: string\n}): CrawlReport | undefined {\n if (input.value !== 'latest' && input.value !== 'previous') {\n return loadCrawlReport(input.value)\n }\n const reports = listCrawlReports({ site: input.site, limit: 20 })\n const meta = selectReportAliasMeta(reports, {\n value: input.value,\n skipId: input.skipId,\n })\n return meta ? loadCrawlReport(meta.id) : undefined\n}\n\nexport const crawlReportsCommand = defineCommand({\n meta: {\n name: 'crawl-reports',\n description: 'List, show, or delete saved crawl reports',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL for filtering reports.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n id: {\n type: 'string',\n description: 'Saved crawl report id to show.',\n },\n latest: {\n type: 'boolean',\n default: false,\n description: 'Show the latest saved crawl report.',\n },\n delete: {\n type: 'string',\n description: 'Delete a saved crawl report by id.',\n },\n rerun: {\n type: 'string',\n description: 'Rerun a saved crawl report by id, or pass latest.',\n },\n compare: {\n type: 'string',\n description: 'Compare a saved report id, latest, or previous.',\n },\n against: {\n type: 'string',\n description: 'Baseline report id. Defaults to previous.',\n },\n limit: {\n type: 'string',\n description: 'Maximum reports to list. Defaults to 20.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const site = await reportSiteFilter(args, json)\n const deleteId = stringArg(args.delete)\n const rerunId = stringArg(args.rerun)\n const compareId = stringArg(args.compare)\n const id = stringArg(args.id)\n\n if (deleteId) {\n const deleted = deleteCrawlReport(deleteId)\n if (json) {\n printJson({ id: deleteId, deleted })\n return\n }\n process.stdout.write(\n deleted\n ? `Deleted crawl report ${deleteId}.\\n`\n : `No saved crawl report found for ${deleteId}.\\n`,\n )\n return\n }\n\n if (rerunId) {\n const previous =\n rerunId === 'latest'\n ? latestCrawlReport(site)\n : loadCrawlReport(rerunId)\n if (!previous) {\n throw new Error(\n rerunId === 'latest'\n ? 'No saved crawl reports found.'\n : `No saved crawl report found for ${rerunId}.`,\n )\n }\n const report = await crawlSite({\n ...previous.config,\n projectId: previous.projectId,\n site: previous.site,\n googleAnalyticsPropertyId: previous.googleAnalyticsPropertyId,\n })\n const saved = saveCrawlReport(report)\n if (json) {\n printJson({\n ...report,\n rerunOf: previous.id,\n saved,\n topFixes: topFixes(report),\n reviewObservations: reviewObservations(report),\n })\n return\n }\n process.stdout.write(`Reran crawl report ${previous.id}.\\n\\n`)\n printReport(report)\n return\n }\n\n if (compareId) {\n const after = resolveReportAlias({ value: compareId, site })\n if (!after) {\n throw new Error(`No saved crawl report found for ${compareId}.`)\n }\n const beforeAlias = stringArg(args.against) ?? 'previous'\n const before = resolveReportAlias({\n value: beforeAlias,\n site: after.site ?? site,\n skipId: after.id,\n })\n if (!before) {\n throw new Error(\n `No baseline crawl report found for ${beforeAlias}. Save at least two reports or pass --against <id>.`,\n )\n }\n const diff = compareCrawlReports({ before, after })\n if (json) {\n printJson(diff)\n return\n }\n printReportDiff(diff)\n return\n }\n\n if (id || booleanArg(args.latest)) {\n const report = id ? loadCrawlReport(id) : latestCrawlReport(site)\n if (!report) {\n throw new Error(\n id\n ? `No saved crawl report found for ${id}.`\n : 'No saved crawl reports found.',\n )\n }\n if (json) {\n printJson(report)\n return\n }\n printReport(report)\n return\n }\n\n const reports = listCrawlReports({\n site,\n limit: numberArg(args.limit),\n })\n if (json) {\n printJson({ reports })\n return\n }\n printReportList(reports)\n },\n})\n","import { inspectUrl, querySearchAnalytics } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonBodyArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printJson, printTable } from '../utils.js'\nimport { printReportSummary } from './output.js'\nimport { selectedSiteOrThrow } from './shared.js'\n\nexport const gscQueryCommand = defineCommand({\n meta: {\n name: 'gsc-query',\n description: 'Run a raw Search Console Search Analytics query',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n 'start-date': { type: 'string', description: 'Start date YYYY-MM-DD.' },\n 'end-date': { type: 'string', description: 'End date YYYY-MM-DD.' },\n dimensions: {\n type: 'string',\n description: 'Comma-separated GSC dimensions, for example query,page.',\n },\n type: { type: 'string', description: 'Search type. Defaults to web.' },\n limit: {\n type: 'string',\n description: 'Maximum rows to request and print.',\n },\n body: { type: 'string', description: 'Raw Search Analytics JSON body.' },\n 'body-file': {\n type: 'string',\n description: 'Path to a Search Analytics JSON body file.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n },\n run: async ({ args }) => {\n const body =\n (await jsonBodyArg(args.body, args['body-file'])) ??\n ({\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n dimensions: csvArg(args.dimensions) ?? ['query', 'page'],\n type: stringArg(args.type) ?? 'web',\n rowLimit: numberArg(args.limit),\n dataState: 'final',\n } as Record<string, unknown>)\n const json = jsonFlag(args)\n const site = await selectedSiteOrThrow(\n {\n client: projectArg(args),\n site: stringArg(args.site) ?? stringArg(body.siteUrl),\n },\n {\n json,\n refresh: booleanArg(args.refresh),\n account: stringArg(args.account),\n },\n )\n delete body.siteUrl\n const result = await querySearchAnalytics(site, body as never, {\n refresh: booleanArg(args.refresh),\n accountEmail: stringArg(args.account),\n })\n const limit = numberArg(args.limit)\n const rows = limit ? result.rows.slice(0, limit) : result.rows\n if (json) {\n printJson({\n site,\n request: body,\n ...result,\n rows,\n rowsReturned: rows.length,\n })\n return\n }\n printReportSummary({\n title: 'Search Console query',\n target: site,\n status: result.rowsFetched > rows.length ? 'unknown' : 'info',\n summary: `${rows.length} rows returned from ${result.rowsFetched} fetched rows.`,\n metrics: [\n { label: 'Rows returned', value: rows.length },\n { label: 'Rows fetched', value: result.rowsFetched },\n { label: 'API calls', value: result.calls },\n ],\n })\n printTable(\n ['Keys', 'Clicks', 'Impr', 'CTR', 'Pos'],\n rows\n .slice(0, 25)\n .map((row) => [\n row.keys.join(' | '),\n Math.round(row.clicks),\n Math.round(row.impressions),\n row.ctr.toFixed(3),\n row.position.toFixed(1),\n ]),\n )\n },\n})\n\nexport const urlInspectCommand = defineCommand({\n meta: {\n name: 'url-inspect',\n description: 'Inspect a URL with the Search Console URL Inspection API',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n url: { type: 'string', description: 'URL to inspect.' },\n language: {\n type: 'string',\n description: 'Optional inspection language code.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const siteUrl = await selectedSiteOrThrow(\n { client: projectArg(args), site: stringArg(args.site) },\n { json, account: stringArg(args.account) },\n )\n const inspectionUrl = stringArg(args.url)\n if (!inspectionUrl) throw new Error('Pass --url.')\n const result = await inspectUrl({\n siteUrl,\n inspectionUrl,\n accountEmail: stringArg(args.account),\n languageCode: stringArg(args.language),\n })\n if (json) {\n printJson(result)\n return\n }\n const indexStatus = result.inspectionResult?.indexStatusResult\n printReportSummary({\n title: 'URL Inspection',\n target: inspectionUrl,\n status:\n indexStatus === undefined\n ? 'unknown'\n : indexStatus.verdict === 'PASS'\n ? 'pass'\n : 'warning',\n summary:\n indexStatus === undefined\n ? 'Google did not return index status evidence for this URL.'\n : `${indexStatus.verdict ?? 'Unknown'}: ${indexStatus.coverageState ?? 'Coverage state unavailable'}.`,\n metrics: [\n { label: 'Property', value: siteUrl },\n { label: 'Robots', value: indexStatus?.robotsTxtState ?? 'Unknown' },\n { label: 'Last crawl', value: indexStatus?.lastCrawlTime ?? 'Unknown' },\n {\n label: 'Google canonical',\n value: indexStatus?.googleCanonical ?? 'Unknown',\n },\n ],\n })\n },\n})\n","import type { ArgDef } from 'citty'\n\n// Shared report option metadata used by CLI commands. The parity check keeps\n// this aligned with scripts/report-surface-catalog.mjs.\ntype CliReportOption = {\n cli: string\n arg: ArgDef\n}\n\nconst REPORT_OPTIONS = {\n days: {\n cli: 'days',\n arg: {\n type: 'string',\n description: 'GSC lookback window. Defaults to 28.',\n },\n },\n recentDays: {\n cli: 'recent',\n arg: {\n type: 'string',\n description: 'Recent anomaly window in days. Defaults to 14.',\n },\n },\n range: {\n cli: 'days',\n arg: {\n type: 'string',\n description: 'GSC lookback window. Defaults to 28.',\n },\n },\n limit: {\n cli: 'limit',\n arg: {\n type: 'string',\n description: 'Maximum rows to return.',\n },\n },\n checkLimit: {\n cli: 'check-limit',\n arg: {\n type: 'string',\n description: 'Maximum candidate pages to fetch and check.',\n },\n },\n minImpressions: {\n cli: 'min-impressions',\n arg: {\n type: 'string',\n description: 'Minimum query impressions.',\n },\n },\n includeBrand: {\n cli: 'include-brand',\n arg: {\n type: 'boolean',\n default: false,\n description: 'Include branded queries in opportunity reports.',\n },\n },\n verifyContent: {\n cli: 'verify-content',\n arg: {\n type: 'boolean',\n default: false,\n description:\n 'Verify top opportunities against page title, meta, and content.',\n },\n },\n verifyLimit: {\n cli: 'verify-limit',\n arg: {\n type: 'string',\n description: 'Maximum opportunity URLs to verify.',\n },\n },\n js: {\n cli: 'js',\n arg: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for verified pages.',\n },\n },\n fetchConcurrency: {\n cli: 'fetch-concurrency',\n arg: {\n type: 'string',\n description:\n 'Maximum concurrent page fetches per host, up to 16. Defaults to 4.',\n },\n },\n fetchIntervalCap: {\n cli: 'fetch-interval-cap',\n arg: {\n type: 'string',\n description: 'Maximum page fetches per interval per host. Defaults to 4.',\n },\n },\n fetchIntervalMs: {\n cli: 'fetch-interval-ms',\n arg: {\n type: 'string',\n description: 'Fetch rate interval in milliseconds. Defaults to 1000.',\n },\n },\n refresh: {\n cli: 'refresh',\n arg: {\n type: 'boolean',\n default: false,\n description: 'Bypass local cache and fetch fresh data.',\n },\n },\n} as const satisfies Record<string, CliReportOption>\n\ntype ReportOptionKey = keyof typeof REPORT_OPTIONS\n\nexport function cliReportArgs<const T extends readonly ReportOptionKey[]>(\n keys: T,\n overrides: Partial<Record<ReportOptionKey, Partial<ArgDef>>> = {},\n): Record<(typeof REPORT_OPTIONS)[T[number]]['cli'], ArgDef> {\n return Object.fromEntries(\n keys.map((key) => {\n const option = REPORT_OPTIONS[key]\n return [option.cli, { ...option.arg, ...overrides[key] }]\n }),\n ) as Record<(typeof REPORT_OPTIONS)[T[number]]['cli'], ArgDef>\n}\n","import { trafficAnomaly, updateCorrelation } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printJson, printTable } from '../utils.js'\nimport {\n printLimitedTable,\n printNextCommand,\n printNotes,\n printReportSummary,\n} from './output.js'\nimport { cliReportArgs } from './report-options.js'\nimport { selectedSiteOrThrow } from './shared.js'\n\nfunction formatNumber(value: number): string {\n return value.toLocaleString('en-GB', {\n maximumFractionDigits: value >= 100 ? 0 : 1,\n })\n}\n\nfunction formatChange(value: number | null): string {\n if (value === null) return 'n/a'\n const rounded = Math.abs(value) >= 10 ? value.toFixed(0) : value.toFixed(1)\n return `${value > 0 ? '+' : ''}${rounded}%`\n}\n\nexport const trafficAnomalyCommand = defineCommand({\n meta: {\n name: 'traffic-anomaly',\n description: 'Detect unusual recent GSC traffic movement',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'recentDays', 'refresh'], {\n days: { description: 'Baseline window length in days. Defaults to 90.' },\n recentDays: {\n description: 'Recent anomaly window in days. Defaults to 7.',\n },\n refresh: {\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n }),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const report = await trafficAnomaly({\n site: await selectedSiteOrThrow(\n { client: projectArg(args), site: stringArg(args.site) },\n {\n json,\n refresh: booleanArg(args.refresh),\n },\n ),\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Traffic anomaly report',\n target: report.site,\n status:\n report.coverage?.status !== 'complete'\n ? 'unknown'\n : report.anomalies.some((anomaly) => anomaly.significant)\n ? 'warning'\n : 'pass',\n summary: report.anomalies.some((anomaly) => anomaly.significant)\n ? 'At least one recent metric moved beyond the report threshold.'\n : 'No significant recent movement was found in the retained evidence.',\n metrics: [\n { label: 'Metrics checked', value: report.anomalies.length },\n {\n label: 'Significant',\n value: report.anomalies.filter((anomaly) => anomaly.significant)\n .length,\n },\n {\n label: 'Observed days',\n value: report.coverage?.observedDays ?? 'Unavailable',\n },\n {\n label: 'Expected days',\n value: report.coverage?.expectedDays ?? 'Unavailable',\n },\n ],\n })\n printLimitedTable(\n [\n 'Metric',\n 'Direction',\n 'Baseline/day',\n 'Recent/day',\n 'Change',\n 'z',\n 'Significant',\n ],\n report.anomalies.map((anomaly) => [\n anomaly.metric,\n anomaly.direction,\n formatNumber(anomaly.baselineMean),\n formatNumber(anomaly.comparisonMean),\n formatChange(anomaly.percentChange),\n anomaly.zScore ?? 'n/a',\n anomaly.significant ? 'yes' : 'no',\n ]),\n )\n if (report.coverage) {\n printNotes('Evidence coverage', [\n `${report.coverage.observedDays} of ${report.coverage.expectedDays} requested calendar days returned date aggregates.`,\n ...report.coverage.caveats,\n ])\n }\n },\n})\n\nexport const updateCorrelateCommand = defineCommand({\n meta: {\n name: 'update-correlate',\n description: 'Compare traffic movement with official Google update windows',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'recentDays', 'refresh'], {\n days: { description: 'Baseline window length in days. Defaults to 90.' },\n recentDays: {\n description: 'Recent anomaly window in days. Defaults to 7.',\n },\n refresh: {\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n }),\n 'padding-days': {\n type: 'string',\n description: 'Days around update windows to count as overlap.',\n },\n 'known-change': {\n type: 'string',\n description:\n 'Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.',\n },\n 'ignore-change-log': {\n type: 'boolean',\n default: false,\n description: 'Do not use saved change-log entries as confounders.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const client = projectArg(args)\n const site = await selectedSiteOrThrow(\n { client, site: stringArg(args.site) },\n {\n json,\n refresh: booleanArg(args.refresh),\n },\n )\n const report = await updateCorrelation({\n site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n paddingDays: numberArg(args['padding-days']),\n knownConfounders: stringArg(args['known-change'])\n ? [stringArg(args['known-change']) ?? '']\n : undefined,\n includeChangeLog: !booleanArg(args['ignore-change-log']),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Google update correlation',\n target: report.site,\n status: 'unknown',\n summary: report.summary,\n metrics: [\n {\n label: 'Classification',\n value: report.classification.replaceAll('-', ' '),\n },\n {\n label: 'Attribution',\n value: report.attribution.replaceAll('-', ' '),\n },\n { label: 'Confidence', value: report.confidence },\n { label: 'Updates matched', value: report.overlappingUpdates.length },\n { label: 'Known confounders', value: report.confounders.length },\n { label: 'Source', value: report.source.name },\n ],\n })\n printNotes('Evidence', report.evidence)\n printNotes('Report caveats', report.caveats)\n printNotes('Recommended next checks', report.actions)\n printLimitedTable(\n ['Metric', 'Direction', 'Baseline/day', 'Recent/day', 'Change', 'z'],\n report.anomalies.map((anomaly) => [\n anomaly.metric,\n anomaly.direction,\n formatNumber(anomaly.baselineMean),\n formatNumber(anomaly.comparisonMean),\n formatChange(anomaly.percentChange),\n anomaly.zScore ?? 'n/a',\n ]),\n )\n if (report.overlappingUpdates.length) {\n process.stdout.write('\\nUpdates\\n')\n printTable(\n ['Start', 'End', 'Type', 'Name'],\n report.overlappingUpdates.map((update) => [\n update.start.slice(0, 10),\n update.end?.slice(0, 10) ?? 'open',\n update.type,\n update.name,\n ]),\n )\n }\n const target = client\n ? `--project ${JSON.stringify(client)}`\n : `--site ${JSON.stringify(site)}`\n printNextCommand(`seo segment-impact ${target} --dimension page`)\n },\n})\n","import {\n type ChangeScope,\n deleteChange,\n listChanges,\n measureChange,\n recordChange,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary } from '../output.js'\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction changeScope(value: unknown): ChangeScope {\n const scope = stringArg(value) ?? 'page'\n if (\n scope !== 'site' &&\n scope !== 'page' &&\n scope !== 'query' &&\n scope !== 'group'\n ) {\n throw new Error('Invalid --scope. Use site, page, query, or group.')\n }\n return scope\n}\n\nexport const changeLogCommand = defineCommand({\n meta: {\n name: 'change-log',\n description: 'Annotate SEO changes and measure before/after impact',\n },\n subCommands: {\n list: defineCommand({\n meta: {\n name: 'list',\n description: 'List recorded SEO changes',\n },\n args: {\n site: { type: 'string' },\n limit: { type: 'string' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const changes = listChanges({\n site: stringArg(args.site),\n limit: numberArg(args.limit),\n })\n if (jsonFlag(args)) {\n printJson({ changes })\n return\n }\n printTable(\n ['ID', 'Date', 'Site', 'Scope', 'Target', 'Title'],\n changes.map((change) => [\n change.id,\n change.changedAt,\n change.site,\n change.scope,\n change.target,\n change.title,\n ]),\n )\n },\n }),\n add: defineCommand({\n meta: {\n name: 'add',\n description: 'Record an SEO change',\n },\n args: {\n site: { type: 'string' },\n scope: { type: 'string', default: 'page' },\n target: { type: 'string', required: true },\n title: { type: 'string', required: true },\n description: { type: 'string' },\n date: { type: 'string' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const change = recordChange({\n site: await resolveSite({\n site: stringArg(args.site),\n options: { json },\n }),\n scope: changeScope(args.scope),\n target: stringArg(args.target) ?? '',\n title: stringArg(args.title) ?? '',\n description: stringArg(args.description),\n changedAt: stringArg(args.date) ?? today(),\n })\n if (json) {\n printJson(change)\n return\n }\n printKeyValue([\n ['ID', change.id],\n ['Date', change.changedAt],\n ['Site', change.site],\n ['Scope', change.scope],\n ['Target', change.target],\n ['Title', change.title],\n ])\n },\n }),\n delete: defineCommand({\n meta: {\n name: 'delete',\n description: 'Delete a recorded SEO change',\n },\n args: {\n id: { type: 'string', required: true },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const deleted = deleteChange(id)\n if (jsonFlag(args)) {\n printJson({ id, deleted })\n return\n }\n process.stdout.write(`${deleted ? 'Deleted' : 'Not found'} ${id}.\\n`)\n },\n }),\n measure: defineCommand({\n meta: {\n name: 'measure',\n description:\n 'Measure a change with equal finalized before/after windows',\n },\n args: {\n id: { type: 'string' },\n site: { type: 'string' },\n scope: { type: 'string' },\n target: { type: 'string' },\n title: { type: 'string' },\n date: { type: 'string' },\n before: { type: 'string' },\n after: { type: 'string' },\n json: { type: 'boolean', default: false },\n refresh: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const id = stringArg(args.id)\n if (\n !id &&\n (!stringArg(args.site) ||\n !stringArg(args.scope) ||\n !stringArg(args.target) ||\n !stringArg(args.date))\n ) {\n throw new Error(\n 'Pass --id, or pass --site, --scope, --target, and --date for an ad hoc measurement.',\n )\n }\n const report = await measureChange({\n id,\n site: id\n ? undefined\n : await resolveSite({\n site: stringArg(args.site),\n options: { json },\n }),\n scope: id ? undefined : changeScope(args.scope),\n target: id ? undefined : stringArg(args.target),\n title: stringArg(args.title),\n changedAt: id ? undefined : stringArg(args.date),\n beforeDays: strictNumberArg(args.before, '--before'),\n afterDays: strictNumberArg(args.after, '--after'),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Change measurement',\n target: report.change.title,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.note,\n metrics: [\n { label: 'Verdict', value: report.verdict },\n { label: 'Confidence', value: report.confidence },\n {\n label: 'Before',\n value: `${report.before.startDate} to ${report.before.endDate}`,\n },\n {\n label: 'After',\n value: `${report.after.startDate} to ${report.after.endDate}`,\n },\n {\n label: 'Window',\n value: `${report.window.effectiveDays}/${report.window.requestedDays} finalized days`,\n },\n ],\n })\n printTable(\n ['Metric', 'Before', 'After', 'Delta'],\n [\n [\n 'Clicks',\n report.before.metrics?.clicks ?? 'unavailable',\n report.after.metrics?.clicks ?? 'unavailable',\n report.delta.clicks === null\n ? 'unavailable'\n : report.delta.clickPct === null\n ? `${report.delta.clicks}`\n : `${report.delta.clicks} (${report.delta.clickPct}%)`,\n ],\n [\n 'Impressions',\n report.before.metrics?.impressions ?? 'unavailable',\n report.after.metrics?.impressions ?? 'unavailable',\n report.delta.impressions === null\n ? 'unavailable'\n : report.delta.impressionPct === null\n ? `${report.delta.impressions}`\n : `${report.delta.impressions} (${report.delta.impressionPct}%)`,\n ],\n [\n 'CTR',\n report.before.metrics?.ctr ?? 'unavailable',\n report.after.metrics?.ctr ?? 'unavailable',\n report.delta.ctr ?? 'unavailable',\n ],\n [\n 'Position',\n report.before.metrics?.position ?? 'unavailable',\n report.after.metrics?.position ?? 'unavailable',\n report.delta.position ?? 'unavailable',\n ],\n ],\n )\n printNotes('Warnings', report.warnings)\n printNotes('Caveats', report.caveats)\n },\n }),\n },\n})\n","import {\n type ContentGroupDimension,\n type ContentGroupMatchType,\n createContentGroup,\n deleteContentGroup,\n listContentGroups,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\n\nfunction groupDimension(value: unknown): ContentGroupDimension {\n const dimension = stringArg(value) ?? 'page'\n if (dimension !== 'page' && dimension !== 'query') {\n throw new Error('Invalid --dimension. Use page or query.')\n }\n return dimension\n}\n\nfunction matchType(value: unknown): ContentGroupMatchType {\n const type = stringArg(value) ?? 'contains'\n if (type !== 'equals' && type !== 'contains' && type !== 'regex') {\n throw new Error('Invalid --match. Use equals, contains, or regex.')\n }\n return type\n}\n\nexport const contentGroupsCommand = defineCommand({\n meta: {\n name: 'content-groups',\n description: 'Create and manage reusable page/query groups',\n },\n subCommands: {\n list: defineCommand({\n meta: {\n name: 'list',\n description: 'List saved content groups',\n },\n args: {\n site: { type: 'string' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const groups = listContentGroups(stringArg(args.site))\n if (jsonFlag(args)) {\n printJson({ groups })\n return\n }\n printTable(\n ['ID', 'Site', 'Name', 'Dimension', 'Match', 'Pattern'],\n groups.map((group) => [\n group.id,\n group.site,\n group.name,\n group.dimension,\n group.matchType,\n group.pattern,\n ]),\n )\n },\n }),\n add: defineCommand({\n meta: {\n name: 'add',\n description: 'Create a reusable page or query group',\n },\n args: {\n site: { type: 'string' },\n name: { type: 'string', required: true },\n dimension: { type: 'string', default: 'page' },\n match: { type: 'string', default: 'contains' },\n pattern: { type: 'string', required: true },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const group = createContentGroup({\n site: await resolveSite({\n site: stringArg(args.site),\n options: { json },\n }),\n name: stringArg(args.name) ?? '',\n dimension: groupDimension(args.dimension),\n matchType: matchType(args.match),\n pattern: stringArg(args.pattern) ?? '',\n })\n if (json) {\n printJson(group)\n return\n }\n printKeyValue([\n ['ID', group.id],\n ['Site', group.site],\n ['Name', group.name],\n ['Filter', `${group.dimension} ${group.matchType} ${group.pattern}`],\n ])\n },\n }),\n delete: defineCommand({\n meta: {\n name: 'delete',\n description: 'Delete a content group',\n },\n args: {\n id: { type: 'string', required: true },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const deleted = deleteContentGroup(id)\n if (jsonFlag(args)) {\n printJson({ id, deleted })\n return\n }\n process.stdout.write(`${deleted ? 'Deleted' : 'Not found'} ${id}.\\n`)\n },\n }),\n },\n})\n","import {\n type ChangeMeasurement,\n type ChangeScope,\n listChanges,\n measureChange,\n recordChange,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\nimport { formatCount, printNotes, printReportSummary } from '../output.js'\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction changeScope(value: unknown): ChangeScope {\n const scope = stringArg(value) ?? 'page'\n if (\n scope !== 'site' &&\n scope !== 'page' &&\n scope !== 'query' &&\n scope !== 'group'\n ) {\n throw new Error('Invalid --scope. Use site, page, query, or group.')\n }\n return scope\n}\n\nfunction maybeScope(value: unknown): ChangeScope | undefined {\n return value ? changeScope(value) : undefined\n}\n\nfunction pct(value: number | null): string {\n return value === null ? 'n/a' : `${value.toFixed(1)}%`\n}\n\nfunction countMetric(value: number | null | undefined): string {\n return value === null || value === undefined\n ? 'unavailable'\n : formatCount(value)\n}\n\nfunction countDelta(value: number | null, percentage: number | null): string {\n return value === null\n ? 'unavailable'\n : `${formatCount(value)} (${pct(percentage)})`\n}\n\nfunction decimalMetric(value: number | null | undefined, digits = 1): string {\n return value === null || value === undefined\n ? 'unavailable'\n : value.toFixed(digits)\n}\n\nfunction printMeasurement(report: ChangeMeasurement): void {\n printReportSummary({\n title: 'SEO test report',\n target: report.change.title,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.note,\n metrics: [\n { label: 'Verdict', value: report.verdict },\n { label: 'Confidence', value: report.confidence },\n {\n label: 'Before',\n value: `${report.before.startDate} to ${report.before.endDate}`,\n },\n {\n label: 'After',\n value: `${report.after.startDate} to ${report.after.endDate}`,\n },\n {\n label: 'Window',\n value: `${report.window.effectiveDays}/${report.window.requestedDays} finalized days`,\n },\n ],\n })\n printTable(\n ['Metric', 'Before', 'After', 'Delta'],\n [\n [\n 'GSC clicks',\n countMetric(report.before.metrics?.clicks),\n countMetric(report.after.metrics?.clicks),\n countDelta(report.delta.clicks, report.delta.clickPct),\n ],\n [\n 'GSC impressions',\n countMetric(report.before.metrics?.impressions),\n countMetric(report.after.metrics?.impressions),\n countDelta(report.delta.impressions, report.delta.impressionPct),\n ],\n [\n 'GSC CTR',\n report.before.metrics\n ? `${(report.before.metrics.ctr * 100).toFixed(1)}%`\n : 'unavailable',\n report.after.metrics\n ? `${(report.after.metrics.ctr * 100).toFixed(1)}%`\n : 'unavailable',\n report.delta.ctr === null\n ? 'unavailable'\n : `${(report.delta.ctr * 100).toFixed(1)} pts`,\n ],\n [\n 'GSC position',\n decimalMetric(report.before.metrics?.position),\n decimalMetric(report.after.metrics?.position),\n decimalMetric(report.delta.position),\n ],\n ],\n )\n\n if (report.analytics) {\n process.stdout.write('\\nGoogle Analytics impact\\n')\n printTable(\n ['Metric', 'Before', 'After', 'Delta'],\n [\n [\n 'Sessions',\n formatCount(report.analytics.before.metrics.sessions),\n formatCount(report.analytics.after.metrics.sessions),\n `${formatCount(report.analytics.delta.sessions)} (${pct(report.analytics.delta.sessionPct)})`,\n ],\n [\n 'Conversions',\n formatCount(report.analytics.before.metrics.conversions),\n formatCount(report.analytics.after.metrics.conversions),\n `${formatCount(report.analytics.delta.conversions)} (${pct(report.analytics.delta.conversionPct)})`,\n ],\n [\n 'Revenue',\n report.analytics.before.metrics.totalRevenue.toFixed(2),\n report.analytics.after.metrics.totalRevenue.toFixed(2),\n `${report.analytics.delta.totalRevenue.toFixed(2)} (${pct(report.analytics.delta.revenuePct)})`,\n ],\n ],\n )\n }\n\n if (report.control) {\n process.stdout.write('\\nControl comparison\\n')\n printKeyValue([\n ['Control', report.control.change.title],\n [\n 'Adjusted clicks',\n report.control.adjusted.clickDelta === null\n ? 'n/a'\n : formatCount(report.control.adjusted.clickDelta),\n ],\n [\n 'Adjusted click %',\n report.control.adjusted.clickPctPoints === null\n ? 'n/a'\n : `${report.control.adjusted.clickPctPoints.toFixed(1)} pts`,\n ],\n ['Note', report.control.note],\n ])\n }\n printNotes('Warnings', report.warnings)\n printNotes('Caveats', report.caveats)\n}\n\nexport const testsCommand = defineCommand({\n meta: {\n name: 'tests',\n description:\n 'Create and report local SEO tests from Search Console and Google Analytics data',\n },\n subCommands: {\n list: defineCommand({\n meta: { name: 'list', description: 'List saved SEO tests' },\n args: {\n site: { type: 'string', description: 'GSC property URL.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n limit: {\n type: 'string',\n description: 'Maximum tests to list. Defaults to 20.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = projectArg(args)\n const selection =\n project || stringArg(args.site)\n ? await resolveClientSelection({\n client: project,\n site: stringArg(args.site),\n options: { json },\n })\n : undefined\n const changes = listChanges({\n site: selection?.site,\n limit: numberArg(args.limit),\n })\n if (json) {\n printJson({ tests: changes })\n return\n }\n printTable(\n ['ID', 'Date', 'Scope', 'Target', 'Title'],\n changes.map((change) => [\n change.id,\n change.changedAt,\n change.scope,\n change.target,\n change.title,\n ]),\n )\n },\n }),\n create: defineCommand({\n meta: { name: 'create', description: 'Create a local SEO test' },\n args: {\n site: { type: 'string', description: 'GSC property URL.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n scope: {\n type: 'string',\n default: 'page',\n description: 'Change scope: site, page, query, or group.',\n },\n target: {\n type: 'string',\n required: true,\n description: 'Changed URL, query, group pattern, or site marker.',\n },\n title: {\n type: 'string',\n required: true,\n description: 'Plain-English name for the test.',\n },\n description: {\n type: 'string',\n description: 'Optional note about what changed.',\n },\n date: {\n type: 'string',\n description: 'Change date in YYYY-MM-DD. Defaults to today.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const change = recordChange({\n site: selection.site,\n scope: changeScope(args.scope),\n target: stringArg(args.target) ?? '',\n title: stringArg(args.title) ?? '',\n description: stringArg(args.description),\n changedAt: stringArg(args.date) ?? today(),\n })\n if (json) {\n printJson(change)\n return\n }\n printKeyValue([\n ['ID', change.id],\n ['Date', change.changedAt],\n ['Project', selection.client?.name ?? selection.site],\n ['Scope', change.scope],\n ['Target', change.target],\n ['Title', change.title],\n ])\n },\n }),\n report: defineCommand({\n meta: {\n name: 'report',\n description:\n 'Report an SEO test with equal finalized before/after windows',\n },\n args: {\n id: { type: 'string', description: 'Saved SEO test id.' },\n site: { type: 'string', description: 'GSC property URL.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n scope: {\n type: 'string',\n description: 'Ad-hoc change scope: site, page, query, or group.',\n },\n target: {\n type: 'string',\n description:\n 'Ad-hoc changed URL, query, group pattern, or site marker.',\n },\n title: { type: 'string', description: 'Ad-hoc test title.' },\n date: {\n type: 'string',\n description: 'Ad-hoc change date in YYYY-MM-DD.',\n },\n property: {\n type: 'string',\n description: 'Google Analytics property ID.',\n },\n 'control-scope': {\n type: 'string',\n description: 'Control scope: site, page, query, or group.',\n },\n 'control-target': {\n type: 'string',\n description: 'Control URL, query, group pattern, or site marker.',\n },\n 'control-title': {\n type: 'string',\n description: 'Plain-English name for the control group.',\n },\n before: {\n type: 'string',\n description: 'Days before the change date. Defaults to 28.',\n },\n after: {\n type: 'string',\n description: 'Days after the change date. Defaults to 28.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description:\n 'Bypass the local Search Console and Google Analytics cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const id = stringArg(args.id)\n const needsSelection =\n !id || Boolean(projectArg(args) || stringArg(args.site))\n const selection = needsSelection\n ? await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n : undefined\n const report = await measureChange({\n id,\n site: id ? undefined : selection?.site,\n scope: id ? undefined : maybeScope(args.scope),\n target: id ? undefined : stringArg(args.target),\n title: stringArg(args.title),\n changedAt: id ? undefined : stringArg(args.date),\n googleAnalyticsPropertyId:\n stringArg(args.property) ??\n selection?.client?.analytics.google?.propertyId,\n controlScope: maybeScope(args['control-scope']),\n controlTarget: stringArg(args['control-target']),\n controlTitle: stringArg(args['control-title']),\n beforeDays: strictNumberArg(args.before, '--before'),\n afterDays: strictNumberArg(args.after, '--after'),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printMeasurement(report)\n },\n }),\n },\n})\n","import type { ProgressReporter } from '@seo/core'\n\nexport function createProgressReporter(\n enabled: boolean,\n): ProgressReporter | undefined {\n if (!enabled) return undefined\n const startedAt = Date.now()\n return (message) => {\n const elapsed = ((Date.now() - startedAt) / 1000).toFixed(1)\n process.stderr.write(`[seo ${elapsed}s] ${message}\\n`)\n }\n}\n","import { mkdir, writeFile } from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport { type CsvFile, countLabel, renderCsv } from '@seo/core'\nexport const exportSelectionArgs = {\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description:\n 'Saved project id or name. Defaults to the configured default.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL/id when not using a saved project.',\n },\n} as const\n\nexport function outArg(report: string) {\n return {\n type: 'string',\n description: `Output folder. Defaults to ./seo-export/<project>-${report}-YYYY-MM-DD.`,\n } as const\n}\n\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/^sc-domain:/, '')\n .replace(/^https?:\\/\\//, '')\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\nexport function defaultOutDir(input: {\n report: string\n clientId?: string\n site: string\n}) {\n const day = new Date().toISOString().slice(0, 10)\n const id = slug(input.clientId ?? input.site)\n return resolve(process.cwd(), 'seo-export', `${id}-${input.report}-${day}`)\n}\n\nexport async function writeCsvFiles(outDir: string, files: CsvFile[]) {\n await mkdir(outDir, { recursive: true })\n const written: string[] = []\n for (const file of files) {\n const path = resolve(outDir, file.filename)\n await writeFile(path, renderCsv(file.rows, file.headers), 'utf8')\n written.push(path)\n }\n return written\n}\n\nexport function printWritten(outDir: string, files: string[]) {\n process.stdout.write(\n `Wrote ${countLabel(files.length, 'CSV file')} to ${outDir}\\n`,\n )\n for (const file of files) {\n process.stdout.write(`- ${file}\\n`)\n }\n}\n","import { diagnoseCsvFiles, diagnoseProperty } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n fetchRateArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { createProgressReporter } from '../../progress.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport {\n defaultOutDir,\n exportSelectionArgs,\n outArg,\n printWritten,\n writeCsvFiles,\n} from './shared.js'\n\nexport const exportDiagnoseCommand = defineCommand({\n meta: {\n name: 'diagnose',\n description:\n 'Export diagnosis tables: priorities, anomalies, movement, decay, cannibalisation, striking-distance, and quick wins.',\n },\n args: {\n ...exportSelectionArgs,\n out: outArg('diagnose'),\n days: {\n type: 'string',\n description: 'GSC lookback window. Defaults to 90.',\n },\n recent: {\n type: 'string',\n description: 'Recent anomaly window in days.',\n },\n limit: {\n type: 'string',\n description: 'Maximum rows per movement/opportunity table.',\n },\n 'include-brand': {\n type: 'boolean',\n default: false,\n description: 'Include branded queries in opportunity reports.',\n },\n 'verify-content': {\n type: 'boolean',\n default: false,\n description:\n 'Verify top opportunities against page title, meta, and content.',\n },\n 'verify-limit': {\n type: 'string',\n description: 'Maximum opportunity URLs to verify.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for verified pages.',\n },\n 'fetch-concurrency': {\n type: 'string',\n description: 'Maximum concurrent page fetches per host. Defaults to 4.',\n },\n 'fetch-interval-cap': {\n type: 'string',\n description: 'Maximum page fetches per interval per host. Defaults to 4.',\n },\n 'fetch-interval-ms': {\n type: 'string',\n description: 'Fetch rate interval in milliseconds. Defaults to 1000.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local cache and fetch fresh data.',\n },\n },\n run: async ({ args }) => {\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n })\n const report = await diagnoseProperty({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent: booleanArg(args['verify-content']),\n verifyLimit: numberArg(args['verify-limit']),\n js: booleanArg(args.js) ? true : 'auto',\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n progress: createProgressReporter(true),\n })\n const outDir =\n stringArg(args.out) ??\n defaultOutDir({\n report: 'diagnose',\n clientId: selection.client?.id,\n site: selection.site,\n })\n const written = await writeCsvFiles(outDir, diagnoseCsvFiles(report))\n printWritten(outDir, written)\n },\n})\n","import {\n analyticsConnection,\n refreshPrioritiesCsvFiles,\n refreshPrioritiesWorkflow,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from '../analytics/connection.js'\nimport { cliReportArgs } from '../report-options.js'\nimport {\n defaultOutDir,\n exportSelectionArgs,\n outArg,\n printWritten,\n writeCsvFiles,\n} from './shared.js'\n\nexport const exportRefreshPrioritiesCommand = defineCommand({\n meta: {\n name: 'refresh-priorities',\n description:\n 'Export the ranked SEO priority queue, score breakdowns, grouped findings, and diagnosis detail CSVs.',\n },\n args: {\n ...exportSelectionArgs,\n out: outArg('refresh-priorities'),\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum queue items to export. Defaults to 25.',\n },\n },\n ),\n ...analyticsConnectionArgs,\n 'verify-content': defaultTrueBooleanArg(\n 'Verify top opportunities against page title, meta, and content. Defaults to true.',\n 'Skip page content verification.',\n ),\n 'verify-limit': {\n type: 'string',\n description: 'Maximum opportunity URLs to verify. Defaults to 5.',\n },\n },\n run: async ({ args }) => {\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { refresh: booleanArg(args.refresh) },\n })\n const report = await refreshPrioritiesWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n googleAnalyticsPropertyId:\n stringArg(args['google-analytics-property']) ??\n selection.client?.analytics.google?.propertyId,\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection.client),\n ),\n verifyContent: booleanArg(args['verify-content']),\n verifyLimit: numberArg(args['verify-limit']),\n refresh: booleanArg(args.refresh),\n })\n const outDir =\n stringArg(args.out) ??\n defaultOutDir({\n report: 'refresh-priorities',\n clientId: selection.client?.id,\n site: selection.site,\n })\n const written = await writeCsvFiles(\n outDir,\n refreshPrioritiesCsvFiles(report),\n )\n printWritten(outDir, written)\n },\n})\n","import { updatePostmortemCsvFiles, updatePostmortemWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, numberArg, projectArg, stringArg } from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { cliReportArgs } from '../report-options.js'\nimport {\n defaultOutDir,\n exportSelectionArgs,\n outArg,\n printWritten,\n writeCsvFiles,\n} from './shared.js'\n\nexport const exportUpdatePostmortemCommand = defineCommand({\n meta: {\n name: 'update-postmortem',\n description:\n 'Export update postmortem attribution, findings, template movement, and segment movers.',\n },\n args: {\n ...exportSelectionArgs,\n out: outArg('update-postmortem'),\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum winners/losers per segment. Defaults to 20.',\n },\n },\n ),\n 'known-change': {\n type: 'string',\n description:\n 'Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.',\n },\n 'ignore-change-log': {\n type: 'boolean',\n default: false,\n description: 'Do not use saved change-log entries as confounders.',\n },\n },\n run: async ({ args }) => {\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { refresh: booleanArg(args.refresh) },\n })\n const report = await updatePostmortemWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n knownConfounders: stringArg(args['known-change'])\n ? [stringArg(args['known-change']) ?? '']\n : undefined,\n includeChangeLog: !booleanArg(args['ignore-change-log']),\n refresh: booleanArg(args.refresh),\n })\n const outDir =\n stringArg(args.out) ??\n defaultOutDir({\n report: 'update-postmortem',\n clientId: selection.client?.id,\n site: selection.site,\n })\n const written = await writeCsvFiles(\n outDir,\n updatePostmortemCsvFiles(report),\n )\n printWritten(outDir, written)\n },\n})\n","import { defineCommand } from 'citty'\nimport { exportDiagnoseCommand } from './diagnose.js'\nimport { exportRefreshPrioritiesCommand } from './refresh-priorities.js'\nimport { exportUpdatePostmortemCommand } from './update-postmortem.js'\n\nexport const exportCommand = defineCommand({\n meta: {\n name: 'export',\n description: 'Export full report data to CSV files',\n },\n subCommands: {\n diagnose: exportDiagnoseCommand,\n 'update-postmortem': exportUpdatePostmortemCommand,\n 'refresh-priorities': exportRefreshPrioritiesCommand,\n },\n})\n","import { defineCommand } from 'citty'\nimport { startCommand } from './setup/index.js'\n\n/**\n * Kept for existing scripts. New users should start with `seo start`.\n *\n * Do not let this become a second onboarding flow. A person should see the\n * same calm Google, project-profile, and MCP setup whichever entry they use.\n */\nexport const initCommand = defineCommand({\n ...startCommand,\n meta: {\n name: 'init',\n description: 'Legacy alias for `seo start`.',\n },\n})\n","import { pruneLogs } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../args.js'\nimport { formatBytes, printJson } from '../utils.js'\n\nexport const logsCommand = defineCommand({\n meta: { name: 'logs', description: 'Manage local log retention' },\n subCommands: {\n prune: defineCommand({\n meta: {\n name: 'prune',\n description: 'Rotate large logs and remove old local logs',\n },\n args: {\n quiet: {\n type: 'boolean',\n default: false,\n description: 'Do not print a result.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const result = pruneLogs()\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n if (!args.quiet) {\n process.stdout.write(\n `Rotated ${result.rotated} and removed ${result.removed} log files. ${formatBytes(result.sizeBytes)} retained.\\n`,\n )\n }\n },\n }),\n },\n})\n","import { multiselect } from '@clack/prompts'\nimport { SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag } from '../args.js'\nimport { canPrompt, maybeExitCancelled, printJson } from '../utils.js'\nimport {\n detectMcpClients,\n mcpClientTargets,\n type SupportedClient,\n} from './mcp-clients.js'\nimport { installMcpConfig, uninstallMcpConfig } from './mcp-config.js'\n\nconst targetFlags: Array<{\n client: SupportedClient\n flag: 'claude-desktop' | 'claude-code' | 'codex' | 'cursor'\n}> = [\n {\n client: 'claude-desktop',\n flag: 'claude-desktop',\n },\n { client: 'claude-code', flag: 'claude-code' },\n { client: 'codex', flag: 'codex' },\n { client: 'cursor', flag: 'cursor' },\n]\n\nfunction selectedClients(\n args: Record<string, unknown>,\n available: SupportedClient[],\n): SupportedClient[] {\n if (booleanArg(args.all)) return available\n return targetFlags\n .filter(({ flag }) => booleanArg(args[flag]))\n .map(({ client }) => client)\n}\n\nexport const mcpCommand = defineCommand({\n meta: { name: 'mcp', description: 'MCP server helpers' },\n subCommands: {\n serve: defineCommand({\n meta: {\n name: 'serve',\n description: 'Run the SEO MCP server',\n },\n args: {\n test: {\n type: 'boolean',\n default: false,\n description: 'Start in test mode',\n },\n },\n run: async ({ args }) => {\n const { startMcpServer } = await import('@seo/mcp')\n await startMcpServer({ test: booleanArg(args.test) })\n },\n }),\n install: defineCommand({\n meta: {\n name: 'install',\n description: 'Install or remove SEO MCP config for local clients',\n },\n args: {\n uninstall: {\n type: 'boolean',\n default: false,\n description: 'Remove the SEO MCP config instead of adding it',\n },\n reinstall: {\n type: 'boolean',\n default: false,\n description: 'Rewrite an existing managed SEO MCP config',\n },\n 'claude-desktop': {\n type: 'boolean',\n default: false,\n description: 'Update Claude Desktop',\n },\n 'claude-code': {\n type: 'boolean',\n default: false,\n description: 'Update Claude Code',\n },\n codex: {\n type: 'boolean',\n default: false,\n description: 'Update Codex CLI, app, and IDE extension',\n },\n cursor: {\n type: 'boolean',\n default: false,\n description: 'Update Cursor',\n },\n all: {\n type: 'boolean',\n default: false,\n description: 'Update every detected MCP client',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print structured JSON output',\n },\n },\n run: async ({ args }) => {\n if (booleanArg(args.uninstall) && booleanArg(args.reinstall)) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --uninstall or --reinstall, not both.',\n )\n }\n const targets = mcpClientTargets()\n const detected = detectMcpClients({ targets })\n const json = jsonFlag(args)\n let selected = selectedClients(\n args,\n detected.map((target) => target.client),\n )\n\n if (selected.length === 0) {\n if (!canPrompt({ json })) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Choose an MCP client with --claude-desktop, --claude-code, --codex, --cursor, or --all.',\n )\n }\n const choices = detected.length > 0 ? detected : targets\n selected = maybeExitCancelled(\n await multiselect({\n message: args.uninstall\n ? 'Remove seo from which MCP clients?'\n : 'Install seo into which MCP clients?',\n options: choices.map((target) => ({\n value: target.client,\n label: target.label,\n hint: target.path,\n })),\n initialValues: detected.map((target) => target.client),\n required: true,\n }),\n )\n }\n\n const unavailable = selected.filter(\n (client) => !targets.some((target) => target.client === client),\n )\n if (unavailable.length > 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `MCP setup is not supported for ${unavailable.join(', ')} on ${process.platform}.`,\n )\n }\n\n const results = targets\n .filter((entry) => selected.includes(entry.client))\n .map((target) =>\n booleanArg(args.uninstall)\n ? uninstallMcpConfig(target)\n : installMcpConfig(target, {\n reinstall: booleanArg(args.reinstall),\n }),\n )\n\n if (json) {\n printJson({\n operation: booleanArg(args.uninstall) ? 'uninstall' : 'install',\n results,\n })\n return\n }\n\n for (const result of results) {\n process.stdout.write(\n `${result.changed ? 'updated' : 'skipped'} ${result.client} · ${result.path}\\n`,\n )\n }\n },\n }),\n },\n})\n","import { crawlDiff } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, numberArg, stringArg } from '../../args.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printActionDetails, printReportSummary, truncate } from '../output.js'\n\nexport const crawlDiffCommand = defineCommand({\n meta: {\n name: 'crawl-diff',\n description: 'Crawl a site and diff technical/page changes vs last run',\n },\n args: {\n url: {\n type: 'string',\n required: true,\n description: 'Start URL to crawl.',\n },\n site: {\n type: 'string',\n description: 'Optional GSC property to associate with the crawl.',\n },\n limit: {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 50.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n },\n run: async ({ args }) => {\n const report = await crawlDiff({\n startUrl: stringArg(args.url) ?? '',\n site: stringArg(args.site),\n limit: numberArg(args.limit),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n })\n if (jsonFlag(args)) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Crawl history comparison',\n target: report.run.startUrl,\n status:\n report.previousRun === undefined\n ? 'unknown'\n : report.summary.newErrors > 0 || report.summary.indexabilityFlips > 0\n ? 'warning'\n : 'pass',\n summary:\n report.previousRun === undefined\n ? 'No previous crawl was available for comparison.'\n : `${report.summary.changed} changed, ${report.summary.added} added, and ${report.summary.removed} removed URLs.`,\n metrics: [\n { label: 'Run', value: report.run.id },\n { label: 'Crawled', value: report.summary.crawled },\n { label: 'Previous run', value: report.previousRun?.id ?? 'None' },\n { label: 'Added', value: report.summary.added },\n { label: 'Removed', value: report.summary.removed },\n { label: 'Changed', value: report.summary.changed },\n { label: 'New errors', value: report.summary.newErrors },\n {\n label: 'Indexability flips',\n value: report.summary.indexabilityFlips,\n },\n {\n label: 'High priority',\n value: report.summary.highPriorityRecommendations,\n },\n ],\n })\n if (report.recommendations.length) {\n process.stdout.write('\\nRecommended actions\\n')\n printTable(\n ['Severity', 'Category', 'URL', 'Action'],\n report.recommendations\n .slice(0, 10)\n .map((item) => [\n item.severity,\n item.category,\n truncate(item.url, 56),\n truncate(item.action, 72),\n ]),\n )\n printActionDetails(\n 'Top crawl actions',\n report.recommendations.map((item) => ({\n label: item.category,\n context: `${item.severity}, ${truncate(item.url, 96)}`,\n action: item.action,\n })),\n )\n }\n if (report.items.length) {\n process.stdout.write('\\nChanged URLs\\n')\n printTable(\n ['Kind', 'URL', 'Changes', 'Recommendation'],\n report.items\n .slice(0, 50)\n .map((item) => [\n item.kind,\n truncate(item.url, 56),\n item.changes.join(', '),\n item.recommendation?.title ?? '-',\n ]),\n )\n }\n if (report.warnings.length) {\n process.stdout.write('\\nWarnings\\n')\n for (const warning of report.warnings.slice(0, 10)) {\n process.stdout.write(`- ${warning}\\n`)\n }\n }\n },\n})\n","import { defaultTrueBooleanArg } from '../../args.js'\n\nexport function monitoringRunArgs() {\n return {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Defaults from the project or GSC property.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to inspect with URL Inspection.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs for quota-aware index monitoring.',\n },\n properties: {\n type: 'string',\n description:\n 'Comma-separated GSC properties for sitemap index monitoring.',\n },\n limit: {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 50.',\n },\n 'daily-limit': {\n type: 'string',\n description: 'URL Inspection daily limit per property. Defaults to 2000.',\n },\n 'inspect-limit': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to inspect in this run. Defaults to 100.',\n },\n 'max-urls': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to load for monitoring. Defaults to 50000.',\n },\n language: {\n type: 'string',\n description: 'Optional URL Inspection language code.',\n },\n 'recover-links': defaultTrueBooleanArg(\n 'Check search-value GSC pages for broken, blocked, or poorly redirected URLs.',\n 'Skip link recovery checks.',\n ),\n 'recover-days': {\n type: 'string',\n description: 'GSC lookback window for link recovery. Defaults to 90.',\n },\n 'recover-limit': {\n type: 'string',\n description:\n 'Maximum search-value pages to check for link recovery. Defaults to 10.',\n },\n 'recover-min-clicks': {\n type: 'string',\n description:\n 'Minimum clicks for link recovery candidates. Defaults to 1.',\n },\n 'recover-min-impressions': {\n type: 'string',\n description:\n 'Minimum impressions for link recovery candidates. Defaults to 100.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP/GSC cache where supported.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n } as const\n}\n\nexport function monitoringStatusArgs() {\n return {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n 'stale-days': {\n type: 'string',\n description: 'Mark checks stale after this many days. Defaults to 8.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Refresh property selection data when prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n } as const\n}\n","import { printSemanticReport } from '../../utils.js'\n\nfunction stepStatus(\n value: string,\n): 'pass' | 'warning' | 'fail' | 'unknown' | 'info' {\n const status = value.toLowerCase()\n if (['pass', 'passed', 'complete', 'completed', 'joined'].includes(status)) {\n return 'pass'\n }\n if (['warn', 'warning', 'partial', 'review'].includes(status)) {\n return 'warning'\n }\n if (['fail', 'failed', 'error'].includes(status)) return 'fail'\n if (['unknown', 'unavailable'].includes(status)) return 'unknown'\n return 'info'\n}\n\nexport function printWorkflow(report: {\n workflow: string\n site: string\n summary: string\n steps: Array<{ tool: string; status: string; summary: string }>\n actions: Array<{ title: string; confidence: string; action: string }>\n}): void {\n const statuses = report.steps.map((step) => stepStatus(step.status))\n const status = statuses.includes('fail')\n ? 'fail'\n : statuses.includes('warning')\n ? 'warning'\n : statuses.includes('unknown')\n ? 'unknown'\n : 'pass'\n printSemanticReport({\n title: report.workflow,\n target: report.site,\n status,\n summary: report.summary,\n metrics: [\n {\n label: 'Completed',\n value: statuses.filter((value) => value === 'pass').length,\n status: 'pass',\n },\n {\n label: 'Review',\n value: statuses.filter((value) => value === 'warning').length,\n status: 'warning',\n },\n {\n label: 'Unknown',\n value: statuses.filter((value) => value === 'unknown').length,\n status: 'unknown',\n },\n ],\n sections: [\n {\n title: 'Evidence collection',\n diagnostics: report.steps.map((step) => ({\n status: stepStatus(step.status),\n title: step.tool,\n explanation: step.summary,\n evidence: [`Status: ${step.status}`],\n })),\n },\n {\n title: 'Priority actions',\n diagnostics: report.actions.map((action) => ({\n status: 'warning' as const,\n title: action.title,\n explanation: `Confidence: ${action.confidence}.`,\n fix: action.action,\n })),\n },\n ],\n })\n}\n","import type { MonitoringStatusReport, technicalWatchWorkflow } from '@seo/core'\nimport { printTable } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { printWorkflow } from '../workflows/output.js'\n\ntype TechnicalWatchReport = Awaited<ReturnType<typeof technicalWatchWorkflow>>\n\nexport function printMonitoringRun(report: TechnicalWatchReport): void {\n printWorkflow(report)\n\n if (report.output.crawl?.recommendations.length) {\n process.stdout.write('\\nCrawl actions\\n')\n printTable(\n ['Severity', 'URL', 'Action'],\n report.output.crawl.recommendations\n .slice(0, 10)\n .map((item) => [\n item.severity,\n truncate(item.url, 56),\n truncate(item.action, 72),\n ]),\n )\n printActionDetails(\n 'Top crawl actions',\n report.output.crawl.recommendations.map((item) => ({\n label: item.severity,\n context: truncate(item.url, 96),\n action: item.action,\n })),\n )\n }\n\n if (report.output.index?.items.length) {\n const items = report.output.index.items\n .filter(\n (item) =>\n item.currentIssue ||\n item.changed ||\n item.inspectionStatus !== 'succeeded',\n )\n .slice(0, 25)\n if (items.length) {\n process.stdout.write('\\nIndex reviews, changes, and failed checks\\n')\n printTable(\n ['Check', 'Change', 'Index state', 'Evidence', 'URL'],\n items.map((item) => [\n item.inspectionStatus,\n item.changeKind,\n item.indexStatus,\n truncate(\n (item.errorCode ?? item.issueCodes.join(', ')) || 'none',\n 40,\n ),\n truncate(item.url, 64),\n ]),\n )\n }\n }\n\n if (report.output.recovery?.items.length) {\n process.stdout.write('\\nRecoverable URLs\\n')\n printTable(\n ['Severity', 'Issue', 'Clicks', 'Impr', 'URL', 'Action'],\n report.output.recovery.items\n .slice(0, 10)\n .map((item) => [\n item.severity,\n item.issue,\n formatCount(item.clicks),\n formatCount(item.impressions),\n truncate(item.url, 56),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top recovery actions',\n report.output.recovery.items.map((item) => ({\n label: truncate(item.url, 96),\n context: `${item.severity}, ${formatCount(item.clicks)} clicks at risk`,\n action: item.recommendation.action,\n })),\n )\n }\n}\n\nexport function printMonitoringStatus(report: MonitoringStatusReport): void {\n printReportSummary({\n title: 'Technical monitoring status',\n target: report.site,\n status:\n report.health === 'clear'\n ? 'pass'\n : report.health === 'attention'\n ? 'warning'\n : 'unknown',\n summary:\n report.summary.attention > 0\n ? `${report.summary.attention} checks need attention.`\n : report.summary.stale > 0 || report.summary.notRun > 0\n ? `${report.summary.stale} checks are stale and ${report.summary.notRun} have not run.`\n : 'No monitoring checks currently need attention.',\n metrics: [\n { label: 'Health', value: report.health },\n { label: 'Attention', value: report.summary.attention },\n { label: 'Stale', value: report.summary.stale },\n { label: 'Not run', value: report.summary.notRun },\n ],\n })\n\n printTable(\n ['Check', 'Status', 'Last run', 'Summary'],\n report.checks.map((check) => [\n check.name,\n check.status,\n check.lastRunAt ?? '-',\n check.summary,\n ]),\n )\n\n const actions = report.checks.filter((check) => check.action)\n if (actions.length) {\n process.stdout.write('\\nNext actions\\n')\n printTable(\n ['Check', 'Action'],\n actions.map((check) => [check.name, truncate(check.action ?? '', 96)]),\n )\n printActionDetails(\n 'Next action details',\n actions.map((check) => ({\n label: check.name,\n action: check.action ?? '',\n })),\n )\n }\n}\n","import { monitoringStatus, technicalWatchWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printKeyValue } from '../../utils.js'\nimport { startUrlForSite } from '../shared.js'\nimport { monitoringRunArgs, monitoringStatusArgs } from './args.js'\nimport { printMonitoringRun, printMonitoringStatus } from './output.js'\n\nfunction quotedFlag(name: string, value: unknown): string | undefined {\n const text = stringArg(value)\n return text ? `--${name} ${JSON.stringify(text)}` : undefined\n}\n\nfunction booleanFlag(name: string, value: unknown): string | undefined {\n return booleanArg(value) ? `--${name}` : undefined\n}\n\nfunction recoverLinksFlag(value: unknown): string | undefined {\n return booleanArg(value) === false ? '--recover-links=false' : undefined\n}\n\nexport const monitoringCommand = defineCommand({\n meta: {\n name: 'monitoring',\n description: 'Run and review recurring technical SEO monitoring',\n },\n subCommands: {\n run: defineCommand({\n meta: {\n name: 'run',\n description:\n 'Run crawl, index, and link recovery monitoring for a property',\n },\n args: monitoringRunArgs(),\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const urls = listArg(args.urls)\n const sitemaps = listArg(args.sitemaps)\n const startUrl =\n stringArg(args.url) ??\n selection.client?.startUrl ??\n startUrlForSite(selection.site)\n const report = await technicalWatchWorkflow({\n site: selection.site,\n startUrl,\n urls: urls.length ? urls : selection.client?.watchUrls,\n sitemaps: sitemaps.length ? sitemaps : undefined,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n limit: numberArg(args.limit),\n languageCode: stringArg(args.language),\n dailyLimit: numberArg(args['daily-limit']),\n inspectLimit: numberArg(args['inspect-limit']),\n maxUrls: numberArg(args['max-urls']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n recoverLinks: booleanArg(args['recover-links']),\n recoverDays: numberArg(args['recover-days']),\n recoverLimit: numberArg(args['recover-limit']),\n recoverMinClicks: numberArg(args['recover-min-clicks']),\n recoverMinImpressions: numberArg(args['recover-min-impressions']),\n })\n\n if (json) {\n printJson(report)\n return\n }\n printMonitoringRun(report)\n },\n }),\n status: defineCommand({\n meta: {\n name: 'status',\n description: 'Show the latest saved monitoring state for a property',\n },\n args: monitoringStatusArgs(),\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = monitoringStatus({\n site: selection.site,\n staleAfterDays: numberArg(args['stale-days']),\n })\n if (json) {\n printJson(report)\n return\n }\n printMonitoringStatus(report)\n },\n }),\n cron: defineCommand({\n meta: {\n name: 'cron',\n description: 'Print a local cron line for recurring monitoring',\n },\n args: {\n ...monitoringRunArgs(),\n hour: {\n type: 'string',\n default: '9',\n description: 'Hour in local cron time. Defaults to 9.',\n },\n minute: {\n type: 'string',\n default: '0',\n description: 'Minute in local cron time. Defaults to 0.',\n },\n weekday: {\n type: 'string',\n description:\n 'Weekly monitoring day. Defaults to client setting, then Monday.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const hour = numberArg(args.hour) ?? 9\n const minute = numberArg(args.minute) ?? 0\n const weekday =\n numberArg(args.weekday) ?? selection.client?.technicalWeekday ?? 1\n const identityArg = selection.client\n ? `--project ${JSON.stringify(selection.client.id)}`\n : `--site ${JSON.stringify(selection.site)}`\n const command = [\n 'seo monitoring run',\n identityArg,\n quotedFlag('url', args.url),\n quotedFlag('urls', args.urls),\n quotedFlag('sitemaps', args.sitemaps),\n quotedFlag('properties', args.properties),\n quotedFlag('limit', args.limit),\n quotedFlag('daily-limit', args['daily-limit']),\n quotedFlag('inspect-limit', args['inspect-limit']),\n quotedFlag('max-urls', args['max-urls']),\n quotedFlag('language', args.language),\n quotedFlag('recover-days', args['recover-days']),\n quotedFlag('recover-limit', args['recover-limit']),\n quotedFlag('recover-min-clicks', args['recover-min-clicks']),\n quotedFlag(\n 'recover-min-impressions',\n args['recover-min-impressions'],\n ),\n recoverLinksFlag(args['recover-links']),\n booleanFlag('refresh', args.refresh),\n booleanFlag('js', args.js),\n '--json',\n ]\n .filter(Boolean)\n .join(' ')\n const line = {\n name: 'monitoring',\n cron: `${minute} ${hour} * * ${weekday}`,\n command,\n }\n\n if (json) {\n printJson({ site: selection.site, line })\n return\n }\n printKeyValue([\n ['Property', selection.site],\n ['Install', 'crontab -e'],\n ])\n process.stdout.write(`${line.cron} ${line.command}\\n`)\n },\n }),\n },\n})\n","import { indexCoverageSignals } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary, truncate } from '../output.js'\n\nexport const indexCoverageCommand = defineCommand({\n meta: {\n name: 'index-coverage',\n description:\n 'Find crawlable pages that deserve a closer Google index check',\n },\n args: {\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n 'crawl-report-id': {\n type: 'string',\n description:\n 'Saved crawl report id. Defaults to the latest for the site.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs. Defaults to declarations captured by the crawl.',\n },\n days: {\n type: 'string',\n description: 'Finalized Search Console date range. Defaults to 90 days.',\n },\n 'row-limit': {\n type: 'string',\n description: 'Maximum Search Console page rows. Defaults to 100000.',\n },\n 'max-sitemap-urls': {\n type: 'string',\n description: 'Maximum sitemap inventory URLs. Defaults to 100000.',\n },\n limit: {\n type: 'string',\n description:\n 'Maximum URLs returned in each evidence group. Defaults to 100.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local Search Console cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const sitemapValues = listArg(args.sitemaps)\n const report = await indexCoverageSignals({\n site: selection.site,\n crawlReportId: stringArg(args['crawl-report-id']),\n sitemaps: sitemapValues.length ? sitemapValues : undefined,\n days: numberArg(args.days),\n rowLimit: numberArg(args['row-limit']),\n maxSitemapUrls: numberArg(args['max-sitemap-urls']),\n itemsPerSection: numberArg(args.limit),\n refresh: booleanArg(args.refresh),\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Index coverage',\n target: report.site,\n status:\n report.sources.crawl.completeness === 'complete' &&\n report.sources.searchConsole.completeness === 'complete'\n ? report.summary.crawlableCandidatesWithoutRetainedSearchVisibility >\n 0\n ? 'warning'\n : 'pass'\n : 'unknown',\n summary: `${report.summary.crawlableCandidatesWithoutRetainedSearchVisibility} crawlable pages need URL Inspection review.`,\n metrics: [\n { label: 'Crawl report', value: report.input.crawlReport.id },\n { label: 'Crawl evidence', value: report.sources.crawl.completeness },\n {\n label: 'Sitemap evidence',\n value: report.sources.sitemap.completeness,\n },\n {\n label: 'Search evidence',\n value: report.sources.searchConsole.completeness,\n },\n {\n label: 'Search window',\n value: `${report.sources.searchConsole.startDate} to ${report.sources.searchConsole.endDate}`,\n },\n {\n label: 'Search-visible pages',\n value: report.summary.retainedSearchVisibleUrls,\n },\n {\n label: 'Blocked/non-indexable',\n value: report.summary.blockedOrNonIndexableCrawlUrls,\n },\n { label: 'Sitemap only', value: report.summary.sitemapOnlyUrls },\n {\n label: 'Search Console only',\n value: report.summary.searchConsoleOnlyUrls,\n },\n ],\n })\n\n if (report.crawlableWithoutRetainedSearchVisibility.items.length) {\n process.stdout.write('\\nRepresentative URL Inspection candidates\\n')\n printTable(\n ['URL', 'Status', 'In sitemap'],\n report.crawlableWithoutRetainedSearchVisibility.items.map((item) => [\n truncate(item.url, 80),\n item.status,\n item.inSitemap ? 'yes' : 'no',\n ]),\n )\n }\n\n printNotes('How to read this report', report.caveats)\n },\n})\n","import {\n countLabel,\n indexCoveragePlan,\n indexMonitor,\n indexWatch,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary } from '../output.js'\n\nexport const indexWatchCommand = defineCommand({\n meta: {\n name: 'index-watch',\n description: 'Inspect URLs with GSC and alert on index status changes',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to inspect.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs to plan quota-aware monitoring.',\n },\n plan: {\n type: 'boolean',\n default: false,\n description:\n 'Plan sitemap URL allocation across GSC properties without inspecting URLs.',\n },\n properties: {\n type: 'string',\n description:\n 'Comma-separated GSC properties to use for planning. Defaults to account properties.',\n },\n 'daily-limit': {\n type: 'string',\n description: 'URL Inspection daily limit per property. Defaults to 2000.',\n },\n 'target-days': {\n type: 'string',\n description:\n 'Target number of days to inspect all monitored URLs. Defaults to 1.',\n },\n 'max-urls': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to load for planning. Defaults to 50000.',\n },\n 'inspect-limit': {\n type: 'string',\n description:\n 'Maximum URLs to inspect in this run from sitemap mode. Defaults to 100.',\n },\n language: {\n type: 'string',\n description: 'Optional URL Inspection language code.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const urls = listArg(args.urls)\n const site = await resolveSite({\n site: stringArg(args.site),\n options: { json },\n })\n\n const sitemaps = listArg(args.sitemaps)\n\n if (booleanArg(args.plan)) {\n if (!sitemaps.length) {\n throw new Error('Pass at least one sitemap with --sitemaps.')\n }\n const report = await indexCoveragePlan({\n site,\n sitemaps,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n dailyLimit: numberArg(args['daily-limit']),\n targetCycleDays: numberArg(args['target-days']),\n maxUrls: numberArg(args['max-urls']),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Index monitoring plan',\n target: report.site,\n status: report.warnings.length > 0 ? 'warning' : 'info',\n summary: `${report.summary.urlCount} sitemap URLs can be checked in an estimated ${countLabel(report.summary.estimatedCycleDays, 'day')}.`,\n metrics: [\n { label: 'Sitemap URLs', value: report.summary.urlCount },\n { label: 'Properties', value: report.summary.properties },\n { label: 'Daily capacity', value: report.summary.dailyCapacity },\n {\n label: 'Target cycle',\n value: countLabel(report.summary.targetCycleDays, 'day'),\n },\n {\n label: 'Suggested properties',\n value: report.summary.suggestedProperties,\n },\n ],\n })\n if (report.properties.length) {\n printTable(\n ['Property', 'URLs', 'Cycle', 'Sample URL'],\n report.properties.map((property) => [\n property.property,\n property.urlCount,\n countLabel(property.cycleDays, 'day'),\n property.sampleUrls[0] ?? '-',\n ]),\n )\n }\n if (report.suggestions.length) {\n process.stdout.write('\\nSuggested URL-prefix properties\\n')\n printTable(\n ['Property', 'URLs', 'Current property', 'Cycle', 'Reason'],\n report.suggestions.map((suggestion) => [\n suggestion.property,\n suggestion.urlCount,\n suggestion.currentProperty,\n countLabel(suggestion.estimatedCycleDays, 'day'),\n suggestion.reason,\n ]),\n )\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n return\n }\n\n if (sitemaps.length) {\n const report = await indexMonitor({\n site,\n sitemaps,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n dailyLimit: numberArg(args['daily-limit']),\n inspectLimit: numberArg(args['inspect-limit']),\n maxUrls: numberArg(args['max-urls']),\n languageCode: stringArg(args.language),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Index monitoring run',\n target: report.site,\n status:\n report.summary.failed > 0 || report.summary.quotaBlocked > 0\n ? 'unknown'\n : report.summary.alerts > 0 || report.summary.regressions > 0\n ? 'warning'\n : report.summary.attempted > 0\n ? 'pass'\n : 'info',\n summary: `${report.summary.inspected} URLs inspected, with ${report.summary.alerts} new alerts and ${report.summary.regressions} regressions.`,\n metrics: [\n { label: 'Inventory URLs', value: report.summary.inventoryUrls },\n { label: 'Selected', value: report.summary.selected },\n { label: 'Inspected', value: report.summary.inspected },\n { label: 'Failed', value: report.summary.failed },\n { label: 'Quota blocked', value: report.summary.quotaBlocked },\n { label: 'Current reviews', value: report.summary.currentIssues },\n { label: 'Regressions', value: report.summary.regressions },\n { label: 'Recoveries', value: report.summary.recoveries },\n { label: 'New alerts', value: report.summary.alerts },\n ],\n })\n if (report.properties.length) {\n printTable(\n [\n 'Property',\n 'Inventory',\n 'Selected',\n 'Inspected',\n 'Failed',\n 'Current',\n 'Alerts',\n ],\n report.properties.map((property) => [\n property.property,\n property.inventoryUrls,\n property.selectedUrls,\n property.inspected,\n property.failed + property.quotaBlocked,\n property.currentIssues,\n property.alerts,\n ]),\n )\n }\n const issueItems = report.items\n .filter(\n (item) =>\n item.currentIssue ||\n item.changed ||\n item.inspectionStatus !== 'succeeded',\n )\n .slice(0, 50)\n if (issueItems.length) {\n process.stdout.write('\\nIndex reviews, changes, and failed checks\\n')\n printTable(\n ['Check', 'Change', 'Index state', 'Evidence', 'URL'],\n issueItems.map((item) => [\n item.inspectionStatus,\n item.changeKind,\n item.indexStatus,\n (item.errorCode ?? item.issueCodes.join(', ')) || 'none',\n item.url,\n ]),\n )\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n return\n }\n\n if (!urls.length) throw new Error('Pass at least one URL with --urls.')\n\n const report = await indexWatch({\n site,\n urls,\n languageCode: stringArg(args.language),\n dailyLimit: numberArg(args['daily-limit']),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Index watch',\n target: report.site,\n status:\n report.summary.failed > 0 || report.summary.quotaBlocked > 0\n ? 'unknown'\n : report.summary.alerts > 0 || report.summary.regressions > 0\n ? 'warning'\n : report.summary.attempted > 0\n ? 'pass'\n : 'info',\n summary: `${report.summary.inspected} URLs inspected, with ${report.summary.alerts} new alerts.`,\n metrics: [\n { label: 'Property', value: report.source.property },\n { label: 'Attempted', value: report.summary.attempted },\n { label: 'Inspected', value: report.summary.inspected },\n { label: 'Failed', value: report.summary.failed },\n { label: 'Quota blocked', value: report.summary.quotaBlocked },\n { label: 'Current reviews', value: report.summary.currentIssues },\n { label: 'Regressions', value: report.summary.regressions },\n { label: 'Recoveries', value: report.summary.recoveries },\n { label: 'New alerts', value: report.summary.alerts },\n ],\n })\n printTable(\n ['Check', 'Change', 'Index state', 'Evidence', 'URL'],\n report.items.map((item) => [\n item.inspectionStatus,\n item.changeKind,\n item.indexStatus,\n (item.errorCode ?? item.issueCodes.join(', ')) || 'none',\n item.url,\n ]),\n )\n },\n})\n","import { linkRecover } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { selectedSiteOrThrow } from '../shared.js'\n\nexport const linkRecoverCommand = defineCommand({\n meta: {\n name: 'link-recover',\n description:\n 'Find search-value URLs that are now broken, blocked, or poorly redirected',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'limit', 'minImpressions', 'refresh', 'js'], {\n days: {\n description: 'GSC lookback window. Defaults to 90.',\n },\n limit: {\n description: 'Maximum GSC pages to check. Defaults to 50.',\n },\n minImpressions: {\n description: 'Minimum impressions to check a page. Defaults to 100.',\n },\n refresh: {\n description: 'Bypass local GSC and HTTP caches.',\n },\n js: {\n description: 'Force JavaScript rendering for final page extraction.',\n },\n }),\n 'min-clicks': {\n type: 'string',\n description: 'Minimum clicks to check a page. Defaults to 1.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const report = await linkRecover({\n site: await selectedSiteOrThrow(\n { client: projectArg(args), site: stringArg(args.site) },\n { json },\n ),\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minClicks: numberArg(args['min-clicks']),\n minImpressions: numberArg(args['min-impressions']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n })\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Link recovery',\n target: report.site,\n status:\n report.warnings.length > 0\n ? 'unknown'\n : report.summary.recoverable > 0\n ? 'warning'\n : 'pass',\n summary:\n report.summary.recoverable > 0\n ? `${formatCount(report.summary.recoverable)} previously visible URLs need recovery review.`\n : 'No recoverable URLs were found in the retained evidence.',\n metrics: [\n {\n label: 'Range',\n value: `${report.range.startDate} to ${report.range.endDate}`,\n },\n { label: 'Checked', value: formatCount(report.summary.checked) },\n {\n label: 'Recoverable',\n value: formatCount(report.summary.recoverable),\n },\n { label: 'High severity', value: formatCount(report.summary.high) },\n {\n label: 'Clicks at risk',\n value: formatCount(report.summary.clicksAtRisk),\n },\n {\n label: 'Impressions at risk',\n value: formatCount(report.summary.impressionsAtRisk),\n },\n ],\n })\n if (report.items.length) {\n printLimitedTable(\n ['Severity', 'Issue', 'Clicks', 'Impr', 'URL', 'Action'],\n report.items.map((item) => [\n item.severity,\n item.issue,\n formatCount(item.clicks),\n formatCount(item.impressions),\n truncate(item.url, 56),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top recovery actions',\n report.items.map((item) => ({\n label: truncate(item.url, 96),\n context: `${item.severity}, ${formatCount(item.clicks)} clicks at risk`,\n action: item.recommendation.action,\n })),\n )\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n },\n})\n","import { redirectTrace } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, numberArg, stringArg } from '../../args.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary, truncate } from '../output.js'\n\nexport const redirectTraceCommand = defineCommand({\n meta: {\n name: 'redirect-trace',\n description:\n 'Trace redirects and report final indexability/canonical issues',\n },\n args: {\n url: {\n type: 'string',\n required: true,\n description: 'URL to trace.',\n },\n 'max-hops': {\n type: 'string',\n description: 'Maximum redirect hops to follow. Defaults to 10.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache for final page extraction.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for final page extraction.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const report = await redirectTrace({\n url: stringArg(args.url) ?? '',\n maxHops: numberArg(args['max-hops']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n })\n if (jsonFlag(args)) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Redirect trace',\n target: report.url,\n status:\n report.summary.issues.length > 0\n ? 'warning'\n : report.summary.finalIndexable === undefined\n ? 'unknown'\n : 'pass',\n summary:\n report.summary.issues.length > 0\n ? report.summary.issues.join(', ')\n : `${report.summary.hops} redirect hops ended at HTTP ${report.summary.finalStatus}.`,\n metrics: [\n { label: 'Final URL', value: report.finalUrl },\n { label: 'Final status', value: report.summary.finalStatus },\n {\n label: 'Indexable',\n value:\n report.summary.finalIndexable === undefined\n ? 'Unknown'\n : report.summary.finalIndexable\n ? 'Yes'\n : 'No',\n },\n { label: 'Hops', value: report.summary.hops },\n ],\n })\n printTable(\n ['#', 'Status', 'URL', 'Next'],\n report.chain.map((step, index) => [\n index + 1,\n step.status,\n truncate(step.url, 72),\n truncate(step.nextUrl ?? '-', 72),\n ]),\n )\n if (report.finalPage) {\n process.stdout.write('\\nFinal page\\n')\n printKeyValue([\n ['Title', report.finalPage.title ?? '-'],\n ['Canonical', report.finalPage.canonical ?? '-'],\n ['Meta robots', report.finalPage.metaRobots ?? '-'],\n ])\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n },\n})\n","import { aiReferralsReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, projectArg, strictNumberArg, stringArg } from '../../args.js'\nimport {\n resolveClient,\n resolveGoogleAnalyticsProperty,\n} from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n printLimitedTable,\n printReportSummary,\n truncate,\n} from '../output.js'\n\nexport const aiReferralsCommand = defineCommand({\n meta: {\n name: 'ai-referrals',\n description: 'Find AI referral traffic detected in Google Analytics',\n },\n args: {\n property: {\n type: 'string',\n description:\n 'Google Analytics property ID. If omitted in a terminal, choose one.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description:\n 'Saved project id or name with an optional Google Analytics property.',\n },\n 'start-date': { type: 'string', default: '28daysAgo' },\n 'end-date': { type: 'string', default: 'yesterday' },\n 'max-rows': {\n type: 'string',\n description:\n 'Maximum Google Analytics rows per query. Defaults to 100000.',\n },\n 'result-limit': {\n type: 'string',\n description: 'Maximum ranked landing pages returned. Defaults to 25.',\n },\n limit: {\n type: 'string',\n description: 'Legacy alias for --max-rows.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass cached Google Analytics responses.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const client = await resolveClient({\n client: projectArg(args),\n options: { json },\n })\n const property = await resolveGoogleAnalyticsProperty({\n property:\n stringArg(args.property) ?? client?.analytics.google?.propertyId,\n options: { json },\n })\n const report = await aiReferralsReport({\n property,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n maxRows: strictNumberArg(args['max-rows'], '--max-rows'),\n resultLimit: strictNumberArg(args['result-limit'], '--result-limit'),\n limit: strictNumberArg(args.limit, '--limit'),\n refresh: args.refresh === true,\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'AI referral report',\n target: report.property,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Evidence',\n value: report.dataStatus === 'complete' ? 'Complete' : 'Partial',\n status: report.dataStatus === 'complete' ? 'pass' : 'unknown',\n },\n { label: 'AI sessions', value: formatCount(report.summary.sessions) },\n {\n label: 'AI users',\n value:\n report.summary.totalUsers === null\n ? 'Unavailable'\n : formatCount(report.summary.totalUsers),\n },\n { label: 'Sources', value: formatCount(report.summary.sources) },\n {\n label: 'Landing pages',\n value: formatCount(report.summary.landingPages),\n },\n {\n label: 'Landing-page output',\n value: `${formatCount(report.selection.landingPages.returnedRows)} returned / ${formatCount(report.selection.landingPages.retainedRows)} retained`,\n },\n {\n label: 'Source rows',\n value: formatCount(report.dataSource.sourceDiscovery.returnedRows),\n },\n ],\n })\n\n if (report.sources.length) {\n process.stdout.write('\\nAI sources\\n')\n printLimitedTable(\n ['Source', 'Sessions', 'Events', 'Share of AI sessions'],\n report.sources.map((source) => [\n source.label,\n formatCount(source.sessions),\n formatCount(source.eventCount),\n formatPercent(source.shareOfAiSessions),\n ]),\n )\n }\n\n if (report.landingPages.length) {\n process.stdout.write('\\nLanding pages\\n')\n printLimitedTable(\n ['Landing page', 'Sessions', 'Events', 'Top source'],\n report.landingPages.map((page) => [\n truncate(page.landingPage, 64),\n formatCount(page.sessions),\n formatCount(page.eventCount),\n page.topSourceDetails.label,\n ]),\n )\n }\n\n if (report.dataSource.partialReasons.length) {\n process.stdout.write('\\nEvidence warnings\\n')\n for (const warning of report.dataSource.partialReasons) {\n process.stdout.write(`- ${warning}\\n`)\n }\n }\n\n process.stdout.write(`\\nNote: ${report.summary.caveat}\\n`)\n },\n})\n","import { cannibalReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const cannibalCommand = defineCommand({\n meta: {\n name: 'cannibal',\n description: 'Find queries with material exposure across multiple URLs',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(\n ['days', 'limit', 'includeBrand', 'minImpressions', 'refresh'],\n {\n minImpressions: {\n description: 'Minimum query impressions. Defaults to 50.',\n },\n },\n ),\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const refresh = booleanArg(args.refresh)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh },\n })\n const report = await cannibalReport({\n site: selection.site,\n days: strictNumberArg(args.days, '--days'),\n limit: strictNumberArg(args.limit, '--limit'),\n minImpressions: strictNumberArg(\n args['min-impressions'],\n '--min-impressions',\n ),\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n refresh,\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Cannibalisation report',\n target: report.site,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'Range',\n value: `${report.range.startDate} to ${report.range.endDate}`,\n },\n {\n label: 'Eligible',\n value: formatCount(report.summary.eligibleClusters),\n },\n {\n label: 'Returned',\n value: formatCount(report.summary.returnedClusters),\n },\n {\n label: 'Suppressed brand queries',\n value: formatCount(report.summary.suppressedQueries),\n },\n { label: 'GSC completeness', value: report.source.completeness },\n {\n label: 'Brand queries',\n value: booleanArg(args['include-brand']) ? 'included' : 'excluded',\n },\n ],\n })\n printLimitedTable(\n ['Query', 'URLs', 'Property impr', 'Exposure', 'HHI', 'Review first'],\n report.items.map((item) => [\n truncate(item.query, 42),\n item.pages.length,\n item.propertyImpressions === undefined\n ? 'n/a'\n : formatCount(item.propertyImpressions),\n formatCount(item.pageExposureImpressions),\n item.hhi.toFixed(2),\n truncate(item.suggestedOwnerUrl, 56),\n ]),\n )\n printActionDetails(\n 'Top cannibalisation actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.pages.length} material URLs; first review ${truncate(item.suggestedOwnerUrl, 64)}`,\n action: item.recommendation.action,\n })),\n )\n printNotes('Report caveats', report.caveats)\n printNotes('Provider usage', [report.ledgerSummary])\n },\n})\n","import { ctrUnderperformersReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const ctrUnderperformersCommand = defineCommand({\n meta: {\n name: 'ctr-underperformers',\n description:\n 'Find high-impression queries with weak CTR for their position',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['includeBrand', 'minImpressions'], {\n minImpressions: {\n description:\n 'Minimum query impressions. Defaults to 1 per 5,000 retained impressions, from 30 to 200.',\n },\n }),\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const report = await ctrUnderperformersReport({\n site: selection.site,\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'CTR underperformers',\n target: report.site,\n status: report.dataStatus === 'partial' ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Underperformers',\n value: formatCount(report.summary.underperformers),\n },\n {\n label: 'Estimated click gap',\n value: formatCount(report.summary.estimatedClickShortfall),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Evidence', value: report.dataStatus },\n { label: 'GSC completeness', value: report.source.completeness },\n ],\n })\n printNotes('Why this matters', [\n 'These queries already have visibility; the fastest win is usually better SERP framing, not new content.',\n 'Start with high-impression rows where actual CTR is far below the expected CTR for that ranking position.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n printLimitedTable(\n ['Query', 'URL', 'Pos', 'Impr', 'CTR', 'Expected', 'Gap', 'Action'],\n report.items.map((item) => [\n truncate(item.query, 36),\n truncate(item.url, 48),\n formatPosition(item.position),\n formatCount(item.impressions),\n formatPercent(item.actualCtr),\n formatPercent(item.expectedCtr),\n formatCount(item.clickShortfall),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top CTR actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${formatCount(item.clickShortfall)} click gap, ${formatPercent(item.actualCtr)} CTR`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","import { decayingReport, SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nfunction formatMaybePosition(value: number): string {\n return value > 0 ? formatPosition(value) : 'n/a'\n}\n\nexport const decayingCommand = defineCommand({\n meta: {\n name: 'decaying',\n description: 'Find query/page rows losing clicks between two GSC windows',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'limit', 'includeBrand', 'refresh']),\n comparison: {\n type: 'string',\n description: 'Comparison: previous-period or year-over-year.',\n },\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n 'min-drop-pct': {\n type: 'string',\n description: 'Minimum click drop percentage. Defaults to 20.',\n },\n 'min-previous-clicks': {\n type: 'string',\n description:\n 'Minimum previous-window clicks for a query/page row. Defaults to 2.',\n },\n 'min-click-loss': {\n type: 'string',\n description: 'Minimum absolute click loss. Defaults to 1.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const refresh = booleanArg(args.refresh)\n const comparison = stringArg(args.comparison)\n const days = strictNumberArg(args.days, '--days')\n const limit = strictNumberArg(args.limit, '--limit')\n const minDropPct = strictNumberArg(args['min-drop-pct'], '--min-drop-pct')\n const minPreviousClicks = strictNumberArg(\n args['min-previous-clicks'],\n '--min-previous-clicks',\n )\n const minClickLoss = strictNumberArg(\n args['min-click-loss'],\n '--min-click-loss',\n )\n if (\n comparison !== undefined &&\n comparison !== 'previous-period' &&\n comparison !== 'year-over-year'\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--comparison must be previous-period or year-over-year.',\n )\n }\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh },\n })\n const report = await decayingReport({\n site: selection.site,\n days,\n limit,\n comparison,\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n minDropPct,\n minPreviousClicks,\n minClickLoss,\n refresh,\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Decaying pages',\n target: report.site,\n status:\n report.dataStatus === 'complete'\n ? report.summary.returnedRows > 0\n ? 'warning'\n : 'pass'\n : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Evidence', value: report.dataStatus },\n { label: 'Comparison', value: report.comparison },\n {\n label: 'Observed declines',\n value: formatCount(report.summary.returnedRows),\n },\n {\n label: 'Eligible declines',\n value: formatCount(report.summary.eligibleRows),\n },\n { label: 'Decay clusters', value: formatCount(report.summary.groups) },\n {\n label: 'Observed click decline',\n value: formatCount(\n report.summary.returnedObservedRetainedQueryClickLoss,\n ),\n },\n {\n label: 'Eligible click decline',\n value: formatCount(report.summary.observedRetainedQueryClickLoss),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Minimum drop', value: `${report.filters.minDropPct}%` },\n {\n label: 'Minimum previous clicks',\n value: formatCount(report.filters.minPreviousClicks),\n },\n { label: 'GSC completeness', value: report.source.completeness },\n ],\n })\n printNotes('Why this matters', [\n 'This report compares retained query/page rows and only counts declines observed in both windows.',\n 'Position, CTR, and impression movements are signals for investigation, not proof of cause.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n printNotes('Warnings', report.warnings)\n\n if (!report.items.length) {\n return\n }\n\n if (report.groups.length) {\n printLimitedTable(\n ['Cluster', 'Rows', 'Observed loss', 'Drop', 'Sample query', 'Action'],\n report.groups.map((group) => [\n truncate(group.label, 42),\n formatCount(group.count),\n formatCount(group.totalClickLoss),\n `${group.averageDropPct.toFixed(1)}%`,\n truncate(group.sampleQueries[0] ?? '-', 40),\n truncate(group.recommendation, 72),\n ]),\n )\n printActionDetails(\n 'Top decay cluster actions',\n report.groups.map((group) => ({\n label: group.label,\n context: `${formatCount(group.count)} retained rows, ${formatCount(group.totalClickLoss)} observed click decline`,\n action: group.recommendation,\n })),\n )\n }\n\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'URL',\n 'Signals',\n 'Decline',\n 'Clicks',\n 'Impr',\n 'CTR',\n 'Pos',\n 'Action',\n ],\n report.items.map((item) => [\n truncate(item.query, 32),\n truncate(item.template.label, 26),\n truncate(item.url, 44),\n item.signals.join(', '),\n formatCount(item.clickLoss),\n `${formatCount(item.previous.clicks)} -> ${formatCount(item.current.clicks)}`,\n `${formatCount(item.previous.impressions)} -> ${formatCount(item.current.impressions)}`,\n `${formatPercent(item.previous.ctr)} -> ${formatPercent(item.current.ctr)}`,\n `${formatMaybePosition(item.previous.position)} -> ${formatMaybePosition(item.current.position)}`,\n truncate(item.recommendation.action, 64),\n ]),\n )\n printActionDetails(\n 'Top decay actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.template.label}, ${formatCount(item.clickLoss)} fewer observed clicks`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","import { internalLinksReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n projectArg,\n strictFetchRateArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const internalLinksCommand = defineCommand({\n meta: {\n name: 'internal-links',\n description: 'Find verified internal-link review candidates for one URL',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n url: {\n type: 'string',\n required: true,\n description: 'Target page that should receive relevant internal links.',\n },\n ...cliReportArgs([\n 'days',\n 'limit',\n 'checkLimit',\n 'minImpressions',\n 'includeBrand',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const refresh = booleanArg(args.refresh)\n const days = strictNumberArg(args.days, '--days')\n const limit = strictNumberArg(args.limit, '--limit')\n const checkLimit = strictNumberArg(args['check-limit'], '--check-limit')\n const minImpressions = strictNumberArg(\n args['min-impressions'],\n '--min-impressions',\n )\n const rate = strictFetchRateArg(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh },\n })\n const report = await internalLinksReport({\n site: selection.site,\n targetUrl: stringArg(args.url) ?? '',\n days,\n limit,\n checkLimit,\n minImpressions,\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n js: booleanArg(args.js) ? true : undefined,\n rate,\n refresh,\n })\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Internal link opportunities',\n target: report.targetUrl,\n status:\n report.summary.failedChecks > 0 ||\n report.summary.uncheckedCandidates > 0\n ? 'unknown'\n : 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Target state', value: report.target.verification },\n { label: 'Preferred target', value: report.target.preferredUrl },\n {\n label: 'Target queries',\n value: formatCount(report.summary.targetQueries),\n },\n {\n label: 'Matched sources',\n value: formatCount(report.summary.candidateSources),\n },\n {\n label: 'Checked sources',\n value: formatCount(report.summary.checkedSources),\n },\n {\n label: 'Attempted sources',\n value: formatCount(report.summary.attemptedSources),\n },\n {\n label: 'Review candidates',\n value: formatCount(report.summary.returnedSources),\n },\n {\n label: 'Technical exclusions',\n value: formatCount(report.summary.technicalExclusions),\n },\n {\n label: 'Existing links',\n value: formatCount(report.summary.existingLinksObserved),\n },\n {\n label: 'Failed checks',\n value: formatCount(report.summary.failedChecks),\n },\n {\n label: 'Unchecked sources',\n value: formatCount(report.summary.uncheckedCandidates),\n },\n { label: 'GSC completeness', value: report.source.completeness },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n ],\n })\n printNotes('Why this matters', [\n 'Exact-query overlap is useful affinity evidence; precision lexical matches are review evidence only.',\n 'Source and target pages are checked for redirects, indexability, canonicals, and existing link placement before an action is returned.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n if (!report.items.length) return\n\n printLimitedTable(\n ['Source URL', 'Matched impr', 'Match', 'Link evidence', 'Action'],\n report.items.map((item) => [\n truncate(item.sourceUrl, 52),\n formatCount(item.matchedQueryImpressions),\n item.bestMatchKind,\n item.linkEvidence.status,\n item.actionType,\n ]),\n )\n printActionDetails(\n 'Top internal-link reviews',\n report.items.map((item) => ({\n label: truncate(item.sourceUrl, 96),\n context: `${formatCount(item.matchedQueryImpressions)} matched-query impressions; ${item.bestMatchKind}`,\n action: item.recommendation.action,\n })),\n )\n printNotes('Provider usage', [report.ledgerSummary])\n },\n})\n","import { pageOpportunitiesReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatFetchDiagnostics } from '../shared.js'\n\nexport const pageOpportunitiesCommand = defineCommand({\n meta: {\n name: 'page-opportunities',\n description: 'Find first-party traffic growth opportunities for one URL',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n url: { type: 'string', required: true },\n ...cliReportArgs(\n ['days', 'limit', 'minImpressions', 'includeBrand', 'js', 'refresh'],\n {\n limit: {\n description: 'Maximum page queries to inspect. Defaults to 25.',\n },\n minImpressions: {\n description: 'Minimum query impressions. Defaults to 10.',\n },\n includeBrand: {\n description: 'Include branded queries in page opportunity reports.',\n },\n js: {\n description: 'Force JavaScript rendering for page extraction.',\n },\n refresh: {\n description: 'Bypass local GSC and HTTP cache.',\n },\n },\n ),\n 'verify-content': defaultTrueBooleanArg(\n 'Fetch the page for title/H1/body checks. Defaults to true.',\n 'Skip fetching the page for title/H1/body checks.',\n ),\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await pageOpportunitiesReport({\n site: selection.site,\n url: stringArg(args.url) ?? '',\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent: booleanArg(args['verify-content']) !== false,\n js: booleanArg(args.js) ? true : 'auto',\n refresh: booleanArg(args.refresh),\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Page opportunities',\n target: report.url,\n status: report.verification.status === 'failed' ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Title', value: report.page?.title ?? 'Not fetched' },\n {\n label: 'Fetch',\n value: formatFetchDiagnostics(report.page?.fetchDiagnostics),\n },\n { label: 'Verification', value: report.verification.status },\n {\n label: 'Rows',\n value: `${formatCount(report.selection.returnedRows)} returned / ${formatCount(report.selection.eligibleRows)} eligible / ${formatCount(report.selection.sourceRows)} source`,\n },\n { label: 'Queries', value: formatCount(report.summary.queries) },\n {\n label: 'Impressions',\n value: formatCount(report.summary.impressions),\n },\n {\n label: 'Opportunities',\n value: formatCount(report.summary.opportunities),\n },\n {\n label: 'CTR shortfall',\n value: formatCount(report.summary.estimatedCtrClickShortfall),\n },\n { label: 'Focus', value: report.summary.focus },\n { label: 'Evidence', value: report.dataStatus },\n ],\n })\n printNotes('Why this matters', [\n 'This report starts from queries where this exact URL already has impressions, so recommendations stay tied to first-party demand.',\n 'Content verification separates body gaps from title/meta framing issues, which helps avoid adding copy when the page already covers the query.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n\n if (!report.items.length) {\n process.stdout.write(\n report.dataStatus === 'empty'\n ? 'No GSC query rows found for this exact URL.\\n'\n : 'GSC rows were found, but none met the report criteria.\\n',\n )\n return\n }\n\n printLimitedTable(\n [\n 'Type',\n 'Query',\n 'Evidence',\n 'Pos',\n 'CTR',\n 'Expected',\n 'Impr',\n 'Shortfall',\n 'Action',\n ],\n report.items.map((item) => [\n item.opportunityType,\n truncate(item.query, 38),\n item.verification.signals.length\n ? item.verification.signals.join(', ')\n : item.verification.status,\n item.position.toFixed(1),\n formatPercent(item.ctr),\n item.expectedCtr === undefined\n ? 'n/a'\n : formatPercent(item.expectedCtr),\n formatCount(item.impressions),\n item.estimatedCtrClickShortfall === undefined\n ? 'n/a'\n : formatCount(item.estimatedCtrClickShortfall),\n truncate(item.recommendation, 72),\n ]),\n )\n printActionDetails(\n 'Top page actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.opportunityType}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation,\n })),\n )\n },\n})\n","import { queryClusterReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const queryClusterCommand = defineCommand({\n meta: {\n name: 'query-cluster',\n description: 'Cluster GSC queries into repeated demand themes',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n scope: { type: 'string' },\n ...cliReportArgs(['includeBrand', 'minImpressions', 'limit'], {\n includeBrand: {\n description: 'Include branded queries in query clustering.',\n },\n minImpressions: {\n description: 'Minimum impressions per query. Defaults to 25.',\n },\n limit: {\n description: 'Maximum clusters to return. Defaults to 25; max 100.',\n },\n }),\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const report = await queryClusterReport({\n site: selection.site,\n scope: stringArg(args.scope),\n brand: selection.client?.brandTerms?.[0],\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n minImpressions: numberArg(args['min-impressions']),\n limit: numberArg(args.limit),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Query clusters',\n target: report.site,\n status: 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Scope', value: report.scope ?? 'All pages' },\n { label: 'Clusters', value: formatCount(report.summary.clusters) },\n { label: 'Queries', value: formatCount(report.summary.queries) },\n {\n label: 'Impressions',\n value: formatCount(report.summary.impressions),\n },\n { label: 'Clicks', value: formatCount(report.summary.clicks) },\n {\n label: 'Minimum impressions',\n value: formatCount(report.summary.minImpressions),\n },\n { label: 'Result limit', value: formatCount(report.summary.limit) },\n {\n label: 'High opportunity',\n value: formatCount(report.summary.highOpportunityClusters),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n ],\n })\n printNotes('Why this matters', [\n 'Clusters show repeated demand themes, so they are better inputs for page sections, hubs, and templates than one-off query exports.',\n 'Prioritise clusters with high impressions and low clicks; they usually reveal unclear intent coverage or weak SERP framing.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n printLimitedTable(\n [\n 'Cluster',\n 'Intent',\n 'Queries',\n 'Impr',\n 'CTR',\n 'Expected',\n 'Lift',\n 'Action',\n ],\n report.clusters.map((cluster) => {\n return [\n truncate(cluster.label, 32),\n cluster.intent,\n cluster.queries.length,\n formatCount(cluster.totals?.impressions ?? 0),\n formatPercent(cluster.totals?.ctr ?? 0),\n formatPercent(cluster.benchmark?.expectedCtr ?? 0),\n cluster.estimatedClickLift === undefined\n ? '-'\n : formatCount(cluster.estimatedClickLift),\n truncate(cluster.recommendation ?? '', 72),\n ]\n }),\n )\n printActionDetails(\n 'Top cluster actions',\n report.clusters.map((cluster) => ({\n label: cluster.label,\n context: `${formatCount(cluster.totals?.impressions ?? 0)} impressions, ${cluster.estimatedClickLift === undefined ? 'ranking opportunity' : `${formatCount(cluster.estimatedClickLift)} estimated click lift`}`,\n action: cluster.recommendation ?? '',\n })),\n )\n },\n})\n","import { quickWinsReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n fetchRateArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n verificationSummary,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatContentCheck, formatFetchDiagnostics } from '../shared.js'\n\nexport const quickWinsCommand = defineCommand({\n meta: {\n name: 'quick-wins',\n description: 'Find high-ranking low-CTR query/page opportunities',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs([\n 'days',\n 'limit',\n 'includeBrand',\n 'minImpressions',\n 'verifyContent',\n 'verifyLimit',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const verifyLimit = numberArg(args['verify-limit'])\n const verifyContent =\n booleanArg(args['verify-content']) === true || verifyLimit !== undefined\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const report = await quickWinsReport({\n site: selection.site,\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n verifyContent,\n verifyLimit,\n js: booleanArg(args.js) ? true : undefined,\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Quick wins',\n target: report.site,\n status: report.source.possiblyTruncated ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Eligible rows',\n value: formatCount(report.summary.eligibleRows),\n },\n {\n label: 'Returned rows',\n value: formatCount(report.summary.returnedRows),\n },\n {\n label: 'Query clusters',\n value: formatCount(report.summary.repeatedQueryGroups),\n },\n {\n label: 'Template patterns',\n value: formatCount(report.summary.templatePatterns),\n },\n {\n label: 'CTR click shortfall',\n value: formatCount(report.summary.returnedEstimatedCtrClickShortfall),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Evidence', value: report.dataStatus },\n { label: 'Verification', value: verificationSummary(report) },\n ],\n })\n printNotes('Why this matters', [\n 'These rows have GSC average positions from 4 to 10 and observed CTR below a site-peer or versioned fallback target.',\n 'Page evidence is needed before treating a CTR shortfall as a title, content, or technical finding.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n\n if (!report.items.length) {\n return\n }\n\n if (report.templateRecommendations.length) {\n printLimitedTable(\n ['Template', 'URLs', 'Rows', 'Shortfall', 'Impr', 'Action'],\n report.templateRecommendations.map((template) => [\n truncate(template.templateLabel, 34),\n formatCount(template.urlCount),\n formatCount(template.rowCount),\n formatCount(template.totalEstimatedCtrClickShortfall),\n formatCount(template.totalImpressions),\n truncate(template.action, 72),\n ]),\n )\n printActionDetails(\n 'Top template actions',\n report.templateRecommendations.map((template) => ({\n label: template.templateLabel,\n context: `${formatCount(template.urlCount)} URLs, ${formatCount(template.totalEstimatedCtrClickShortfall)} heuristic CTR click shortfall`,\n action: `${template.action} ${template.evidence}`,\n })),\n )\n }\n\n if (report.groups.length) {\n printLimitedTable(\n [\n 'Cluster',\n 'URLs',\n 'Rows',\n 'Shortfall',\n 'Impr',\n 'Sample URL',\n 'Action',\n ],\n report.groups.map((group) => [\n truncate(group.label, 44),\n formatCount(group.urlCount),\n formatCount(group.rowCount),\n formatCount(group.totalEstimatedCtrClickShortfall),\n formatCount(group.totalImpressions),\n truncate(group.sampleUrls[0] ?? '-', 46),\n truncate(group.recommendation, 72),\n ]),\n )\n printActionDetails(\n 'Top cluster actions',\n report.groups.map((group) => ({\n label: group.label,\n context: `${formatCount(group.urlCount)} URLs, ${formatCount(group.totalEstimatedCtrClickShortfall)} heuristic CTR click shortfall`,\n action: group.recommendation,\n })),\n )\n }\n\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'URL',\n 'Pos',\n 'Impr',\n 'CTR / target',\n 'Shortfall',\n 'Fetch',\n 'Check',\n 'Action',\n ],\n report.items.map((item) => [\n truncate(item.query, 36),\n truncate(item.template.label, 24),\n truncate(item.url, 48),\n formatPosition(item.position),\n formatCount(item.impressions),\n `${formatPercent(item.ctr)} / ${formatPercent(item.targetCtr)}`,\n formatCount(item.estimatedCtrClickShortfall),\n formatFetchDiagnostics(item.contentVerification?.fetchDiagnostics),\n formatContentCheck(item.contentVerification?.classification),\n truncate(item.recommendation.action, 64),\n ]),\n )\n printActionDetails(\n 'Top opportunity actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.template.label}, pos ${formatPosition(item.position)}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","import { secondPage } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n fetchRateArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n verificationSummary,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatContentCheck, formatFetchDiagnostics } from '../shared.js'\n\nexport const secondPageCommand = defineCommand({\n meta: {\n name: 'second-page',\n description: 'Find URLs averaging positions above 10 through 20 in GSC',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs([\n 'range',\n 'minImpressions',\n 'limit',\n 'includeBrand',\n 'verifyContent',\n 'verifyLimit',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const verifyLimit = numberArg(args['verify-limit'])\n const verifyContent =\n booleanArg(args['verify-content']) === true || verifyLimit !== undefined\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await secondPage({\n site: selection.site,\n range: numberArg(args.days),\n minImpressions: numberArg(args['min-impressions']),\n limit: stringArg(args.limit) ? Number(stringArg(args.limit)) : 10,\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent,\n verifyLimit,\n js: booleanArg(args.js) ? true : undefined,\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Second-page opportunities',\n target: report.site,\n status:\n report.source.possiblyTruncated || report.summary.fetchFailures > 0\n ? 'unknown'\n : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Eligible pages',\n value: formatCount(report.summary.eligiblePages),\n },\n {\n label: 'Returned pages',\n value: formatCount(report.summary.returnedPages),\n },\n {\n label: 'Eligible queries',\n value: formatCount(report.summary.eligibleQueries),\n },\n {\n label: 'Impressions',\n value: formatCount(report.summary.eligibleImpressions),\n },\n {\n label: 'Content issues',\n value: formatCount(report.summary.contentIssues),\n },\n {\n label: 'Technical issues',\n value: formatCount(report.summary.technicalIssues),\n },\n {\n label: 'Fetch failures',\n value: formatCount(report.summary.fetchFailures),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Evidence', value: report.dataStatus },\n { label: 'Verification', value: verificationSummary(report) },\n ],\n })\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n if (!report.items.length) {\n process.stdout.write(\n 'No average-position candidates matched this report.\\n',\n )\n process.stdout.write(`${report.ledgerSummary}\\n`)\n return\n }\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'Pos',\n 'Impr',\n 'CTR',\n 'Queries',\n 'Fetch',\n 'Check',\n 'Action',\n ],\n report.items.map((item) => [\n item.primaryQuery,\n item.template.label,\n item.position.toFixed(1),\n Math.round(item.impressions),\n item.ctr.toFixed(3),\n formatCount(item.queryCount),\n formatFetchDiagnostics(item.fetchDiagnostics),\n formatContentCheck(item.contentVerification?.classification),\n item.recommendation.action,\n ]),\n )\n printActionDetails(\n 'Top second-page actions',\n report.items.map((item) => ({\n label: item.primaryQuery,\n context: `${item.template.label}, pos ${formatPosition(item.position)}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation.action,\n })),\n )\n process.stdout.write(`${report.ledgerSummary}\\n`)\n },\n})\n","import { auditPage } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, projectArg, stringArg } from '../args.js'\nimport { resolveClient } from '../selection.js'\nimport { printJson } from '../utils.js'\nimport { printReportSummary } from './output.js'\nimport { formatFetchDiagnostics } from './shared.js'\n\nexport const auditPageCommand = defineCommand({\n meta: {\n name: 'audit-page',\n description:\n 'Fetch one page and audit title, metadata, content, links, and schema',\n },\n args: {\n url: { type: 'string', required: true, description: 'URL to audit.' },\n site: {\n type: 'string',\n description:\n 'Optional GSC property for page search metrics, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for extraction.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache.',\n },\n },\n run: async ({ args }) => {\n const project = projectArg(args)\n const explicitSite = stringArg(args.site)\n const selectedProject = project\n ? await resolveClient({ project, options: { json: jsonFlag(args) } })\n : undefined\n const defaultProject =\n project || explicitSite\n ? undefined\n : await resolveClient({ options: { json: jsonFlag(args) } })\n const report = await auditPage({\n url: stringArg(args.url) ?? '',\n site: selectedProject?.siteUrl ?? explicitSite ?? defaultProject?.siteUrl,\n js: booleanArg(args.js) ? true : 'auto',\n refresh: booleanArg(args.refresh),\n })\n if (jsonFlag(args)) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Page audit',\n target: report.url,\n status: report.issues.some((issue) => issue.severity === 'high')\n ? 'fail'\n : report.issues.length > 0\n ? 'warning'\n : 'pass',\n summary:\n report.issues.length > 0\n ? `${report.issues.length} ${report.issues.length === 1 ? 'issue needs' : 'issues need'} review.`\n : 'No page issues were found by the available checks.',\n metrics: [\n { label: 'Final URL', value: report.page.finalUrl },\n { label: 'Title', value: report.page.title ?? 'Missing' },\n {\n label: 'Meta description',\n value: report.page.metaDescription ?? 'Missing',\n },\n { label: 'Words', value: report.page.wordCount },\n {\n label: 'Fetch',\n value: formatFetchDiagnostics(report.fetchDiagnostics),\n },\n ],\n diagnostics: [\n {\n title: 'Issues',\n items: report.issues.map((issue) => ({\n status: issue.severity === 'high' ? 'fail' : 'warning',\n title: `${issue.code}: ${issue.principle}`,\n explanation: issue.detail,\n })),\n },\n ],\n })\n },\n})\n","import { performanceAudit, SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, projectArg, stringArg } from '../args.js'\nimport { resolveClient } from '../selection.js'\nimport { printJson } from '../utils.js'\nimport { printActionDetails, printNotes, printReportSummary } from './output.js'\n\nfunction strategy(value: unknown): 'mobile' | 'desktop' {\n const selected = stringArg(value) ?? 'mobile'\n if (selected !== 'mobile' && selected !== 'desktop') {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Invalid --strategy. Use mobile or desktop.',\n )\n }\n return selected\n}\n\nfunction metric(value?: { displayValue?: string; value?: number }): string {\n if (!value) return 'not measured'\n return value.displayValue ?? String(value.value ?? 'not measured')\n}\n\nfunction fieldMetric(value?: {\n p75: number\n rating: string\n unit: 'milliseconds' | 'score'\n}): string {\n if (!value) return 'not available'\n const suffix = value.unit === 'milliseconds' ? 'ms' : ''\n return `${value.p75}${suffix} (${value.rating})`\n}\n\nexport const performanceCommand = defineCommand({\n meta: {\n name: 'perf',\n description: 'Audit lab performance and field Core Web Vitals',\n },\n subCommands: {\n audit: defineCommand({\n meta: {\n name: 'audit',\n description: 'Run a Lighthouse/Core Web Vitals performance audit',\n },\n args: {\n url: {\n type: 'string',\n description:\n 'URL to audit. Defaults to the selected project crawl URL.',\n },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n strategy: {\n type: 'string',\n default: 'mobile',\n description: 'Audit strategy: mobile or desktop.',\n },\n 'lighthouse-bin': {\n type: 'string',\n description:\n 'Custom Lighthouse binary path. Defaults to the bundled version.',\n },\n 'crux-key': {\n type: 'string',\n description:\n 'CrUX API key. Prefer SEO_CRUX_API_KEY to avoid shell history.',\n },\n raw: {\n type: 'boolean',\n default: false,\n description: 'Include the full Lighthouse JSON in JSON output.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local performance report cache.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = await resolveClient({\n client: projectArg(args),\n options: { json },\n })\n const url = stringArg(args.url) ?? project?.startUrl\n if (!url) {\n throw new Error(\n 'No URL selected. Pass --url or use --project with a crawl URL.',\n )\n }\n const report = await performanceAudit({\n url,\n strategy: strategy(args.strategy),\n lighthouseBin: stringArg(args['lighthouse-bin']),\n cruxApiKey: stringArg(args['crux-key']),\n refresh: booleanArg(args.refresh),\n includeRaw: json && booleanArg(args.raw),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Performance report',\n target: report.url,\n status:\n report.dataStatus === 'partial'\n ? 'unknown'\n : report.grade === 'good'\n ? 'pass'\n : 'warning',\n summary: report.headline,\n metrics: [\n { label: 'Source', value: report.source },\n { label: 'Strategy', value: report.strategy },\n {\n label: 'Lab score',\n value:\n report.score === undefined ? 'Unknown' : `${report.score}/100`,\n },\n { label: 'Lab grade', value: report.grade },\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'FCP',\n value: metric(report.metrics.firstContentfulPaint),\n },\n {\n label: 'LCP',\n value: metric(report.metrics.largestContentfulPaint),\n },\n { label: 'TBT', value: metric(report.metrics.totalBlockingTime) },\n {\n label: 'CLS',\n value: metric(report.metrics.cumulativeLayoutShift),\n },\n {\n label: 'INP',\n value: metric(report.metrics.interactionToNextPaint),\n },\n {\n label: 'Server response',\n value: metric(report.metrics.serverResponseTime),\n },\n {\n label: 'Fallback fetch',\n value: metric(report.metrics.fallbackFetchDuration),\n },\n {\n label: 'Field data',\n value: report.fieldData\n ? `${report.fieldData.scope} ${report.fieldData.formFactor.toLowerCase()} (${report.fieldData.assessment.status})`\n : report.fieldDataStatus.status,\n },\n {\n label: 'Field LCP p75',\n value: fieldMetric(\n report.fieldData?.metrics.largestContentfulPaint,\n ),\n },\n {\n label: 'Field INP p75',\n value: fieldMetric(\n report.fieldData?.metrics.interactionToNextPaint,\n ),\n },\n {\n label: 'Field CLS p75',\n value: fieldMetric(\n report.fieldData?.metrics.cumulativeLayoutShift,\n ),\n },\n {\n label: 'Field period',\n value:\n report.fieldData?.collectionPeriod?.firstDate &&\n report.fieldData.collectionPeriod.lastDate\n ? `${report.fieldData.collectionPeriod.firstDate} to ${report.fieldData.collectionPeriod.lastDate}`\n : 'Unavailable',\n },\n ],\n })\n printActionDetails(\n 'Top actions',\n report.topActions.map((action) => ({\n label: action.title,\n action: action.action,\n context: action.plainEnglish,\n })),\n )\n printNotes('Caveats', report.caveats)\n },\n }),\n },\n})\n","import { diagnoseProperty } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { createProgressReporter } from '../../progress.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printActionDetails, printReportSummary } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const diagnoseCommand = defineCommand({\n meta: {\n name: 'diagnose',\n description: 'Find where Google Search performance changed',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Baseline window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum rows per diagnostic section. Defaults to 10.',\n },\n },\n ),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await diagnoseProperty({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n refresh: booleanArg(args.refresh),\n progress: createProgressReporter(!json),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'SEO diagnosis',\n target: report.site,\n status:\n report.dataStatus === 'complete'\n ? report.priorities.length > 0\n ? 'warning'\n : 'pass'\n : 'unknown',\n summary:\n report.priorities.length > 0\n ? `${report.priorities.length} priorities need review.`\n : 'No priorities were returned by the available evidence.',\n metrics: [\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'Update overlap',\n value: report.summary.updateAttribution.replaceAll('-', ' '),\n },\n {\n label: 'Significant anomalies',\n value: report.summary.significantAnomalies,\n },\n { label: 'Update matches', value: report.summary.updateMatches },\n { label: 'Decay items', value: report.summary.decayItems },\n { label: 'Cannibal items', value: report.summary.cannibalItems },\n {\n label: 'Striking distance',\n value: report.summary.strikingDistanceItems,\n },\n { label: 'Quick wins', value: report.summary.quickWinItems },\n ],\n })\n printTable(\n ['Priority', 'Confidence', 'Reason', 'Action'],\n report.priorities.map((priority) => [\n priority.label,\n priority.confidence,\n priority.reason,\n priority.action,\n ]),\n )\n if (report.skippedSections?.length) {\n printTable(\n ['Skipped section', 'Reason'],\n report.skippedSections.map((section) => [\n section.section,\n section.reason,\n ]),\n )\n }\n printActionDetails(\n 'Priority action details',\n report.priorities.map((priority) => ({\n label: priority.label,\n context: priority.confidence,\n action: priority.action,\n })),\n )\n },\n})\n","import { runDoctor } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport { checkSummary } from '../../presentation/views.js'\nimport { printChecks, printHeading, printJson } from '../../utils.js'\n\nexport const doctorCommand = defineCommand({\n meta: {\n name: 'doctor',\n description: 'Check local auth, scopes, config, and defaults',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const report = await runDoctor()\n if (jsonFlag(args)) {\n printJson(report)\n if (!report.ok) process.exitCode = 1\n return\n }\n printHeading('SEO doctor', checkSummary(report.checks))\n process.stdout.write('\\n')\n printChecks(report.checks)\n process.stdout.write(`\\nChecked ${report.generatedAt}\\n`)\n if (!report.ok) process.exitCode = 1\n },\n})\n","import { type SegmentDimension, segmentImpact } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nconst segmentDimension = (value: unknown): SegmentDimension => {\n const dimension = stringArg(value) ?? 'page'\n if (\n dimension !== 'page' &&\n dimension !== 'query' &&\n dimension !== 'country' &&\n dimension !== 'device'\n ) {\n throw new Error('Invalid --dimension. Use page, query, country, or device.')\n }\n return dimension\n}\n\nexport const segmentImpactCommand = defineCommand({\n meta: {\n name: 'segment-impact',\n description: 'Compare GSC movement by page, query, device, or country',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n dimension: {\n type: 'string',\n default: 'page',\n description: 'Segment by page, query, country, or device.',\n },\n ...cliReportArgs(['days', 'limit', 'refresh'], {\n days: {\n description: 'Recent window length from 1 to 240 days. Defaults to 28.',\n },\n limit: {\n description: 'Maximum segment rows to print. Defaults to 25.',\n },\n refresh: {\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n }),\n compare: {\n type: 'string',\n description:\n 'Legacy 1-240 day comparison length. Must equal the current window.',\n },\n 'start-date': {\n type: 'string',\n description: 'Exact current-window start date in YYYY-MM-DD format.',\n },\n 'end-date': {\n type: 'string',\n description: 'Exact current-window end date in YYYY-MM-DD format.',\n },\n 'max-rows': {\n type: 'string',\n description: 'Maximum retained GSC rows per window. Defaults to 100000.',\n },\n 'unmatched-limit': {\n type: 'string',\n description:\n 'Maximum one-window evidence rows to return. Defaults to 25.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const dimension = segmentDimension(args.dimension)\n const days = strictNumberArg(args.days, '--days')\n const compareDays = strictNumberArg(args.compare, '--compare')\n const limit = strictNumberArg(args.limit, '--limit')\n const unmatchedLimit = strictNumberArg(\n args['unmatched-limit'],\n '--unmatched-limit',\n )\n const maxRows = strictNumberArg(args['max-rows'], '--max-rows')\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await segmentImpact({\n site: selection.site,\n dimension,\n days,\n compareDays,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n limit,\n unmatchedLimit,\n maxRows,\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Segment impact',\n target: report.site,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Dimension', value: report.dimension },\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'Before',\n value: `${report.before.startDate} to ${report.before.endDate}`,\n },\n {\n label: 'After',\n value: `${report.after.startDate} to ${report.after.endDate}`,\n },\n ],\n })\n printTable(\n ['Segment', 'Clicks before', 'Clicks after', 'Delta', 'Pos delta'],\n report.items.map((item) => [\n item.key,\n item.beforeClicks,\n item.afterClicks,\n item.clickDelta,\n item.positionDelta ?? '-',\n ]),\n )\n if (report.unmatchedSegments.length) {\n process.stdout.write('\\nOne-window evidence (not treated as zero)\\n')\n printTable(\n ['Segment', 'Retained in', 'Clicks', 'Impressions'],\n report.unmatchedSegments.map((item) => [\n item.key,\n item.retainedIn,\n item.clicks,\n item.impressions,\n ]),\n )\n }\n printNotes('Warnings', report.warnings)\n },\n})\n","import { strikingDistance } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n fetchRateArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatContentCheck, formatFetchDiagnostics } from '../shared.js'\n\nfunction rowCountLabel(count: number): string {\n return `${formatCount(count)} ${count === 1 ? 'row' : 'rows'}`\n}\n\nexport const strikingDistanceCommand = defineCommand({\n meta: {\n name: 'striking-distance',\n description: 'Find query/page rows averaging positions above 10 through 20',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs([\n 'days',\n 'minImpressions',\n 'limit',\n 'includeBrand',\n 'verifyContent',\n 'verifyLimit',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const verifyLimit = numberArg(args['verify-limit'])\n const verifyContent =\n booleanArg(args['verify-content']) === true || verifyLimit !== undefined\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await strikingDistance({\n site: selection.site,\n days: numberArg(args.days),\n minImpressions: numberArg(args['min-impressions']),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent,\n verifyLimit,\n js: booleanArg(args.js) ? true : undefined,\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Striking-distance opportunities',\n target: report.site,\n status: report.source.possiblyTruncated ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Eligible rows',\n value: formatCount(report.summary.eligibleRows),\n },\n {\n label: 'Returned rows',\n value: formatCount(report.summary.returnedRows),\n },\n { label: 'Template groups', value: formatCount(report.summary.groups) },\n {\n label: 'Impressions',\n value: formatCount(report.summary.eligibleImpressions),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n {\n label: 'Verification',\n value: report.verification.requested ? 'Requested' : 'Off',\n },\n { label: 'Evidence', value: report.dataStatus },\n ],\n })\n printNotes('Why this matters', [\n 'These rows have a GSC average position above 10 and at most 20. Treat them as candidates for investigation, not guaranteed page-two rankings.',\n 'Groups use all eligible rows. A shared-template label is only a candidate until recurring evidence is verified across distinct URLs.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n\n if (report.groups.length) {\n printLimitedTable(\n ['Group', 'Rows', 'URLs', 'Impr', 'Avg pos', 'Scope', 'Action'],\n report.groups.map((group) => [\n truncate(group.label, 36),\n formatCount(group.rowCount),\n formatCount(group.uniqueUrls),\n formatCount(group.totalImpressions),\n formatPosition(group.impressionWeightedPosition),\n group.actionScope,\n truncate(group.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top striking-distance group actions',\n report.groups.map((group) => ({\n label: group.label,\n context: `${rowCountLabel(group.rowCount)}, ${formatCount(group.totalImpressions)} impressions`,\n action: group.recommendation.action,\n })),\n )\n }\n\n if (!report.items.length) {\n process.stdout.write(\n 'No striking-distance opportunities matched these filters.\\n',\n )\n return\n }\n\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'URL',\n 'Impr',\n 'CTR',\n 'Pos',\n 'Score',\n 'Fetch',\n 'Check',\n 'Action',\n ],\n report.items.map((item) => [\n truncate(item.query, 36),\n truncate(item.template.label, 24),\n truncate(item.url, 48),\n formatCount(item.impressions),\n formatPercent(item.ctr),\n formatPosition(item.position),\n item.priority.score,\n formatFetchDiagnostics(item.contentVerification?.fetchDiagnostics),\n formatContentCheck(item.contentVerification?.classification),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top striking-distance actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.template.label}, pos ${formatPosition(item.position)}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","export function credentialSourceLabel(\n source: 'environment' | 'keychain' | 'file' | undefined,\n): string {\n if (source === 'keychain') return 'system keychain'\n if (source === 'file') return 'private local file'\n return source ?? 'missing'\n}\n\nexport function formatUsd(micros: number | null): string {\n return micros === null ? 'unavailable' : `$${(micros / 1_000_000).toFixed(2)}`\n}\n","import { intro, note, outro, password } from '@clack/prompts'\nimport {\n AHREFS_API_KEY_ENV,\n AhrefsClient,\n deleteAhrefsApiKey,\n readAhrefsApiKey,\n SeoError,\n writeAhrefsApiKey,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n} from '../../utils.js'\nimport { credentialSourceLabel } from './shared.js'\n\nfunction unitUsage(input: {\n limit: number | null\n used: number | null\n remaining: number | null\n}): string {\n if (input.limit === null) {\n return input.used === null\n ? 'not reported'\n : `${input.used.toLocaleString('en-US')} used; no key limit`\n }\n return `${(input.remaining ?? 0).toLocaleString('en-US')} of ${input.limit.toLocaleString('en-US')} remaining`\n}\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save an Ahrefs API v3 key',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run \\`seo providers ahrefs connect\\` in a terminal. Agents and CI can set ${AHREFS_API_KEY_ENV}.`,\n )\n }\n\n intro('Connect Ahrefs')\n note(\n 'Paste an API v3 key from Ahrefs Account settings. The validation check and Domain Rating are free; other research can consume API units.',\n 'API key',\n )\n const apiKey = maybeExitCancelled(\n await password({\n message: 'Ahrefs API v3 key',\n validate: (value) =>\n value?.trim() ? undefined : 'API key is required',\n }),\n )\n const account = await new AhrefsClient({ apiKey }).limitsAndUsage()\n const source = await writeAhrefsApiKey(apiKey)\n\n note(\n `${account.subscription} subscription. API key units: ${unitUsage(account.apiKeyUnits)}.`,\n 'Connection verified',\n )\n outro(\n `Saved in the ${credentialSourceLabel(source)}. Run seo providers ahrefs status --check to verify it again.`,\n )\n },\n})\n\nconst statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show the local Ahrefs connection',\n },\n args: {\n check: {\n type: 'boolean',\n default: false,\n description: 'Verify the API key with the free account endpoint.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const credential = await readAhrefsApiKey()\n const shouldCheck = Boolean(args.check)\n const account =\n shouldCheck && credential\n ? await new AhrefsClient().limitsAndUsage()\n : undefined\n const result = {\n connected: Boolean(credential),\n apiVersion: credential ? 3 : null,\n credentialSource: credential?.source,\n liveCheck: account\n ? {\n status: 'passed' as const,\n subscription: account.subscription,\n apiKeyExpiresAt: account.apiKeyExpiresAt,\n usageResetsAt: account.usageResetsAt,\n apiKeyUnits: account.apiKeyUnits,\n workspaceUnits: account.workspaceUnits,\n observedAt: account.observedAt,\n requestCostUnits: account.requestCostUnits,\n }\n : {\n status: (shouldCheck ? 'unavailable' : 'not-requested') as\n | 'unavailable'\n | 'not-requested',\n },\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Connected', result.connected ? 'yes' : 'no'],\n ['API version', result.apiVersion ? 'Version 3' : 'not connected'],\n ['Credential', credentialSourceLabel(result.credentialSource)],\n [\n 'Live check',\n result.liveCheck.status === 'passed'\n ? `passed at ${result.liveCheck.observedAt}`\n : result.liveCheck.status === 'unavailable'\n ? 'not available without credentials'\n : 'not requested; pass --check to verify',\n ],\n ...(account\n ? ([\n ['Subscription', account.subscription],\n ['API key units', unitUsage(account.apiKeyUnits)],\n ['Workspace units', unitUsage(account.workspaceUnits)],\n ['Usage resets', account.usageResetsAt],\n ['Key expires', account.apiKeyExpiresAt],\n ] satisfies Array<[string, string]>)\n : []),\n ])\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove the saved Ahrefs API v3 key',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n await deleteAhrefsApiKey()\n const environmentCredential = Boolean(\n process.env[AHREFS_API_KEY_ENV]?.trim(),\n )\n const result = {\n savedCredentialRemoved: true,\n environmentCredential: environmentCredential\n ? ('active' as const)\n : ('missing' as const),\n note: environmentCredential\n ? `The environment variable was not changed. Clear ${AHREFS_API_KEY_ENV} to fully disconnect.`\n : 'Ahrefs is disconnected.',\n }\n if (jsonFlag(args)) printJson(result)\n else process.stdout.write(`${result.note}\\n`)\n },\n})\n\nexport const ahrefsProviderCommand = defineCommand({\n meta: {\n name: 'ahrefs',\n description: 'Connect Ahrefs for optional search and link data',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n },\n})\n","import { intro, note, outro, password, text } from '@clack/prompts'\nimport {\n DATAFORSEO_LOGIN_ENV,\n DATAFORSEO_PASSWORD_ENV,\n DataForSeoClient,\n deleteDataForSeoCredentials,\n readDataForSeoCredentials,\n SeoError,\n writeDataForSeoCredentials,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n} from '../../utils.js'\nimport { credentialSourceLabel, formatUsd } from './shared.js'\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save DataForSEO API credentials',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run \\`seo providers dataforseo connect\\` in a terminal. Agents and CI can set ${DATAFORSEO_LOGIN_ENV} and ${DATAFORSEO_PASSWORD_ENV}.`,\n )\n }\n\n intro('Connect DataForSEO')\n note(\n 'Use the API login and API password from DataForSEO API Access. The validation call is free; later research reports can make charged requests.',\n 'API credentials',\n )\n const login = maybeExitCancelled(\n await text({\n message: 'DataForSEO API login',\n validate: (value) =>\n value?.trim() ? undefined : 'API login is required',\n }),\n )\n const apiPassword = maybeExitCancelled(\n await password({\n message: 'DataForSEO API password',\n validate: (value) => (value ? undefined : 'API password is required'),\n }),\n )\n const credentials = { login: login.trim(), password: apiPassword }\n const account = await new DataForSeoClient({\n credentials: () => credentials,\n }).userData()\n const source = await writeDataForSeoCredentials(credentials)\n\n note(\n `${account.login} is connected with an account balance of ${formatUsd(account.balanceMicros)}.`,\n 'Connection verified',\n )\n outro(\n `Saved in the ${credentialSourceLabel(source)}. Run seo providers dataforseo status --check to verify it again.`,\n )\n },\n})\n\nconst statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show the local DataForSEO connection',\n },\n args: {\n check: {\n type: 'boolean',\n default: false,\n description: 'Verify credentials with the free account endpoint.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const credentials = await readDataForSeoCredentials()\n const shouldCheck = Boolean(args.check)\n const account =\n shouldCheck && credentials\n ? await new DataForSeoClient().userData()\n : undefined\n const result = {\n connected: Boolean(credentials),\n credentialSource: credentials?.source,\n migratedLegacyCredentials: credentials?.migrated ?? false,\n liveCheck: account\n ? {\n status: 'passed' as const,\n account: account.login,\n timezone: account.timezone,\n balanceMicros: account.balanceMicros,\n observedAt: account.observedAt,\n requestCostMicros: account.requestCostMicros,\n }\n : {\n status: (shouldCheck ? 'unavailable' : 'not-requested') as\n | 'unavailable'\n | 'not-requested',\n },\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Connected', result.connected ? 'yes' : 'no'],\n ['Credential', credentialSourceLabel(result.credentialSource)],\n [\n 'Live check',\n result.liveCheck.status === 'passed'\n ? `passed at ${result.liveCheck.observedAt}`\n : result.liveCheck.status === 'unavailable'\n ? 'not available without credentials'\n : 'not requested; pass --check to verify',\n ],\n ...(account\n ? ([\n ['Account', account.login],\n ['Balance', formatUsd(account.balanceMicros)],\n ] satisfies Array<[string, string]>)\n : []),\n ])\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove saved DataForSEO credentials',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n await deleteDataForSeoCredentials()\n const hasEnvironmentLogin = Boolean(\n process.env[DATAFORSEO_LOGIN_ENV]?.trim(),\n )\n const hasEnvironmentPassword = Boolean(process.env[DATAFORSEO_PASSWORD_ENV])\n const result = {\n savedCredentialsRemoved: true,\n environmentCredentials:\n hasEnvironmentLogin && hasEnvironmentPassword\n ? ('active' as const)\n : hasEnvironmentLogin || hasEnvironmentPassword\n ? ('partial' as const)\n : ('missing' as const),\n note:\n hasEnvironmentLogin || hasEnvironmentPassword\n ? `Environment variables were not changed. Clear ${DATAFORSEO_LOGIN_ENV} and ${DATAFORSEO_PASSWORD_ENV} to fully disconnect.`\n : 'DataForSEO is disconnected.',\n }\n if (jsonFlag(args)) printJson(result)\n else process.stdout.write(`${result.note}\\n`)\n },\n})\n\nexport const dataForSeoProviderCommand = defineCommand({\n meta: {\n name: 'dataforseo',\n description: 'Connect DataForSEO for optional search data',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n },\n})\n","import { confirm, intro, note, outro, password, text } from '@clack/prompts'\nimport {\n deleteProviderExtensionAccount,\n deleteProviderExtensionCredentials,\n describeInstalledProviderExtension,\n inspectProviderPackage,\n installProviderPackage,\n listInstalledProviderExtensions,\n loadInstalledProviderExtensions,\n readProviderExtensionAccount,\n readProviderExtensionCredentials,\n runProviderExtensionAction,\n SeoError,\n type SeoProviderJson,\n uninstallProviderExtension,\n verifyProviderExtension,\n writeProviderExtensionAccount,\n writeProviderExtensionCredentials,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, stringArg } from '../../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n printTable,\n} from '../../utils.js'\n\nfunction parseAccount(value: string | undefined): Record<string, string> {\n if (!value) return {}\n let parsed: unknown\n try {\n parsed = JSON.parse(value)\n } catch {\n throw new SeoError('INVALID_INPUT', '--account must be a JSON object.')\n }\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new SeoError('INVALID_INPUT', '--account must be a JSON object.')\n }\n const entries = Object.entries(parsed)\n if (\n entries.length > 20 ||\n entries.some(\n ([key, item]) =>\n !key ||\n key.length > 64 ||\n typeof item !== 'string' ||\n item.length > 4_096,\n )\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--account must contain at most 20 bounded string fields.',\n )\n }\n return Object.fromEntries(\n entries.map(([key, item]) => [key, (item as string).trim()]),\n )\n}\n\nfunction parseActionParams(\n value: string | undefined,\n): Record<string, SeoProviderJson> {\n if (!value) return {}\n let parsed: unknown\n try {\n parsed = JSON.parse(value)\n } catch {\n throw new SeoError('INVALID_INPUT', '--params must be a JSON object.')\n }\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new SeoError('INVALID_INPUT', '--params must be a JSON object.')\n }\n const entries = Object.entries(parsed)\n if (\n entries.length > 100 ||\n entries.some(([key]) => !/^[A-Za-z][A-Za-z0-9-]{0,63}$/u.test(key)) ||\n Buffer.byteLength(value) > 64 * 1_024\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--params must be a JSON object smaller than 64 KiB.',\n )\n }\n return Object.fromEntries(entries) as Record<string, SeoProviderJson>\n}\n\nasync function installedProvider(id: string) {\n const loaded = await loadInstalledProviderExtensions()\n const provider = loaded.registry.get(id)\n if (provider) return provider\n const failure = loaded.failures.find((item) => item.id === id)\n if (failure) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Provider ${id} could not load: ${failure.message}`,\n )\n }\n throw new SeoError('INVALID_INPUT', `Provider ${id} is not installed.`)\n}\n\nfunction normalizedAccount(\n provider: Awaited<ReturnType<typeof installedProvider>>,\n account: Readonly<Record<string, string>>,\n): Record<string, string> {\n const allowed = new Set(\n provider.connection.fields\n .filter((field) => field.kind === 'account')\n .map((field) => field.id),\n )\n const unknown = Object.keys(account).find((key) => !allowed.has(key))\n if (unknown) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${unknown} is not an account field for ${provider.displayName}.`,\n )\n }\n const normalized = provider.connection.normalizeAccount\n ? provider.connection.normalizeAccount(account)\n : { ...account }\n const unknownNormalized = Object.keys(normalized).find(\n (key) => !allowed.has(key),\n )\n if (unknownNormalized) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n `${provider.displayName} returned an unknown account field.`,\n )\n }\n for (const field of provider.connection.fields.filter(\n (item) => item.kind === 'account' && item.required !== false,\n )) {\n if (!normalized[field.id]?.trim()) {\n throw new SeoError('INVALID_INPUT', `${field.label} is required.`)\n }\n }\n return normalized\n}\n\nexport async function providerExtensionInventory() {\n return listInstalledProviderExtensions()\n}\n\nconst listCommand = defineCommand({\n meta: {\n name: 'list',\n description: 'List installed provider packages',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const inventory = await providerExtensionInventory()\n if (jsonFlag(args)) {\n printJson(inventory)\n return\n }\n if (inventory.installed.length > 0) {\n printTable(\n ['Installed provider', 'Package', 'Version', 'Status'],\n inventory.installed.map((provider) => [\n provider.id,\n provider.package,\n provider.version,\n provider.loadStatus,\n ]),\n )\n } else {\n process.stdout.write('No provider extensions are installed.\\n')\n }\n },\n})\n\nconst describeCommand = defineCommand({\n meta: {\n name: 'describe',\n description: 'Describe one installed provider for an agent',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const result = await describeInstalledProviderExtension(id)\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Provider', result.displayName],\n ['Package', `${result.package}@${result.version}`],\n ['Description', result.description],\n [\n 'Capabilities',\n result.capabilities.map((item) => item.id).join(', ') || 'none',\n ],\n ['Actions', result.actions.map((item) => item.id).join(', ') || 'none'],\n ])\n },\n})\n\nconst installCommand = defineCommand({\n meta: {\n name: 'install',\n description: 'Install one provider package from npm',\n },\n args: {\n package: {\n type: 'positional',\n required: true,\n description: 'npm package name with an optional exact version.',\n },\n yes: {\n type: 'boolean',\n default: false,\n description: 'Approve third-party code installation without prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const packageName = stringArg(args.package) ?? ''\n const json = jsonFlag(args)\n const approved = booleanArg(args.yes)\n const interactive = canPrompt({ json })\n if (!approved && !interactive) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Provider installation runs third-party code. Review the package, then pass --yes to approve it in JSON or CI mode.',\n )\n }\n let release: Awaited<ReturnType<typeof inspectProviderPackage>>\n try {\n release = await inspectProviderPackage(packageName)\n } catch (error) {\n throw new SeoError(\n 'INVALID_INPUT',\n error instanceof Error ? error.message : String(error),\n )\n }\n if (!approved) {\n intro('Install provider package')\n note(\n [\n `${release.package}@${release.version}`,\n `Publisher: ${release.publisher ?? 'not supplied by npm'}`,\n `Repository: ${release.repository ?? 'not supplied by npm'}`,\n `Integrity: ${release.integrity}`,\n ].join('\\n'),\n 'Package',\n )\n note(\n 'This package can read files, use the network, and run with the same local permissions as seo. Installing it is not a security review or endorsement.',\n 'Third-party code',\n )\n const accepted = maybeExitCancelled(\n await confirm({\n message: `Install ${release.package}@${release.version}?`,\n initialValue: false,\n }),\n )\n if (!accepted) {\n outro('Provider was not installed.')\n return\n }\n }\n let installed: Awaited<ReturnType<typeof installProviderPackage>>\n try {\n installed = await installProviderPackage(release)\n } catch (error) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n error instanceof Error ? error.message : String(error),\n )\n }\n const result = { installed, package: release }\n if (json) {\n printJson(result)\n return\n }\n outro(\n `Installed provider ${installed.id} from ${installed.package}@${installed.version}.`,\n )\n },\n})\n\nconst removeCommand = defineCommand({\n meta: {\n name: 'remove',\n description: 'Remove one installed provider extension',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n yes: {\n type: 'boolean',\n default: false,\n description: 'Remove the package without prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const json = jsonFlag(args)\n const approved = booleanArg(args.yes)\n const interactive = canPrompt({ json })\n if (!approved && !interactive) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass --yes to remove a provider extension in JSON or CI mode.',\n )\n }\n if (!approved) {\n const accepted = maybeExitCancelled(\n await confirm({\n message: `Remove provider ${id}?`,\n initialValue: false,\n }),\n )\n if (!accepted) return\n }\n const removed = await uninstallProviderExtension(id)\n if (!removed) {\n throw new SeoError('INVALID_INPUT', `Provider ${id} is not installed.`)\n }\n if (json) {\n printJson({ removed })\n return\n }\n process.stdout.write(`Removed ${id}.\\n`)\n },\n})\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save one installed provider connection',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n account: {\n type: 'string',\n description:\n 'Account fields as JSON. Secret fields must use their environment variables.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const json = jsonFlag(args)\n const interactive = canPrompt({ json })\n const provider = await installedProvider(id)\n let account = {\n ...readProviderExtensionAccount(id),\n ...parseAccount(stringArg(args.account)),\n }\n const enteredCredentials: Record<string, string> = {}\n\n if (interactive) {\n intro(`Connect ${provider.displayName}`)\n if (provider.connection.verificationNotice) {\n note(provider.connection.verificationNotice, 'Connection check')\n }\n for (const field of provider.connection.fields) {\n if (field.kind === 'account') {\n const value = maybeExitCancelled(\n await text({\n message: field.label,\n placeholder: field.description,\n initialValue: account[field.id],\n validate: (item) =>\n field.required !== false && !item?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n )\n if (value?.trim()) account[field.id] = value.trim()\n continue\n }\n if (field.envVar && process.env[field.envVar]?.trim()) continue\n const value = maybeExitCancelled(\n await password({\n message: field.label,\n validate: (item) =>\n field.required !== false && !item?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n )\n if (value?.trim()) enteredCredentials[field.id] = value.trim()\n }\n }\n\n account = normalizedAccount(provider, account)\n let credentials = { ...enteredCredentials }\n if (Object.keys(credentials).length === 0) {\n credentials = await readProviderExtensionCredentials({\n providerId: id,\n account,\n fields: provider.connection.fields,\n })\n }\n await verifyProviderExtension({ providerId: id, account, credentials })\n if (Object.keys(enteredCredentials).length > 0) {\n await writeProviderExtensionCredentials({\n providerId: id,\n account,\n credentials: enteredCredentials,\n })\n }\n writeProviderExtensionAccount(id, account)\n const result = {\n provider: id,\n connected: true,\n account,\n capabilities: (provider.capabilities ?? []).map((item) => item.id),\n actions: (provider.actions ?? []).map((item) => item.id),\n }\n if (json) printJson(result)\n else\n outro(\n `Connected ${provider.displayName}. Run seo providers describe ${id} to see what it can do.`,\n )\n },\n})\n\nconst statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show one installed provider connection',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n check: {\n type: 'boolean',\n default: false,\n description: 'Run the provider connection check.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const provider = await installedProvider(id)\n const account = readProviderExtensionAccount(id)\n let credentials: Record<string, string> | undefined\n try {\n credentials = await readProviderExtensionCredentials({\n providerId: id,\n account,\n fields: provider.connection.fields,\n })\n } catch {\n credentials = undefined\n }\n const accountReady = provider.connection.fields\n .filter((field) => field.kind === 'account' && field.required !== false)\n .every((field) => Boolean(account[field.id]?.trim()))\n const connected = accountReady && credentials !== undefined\n const shouldCheck = booleanArg(args.check)\n if (shouldCheck && !connected) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Provider ${id} is not connected. Run \\`seo providers connect ${id}\\`.`,\n )\n }\n if (shouldCheck && credentials) {\n await verifyProviderExtension({ providerId: id, account, credentials })\n }\n const result = {\n provider: id,\n installed: true,\n connected,\n account,\n capabilities: (provider.capabilities ?? []).map((item) => item.id),\n actions: (provider.actions ?? []).map((item) => item.id),\n check: shouldCheck ? ('passed' as const) : ('not-requested' as const),\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printTable(\n ['Provider', 'Connected', 'Capabilities', 'Check'],\n [\n [\n provider.displayName,\n connected ? 'yes' : 'no',\n result.capabilities.join(', '),\n result.check,\n ],\n ],\n )\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove one saved provider connection',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n await installedProvider(id)\n const account = readProviderExtensionAccount(id)\n await deleteProviderExtensionCredentials({ providerId: id, account })\n deleteProviderExtensionAccount(id)\n const result = {\n provider: id,\n disconnected: true,\n note: 'Environment variables were not changed.',\n }\n if (jsonFlag(args)) printJson(result)\n else process.stdout.write(`Disconnected ${id}. ${result.note}\\n`)\n },\n})\n\nconst runCommand = defineCommand({\n meta: {\n name: 'run',\n description: 'Run one action supplied by an installed provider',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n action: {\n type: 'positional',\n required: true,\n description: 'Provider action id.',\n },\n account: {\n type: 'string',\n description: 'Account fields as JSON. Defaults to the saved connection.',\n },\n params: {\n type: 'string',\n description: 'Action parameters as a JSON object.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local provider cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const action = stringArg(args.action) ?? ''\n await installedProvider(id)\n const account = {\n ...readProviderExtensionAccount(id),\n ...parseAccount(stringArg(args.account)),\n }\n const result = await runProviderExtensionAction({\n providerId: id,\n actionId: action,\n account,\n params: parseActionParams(stringArg(args.params)),\n refresh: booleanArg(args.refresh),\n })\n printJson(result)\n },\n})\n\nconst doctorCommand = defineCommand({\n meta: {\n name: 'doctor',\n description: 'Validate installed provider packages and entry points',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const inventory = await providerExtensionInventory()\n const result = {\n ok: inventory.installed.every(\n (provider) => provider.loadStatus === 'ready',\n ),\n installed: inventory.installed,\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n if (result.installed.length === 0) {\n process.stdout.write('No provider extensions are installed.\\n')\n return\n }\n printTable(\n ['Provider', 'Package', 'Version', 'Status'],\n result.installed.map((provider) => [\n provider.id,\n provider.package,\n provider.version,\n provider.error ?? provider.loadStatus,\n ]),\n )\n },\n})\n\nexport const providerExtensionCommands = {\n list: listCommand,\n describe: describeCommand,\n install: installCommand,\n remove: removeCommand,\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n run: runCommand,\n doctor: doctorCommand,\n}\n","import { defineCommand } from 'citty'\nimport { ahrefsProviderCommand } from './ahrefs.js'\nimport { dataForSeoProviderCommand } from './dataforseo.js'\nimport { providerExtensionCommands } from './extensions.js'\n\nexport const providersCommand = defineCommand({\n meta: { name: 'providers', description: 'Connect optional data providers' },\n subCommands: {\n ...providerExtensionCommands,\n ahrefs: ahrefsProviderCommand,\n dataforseo: dataForSeoProviderCommand,\n },\n})\n","import { readFile } from 'node:fs/promises'\nimport { SeoError, type SeoErrorCode } from '@seo/core'\nimport {\n describeReport,\n executeReport,\n listReports,\n REPORT_CATEGORIES,\n type ReportCategory,\n} from '@seo/mcp'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, stringArg } from '../args.js'\nimport {\n printBulletSection,\n printCallout,\n printCatalog,\n printHeading,\n printJson,\n printKeyValue,\n printParameters,\n printSection,\n} from '../utils.js'\n\nconst CATEGORY_LABELS: Record<ReportCategory, string> = {\n 'ai-search': 'AI search',\n crawl: 'Crawling and technical checks',\n diagnosis: 'Diagnosis',\n experiments: 'Experiments',\n monitoring: 'Monitoring',\n opportunities: 'Opportunities',\n reporting: 'Reporting',\n setup: 'Setup',\n workflows: 'Workflows',\n}\n\nfunction categoryArg(value: unknown): ReportCategory | undefined {\n const category = stringArg(value)\n if (!category) return undefined\n if (!REPORT_CATEGORIES.includes(category as ReportCategory)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Unknown report category: ${category}. Choose ${REPORT_CATEGORIES.join(', ')}.`,\n )\n }\n return category as ReportCategory\n}\n\nasync function paramsArg(\n inlineValue: unknown,\n fileValue: unknown,\n): Promise<Record<string, unknown>> {\n const inline = stringArg(inlineValue)\n const file = stringArg(fileValue)\n if (inline && file) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --params or --params-file, not both.',\n )\n }\n if (!inline && !file) return {}\n\n const source = inline ?? (await readFile(file ?? '', 'utf8'))\n let parsed: unknown\n try {\n parsed = JSON.parse(source)\n } catch {\n throw new SeoError('INVALID_INPUT', 'Report parameters must be valid JSON.')\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new SeoError('INVALID_INPUT', 'Report parameters must be an object.')\n }\n return parsed as Record<string, unknown>\n}\n\nfunction throwToolError(result: {\n isError?: boolean\n structuredContent?: Record<string, unknown>\n}): void {\n if (!result.isError) return\n const envelope = result.structuredContent as\n | { error?: { code?: SeoErrorCode; message?: string } }\n | undefined\n throw new SeoError(\n envelope?.error?.code ?? 'INTERNAL_ERROR',\n envelope?.error?.message ?? 'The report could not be completed.',\n )\n}\n\ntype JsonSchemaProperty = {\n description?: string\n format?: string\n items?: { type?: string }\n type?: string | string[]\n}\n\nfunction reportParameters(inputSchema: unknown) {\n if (!inputSchema || typeof inputSchema !== 'object') return []\n const schema = inputSchema as {\n properties?: Record<string, JsonSchemaProperty>\n required?: string[]\n }\n const required = new Set(schema.required ?? [])\n return Object.entries(schema.properties ?? {}).map(([name, property]) => {\n const rawType = Array.isArray(property.type)\n ? property.type.join(' | ')\n : (property.type ?? 'any')\n const type =\n rawType === 'array' && property.items?.type\n ? `${property.items.type}[]`\n : property.format\n ? `${rawType} (${property.format})`\n : rawType\n return {\n name,\n type,\n required: required.has(name),\n description: property.description,\n }\n })\n}\n\nconst listCommand = defineCommand({\n meta: {\n name: 'list',\n description: 'List report ids available to the CLI and MCP server',\n },\n args: {\n category: {\n type: 'string',\n description: `Filter by category: ${REPORT_CATEGORIES.join(', ')}.`,\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const category = categoryArg(args.category)\n const reports = listReports(category)\n if (jsonFlag(args)) {\n printJson({ reports, categories: REPORT_CATEGORIES })\n return\n }\n printCatalog(reports, {\n noun: 'report',\n categoryLabels: CATEGORY_LABELS,\n })\n process.stdout.write('\\n')\n printCallout({\n title: 'Need the detail?',\n body: 'Describe one report to see when to use it, what it needs, and what the result can prove.',\n command: 'seo reports describe <id>',\n })\n },\n})\n\nconst describeCommand = defineCommand({\n meta: {\n name: 'describe',\n description: 'Show the purpose and parameter schema for one report',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Report id from `seo reports list`.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const report = describeReport(stringArg(args.id) ?? '')\n if (jsonFlag(args)) {\n printJson({ report })\n return\n }\n printHeading(report.name, report.description)\n process.stdout.write('\\n')\n printKeyValue([\n ['ID', report.id],\n ['Category', report.category],\n ['Outcome', report.outcome],\n ])\n process.stdout.write('\\n')\n printBulletSection('Use when', report.useWhen)\n process.stdout.write('\\n')\n printBulletSection('Avoid when', report.avoidWhen)\n process.stdout.write('\\n')\n printBulletSection('Read in order', report.readOrder)\n process.stdout.write('\\n')\n printBulletSection('Do not claim', report.doNotClaim)\n process.stdout.write('\\n')\n printSection('Verify', report.verify)\n process.stdout.write('\\n')\n printCallout({\n title: 'Implement findings',\n body: report.agentWorkflow.completion,\n command: report.agentWorkflow.actionView.cli,\n })\n if (report.related.length > 0) {\n process.stdout.write('\\n')\n printBulletSection(\n 'Related reports',\n report.related.map((item) => `${item.id}: ${item.reason}`),\n )\n }\n process.stdout.write('\\nParameters\\n')\n printParameters(reportParameters(report.inputSchema))\n process.stdout.write('\\n')\n printCallout({\n title: 'Need the exact schema?',\n command: `seo reports describe ${report.id} --json`,\n })\n },\n})\n\nconst runCommand = defineCommand({\n meta: {\n name: 'run',\n description: 'Run one report with JSON parameters',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Report id from `seo reports list`.',\n },\n params: {\n type: 'string',\n description: 'Report parameters as a JSON object.',\n },\n 'params-file': {\n type: 'string',\n description: 'Read report parameters from a JSON file.',\n },\n 'actions-only': {\n type: 'boolean',\n default: false,\n description:\n 'Return findings, verification, and retained inventories without the full report body.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const params = await paramsArg(args.params, args['params-file'])\n const result = await executeReport(id, params, {\n view: booleanArg(args['actions-only']) ? 'actions' : 'full',\n })\n throwToolError(result)\n\n if (jsonFlag(args)) {\n printJson(result.structuredContent ?? {})\n return\n }\n for (const item of result.content) {\n process.stdout.write(`${item.text}\\n`)\n }\n },\n})\n\nexport const reportCatalogCommand = defineCommand({\n meta: {\n name: 'reports',\n description: 'Discover and run the complete report catalog',\n },\n subCommands: {\n list: listCommand,\n describe: describeCommand,\n run: runCommand,\n },\n})\n","import { explainRule, listRules } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../args.js'\nimport {\n printCatalog,\n printJson,\n printKeyValue,\n printSection,\n} from '../utils.js'\n\nexport const rulesCommand = defineCommand({\n meta: {\n name: 'rules',\n description: 'List crawler rule ids and default guidance',\n },\n args: {\n category: {\n type: 'string',\n description: 'Filter rules by category.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const category = stringArg(args.category)\n const rules = listRules().filter((rule) =>\n category ? rule.category === category : true,\n )\n\n if (jsonFlag(args)) {\n printJson({ rules })\n return\n }\n\n printCatalog(\n rules.map((rule) => ({\n id: rule.id,\n category: rule.category,\n name: `${rule.title} · ${rule.defaultSeverity}`,\n })),\n { noun: 'rule' },\n )\n },\n})\n\nexport const explainCommand = defineCommand({\n meta: {\n name: 'explain',\n description: 'Explain one crawler rule in plain English',\n },\n args: {\n rule: {\n type: 'string',\n required: true,\n description: 'Rule id to explain, for example missing_title.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const ruleId = stringArg(args.rule) ?? ''\n const rule = explainRule(ruleId)\n if (!rule) {\n throw new Error(`Unknown rule: ${ruleId}`)\n }\n\n if (jsonFlag(args)) {\n printJson(rule)\n return\n }\n\n printKeyValue([\n ['Rule', rule.id],\n ['Title', rule.title],\n ['Category', rule.category],\n ['Severity', rule.defaultSeverity],\n ])\n process.stdout.write('\\n')\n printSection('Why it matters', rule.whyItMatters)\n process.stdout.write('\\n')\n printSection('How to fix', rule.howToFix)\n process.stdout.write('\\n')\n printSection('Impact if ignored', rule.impactIfIgnored)\n process.stdout.write('\\n')\n printSection('How to verify', rule.howToVerify)\n },\n})\n","import { ensureSeoCliDirs } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, numberArg, projectArg, stringArg } from '../args.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printJson, printKeyValue } from '../utils.js'\nimport { startUrlForSite } from './shared.js'\n\nfunction quote(value: string): string {\n return JSON.stringify(value)\n}\n\nexport const scheduleCommand = defineCommand({\n meta: {\n name: 'schedule',\n description: 'Print local cron entries for recurring SEO workflows',\n },\n subCommands: {\n cron: defineCommand({\n meta: {\n name: 'cron',\n description: 'Print crontab lines for local recurring SEO workflows',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL for technical-watch. Defaults from the GSC property when possible.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs for index-watch.',\n },\n hour: {\n type: 'string',\n default: '9',\n description: 'Hour in local cron time. Defaults to 9.',\n },\n minute: {\n type: 'string',\n default: '0',\n description: 'Minute in local cron time. Defaults to 0.',\n },\n weekday: {\n type: 'string',\n description:\n 'Weekly technical-watch day. Defaults to client setting, then Monday.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const site = selection.site\n const startUrl =\n stringArg(args.url) ??\n selection.client?.startUrl ??\n startUrlForSite(selection.site)\n const hour = numberArg(args.hour) ?? 9\n const minute = numberArg(args.minute) ?? 0\n const weekday =\n numberArg(args.weekday) ?? selection.client?.technicalWeekday ?? 1\n const identityArg = selection.client\n ? `--project ${quote(selection.client.id)}`\n : `--site ${quote(site)}`\n const watchUrls =\n stringArg(args.urls) ?? selection.client?.watchUrls.join(',')\n\n const lines = [\n {\n name: 'technical-watch',\n cron: `${minute} ${hour} * * ${weekday}`,\n command: [\n 'seo technical-watch',\n identityArg,\n startUrl ? `--url ${quote(startUrl)}` : undefined,\n watchUrls ? `--urls ${quote(watchUrls)}` : undefined,\n '--json',\n ]\n .filter(Boolean)\n .join(' '),\n },\n ]\n if (json) {\n printJson({ site, lines })\n return\n }\n\n const paths = ensureSeoCliDirs()\n printKeyValue([\n ['Property', site],\n ['Install', 'crontab -e'],\n ])\n for (const line of lines) {\n process.stdout.write(\n `${line.cron} seo logs prune --quiet; ${line.command} >> ${quote(`${paths.logDir}/${line.name}.log`)} 2>&1\\n`,\n )\n }\n },\n }),\n },\n})\n","import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { SeoError } from '@seo/core'\n\n// Skills and evals ship at the package root. Both resolvers honour an explicit\n// override, otherwise walk up from the bundled CLI until the directory and its\n// README appear. Kept in its own module so the skills command and the eval\n// command can share it without importing each other.\nexport function skillsDirectory(): string {\n return resolvePackagedDirectory('skills', process.env.SEO_SKILLS_DIR)\n}\n\nexport function evalsDirectory(): string {\n return resolvePackagedDirectory('evals', process.env.SEO_EVALS_DIR)\n}\n\nfunction resolvePackagedDirectory(name: string, override?: string): string {\n if (override) return resolve(override)\n\n let current = dirname(fileURLToPath(import.meta.url))\n for (let depth = 0; depth < 6; depth += 1) {\n const candidate = join(current, name)\n if (existsSync(join(candidate, 'README.md'))) return candidate\n current = dirname(current)\n }\n\n throw new SeoError(\n 'INTERNAL_ERROR',\n `Packaged ${name} could not be found. Reinstall \\`seo\\` and try again.`,\n )\n}\n\nexport function readSkillDescription(path: string): string {\n const source = readFileSync(join(path, 'SKILL.md'), 'utf8')\n return source.match(/^description:\\s*(.+)$/m)?.[1]?.trim() ?? ''\n}\n","import { spawn } from 'node:child_process'\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { basename, join } from 'node:path'\nimport { SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n stringArg,\n} from '../args.js'\nimport { printJson } from '../utils.js'\nimport { evalsDirectory, skillsDirectory } from './skill-paths.js'\n\nconst SCHEMA_VERSION = 1\nconst DEFAULT_AGENT = 'claude -p'\nconst DEFAULT_TIMEOUT_SECONDS = 300\nconst MAX_CONCURRENCY = 4\nconst ROUTER_SKILL = 'seo'\n\ntype EvalItem = {\n id: number\n prompt: string\n expected_output: string\n assertions: string[]\n files: string[]\n}\n\ntype EvalFile = {\n subject: string\n evals: EvalItem[]\n}\n\ntype AssertionVerdict = {\n assertion: string\n verdict: 'pass' | 'fail' | 'unjudged'\n reason?: string\n source?: 'judge verdict'\n}\n\ntype EvalStatus = 'passed' | 'failed' | 'errored' | 'unjudged'\n\ntype EvalResult = {\n id: number\n prompt: string\n status: EvalStatus\n reply: string\n error?: string\n agentDurationMs: number\n judgeDurationMs?: number\n durationMs: number\n assertions: AssertionVerdict[]\n}\n\ntype SubjectResult = {\n subject: string\n passed: number\n failed: number\n errored: number\n unjudged: number\n evals: EvalResult[]\n}\n\nfunction listSubjectFiles(): Array<{ subject: string; path: string }> {\n const root = evalsDirectory()\n return readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isFile() && entry.name.endsWith('.json'))\n .map((entry) => ({\n subject: basename(entry.name, '.json'),\n path: join(root, entry.name),\n }))\n .sort((a, b) =>\n a.subject < b.subject ? -1 : a.subject > b.subject ? 1 : 0,\n )\n}\n\nexport function loadEvalFile(subject: string, path: string): EvalFile {\n let raw: string\n try {\n raw = readFileSync(path, 'utf8')\n } catch {\n throw new SeoError('INVALID_INPUT', `Cannot read eval file for ${subject}.`)\n }\n let doc: unknown\n try {\n doc = JSON.parse(raw)\n } catch {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json is not valid JSON.`,\n )\n }\n if (!doc || typeof doc !== 'object' || Array.isArray(doc)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json must be an object.`,\n )\n }\n const record = doc as Record<string, unknown>\n if (record.subject !== subject) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json must set subject to \"${subject}\".`,\n )\n }\n if (!Array.isArray(record.evals) || record.evals.length === 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json must have a non-empty evals array.`,\n )\n }\n const seen = new Set<number>()\n const evals: EvalItem[] = record.evals.map((entry, index) => {\n const item = entry as Record<string, unknown>\n const label = `${subject}.json eval ${index + 1}`\n if (!Number.isInteger(item?.id)) {\n throw new SeoError('INVALID_INPUT', `${label}: id must be an integer.`)\n }\n const id = item.id as number\n if (seen.has(id)) {\n throw new SeoError('INVALID_INPUT', `${label}: duplicate id ${id}.`)\n }\n seen.add(id)\n if (typeof item.prompt !== 'string' || item.prompt.trim().length === 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${label}: prompt must be a non-empty string.`,\n )\n }\n if (\n typeof item.expected_output !== 'string' ||\n item.expected_output.trim().length === 0\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${label}: expected_output must be a non-empty string.`,\n )\n }\n if (\n !Array.isArray(item.assertions) ||\n item.assertions.length === 0 ||\n item.assertions.some(\n (value) => typeof value !== 'string' || value.trim().length === 0,\n )\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${label}: assertions must be a non-empty array of non-empty strings.`,\n )\n }\n if (item.files !== undefined && !Array.isArray(item.files)) {\n throw new SeoError('INVALID_INPUT', `${label}: files must be an array.`)\n }\n return {\n id,\n prompt: item.prompt,\n expected_output: item.expected_output,\n assertions: item.assertions as string[],\n files: (item.files as string[] | undefined) ?? [],\n }\n })\n return { subject, evals }\n}\n\nfunction routerSkillBody(): string {\n const path = join(skillsDirectory(), ROUTER_SKILL, 'SKILL.md')\n if (!existsSync(path)) {\n throw new SeoError(\n 'INTERNAL_ERROR',\n 'The seo router skill could not be found. Reinstall `seo` or use --no-skill.',\n )\n }\n return readFileSync(path, 'utf8')\n}\n\n// Split a command template into argv tokens without a shell. Single quotes,\n// double quotes, and backslash escapes group tokens; nothing is expanded, so a\n// substituted prompt can never break out into extra arguments or shell syntax.\nexport function tokenizeCommand(command: string): string[] {\n const tokens: string[] = []\n let current = ''\n let started = false\n let inSingle = false\n let inDouble = false\n for (let i = 0; i < command.length; i += 1) {\n const ch = command[i] as string\n if (inSingle) {\n if (ch === \"'\") inSingle = false\n else current += ch\n started = true\n continue\n }\n if (inDouble) {\n if (ch === '\"') {\n inDouble = false\n } else if (\n ch === '\\\\' &&\n (command[i + 1] === '\"' || command[i + 1] === '\\\\')\n ) {\n current += command[i + 1]\n i += 1\n } else {\n current += ch\n }\n started = true\n continue\n }\n if (ch === \"'\") {\n inSingle = true\n started = true\n continue\n }\n if (ch === '\"') {\n inDouble = true\n started = true\n continue\n }\n if (ch === '\\\\') {\n if (i + 1 < command.length) {\n current += command[i + 1]\n i += 1\n started = true\n }\n continue\n }\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n if (started) {\n tokens.push(current)\n current = ''\n started = false\n }\n continue\n }\n current += ch\n started = true\n }\n if (inSingle || inDouble) {\n throw new SeoError('INVALID_INPUT', 'Unbalanced quote in agent command.')\n }\n if (started) tokens.push(current)\n return tokens\n}\n\nexport function buildArgv(\n template: string,\n prompt: string,\n): { argv: string[]; usesPlaceholder: boolean } {\n const tokens = tokenizeCommand(template)\n if (tokens.length === 0) {\n throw new SeoError('INVALID_INPUT', 'Agent command must not be empty.')\n }\n const usesPlaceholder = tokens.some((token) => token.includes('{prompt}'))\n const argv = usesPlaceholder\n ? tokens.map((token) => token.split('{prompt}').join(prompt))\n : tokens\n return { argv, usesPlaceholder }\n}\n\nexport function assembleAgentPrompt(\n skillBody: string | null,\n prompt: string,\n): string {\n if (!skillBody) return prompt\n return `${skillBody.trim()}\\n\\n---\\n\\nUser request:\\n${prompt}`\n}\n\nconst JUDGE_CORRECTION =\n 'Your previous reply could not be parsed as the required JSON with one result per assertion. Reply again with STRICT JSON only, in the exact shape shown, and nothing else.'\n\nexport function buildJudgePrompt(\n prompt: string,\n reply: string,\n assertions: string[],\n corrective = false,\n): string {\n const list = assertions\n .map((entry, index) => `${index + 1}. ${entry}`)\n .join('\\n')\n const base = [\n 'You are judging whether an AI agent response satisfies a list of assertions.',\n 'Judge only against the assertions. Be strict but fair.',\n '',\n 'Original request:',\n prompt,\n '',\n 'Agent response:',\n reply,\n '',\n 'Assertions to evaluate, in this exact order:',\n '<assertions>',\n list,\n '</assertions>',\n '',\n 'Judge outcomes, not narration. An assertion about reading, checking, or',\n 'following fields or steps passes when the reply demonstrably used that',\n 'information or produced the result it protects, even if the reply never',\n 'names the field or step. Fail it only when the reply contradicts it or',\n 'shows the work was not done.',\n '',\n 'Reply with STRICT JSON only. No prose, no markdown, no code fence:',\n '{\"results\":[{\"assertion\":\"<assertion text>\",\"pass\":true,\"reason\":\"<short reason>\"}]}',\n `Return exactly ${assertions.length} result${assertions.length === 1 ? '' : 's'}, one per assertion, in the same order.`,\n ].join('\\n')\n return corrective ? `${base}\\n\\n${JUDGE_CORRECTION}` : base\n}\n\n// Pull the first complete JSON object out of a larger reply. Judges wrap JSON\n// in prose or code fences, so scan for the first balanced `{...}` and parse it.\nexport function extractJsonObject(text: string): unknown | undefined {\n const start = text.indexOf('{')\n if (start === -1) return undefined\n let depth = 0\n let inString = false\n let escaped = false\n for (let i = start; i < text.length; i += 1) {\n const ch = text[i]\n if (inString) {\n if (escaped) escaped = false\n else if (ch === '\\\\') escaped = true\n else if (ch === '\"') inString = false\n continue\n }\n if (ch === '\"') inString = true\n else if (ch === '{') depth += 1\n else if (ch === '}') {\n depth -= 1\n if (depth === 0) {\n try {\n return JSON.parse(text.slice(start, i + 1))\n } catch {\n return undefined\n }\n }\n }\n }\n return undefined\n}\n\ntype ParsedVerdicts = { verdicts: AssertionVerdict[] } | { error: string }\n\nexport function parseJudgeVerdicts(\n output: string,\n assertions: string[],\n): ParsedVerdicts {\n const parsed = extractJsonObject(output)\n if (!parsed || typeof parsed !== 'object') {\n return { error: 'Judge reply did not contain a JSON object.' }\n }\n const results = (parsed as Record<string, unknown>).results\n if (!Array.isArray(results)) {\n return { error: 'Judge reply had no results array.' }\n }\n if (results.length !== assertions.length) {\n return {\n error: `Judge returned ${results.length} results for ${assertions.length} assertions.`,\n }\n }\n const verdicts = assertions.map((assertion, index) => {\n const entry = results[index] as Record<string, unknown>\n return {\n assertion,\n verdict: entry?.pass === true ? 'pass' : 'fail',\n reason:\n typeof entry?.reason === 'string' && entry.reason.trim().length > 0\n ? entry.reason.trim()\n : 'No reason given.',\n source: 'judge verdict' as const,\n } satisfies AssertionVerdict\n })\n return { verdicts }\n}\n\ntype ProcessResult = {\n stdout: string\n stderr: string\n code: number | null\n timedOut: boolean\n spawnError?: string\n durationMs: number\n}\n\nfunction runProcess(\n argv: string[],\n options: { input?: string; timeoutMs: number },\n): Promise<ProcessResult> {\n return new Promise((resolvePromise) => {\n const start = Date.now()\n const [command, ...rest] = argv\n let child: ReturnType<typeof spawn>\n try {\n child = spawn(command as string, rest, {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n } catch (error) {\n resolvePromise({\n stdout: '',\n stderr: '',\n code: null,\n timedOut: false,\n spawnError: error instanceof Error ? error.message : String(error),\n durationMs: Date.now() - start,\n })\n return\n }\n let stdout = ''\n let stderr = ''\n let settled = false\n let timedOut = false\n let killTimer: NodeJS.Timeout | undefined\n const timer = setTimeout(() => {\n timedOut = true\n child.kill('SIGTERM')\n killTimer = setTimeout(() => {\n try {\n child.kill('SIGKILL')\n } catch {\n // process already gone\n }\n }, 2000)\n killTimer.unref()\n }, options.timeoutMs)\n const finish = (result: Omit<ProcessResult, 'durationMs'>) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n if (killTimer) clearTimeout(killTimer)\n resolvePromise({ ...result, durationMs: Date.now() - start })\n }\n child.stdout?.on('data', (chunk) => {\n stdout += chunk\n })\n child.stderr?.on('data', (chunk) => {\n stderr += chunk\n })\n child.on('error', (error) => {\n finish({\n stdout,\n stderr,\n code: null,\n timedOut,\n spawnError: error.message,\n })\n })\n child.on('close', (code) => {\n finish({ stdout, stderr, code, timedOut })\n })\n if (child.stdin) {\n if (options.input !== undefined) child.stdin.end(options.input)\n else child.stdin.end()\n }\n })\n}\n\nasync function runCommandTemplate(\n template: string,\n prompt: string,\n timeoutMs: number,\n): Promise<ProcessResult> {\n const { argv, usesPlaceholder } = buildArgv(template, prompt)\n return runProcess(argv, {\n input: usesPlaceholder ? undefined : prompt,\n timeoutMs,\n })\n}\n\ntype RunOptions = {\n agent: string\n judge: string | null\n skillBody: string | null\n timeoutMs: number\n}\n\nasync function runSingleEval(\n item: EvalItem,\n options: RunOptions,\n): Promise<EvalResult> {\n const start = Date.now()\n const agentPrompt = assembleAgentPrompt(options.skillBody, item.prompt)\n const agentRun = await runCommandTemplate(\n options.agent,\n agentPrompt,\n options.timeoutMs,\n )\n const reply = agentRun.stdout.trim()\n\n const base = {\n id: item.id,\n prompt: item.prompt,\n reply,\n agentDurationMs: agentRun.durationMs,\n }\n\n if (agentRun.spawnError) {\n return {\n ...base,\n status: 'errored',\n error: `Agent command failed to start: ${agentRun.spawnError}`,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n if (agentRun.timedOut) {\n return {\n ...base,\n status: 'errored',\n error: `Agent timed out after ${Math.round(options.timeoutMs / 1000)}s.`,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n if (reply.length === 0) {\n return {\n ...base,\n status: 'errored',\n error: 'Agent returned no output on stdout.',\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n\n if (!options.judge) {\n return {\n ...base,\n status: 'unjudged',\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n\n let judgeDurationMs = 0\n let parseError = ''\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const judgePrompt = buildJudgePrompt(\n item.prompt,\n reply,\n item.assertions,\n attempt > 0,\n )\n const judgeRun = await runCommandTemplate(\n options.judge,\n judgePrompt,\n options.timeoutMs,\n )\n judgeDurationMs += judgeRun.durationMs\n if (judgeRun.spawnError) {\n return {\n ...base,\n status: 'errored',\n error: `Judge command failed to start: ${judgeRun.spawnError}`,\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n if (judgeRun.timedOut) {\n return {\n ...base,\n status: 'errored',\n error: `Judge timed out after ${Math.round(options.timeoutMs / 1000)}s.`,\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n const parsed = parseJudgeVerdicts(judgeRun.stdout, item.assertions)\n if ('verdicts' in parsed) {\n const failed = parsed.verdicts.some((entry) => entry.verdict === 'fail')\n return {\n ...base,\n status: failed ? 'failed' : 'passed',\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: parsed.verdicts,\n }\n }\n parseError = parsed.error\n }\n\n return {\n ...base,\n status: 'errored',\n error: `Judge output could not be parsed after a retry: ${parseError}`,\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n}\n\nfunction unjudgedAssertions(assertions: string[]): AssertionVerdict[] {\n return assertions.map((assertion) => ({ assertion, verdict: 'unjudged' }))\n}\n\nasync function mapWithConcurrency<T, R>(\n items: T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n const worker = async () => {\n while (true) {\n const index = next\n next += 1\n if (index >= items.length) return\n results[index] = await fn(items[index] as T, index)\n }\n }\n const size = Math.max(1, Math.min(limit, items.length))\n await Promise.all(Array.from({ length: size }, () => worker()))\n return results\n}\n\nfunction tally(evals: EvalResult[]): {\n passed: number\n failed: number\n errored: number\n unjudged: number\n} {\n const counts = { passed: 0, failed: 0, errored: 0, unjudged: 0 }\n for (const item of evals) counts[item.status] += 1\n return counts\n}\n\nfunction collectSubjects(args: Record<string, unknown>): string[] {\n const raw: string[] = []\n const first = stringArg(args.subject)\n if (first) raw.push(first)\n const rest = args._\n if (Array.isArray(rest)) {\n for (const value of rest) {\n if (typeof value === 'string' && value.length > 0) raw.push(value)\n }\n }\n return [...new Set(raw)]\n}\n\nfunction resolveSelectedSubjects(requested: string[]): Array<{\n subject: string\n path: string\n}> {\n const available = listSubjectFiles()\n if (requested.length === 0) return available\n const byName = new Map(available.map((entry) => [entry.subject, entry]))\n return requested.map((subject) => {\n const match = byName.get(subject)\n if (!match) {\n const known = available.map((entry) => entry.subject).join(', ')\n throw new SeoError(\n 'INVALID_INPUT',\n `Unknown eval subject: ${subject}.${known ? ` Known subjects: ${known}.` : ''}`,\n )\n }\n return match\n })\n}\n\nfunction renderList(json: boolean): void {\n const subjects = listSubjectFiles().map((entry) => {\n const doc = loadEvalFile(entry.subject, entry.path)\n return { subject: entry.subject, evals: doc.evals.length }\n })\n if (json) {\n printJson({ schemaVersion: SCHEMA_VERSION, subjects })\n return\n }\n if (subjects.length === 0) {\n process.stdout.write('No eval subjects found.\\n')\n return\n }\n const width = Math.max(...subjects.map((entry) => entry.subject.length))\n process.stdout.write('Eval subjects\\n')\n for (const entry of subjects) {\n const label = entry.evals === 1 ? 'eval' : 'evals'\n process.stdout.write(\n ` ${entry.subject.padEnd(width)} ${entry.evals} ${label}\\n`,\n )\n }\n}\n\nfunction statusLabel(status: EvalStatus): string {\n if (status === 'passed') return 'PASS'\n if (status === 'failed') return 'FAIL'\n if (status === 'errored') return 'ERROR'\n return 'UNJUDGED'\n}\n\nfunction renderHuman(\n subjects: SubjectResult[],\n options: { judged: boolean; agent: string; judge: string | null },\n): void {\n if (options.judged) {\n process.stdout.write(\n 'Assertion verdicts below are judge verdicts, model judgments from the judge agent, not ground truth.\\n\\n',\n )\n } else {\n process.stdout.write(\n 'Judging was skipped. Review each agent reply against the assertion checklist by hand.\\n\\n',\n )\n }\n for (const subject of subjects) {\n process.stdout.write(`# ${subject.subject}\\n`)\n for (const item of subject.evals) {\n process.stdout.write(\n `\\n[${statusLabel(item.status)}] eval ${item.id} (${item.durationMs}ms)\\n`,\n )\n process.stdout.write(` prompt: ${truncate(item.prompt, 100)}\\n`)\n if (item.error) {\n process.stdout.write(` error: ${item.error}\\n`)\n }\n if (!options.judged) {\n process.stdout.write(` reply: ${truncate(item.reply, 200)}\\n`)\n process.stdout.write(' assertions to review:\\n')\n for (const verdict of item.assertions) {\n process.stdout.write(` - [ ] ${verdict.assertion}\\n`)\n }\n continue\n }\n for (const verdict of item.assertions) {\n const mark =\n verdict.verdict === 'pass'\n ? 'pass'\n : verdict.verdict === 'fail'\n ? 'fail'\n : 'unjudged'\n process.stdout.write(` - ${mark}: ${verdict.assertion}\\n`)\n if (verdict.reason) {\n process.stdout.write(` judge verdict: ${verdict.reason}\\n`)\n }\n }\n }\n const counts = tally(subject.evals)\n process.stdout.write(\n `\\nSubject ${subject.subject}: ${counts.passed} passed, ${counts.failed} failed, ${counts.errored} errored${counts.unjudged ? `, ${counts.unjudged} unjudged` : ''}.\\n\\n`,\n )\n }\n const totals = totalCounts(subjects)\n process.stdout.write(\n `Totals: ${totals.passed} passed, ${totals.failed} failed, ${totals.errored} errored${totals.unjudged ? `, ${totals.unjudged} unjudged` : ''} across ${totals.evals} evals.\\n`,\n )\n}\n\nfunction totalCounts(subjects: SubjectResult[]): {\n passed: number\n failed: number\n errored: number\n unjudged: number\n evals: number\n} {\n const totals = { passed: 0, failed: 0, errored: 0, unjudged: 0, evals: 0 }\n for (const subject of subjects) {\n totals.passed += subject.passed\n totals.failed += subject.failed\n totals.errored += subject.errored\n totals.unjudged += subject.unjudged\n totals.evals += subject.evals.length\n }\n return totals\n}\n\nfunction truncate(value: string, max: number): string {\n const collapsed = value.replace(/\\s+/g, ' ').trim()\n return collapsed.length > max ? `${collapsed.slice(0, max - 1)}…` : collapsed\n}\n\nexport const skillsEvalCommand = defineCommand({\n meta: {\n name: 'eval',\n description:\n 'Run behaviour evals for the seo skill against a local agent and judge the results',\n },\n args: {\n subject: {\n type: 'positional',\n required: false,\n description:\n 'Eval subject (report id or job). Omit to run every subject.',\n },\n list: {\n type: 'boolean',\n default: false,\n description: 'List eval subjects with their eval counts and exit.',\n },\n id: {\n type: 'string',\n description: 'Run one eval id within a single subject.',\n },\n agent: {\n type: 'string',\n default: DEFAULT_AGENT,\n description:\n 'Agent command. Use {prompt} to place the prompt in argv, otherwise it is sent on stdin.',\n },\n 'judge-agent': {\n type: 'string',\n description: 'Judge command. Defaults to the same command as --agent.',\n },\n judge: defaultTrueBooleanArg(\n 'Judge assertions with an agent.',\n 'Skip judging and print replies with an assertion checklist.',\n ),\n skill: defaultTrueBooleanArg(\n 'Send the seo router skill as context before the prompt.',\n 'Omit the seo router skill context.',\n ),\n timeout: {\n type: 'string',\n default: String(DEFAULT_TIMEOUT_SECONDS),\n description: 'Timeout in seconds per agent or judge call.',\n },\n concurrency: {\n type: 'string',\n default: '1',\n description: `Evals to run in parallel (max ${MAX_CONCURRENCY}).`,\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n\n if (args.list === true) {\n renderList(json)\n return\n }\n\n const requested = collectSubjects(args)\n const selected = resolveSelectedSubjects(requested)\n\n const idFilter = numberArg(args.id)\n if (idFilter !== undefined && selected.length !== 1) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--id needs exactly one subject. Name the subject to filter.',\n )\n }\n\n const timeoutSeconds = numberArg(args.timeout) ?? DEFAULT_TIMEOUT_SECONDS\n if (!(timeoutSeconds > 0)) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--timeout must be a positive number of seconds.',\n )\n }\n const concurrency = Math.max(\n 1,\n Math.min(MAX_CONCURRENCY, numberArg(args.concurrency) ?? 1),\n )\n\n const agent = stringArg(args.agent) ?? DEFAULT_AGENT\n const judgeEnabled = args.judge !== false\n const judge = judgeEnabled\n ? (stringArg(args['judge-agent']) ?? agent)\n : null\n const skillBody = args.skill === false ? null : routerSkillBody()\n\n const runOptions: RunOptions = {\n agent,\n judge,\n skillBody,\n timeoutMs: timeoutSeconds * 1000,\n }\n\n const subjectResults: SubjectResult[] = []\n for (const entry of selected) {\n const doc = loadEvalFile(entry.subject, entry.path)\n let items = doc.evals\n if (idFilter !== undefined) {\n items = items.filter((item) => item.id === idFilter)\n if (items.length === 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `No eval with id ${idFilter} in subject ${entry.subject}.`,\n )\n }\n }\n if (!json) {\n process.stderr.write(\n `Running ${items.length} eval${items.length === 1 ? '' : 's'} for ${entry.subject}...\\n`,\n )\n }\n const evals = await mapWithConcurrency(items, concurrency, (item) =>\n runSingleEval(item, runOptions),\n )\n const counts = tally(evals)\n subjectResults.push({ subject: entry.subject, ...counts, evals })\n }\n\n const totals = totalCounts(subjectResults)\n const failed = totals.failed > 0 || totals.errored > 0\n\n if (json) {\n printJson({\n schemaVersion: SCHEMA_VERSION,\n agent,\n judge,\n judged: judge !== null,\n skillContext: skillBody !== null,\n timeoutSeconds,\n concurrency,\n subjects: subjectResults,\n totals,\n })\n } else {\n renderHuman(subjectResults, { judged: judge !== null, agent, judge })\n }\n\n if (failed) process.exitCode = 1\n },\n})\n","import { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../args.js'\nimport {\n printCallout,\n printHeading,\n printJson,\n printKeyValue,\n} from '../utils.js'\nimport { installSeoSkill } from './skill-install.js'\nimport { readSkillDescription, skillsDirectory } from './skill-paths.js'\nimport { skillsEvalCommand } from './skills-eval.js'\n\ntype SkillInfo = {\n name: string\n description: string\n path: string\n}\n\nfunction listSkills(): SkillInfo[] {\n const root = skillsDirectory()\n return readdirSync(root, { withFileTypes: true })\n .filter(\n (entry) =>\n entry.isDirectory() && existsSync(join(root, entry.name, 'SKILL.md')),\n )\n .map((entry) => ({\n name: entry.name,\n description: readSkillDescription(join(root, entry.name)),\n path: join(root, entry.name),\n }))\n .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))\n}\n\nfunction selectedSkill(name?: string): SkillInfo[] {\n const skills = listSkills()\n if (!name) return skills\n const skill = skills.find((entry) => entry.name === name)\n if (!skill) {\n throw new SeoError('INVALID_INPUT', `Unknown skill: ${name}.`)\n }\n return [skill]\n}\n\nconst listCommand = defineCommand({\n meta: { name: 'list', description: 'Show the packaged SEO skill' },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const skills = listSkills()\n if (jsonFlag(args)) {\n printJson({ skills })\n return\n }\n printHeading('SEO skill', 'Packaged with this CLI.')\n process.stdout.write('\\n')\n for (const skill of skills) {\n printKeyValue([\n ['Name', skill.name],\n [\n 'Purpose',\n 'Helps agents choose and run the right SEO audit or report.',\n ],\n ['Path', skill.path],\n ])\n }\n process.stdout.write('\\n')\n printCallout({\n title: 'Add it to an agent',\n body: 'Run setup to install the skill and connect your first site.',\n command: 'seo start',\n })\n },\n})\n\nconst pathCommand = defineCommand({\n meta: { name: 'path', description: 'Print a packaged agent skill path' },\n args: {\n name: {\n type: 'positional',\n description: 'Skill name. Omit it for the skill directory.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const name = stringArg(args.name)\n const path = name ? selectedSkill(name)[0]?.path : skillsDirectory()\n if (jsonFlag(args)) {\n printJson({ name, path })\n } else {\n process.stdout.write(`${path}\\n`)\n }\n },\n})\n\nconst installCommand = defineCommand({\n meta: {\n name: 'install',\n description: 'Install the SEO skill for coding agents',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const json = jsonFlag(args)\n const result = installSeoSkill({ quiet: json })\n if (json) {\n printJson(result)\n if (result.status === 'failed') process.exitCode = 1\n return\n }\n if (result.status === 'failed') {\n throw new SeoError(\n 'INTERNAL_ERROR',\n `Skill install failed: ${result.error}`,\n )\n }\n process.stdout.write(\n 'SEO skill installed. Agents that support skills can discover it now.\\n',\n )\n },\n})\n\nexport const skillsCommand = defineCommand({\n meta: {\n name: 'skill',\n description: 'Inspect the packaged SEO skill and run its evals',\n },\n subCommands: {\n list: listCommand,\n path: pathCommand,\n install: installCommand,\n eval: skillsEvalCommand,\n },\n})\n","import { cancel, confirm } from '@clack/prompts'\nimport {\n getCacheStats,\n getPrivacySnapshot,\n listSearchUpdates,\n listSites,\n resetSeoData,\n SeoError,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, numberArg, stringArg } from '../args.js'\nimport {\n canPrompt,\n formatBytes,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n printSummaryList,\n printTable,\n} from '../utils.js'\n\nexport const privacyCommand = defineCommand({\n meta: {\n name: 'privacy',\n description: 'Show local config, token, cache, and log storage paths',\n },\n run: async () => {\n const snapshot = getPrivacySnapshot()\n const stats = getCacheStats()\n printKeyValue(\n snapshot.map((item) => [\n item.label,\n `${item.path} · ${formatBytes(item.sizeBytes)} · ${item.mode}`,\n ]),\n )\n process.stdout.write('\\n')\n printKeyValue(\n Object.entries(stats.counts).map(([key, value]) => [key, String(value)]),\n )\n },\n})\n\nexport const resetCommand = defineCommand({\n meta: {\n name: 'reset',\n description: 'Delete saved credentials and all local data',\n },\n args: {\n yes: {\n type: 'boolean',\n default: false,\n description: 'Confirm deletion without prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n if (!args.yes && !canPrompt({ json })) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Cannot prompt here. Pass --yes to confirm reset.',\n )\n }\n const approved = args.yes\n ? true\n : maybeExitCancelled(\n await confirm({\n message: 'Delete saved credentials and all local data?',\n initialValue: false,\n }),\n )\n if (!approved) {\n cancel('Reset aborted.')\n return\n }\n await resetSeoData()\n if (json) {\n printJson({ reset: true })\n } else {\n process.stdout.write('Reset complete.\\n')\n }\n },\n})\n\nexport const sitesCommand = defineCommand({\n meta: {\n name: 'sites',\n description:\n 'List Search Console properties available to this Google login',\n },\n args: {\n json: { type: 'boolean', default: false },\n refresh: { type: 'boolean', default: false },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n },\n run: async ({ args }) => {\n const sites = await listSites(\n booleanArg(args.refresh),\n stringArg(args.account),\n )\n if (jsonFlag(args)) {\n printJson({ sites })\n return\n }\n printTable(\n ['Property', 'Permission'],\n sites.map((site) => [site.siteUrl, site.permissionLevel ?? 'unknown']),\n )\n },\n})\n\nexport const updatesCommand = defineCommand({\n meta: {\n name: 'updates',\n description: 'List official Google Search Status ranking updates',\n },\n args: {\n product: { type: 'string', default: 'Ranking' },\n limit: { type: 'string', default: '10' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const updates = await listSearchUpdates({\n product: stringArg(args.product),\n limit: numberArg(args.limit),\n })\n if (jsonFlag(args)) {\n printJson({ updates })\n return\n }\n printSummaryList(\n updates.map((update) => ({\n title: update.name,\n meta: [\n update.type,\n update.status,\n `${update.start.slice(0, 10)} to ${update.end?.slice(0, 10) ?? 'present'}`,\n ],\n })),\n { empty: 'No matching Google Search updates.' },\n )\n },\n})\n","import {\n getTelemetryStatus,\n setTelemetryEnabled,\n type TelemetryDisableReason,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../args.js'\nimport { printJson, printKeyValue } from '../utils.js'\n\nconst reasonLabels: Record<TelemetryDisableReason, string> = {\n ci: 'disabled automatically in CI or tests',\n do_not_track: 'disabled by DO_NOT_TRACK',\n environment: 'disabled by a telemetry environment variable',\n local_setting: 'disabled in local settings',\n invalid_state: 'disabled because the local state file is invalid',\n}\n\nfunction statusOutput(status: ReturnType<typeof getTelemetryStatus>) {\n return {\n enabled: status.enabled,\n ...(status.reason ? { reason: status.reason } : {}),\n stateFile: status.stateFile,\n ...(status.state\n ? {\n firstRunAt: status.state.firstRunAt,\n cohort: status.state.cohort,\n sentMilestones: status.state.sentMilestones,\n }\n : {}),\n }\n}\n\nfunction printStatus(\n status: ReturnType<typeof getTelemetryStatus>,\n json: boolean,\n): void {\n const output = statusOutput(status)\n if (json) {\n printJson(output)\n return\n }\n printKeyValue([\n ['Anonymous telemetry', status.enabled ? 'enabled' : 'disabled'],\n ['Reason', status.reason ? reasonLabels[status.reason] : 'local setting'],\n ['State file', status.stateFile],\n ['Install cohort', status.state?.cohort ?? 'not created'],\n ])\n process.stdout.write(\n '\\nOnly tool usage is sent. URLs, report data, Google data, and identifiers are never sent.\\n',\n )\n process.stdout.write('Details: https://seoskill.dev/telemetry\\n')\n}\n\nconst jsonArg = {\n type: 'boolean' as const,\n default: false,\n description: 'Print machine-readable JSON.',\n}\n\nexport const telemetryCommand = defineCommand({\n meta: {\n name: 'telemetry',\n description: 'Check or change anonymous usage telemetry',\n },\n subCommands: {\n status: defineCommand({\n meta: {\n name: 'status',\n description: 'Show whether anonymous usage telemetry is enabled',\n },\n args: { json: jsonArg },\n run: async ({ args }) =>\n printStatus(getTelemetryStatus(), jsonFlag(args)),\n }),\n enable: defineCommand({\n meta: {\n name: 'enable',\n description: 'Enable anonymous usage telemetry in local settings',\n },\n args: { json: jsonArg },\n run: async ({ args }) => {\n printStatus(setTelemetryEnabled(true), jsonFlag(args))\n },\n }),\n disable: defineCommand({\n meta: {\n name: 'disable',\n description: 'Disable anonymous usage telemetry in local settings',\n },\n args: { json: jsonArg },\n run: async ({ args }) => {\n printStatus(setTelemetryEnabled(false), jsonFlag(args))\n },\n }),\n },\n})\n","import { readFile } from 'node:fs/promises'\nimport {\n analyticsConnection,\n crawlImplementationQueueWorkflow,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n fetchRateArg,\n jsonFlag,\n negatedBooleanArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from '../analytics/connection.js'\nimport { printActionDetails } from '../output.js'\nimport { startUrlForSite } from '../shared.js'\nimport { printWorkflow } from './output.js'\n\nexport const crawlQueueCommand = defineCommand({\n meta: {\n name: 'crawl-queue',\n description: 'Run a crawl and return a ranked implementation queue',\n },\n args: {\n crawlUrl: {\n type: 'positional',\n required: false,\n description: 'Start URL to crawl.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Optional when --project has a saved crawl URL.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL for joining page metrics.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...analyticsConnectionArgs,\n mode: {\n type: 'string',\n description:\n 'Crawl mode: site, page, list, or sitemap. Defaults to site.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs for list mode.',\n },\n 'urls-file': {\n type: 'string',\n description: 'File with one URL per line for list mode.',\n },\n 'max-pages': {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 500.',\n },\n 'max-depth': {\n type: 'string',\n description: 'Maximum click depth. Defaults to 16.',\n },\n concurrency: {\n type: 'string',\n description: 'Parallel page fetches. Defaults to 8.',\n },\n 'fetch-interval-cap': {\n type: 'string',\n description: 'Maximum page fetches per interval per host.',\n },\n 'fetch-interval-ms': {\n type: 'string',\n description: 'Fetch rate interval in milliseconds.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache and fetch fresh pages.',\n },\n include: {\n type: 'string',\n description: 'Comma-separated URL patterns to include.',\n },\n exclude: {\n type: 'string',\n description: 'Comma-separated URL patterns to exclude.',\n },\n limit: {\n type: 'string',\n description: 'Maximum queue items to print. Defaults to 25.',\n },\n 'no-sitemap': {\n type: 'boolean',\n default: false,\n description: 'Do not seed URLs from sitemap.xml.',\n },\n 'no-robots': {\n type: 'boolean',\n default: false,\n description: 'Do not skip URLs disallowed by robots.txt.',\n },\n 'no-external': {\n type: 'boolean',\n default: false,\n description: 'Do not check external links.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = projectArg(args)\n const urls = await urlListArgs(args)\n const explicitUrl = crawlUrlArg(args)\n const selection =\n stringArg(args.site) || project || (!explicitUrl && !urls.length)\n ? await resolveClientSelection({\n client: project,\n site: stringArg(args.site),\n options: { json },\n })\n : undefined\n const crawlUrl =\n explicitUrl ??\n selection?.client?.startUrl ??\n (selection?.site ? startUrlForSite(selection.site) : undefined) ??\n urls[0]\n if (!crawlUrl) {\n throw new Error(\n 'No crawl URL selected. Pass a URL, --url, or use --project with a saved crawl URL.',\n )\n }\n\n const report = await crawlImplementationQueueWorkflow({\n url: crawlUrl,\n projectId: selection?.client?.id,\n site: selection?.site,\n mode: crawlModeArg(args.mode) ?? (urls.length ? 'list' : undefined),\n urls,\n maxPages: numberArg(args['max-pages']),\n maxDepth: numberArg(args['max-depth']),\n concurrency: numberArg(args.concurrency),\n refresh: booleanArg(args.refresh),\n fetchRate: fetchRateArg({\n ...args,\n 'fetch-concurrency': args.concurrency,\n }),\n include: csvArg(args.include),\n exclude: csvArg(args.exclude),\n googleAnalyticsPropertyId: stringArg(args['google-analytics-property']),\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection?.client),\n ),\n useSitemap: !negatedBooleanArg(args, 'sitemap'),\n respectRobots: !negatedBooleanArg(args, 'robots'),\n checkExternal: !negatedBooleanArg(args, 'external'),\n js: Boolean(booleanArg(args.js)),\n limit: numberArg(args.limit),\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printWorkflow(report)\n printTable(\n ['Rank', 'Score', 'Rule', 'Severity', 'Affected', 'Target', 'Action'],\n report.output.queue.map((item, index) => [\n index + 1,\n item.score,\n item.ruleId,\n item.severity,\n item.affectedUrls,\n item.target,\n item.action,\n ]),\n )\n printActionDetails(\n 'Implementation queue details',\n report.output.queue.map((item) => ({\n label: `${item.ruleId} (${item.affectedUrls} URLs)`,\n context: `${item.severity}, score ${item.score}`,\n action: `${item.action} Verify with: ${item.verification.command}`,\n })),\n )\n },\n})\n\nfunction crawlModeArg(value: unknown) {\n const mode = stringArg(value)\n if (!mode) return undefined\n if (['site', 'page', 'list', 'sitemap'].includes(mode)) {\n return mode as 'site' | 'page' | 'list' | 'sitemap'\n }\n throw new Error('Mode must be one of: site, page, list, sitemap.')\n}\n\nfunction crawlUrlArg(args: Record<string, unknown>): string | undefined {\n const positional = stringArg(args.crawlUrl)\n const flag = stringArg(args.url)\n if (positional && flag && positional !== flag) {\n throw new Error('Use either a URL argument or --url, not both.')\n }\n return positional ?? flag\n}\n\nasync function urlListArgs(args: Record<string, unknown>): Promise<string[]> {\n const urls = csvArg(args.urls) ?? []\n const file = stringArg(args['urls-file'])\n if (file) urls.push(...parseUrlList(await readFile(file, 'utf8')))\n return [...new Set(urls)]\n}\n\nfunction parseUrlList(value: string): string[] {\n return value\n .split(/[\\n,]/)\n .map((item) => item.trim())\n .filter((item) => item && !item.startsWith('#'))\n}\n","import { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname, resolve } from 'node:path'\nimport {\n type ReportHtmlSection,\n type ReportHtmlView,\n type ReportNarrative,\n renderReportHtml,\n SeoError,\n} from '@seo/core'\nimport { booleanArg, stringArg } from '../args.js'\n\nexport const reportHtmlArgs = {\n format: {\n type: 'string',\n description: 'Output format: terminal or html. Defaults to terminal.',\n },\n output: {\n type: 'string',\n description: 'HTML output file. A dated filename is used by default.',\n },\n view: {\n type: 'string',\n description: 'HTML detail level: client or analyst. Defaults to client.',\n },\n} as const\n\nexport type ReportHtmlOptions = {\n output?: string\n view: ReportHtmlView\n}\n\nexport function reportHtmlOptions(\n args: Record<string, unknown>,\n): ReportHtmlOptions | undefined {\n const format = stringArg(args.format) ?? 'terminal'\n if (format !== 'terminal' && format !== 'html') {\n throw new SeoError('INVALID_INPUT', 'Choose terminal or html for --format.')\n }\n if (format === 'terminal') {\n if (stringArg(args.output) || stringArg(args.view)) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --output and --view with --format html.',\n )\n }\n return undefined\n }\n if (booleanArg(args.json)) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --json or --format html, not both.',\n )\n }\n\n const view = stringArg(args.view) ?? 'client'\n if (view !== 'client' && view !== 'analyst') {\n throw new SeoError('INVALID_INPUT', 'Choose client or analyst for --view.')\n }\n return { output: stringArg(args.output), view }\n}\n\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/^sc-domain:/, '')\n .replace(/^https?:\\/\\//, '')\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80)\n}\n\nexport function defaultReportHtmlPath(input: {\n reportName: string\n projectId?: string\n site: string\n date?: Date\n}): string {\n const day = (input.date ?? new Date()).toISOString().slice(0, 10)\n const identity = slug(input.projectId ?? input.site) || 'site'\n return resolve(\n process.cwd(),\n `${identity}-${slug(input.reportName)}-${day}.html`,\n )\n}\n\nexport async function writeReportHtml(input: {\n report: ReportNarrative\n reportName: string\n title: string\n options: ReportHtmlOptions\n projectId?: string\n additionalSections?: ReportHtmlSection[]\n}): Promise<string> {\n const path = resolve(\n input.options.output ??\n defaultReportHtmlPath({\n reportName: input.reportName,\n projectId: input.projectId,\n site: input.report.site,\n }),\n )\n await mkdir(dirname(path), { recursive: true })\n await writeFile(\n path,\n renderReportHtml({\n report: input.report,\n title: input.title,\n view: input.options.view,\n additionalSections: input.additionalSections,\n }),\n 'utf8',\n )\n return path\n}\n\nexport function printReportHtmlPath(path: string): void {\n process.stdout.write(`Wrote HTML report to ${path}\\n`)\n}\n","import { type diagnosePropertyWorkflow, SeoError } from '@seo/core'\n\nexport type DiagnoseWorkflowReport = Awaited<\n ReturnType<typeof diagnosePropertyWorkflow>\n>\n\nexport function compactMainReportJson(\n report: DiagnoseWorkflowReport,\n workflowName?: string,\n) {\n const { narrative } = report.output\n const { diagnosis } = narrative\n\n return {\n ...report,\n ...(workflowName ? { workflow: workflowName } : {}),\n output: {\n narrative: {\n site: narrative.site,\n generatedAt: narrative.generatedAt,\n dataStatus: narrative.dataStatus,\n periodDays: narrative.periodDays,\n period: narrative.period,\n headline: narrative.headline,\n caveats: narrative.caveats,\n sections: narrative.sections,\n priorities: narrative.priorities,\n diagnosis: {\n site: diagnosis.site,\n generatedAt: diagnosis.generatedAt,\n dataStatus: diagnosis.dataStatus,\n summary: diagnosis.summary,\n skippedSections: diagnosis.skippedSections,\n partialReasons: diagnosis.partialReasons,\n priorities: diagnosis.priorities,\n },\n },\n },\n }\n}\n\nexport function shellArg(value: string): string {\n if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {\n return value\n }\n return `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n}\n\nexport function siteForDirectUrl(url: string): string {\n try {\n return new URL(url).origin\n } catch {\n throw new SeoError('INVALID_INPUT', 'Pass a valid absolute URL with --url.')\n }\n}\n","import type {\n SearchConsoleExportEvidence,\n SearchConsoleExportReconciliation,\n} from '@seo/core'\nimport { printTable } from '../../utils.js'\nimport { truncate } from '../output.js'\nimport type { ExportPageInventory } from './url-report-evidence.js'\n\nexport function searchConsoleExportSection(input: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n pageInventory?: ExportPageInventory\n topRows?: number\n}) {\n const topRows = input.topRows ?? 20\n const { evidence } = input\n return {\n source: evidence.source,\n exportedAt: evidence.exportedAt,\n importedAt: evidence.importedAt,\n files: evidence.files,\n queries: {\n totalRows: evidence.queries.totalRows,\n capped: evidence.queries.capped,\n topRowsShown: Math.min(topRows, evidence.queries.rows.length),\n rows: evidence.queries.rows.slice(0, topRows),\n },\n pages: {\n totalRows: evidence.pages.totalRows,\n capped: evidence.pages.capped,\n topRowsShown: Math.min(topRows, evidence.pages.rows.length),\n rows: evidence.pages.rows.slice(0, topRows),\n },\n ...(input.reconciliation ? { reconciliation: input.reconciliation } : {}),\n ...(input.pageInventory ? { pageInventory: input.pageInventory } : {}),\n warnings: evidence.warnings,\n caveats: evidence.caveats,\n }\n}\n\n/** Terminal table for the export page inventory, capped at 15 printed rows. */\nexport function printExportPageInventory(inventory: ExportPageInventory): void {\n if (!inventory.rows.length) return\n const shown = inventory.rows.slice(0, 15)\n process.stdout.write(\n `\\nContent inventory${inventory.pageCount > 1 ? ` page ${inventory.page} of ${inventory.pageCount}` : ''} (${inventory.rows.length} exported page${inventory.rows.length === 1 ? '' : 's'} with suggested dispositions)\\n`,\n )\n printTable(\n ['Path', 'Clicks', 'Impressions', 'Position', 'Suggested'],\n shown.map((row) => [\n truncate(row.path, 48),\n row.clicks,\n row.impressions,\n row.position ?? '-',\n row.suggestedDisposition,\n ]),\n )\n if (inventory.rows.length > shown.length) {\n process.stdout.write(\n `Showing ${shown.length} of ${inventory.rows.length} tiered rows.\\n`,\n )\n }\n if (inventory.pageCount > 1) {\n process.stdout.write(\n `Showing inventory page ${inventory.page} of ${inventory.pageCount}; ${inventory.totalPages} retained rows are available.\\n`,\n )\n }\n process.stdout.write(`${inventory.note}\\n`)\n}\n\nexport function exportSummarySentence(input: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n}): string {\n const queries = input.evidence.queries.totalRows\n const pages = input.evidence.pages.totalRows\n const base = `Loaded a local Search Console export (${queries} query row${queries === 1 ? '' : 's'}, ${pages} page row${pages === 1 ? '' : 's'}).`\n if (!input.reconciliation) return base\n const unreached = input.reconciliation.unreachedCount\n if (unreached === 0) {\n return `${base} Every exported page URL was reached by the crawl.`\n }\n return `${base} ${unreached} exported page URL${unreached === 1 ? '' : 's'} with impressions were not reached by this crawl.`\n}\n\nexport function issueCountSummarySentence(summary: {\n highIssues: number\n mediumIssues: number\n lowIssues: number\n crawledUrls: number\n}): string {\n const pages = summary.crawledUrls\n return `Found ${summary.highIssues} high, ${summary.mediumIssues} medium, and ${summary.lowIssues} low technical issues across ${pages} crawled ${pages === 1 ? 'page' : 'pages'}.`\n}\n","import {\n type CrawlReport,\n reviewObservations,\n type SearchConsoleExportPageRow,\n type SearchConsoleExportQueryRow,\n type SearchConsoleExportReconciliation,\n SeoError,\n type TopFix,\n topFixes,\n} from '@seo/core'\n\nexport {\n exportSummarySentence,\n issueCountSummarySentence,\n printExportPageInventory,\n searchConsoleExportSection,\n} from './url-report-output.js'\n\nexport type UrlReportAction = {\n id: string\n kind: 'fix' | 'review'\n title: string\n action: string\n confidence: 'high' | 'medium' | 'low'\n severity?: string\n affectedCount?: number\n sampleUrls?: string[]\n affectedUrlsReport?: {\n id: 'affected-urls'\n params: {\n reportId: string\n ruleId: string\n }\n }\n evidence?: Record<string, unknown>\n review?: {\n question: string\n changeOnlyIf: string\n ifConfirmed?: string\n ifNotNeeded: string\n doNot?: string[]\n }\n verification?: {\n command?: string\n expected: string\n }\n}\n\nexport type TopicOverlapCandidate = {\n query: string\n impressions: number\n clicks: number\n pages: Array<{ url: string; title: string }>\n}\n\nexport type TopicOverlapResult = {\n candidates: TopicOverlapCandidate[]\n eligibleQueries: number\n consideredQueries: number\n queryLimitReached: boolean\n candidateLimitReached: boolean\n capped: boolean\n}\n\nexport function completeTopFixes(report: CrawlReport) {\n return topFixes(report, { limit: report.issues.length })\n}\n\nexport function completeReviewObservations(report: CrawlReport) {\n return reviewObservations(report, { limit: report.issues.length })\n}\n\nexport function crawlDataSourceLines(\n dataSources: CrawlReport['dataSources'],\n): string[] {\n if (!dataSources) return []\n\n const sourceLine = (input: {\n label: string\n status: string\n joinedPages: number\n totalPages: number\n window?: { days: number }\n warning?: string\n }): string => {\n const range = input.window ? ` in the last ${input.window.days} days` : ''\n const coverage = `for ${input.joinedPages} of ${input.totalPages} crawled URLs`\n\n if (input.status === 'skipped') return `${input.label}: not connected.`\n if (input.status === 'unavailable') {\n return `${input.label}: unavailable. ${input.warning ?? 'No data was joined.'}`\n }\n if (input.status === 'partial') {\n return `${input.label}: partial data ${coverage}${range}. ${input.warning ?? ''}`.trim()\n }\n if (input.status === 'none') {\n return `${input.label}: no matching crawled URLs${range}.`\n }\n return `${input.label}: joined ${coverage}${range}.`\n }\n\n return [\n sourceLine({\n label: 'Search Console',\n status: dataSources.searchConsole.status,\n joinedPages: Math.max(\n dataSources.searchConsole.joinedMetricPages,\n dataSources.searchConsole.joinedQueryPages,\n ),\n totalPages: dataSources.searchConsole.totalPages,\n window: dataSources.searchConsole.window,\n warning: dataSources.searchConsole.warning,\n }),\n sourceLine({\n label: 'Google Analytics',\n status: dataSources.analytics.status,\n joinedPages: dataSources.analytics.joinedPages,\n totalPages: dataSources.analytics.totalPages,\n window: dataSources.analytics.window,\n warning: dataSources.analytics.warning,\n }),\n ]\n}\n\n// Strict codepoint order (not UTF-16 code-unit order) so tie-breaking is\n// stable regardless of which plane a character lives in.\nfunction codePointCompare(left: string, right: string): number {\n if (left === right) return 0\n const a = [...left]\n const b = [...right]\n const shared = Math.min(a.length, b.length)\n for (let index = 0; index < shared; index += 1) {\n const diff =\n (a[index]?.codePointAt(0) ?? 0) - (b[index]?.codePointAt(0) ?? 0)\n if (diff !== 0) return diff\n }\n return a.length - b.length\n}\n\nfunction normalizeText(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .trim()\n}\n\n// Distinct-page identity: same origin, path (without a trailing slash), and\n// query string. /guide and /guide/ are one page for overlap counting.\nfunction pageIdentityKey(url: string): string {\n try {\n const parsed = new URL(url)\n const path =\n parsed.pathname.length > 1 && parsed.pathname.endsWith('/')\n ? parsed.pathname.slice(0, -1)\n : parsed.pathname\n return `${parsed.origin}${path}${parsed.search}`\n } catch {\n return url.length > 1 && url.endsWith('/') ? url.slice(0, -1) : url\n }\n}\n\n/**\n * Title evidence for export joins: the main crawl's final URLs plus any\n * bounded unreached-audit fetches from the same run.\n */\nexport function titleEvidencePages(\n crawledPages: Array<{\n url: string\n finalUrl?: string | null\n title?: string | null\n }>,\n auditedPages: Array<{ url: string; title: string | null }> = [],\n): Array<{ url: string; title: string | null | undefined }> {\n return [\n ...crawledPages.map((page) => ({\n url: page.finalUrl || page.url,\n title: page.title,\n })),\n ...auditedPages,\n ]\n}\n\n/** Display path for a page URL, used in action copy and terminal tables. */\nexport function pageDisplayPath(url: string): string {\n try {\n const parsed = new URL(url)\n return `${parsed.pathname}${parsed.search}` || '/'\n } catch {\n return url\n }\n}\n\n// Mirrors the path normalization in @seo/core's reconcileExportPagesWithCrawl\n// (strip one trailing slash except at the root, keep the query string) so the\n// inventory joins agree exactly with the reconciliation's path join basis.\nfunction normalizedJoinPath(value: string): string | null {\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n return null\n }\n const pathname =\n parsed.pathname !== '/' && parsed.pathname.endsWith('/')\n ? parsed.pathname.slice(0, -1)\n : parsed.pathname\n return `${pathname}${parsed.search}`\n}\n\nexport type ExportPageInventoryRow = {\n url: string\n path: string\n clicks: number\n impressions: number\n position: number | null\n reachedByCrawl: boolean | null\n title: string | null\n overlapQuery: string | null\n suggestedDisposition: 'keep' | 'update' | 'review'\n tier: string\n}\n\nexport type ExportPageInventory = {\n rows: ExportPageInventoryRow[]\n totalPages: number\n capped: boolean\n sourceCapped: boolean\n page: number\n pageSize: number\n pageCount: number\n nextPage: number | null\n criteria: string[]\n note: string\n}\n\n// Average positions past this value sit outside the usual two result pages.\n// It is an arbitrary review threshold, not a search engine rule.\nconst WEAK_POSITION_THRESHOLD = 20\n\n// The ordered tier rules; the first matching rule wins. Kept as data so every\n// inventory result carries its own methodology.\nconst EXPORT_PAGE_INVENTORY_CRITERIA: readonly string[] = [\n 'review: shares a search phrase with another page title; confirm query-to-page evidence and intent before consolidating',\n 'keep: has clicks in the export window',\n 'review: has impressions but no crawl path reached it',\n `update: has impressions with a weak average position (average position above ${WEAK_POSITION_THRESHOLD} in the export)`,\n 'review: low observed demand in the export window',\n]\n\nexport const EXPORT_PAGE_INVENTORY_NOTE =\n 'Suggested dispositions are heuristic tiers from the export numbers and crawl reach. Decide each page with the owner.'\n\n/**\n * Per-page inventory of the exported page table with a suggested disposition\n * tier for each page. The tiers are heuristics over the export numbers and\n * crawl reach only; the export is a dated snapshot, missing rows are not\n * zeros, and the owner decides intent page by page.\n */\nexport function exportPageInventory(input: {\n pages: SearchConsoleExportPageRow[]\n reconciliation?: SearchConsoleExportReconciliation\n crawledPages: Array<{ url: string; title: string | null | undefined }>\n overlap?: TopicOverlapResult\n maxRows?: number\n page?: number\n sourceCapped?: boolean\n}): ExportPageInventory {\n const maxRows = input.maxRows ?? 50\n const page = input.page ?? 1\n if (!Number.isSafeInteger(maxRows) || maxRows < 1) {\n throw new SeoError('INVALID_INPUT', 'Inventory page size must be positive.')\n }\n if (!Number.isSafeInteger(page) || page < 1) {\n throw new SeoError('INVALID_INPUT', 'Inventory page must be positive.')\n }\n\n // Without a reconciliation there is no unreached evidence, so the\n // unreached rule cannot fire and no reach claim is made from thin air.\n const unreachedPaths = new Set<string>()\n for (const row of input.reconciliation?.unreachedPages ?? []) {\n const path = normalizedJoinPath(row.url)\n if (path !== null) unreachedPaths.add(path)\n }\n\n // Titles join by the same path basis as the reconciliation. Codepoint order\n // plus first-title-wins keeps identical input yielding identical output.\n const titlesByPath = new Map<string, string>()\n const sortedCrawled = [...input.crawledPages].sort((left, right) =>\n codePointCompare(left.url, right.url),\n )\n for (const page of sortedCrawled) {\n if (typeof page.title !== 'string') continue\n const path = normalizedJoinPath(page.url)\n if (path === null) continue\n if (!titlesByPath.has(path)) titlesByPath.set(path, page.title)\n }\n\n // Overlap candidates arrive ranked by impressions, clicks, then query, so\n // the first candidate naming a path wins deterministically.\n const overlapQueryByPath = new Map<string, string>()\n for (const candidate of input.overlap?.candidates ?? []) {\n for (const page of candidate.pages) {\n const path = normalizedJoinPath(page.url)\n if (path === null) continue\n if (!overlapQueryByPath.has(path)) {\n overlapQueryByPath.set(path, candidate.query)\n }\n }\n }\n\n const sortedPages = [...input.pages].sort(\n (left, right) =>\n right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n codePointCompare(left.url, right.url),\n )\n const pageCount = Math.ceil(sortedPages.length / maxRows)\n if (pageCount > 0 && page > pageCount) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Inventory page ${page} does not exist; choose a page from 1 to ${pageCount}.`,\n )\n }\n const pageStart = (page - 1) * maxRows\n const rows = sortedPages\n .slice(pageStart, pageStart + maxRows)\n .map((page): ExportPageInventoryRow => {\n const joinPath = normalizedJoinPath(page.url)\n const reachedByCrawl =\n joinPath === null || !input.reconciliation\n ? null\n : unreachedPaths.has(joinPath)\n ? false\n : input.reconciliation.capped\n ? null\n : true\n const title =\n joinPath !== null ? (titlesByPath.get(joinPath) ?? null) : null\n const overlapQuery =\n joinPath !== null ? (overlapQueryByPath.get(joinPath) ?? null) : null\n let suggestedDisposition: ExportPageInventoryRow['suggestedDisposition']\n let tier: string\n if (overlapQuery !== null) {\n suggestedDisposition = 'review'\n tier =\n 'shares a search phrase with another page title and needs query-to-page and intent verification'\n } else if (page.clicks > 0) {\n suggestedDisposition = 'keep'\n tier = 'has clicks in the export window'\n } else if (page.impressions > 0 && reachedByCrawl === false) {\n suggestedDisposition = 'review'\n tier = 'has impressions but no crawl path reached it'\n } else if (\n page.impressions > 0 &&\n page.position !== null &&\n page.position > WEAK_POSITION_THRESHOLD\n ) {\n suggestedDisposition = 'update'\n tier = 'has impressions with a weak average position'\n } else {\n suggestedDisposition = 'review'\n tier = 'low observed demand in the export window'\n }\n return {\n url: page.url,\n path: pageDisplayPath(page.url),\n clicks: page.clicks,\n impressions: page.impressions,\n position: page.position,\n reachedByCrawl,\n title,\n overlapQuery,\n suggestedDisposition,\n tier,\n }\n })\n\n const paged = pageCount > 1\n const notes = [EXPORT_PAGE_INVENTORY_NOTE]\n if (paged) {\n notes.push(\n `This is inventory page ${page} of ${pageCount}. Fetch every page before treating the returned inventory as complete.`,\n )\n }\n if (input.sourceCapped === true) {\n notes.push(\n 'The source import was capped, so rows missing from this inventory are unknown.',\n )\n }\n return {\n rows,\n totalPages: input.pages.length,\n capped: input.sourceCapped === true || paged,\n sourceCapped: input.sourceCapped === true,\n page,\n pageSize: maxRows,\n pageCount,\n nextPage: page < pageCount ? page + 1 : null,\n criteria: [...EXPORT_PAGE_INVENTORY_CRITERIA],\n note: notes.join(' '),\n }\n}\n\n/**\n * Title-based topic-overlap heuristic for local exports. The standard Search\n * Console UI export keeps query and page tables separate, so no query-to-page\n * mapping exists. This function only observes that an exported query phrase\n * appears in the titles of two or more distinct crawled pages. That is a\n * candidate for review, never a cannibalisation verdict.\n */\nexport function topicOverlapCandidates(input: {\n queries: SearchConsoleExportQueryRow[]\n pages: Array<{ url: string; title: string | null | undefined }>\n maxQueries?: number\n maxCandidates?: number\n}): TopicOverlapResult {\n const maxQueries = input.maxQueries ?? 50\n const maxCandidates = input.maxCandidates ?? 10\n\n // Aggregate duplicate query rows deterministically before ranking.\n // Single-word queries are skipped because they over-match titles.\n const totalsByQuery = new Map<\n string,\n { impressions: number; clicks: number }\n >()\n for (const row of input.queries) {\n const query = normalizeText(row.query)\n if (query.split(' ').length < 2) continue\n const totals = totalsByQuery.get(query)\n if (totals) {\n totals.impressions += row.impressions\n totals.clicks += row.clicks\n } else {\n totalsByQuery.set(query, {\n impressions: row.impressions,\n clicks: row.clicks,\n })\n }\n }\n const eligibleQueries = totalsByQuery.size\n const considered = [...totalsByQuery.entries()]\n .map(([query, totals]) => ({ query, ...totals }))\n .sort(\n (left, right) =>\n right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n codePointCompare(left.query, right.query),\n )\n .slice(0, maxQueries)\n\n // One entry per distinct page path; the codepoint-smallest URL represents\n // a path so identical input always yields identical output.\n const pagesByKey = new Map<\n string,\n { url: string; title: string; normalizedTitle: string }\n >()\n const sortedPages = [...input.pages].sort((left, right) =>\n codePointCompare(left.url, right.url),\n )\n for (const page of sortedPages) {\n if (typeof page.title !== 'string') continue\n const normalizedTitle = normalizeText(page.title)\n if (!normalizedTitle) continue\n const key = pageIdentityKey(page.url)\n if (!pagesByKey.has(key)) {\n pagesByKey.set(key, { url: page.url, title: page.title, normalizedTitle })\n }\n }\n const pagePool = [...pagesByKey.values()]\n\n const candidates: TopicOverlapCandidate[] = []\n for (const item of considered) {\n const phrase = ` ${item.query} `\n const matches = pagePool.filter((page) =>\n ` ${page.normalizedTitle} `.includes(phrase),\n )\n if (matches.length < 2) continue\n candidates.push({\n query: item.query,\n impressions: item.impressions,\n clicks: item.clicks,\n pages: matches\n .map((page) => ({ url: page.url, title: page.title }))\n .sort((left, right) => codePointCompare(left.url, right.url)),\n })\n }\n candidates.sort(\n (left, right) =>\n right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n codePointCompare(left.query, right.query),\n )\n const queryLimitReached = eligibleQueries > considered.length\n const candidateLimitReached = candidates.length > maxCandidates\n return {\n candidates: candidates.slice(0, maxCandidates),\n eligibleQueries,\n consideredQueries: considered.length,\n queryLimitReached,\n candidateLimitReached,\n capped: queryLimitReached || candidateLimitReached,\n }\n}\n\nconst SEVERITY_ORDER = { high: 0, medium: 1, low: 2 } as const\n\ntype PrefixedFix = {\n fix: TopFix\n prefix: string\n source: 'crawl' | 'unreached'\n}\n\n// One queue, best first: a medium issue affecting twelve pages outranks a\n// low issue on one page regardless of which crawl pass surfaced it.\nfunction byPriority(left: PrefixedFix, right: PrefixedFix): number {\n const severity =\n SEVERITY_ORDER[left.fix.severity as keyof typeof SEVERITY_ORDER] -\n SEVERITY_ORDER[right.fix.severity as keyof typeof SEVERITY_ORDER]\n if (severity !== 0) return severity\n if (right.fix.count !== left.fix.count)\n return right.fix.count - left.fix.count\n if (right.fix.score !== left.fix.score)\n return right.fix.score - left.fix.score\n return left.fix.ruleId < right.fix.ruleId\n ? -1\n : left.fix.ruleId > right.fix.ruleId\n ? 1\n : 0\n}\n\n/**\n * Turn the complete crawl issue inventory into workflow actions so the main\n * report does not return an empty or incomplete action list while the crawl\n * holds findings. Fixes carry high confidence because the state was observed;\n * review observations stay medium because intent is unconfirmed.\n */\nexport function technicalCrawlActions(input: {\n topFixes: TopFix[]\n reviewObservations: TopFix[]\n crawlReportId?: string\n reconciliation?: SearchConsoleExportReconciliation\n unreachedAudit?: {\n reportId?: string\n topFixes: TopFix[]\n reviewObservations: TopFix[]\n titlePrefix: string\n }\n topicOverlap?: TopicOverlapResult\n pageInventory?: ExportPageInventory\n}): UrlReportAction[] {\n const audit = input.unreachedAudit\n const fixes: PrefixedFix[] = [\n ...input.topFixes.map((fix) => ({\n fix,\n prefix: '',\n source: 'crawl' as const,\n })),\n ...(audit?.topFixes ?? []).map((fix) => ({\n fix,\n prefix: `${audit?.titlePrefix} `,\n source: 'unreached' as const,\n })),\n ].sort(byPriority)\n const reviews: PrefixedFix[] = [\n ...input.reviewObservations.map((fix) => ({\n fix,\n prefix: '',\n source: 'crawl' as const,\n })),\n ...(audit?.reviewObservations ?? []).map((fix) => ({\n fix,\n prefix: `${audit?.titlePrefix} `,\n source: 'unreached' as const,\n })),\n ].sort(byPriority)\n const actions: UrlReportAction[] = []\n for (const { fix, prefix, source } of fixes) {\n const reportId =\n source === 'crawl' ? input.crawlReportId : input.unreachedAudit?.reportId\n actions.push({\n id: `${source}:${fix.ruleId}`,\n kind: 'fix',\n title: `${prefix}${fix.ruleId}: ${fix.title} (${fix.count} URL${fix.count === 1 ? '' : 's'})`,\n action: fix.howToFix,\n confidence: 'high',\n severity: fix.severity,\n affectedCount: fix.count,\n sampleUrls: fix.sampleUrls,\n ...(reportId\n ? {\n affectedUrlsReport: {\n id: 'affected-urls' as const,\n params: { reportId, ruleId: fix.ruleId },\n },\n }\n : {}),\n evidence: {\n ruleId: fix.ruleId,\n source,\n whyThisRanks: fix.whyThisRanks,\n },\n verification: fix.verification,\n })\n }\n // Export-demand findings rank directly after the fix queue: they carry\n // observed impressions, which outrank convention observations that have\n // no demand link.\n const unreached = input.reconciliation\n if (unreached && unreached.unreachedCount > 0) {\n const impressions = unreached.unreachedPages.reduce(\n (sum, row) => sum + row.impressions,\n 0,\n )\n actions.push({\n id: 'export:unreached-pages',\n kind: 'review',\n title: `${unreached.unreachedCount} exported page URL${unreached.unreachedCount === 1 ? '' : 's'} with search impressions were not reached by this crawl`,\n action: `These pages carry ${impressions} combined impressions across the ${unreached.unreachedPages.length} retained export rows, but no crawl path reached them. Add internal links or sitemap entries when they should be reachable. The join used URL paths from a local export; treat it as a discovery lead within this crawl bound, not proof of orphan status.`,\n confidence: 'medium',\n affectedCount: unreached.unreachedCount,\n evidence: {\n retainedRows: unreached.unreachedPages.length,\n impressions,\n },\n review: {\n question:\n 'Should each retained exported page be reachable from the current site?',\n changeOnlyIf:\n 'Add a crawl path only for a page that should remain part of the current site and has no intended exclusion.',\n ifNotNeeded:\n 'Record no change for a page that is intentionally retired, excluded, or awaiting an owner decision.',\n doNot: [\n 'Do not call a page orphaned from this path-only join.',\n 'Do not redirect unrelated pages to one generic destination.',\n ],\n },\n verification: {\n expected:\n 'Every retained exported page is reachable in the rerun or explicitly accounted for as deferred or no-change with owner intent.',\n },\n })\n }\n const overlap = input.topicOverlap\n const top = overlap?.candidates[0]\n if (overlap && top) {\n const count = overlap.candidates.length\n const paths = top.pages.map((page) => pageDisplayPath(page.url))\n actions.push({\n id: 'export:topic-overlap',\n kind: 'review',\n title: `topic overlap candidates: ${count} exported ${count === 1 ? 'query appears' : 'queries appear'} in 2+ page titles`,\n action: `Top candidate: \"${top.query}\" (${top.impressions} impressions, ${top.clicks} clicks) appears in the titles of ${paths.join(' and ')}. This is a title-based heuristic built from the export's separate query and page tables. The export contains no query-to-page mapping, so it cannot show which pages Google served for the query. Verify with the cannibalisation report (seo cannibal) after connecting a Search Console property.`,\n confidence: 'medium',\n affectedCount: count,\n evidence: {\n topQuery: top.query,\n topPages: top.pages,\n impressions: top.impressions,\n clicks: top.clicks,\n },\n review: {\n question:\n 'Does query-to-page evidence confirm that these pages compete for the same search intent?',\n changeOnlyIf:\n 'Consolidate or redirect only after query-to-page evidence and page intent confirm real overlap.',\n ifNotNeeded:\n 'Keep the pages separate and record why their intents differ.',\n doNot: [\n 'Do not merge or redirect pages from a title-match heuristic alone.',\n ],\n },\n verification: {\n expected:\n 'Confirm intent with query-to-page evidence before consolidating or redirecting either page.',\n },\n })\n }\n const inventory = input.pageInventory\n const topRow = inventory?.rows[0]\n if (inventory && topRow) {\n const counts = { keep: 0, update: 0, review: 0 }\n for (const row of inventory.rows) counts[row.suggestedDisposition] += 1\n const scope = [\n ...(inventory.pageCount > 1\n ? [\n `page ${inventory.page} of ${inventory.pageCount}; ${inventory.rows.length} of ${inventory.totalPages} retained rows`,\n ]\n : []),\n ...(inventory.sourceCapped ? ['source import capped'] : []),\n ]\n const scopeText = scope.length ? ` (${scope.join('; ')})` : ''\n actions.push({\n id: 'export:content-inventory',\n kind: 'review',\n title: `content inventory: ${inventory.rows.length} exported page${inventory.rows.length === 1 ? '' : 's'} tiered with suggested dispositions`,\n action: `Suggested tiers: keep ${counts.keep}, update ${counts.update}, review ${counts.review}${scopeText}. Example: ${topRow.path} (${topRow.clicks} clicks, ${topRow.impressions} impressions, position ${topRow.position ?? 'not in the export'}) is tiered ${topRow.suggestedDisposition} because it ${topRow.tier}. ${inventory.note} Work the inventory page by page instead of applying one blanket policy.`,\n confidence: 'medium',\n affectedCount: inventory.rows.length,\n evidence: { dispositions: counts, capped: inventory.capped },\n review: {\n question:\n 'Has every returned inventory row received an evidence-backed disposition?',\n changeOnlyIf:\n 'Apply a content change, removal, or redirect only after deciding that row from its own evidence and product relevance.',\n ifConfirmed:\n 'Record one disposition and reason for every returned inventory row.',\n ifNotNeeded:\n 'Keep a page unchanged when its evidence and current product role support keeping it.',\n doNot: [\n 'Do not use one blanket disposition for the inventory.',\n 'Do not redirect unrelated URLs to a generic hub.',\n ],\n },\n verification: {\n expected:\n 'Every returned inventory row has an owner-confirmed keep, update, or review decision; every inventory page has been fetched; redirected rows resolve to the intended destination.',\n },\n })\n }\n for (const { fix, prefix, source } of reviews) {\n const reportId =\n source === 'crawl' ? input.crawlReportId : input.unreachedAudit?.reportId\n actions.push({\n id: `${source}:${fix.ruleId}`,\n kind: 'review',\n title: `${prefix}${fix.ruleId}: ${fix.title} (${fix.count} URL${fix.count === 1 ? '' : 's'})`,\n action: `Observed state that needs intent confirmation before treating it as a defect. ${fix.howToFix}`,\n confidence: 'medium',\n severity: fix.severity,\n affectedCount: fix.count,\n sampleUrls: fix.sampleUrls,\n ...(reportId\n ? {\n affectedUrlsReport: {\n id: 'affected-urls' as const,\n params: { reportId, ruleId: fix.ruleId },\n },\n }\n : {}),\n evidence: {\n ruleId: fix.ruleId,\n source,\n whyThisRanks: fix.whyThisRanks,\n },\n verification: fix.verification,\n })\n }\n return actions\n}\n\n/** Map unreached export URLs onto the crawl origin by path, preserving the\n * reconciliation's join basis, so they can be fetched in this environment. */\nexport function unreachedUrlsOnCrawlOrigin(\n reconciliation: SearchConsoleExportReconciliation,\n limit: number,\n): string[] {\n const urls: string[] = []\n for (const row of reconciliation.unreachedPages.slice(0, limit)) {\n try {\n const parsed = new URL(row.url)\n urls.push(\n `${reconciliation.crawlOrigin}${parsed.pathname}${parsed.search}`,\n )\n } catch {\n /* skip unparseable export URLs */\n }\n }\n return urls\n}\n","import {\n agentActionsView,\n analyticsConnection,\n crawlSite,\n diagnosePropertyWorkflow,\n loadSearchConsoleExport,\n type ReportHtmlSection,\n reconcileExportPagesWithCrawl,\n resolveTechnicalBaseline,\n type SearchConsoleExportEvidence,\n type SearchConsoleExportReconciliation,\n SeoError,\n saveCrawlReport,\n type TechnicalBaseline,\n withAgentReportContract,\n} from '@seo/core'\nimport { compactAgentWorkflowOutput } from '@seo/mcp'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n negatedBooleanArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { truncate } from '../output.js'\nimport {\n printReportHtmlPath,\n reportHtmlArgs,\n reportHtmlOptions,\n writeReportHtml,\n} from '../report-html.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { startUrlForSite } from '../shared.js'\nimport {\n compactMainReportJson,\n type DiagnoseWorkflowReport,\n shellArg,\n siteForDirectUrl,\n} from './main-report-json.js'\nimport { printWorkflow } from './output.js'\nimport {\n completeReviewObservations,\n completeTopFixes,\n crawlDataSourceLines,\n type ExportPageInventory,\n exportPageInventory,\n exportSummarySentence,\n issueCountSummarySentence,\n pageDisplayPath,\n printExportPageInventory,\n searchConsoleExportSection,\n type TopicOverlapResult,\n technicalCrawlActions,\n titleEvidencePages,\n topicOverlapCandidates,\n unreachedUrlsOnCrawlOrigin,\n} from './url-report-evidence.js'\n\n// Bound for the in-run audit of exported page URLs the crawl never reached.\n// Keeps the extra fetch work proportional to one crawl worker window.\nconst UNREACHED_AUDIT_LIMIT = 20\n\nfunction addFollowup(\n commands: Array<{ command: string; why: string }>,\n command: string,\n why: string,\n): void {\n if (commands.some((item) => item.command === command)) {\n return\n }\n commands.push({ command, why })\n}\n\nfunction technicalSection(baseline: TechnicalBaseline) {\n const report = baseline.report\n if (!report) {\n return {\n status: baseline.status,\n ...(baseline.reason ? { reason: baseline.reason } : {}),\n }\n }\n return {\n status: baseline.status,\n ...(baseline.reason ? { reason: baseline.reason } : {}),\n reportId: report.id,\n generatedAt: report.generatedAt,\n crawlStatus: report.status,\n capped: report.summary.pageLimitReached,\n maxPages: report.config.maxPages,\n searchDataJoined:\n (report.dataSources?.searchConsole.joinedMetricPages ?? 0) > 0 ||\n (report.dataSources?.searchConsole.joinedQueryPages ?? 0) > 0,\n dataSources: report.dataSources,\n summary: report.summary,\n topFixes: completeTopFixes(report),\n reviewObservations: completeReviewObservations(report),\n issueGroupsComplete: true,\n }\n}\n\nfunction compactTechnicalFinding(\n finding: ReturnType<typeof completeTopFixes>[number],\n) {\n return {\n ruleId: finding.ruleId,\n title: finding.title,\n category: finding.category,\n severity: finding.severity,\n recommendation: finding.recommendation,\n count: finding.count,\n sampleUrls: finding.sampleUrls.slice(0, 3),\n score: finding.score,\n scoreFactors: finding.scoreFactors,\n whyThisRanks: finding.whyThisRanks,\n detailsCommand: `seo explain --rule ${finding.ruleId}`,\n }\n}\n\nfunction compactTechnicalSection(section: ReturnType<typeof technicalSection>) {\n if (!('topFixes' in section)) return section\n\n // Compact trims per-finding fields, never the group list: dropping groups\n // made real findings invisible to agents reading the compact report.\n return {\n ...section,\n topFixes: section.topFixes.map(compactTechnicalFinding),\n reviewObservations: section.reviewObservations.map(compactTechnicalFinding),\n }\n}\n\nexport function reportActionsWithTechnicalEvidence<T, U>(\n reportActions: readonly T[],\n technicalActions?: readonly U[],\n): Array<T | U> {\n return technicalActions\n ? [...reportActions, ...technicalActions]\n : [...reportActions]\n}\n\nfunction printTechnicalSection(\n section: ReturnType<typeof technicalSection>,\n options: { providerFree?: boolean } = {},\n): void {\n if (!('topFixes' in section)) {\n process.stdout.write(\n `\\nTechnical crawl evidence: ${section.reason ?? section.status}\\n`,\n )\n return\n }\n\n const coverage = section.status === 'reused' ? 'saved' : 'new'\n process.stdout.write(`\\nTechnical crawl evidence (${coverage})\\n`)\n if (section.reason) process.stdout.write(`${section.reason}\\n`)\n if (section.capped) {\n process.stdout.write(\n `Coverage is capped at ${section.maxPages} pages. Run \\`seo crawl\\` for a broader investigation.\\n`,\n )\n }\n if (!options.providerFree) {\n for (const line of crawlDataSourceLines(section.dataSources)) {\n process.stdout.write(`${line}\\n`)\n }\n }\n if (!section.topFixes.length) {\n process.stdout.write('No prioritised technical fixes were found.\\n')\n if (section.reviewObservations.length) {\n process.stdout.write(\n `${section.reviewObservations.length} review observation${section.reviewObservations.length === 1 ? '' : 's'} need confirmation before they become implementation work.\\n`,\n )\n }\n return\n }\n process.stdout.write(\n options.providerFree\n ? '\\nPrioritised technical fixes\\n'\n : section.searchDataJoined\n ? '\\nTechnical fixes with search value\\n'\n : '\\nTechnical fixes (no Search Console data joined)\\n',\n )\n if (!section.searchDataJoined) {\n printTable(\n ['#', 'Rule', 'Severity', 'Affected URLs', 'Verify'],\n section.topFixes.map((fix, index) => [\n index + 1,\n fix.ruleId,\n fix.severity,\n fix.count,\n truncate(fix.howToVerify, 72),\n ]),\n )\n } else {\n printTable(\n ['Score', 'Rule', 'Severity', 'Search value', 'Verify'],\n section.topFixes.map((fix) => [\n fix.score,\n fix.ruleId,\n fix.severity,\n `${fix.scoreFactors.clicks} clicks / ${fix.scoreFactors.sessions} visits${fix.scoreFactors.conversions === undefined ? '' : ` / ${fix.scoreFactors.conversions} conv.`}`,\n truncate(fix.howToVerify, 72),\n ]),\n )\n }\n if (section.reviewObservations.length) {\n if (options.providerFree) {\n process.stdout.write(\n '\\nReview observations (confirm intent before treating as defects)\\n',\n )\n printTable(\n ['Rule', 'Severity', 'Affected URLs', 'Sample'],\n section.reviewObservations.map((observation) => [\n observation.ruleId,\n observation.severity,\n observation.count,\n truncate(observation.sampleUrls[0] ?? '', 60),\n ]),\n )\n } else {\n process.stdout.write(\n `\\n${section.reviewObservations.length} review observation${section.reviewObservations.length === 1 ? '' : 's'} were kept out of this action queue.\\n`,\n )\n }\n }\n}\n\nfunction printSearchConsoleExportSection(input: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n unreachedAudit?: {\n auditedUrls: number\n totalUnreached: number\n topFixes: ReturnType<typeof completeTopFixes>\n reviewObservations: ReturnType<typeof completeTopFixes>\n }\n topicOverlap?: TopicOverlapResult\n pageInventory?: ExportPageInventory\n}): void {\n process.stdout.write('\\nSearch Console export (local file evidence)\\n')\n process.stdout.write(`${exportSummarySentence(input)}\\n`)\n for (const warning of input.evidence.warnings) {\n process.stdout.write(`Warning: ${warning}\\n`)\n }\n const unreached = input.reconciliation?.unreachedPages ?? []\n if (unreached.length) {\n process.stdout.write(\n '\\nExported page URLs not reached by this crawl (by impressions)\\n',\n )\n printTable(\n ['URL', 'Clicks', 'Impressions', 'Position'],\n unreached\n .slice(0, 10)\n .map((row) => [\n truncate(row.url, 64),\n row.clicks,\n row.impressions,\n row.position ?? '-',\n ]),\n )\n }\n if (input.unreachedAudit) {\n const audit = input.unreachedAudit\n process.stdout.write(\n `\\nAudited ${audit.auditedUrls} of the ${audit.totalUnreached} unreached URLs in this run\\n`,\n )\n const groups = [...audit.topFixes, ...audit.reviewObservations]\n if (groups.length) {\n printTable(\n ['Rule', 'Severity', 'Affected URLs', 'Sample'],\n groups.map((group) => [\n group.ruleId,\n group.severity,\n group.count,\n truncate(group.sampleUrls[0] ?? '', 60),\n ]),\n )\n }\n }\n if (input.topicOverlap?.candidates.length) {\n process.stdout.write(\n '\\nTopic overlap candidates (title-based heuristic; the export has no query-to-page mapping)\\n',\n )\n printTable(\n ['Query', 'Impressions', 'Pages'],\n input.topicOverlap.candidates.map((candidate) => [\n truncate(candidate.query, 40),\n candidate.impressions,\n truncate(\n candidate.pages.map((page) => pageDisplayPath(page.url)).join(', '),\n 64,\n ),\n ]),\n )\n }\n if (input.pageInventory) printExportPageInventory(input.pageInventory)\n for (const caveat of input.evidence.caveats) {\n process.stdout.write(`Note: ${caveat}\\n`)\n }\n}\n\nfunction printSkippedProviderSections(\n section: ReturnType<typeof technicalSection>,\n): void {\n process.stdout.write('\\nProvider-backed sections skipped\\n')\n const observedLines =\n 'dataSources' in section ? crawlDataSourceLines(section.dataSources) : []\n const lines = observedLines.length\n ? observedLines\n : ['Search Console: not connected.', 'Google Analytics: not connected.']\n for (const line of lines) {\n process.stdout.write(`${line}\\n`)\n }\n process.stdout.write(\n 'Run `seo start` when you want traffic, query, ranking, and analytics evidence added to the report.\\n',\n )\n}\n\nfunction mainReportHtmlSections(input: {\n technicalCrawl?: ReturnType<typeof technicalSection>\n followups?: Array<{ command: string; why: string }>\n}): ReportHtmlSection[] {\n const sections: ReportHtmlSection[] = []\n const technical = input.technicalCrawl\n if (technical) {\n if ('topFixes' in technical) {\n sections.push({\n title: 'Technical crawl evidence',\n summary: `${technical.summary.crawledUrls} pages were included in the ${technical.status === 'reused' ? 'saved' : 'new'} crawl evidence.`,\n items: [\n ...technical.topFixes.map(\n (fix) =>\n `${fix.ruleId}: ${fix.title}. ${fix.count} affected URLs. ${fix.recommendation}`,\n ),\n ...crawlDataSourceLines(technical.dataSources),\n ],\n })\n } else {\n sections.push({\n title: 'Technical crawl evidence',\n summary:\n technical.reason ?? `Technical evidence was ${technical.status}.`,\n items: [],\n })\n }\n }\n if (input.followups?.length) {\n sections.push({\n title: 'Recommended next commands',\n items: input.followups.map((item) => `${item.command}: ${item.why}`),\n })\n }\n return sections\n}\n\nfunction technicalFirstSummary(\n section: ReturnType<typeof technicalSection>,\n exportEvidence?: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n },\n unreachedAudit?: { auditedUrls: number; totalUnreached: number },\n): string {\n if (!('topFixes' in section)) {\n return `Technical crawl evidence was ${section.status}. Search Console and Google Analytics sections were skipped because they are not connected.`\n }\n\n const parts = [issueCountSummarySentence(section.summary)]\n if (exportEvidence) parts.push(exportSummarySentence(exportEvidence))\n if (unreachedAudit) {\n parts.push(\n `Audited ${unreachedAudit.auditedUrls} of the ${unreachedAudit.totalUnreached} unreached URLs in this run; their findings are in the action list.`,\n )\n }\n parts.push(\n 'Search Console and Google Analytics are not connected; provider-backed sections were skipped.',\n )\n return parts.join(' ')\n}\n\nfunction technicalWorkflowStep(section: ReturnType<typeof technicalSection>): {\n tool: string\n status: 'completed' | 'skipped'\n summary: string\n} {\n if (!('topFixes' in section)) {\n return {\n tool: 'seo_crawl',\n status: 'skipped',\n summary:\n section.reason ?? `Technical crawl evidence was ${section.status}.`,\n }\n }\n\n const pages = section.summary.crawledUrls\n return {\n tool: 'seo_crawl',\n status: 'completed',\n summary: `${section.status === 'reused' ? 'Loaded' : 'Completed'} technical evidence for ${pages} crawled ${pages === 1 ? 'page' : 'pages'}.`,\n }\n}\n\nfunction exportWorkflowSteps(exportSummaryInput?: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n}): Array<{ tool: string; status: 'completed'; summary: string }> {\n if (!exportSummaryInput) return []\n return [\n {\n tool: 'seo_search_console_export',\n status: 'completed',\n summary: exportSummarySentence(exportSummaryInput),\n },\n ]\n}\n\n/**\n * Turn unreached export pages into one runnable follow-up. URLs are mapped\n * onto the crawl origin by path (the same join basis as the reconciliation)\n * so the command works in the environment the user pointed --url at.\n */\nfunction unreachedAuditFollowup(\n reconciliation: SearchConsoleExportReconciliation,\n): { command: string; why: string } | undefined {\n if (reconciliation.unreachedCount === 0) return undefined\n const urls: string[] = []\n for (const row of reconciliation.unreachedPages.slice(0, 10)) {\n try {\n const parsed = new URL(row.url)\n urls.push(\n `${reconciliation.crawlOrigin}${parsed.pathname}${parsed.search}`,\n )\n } catch {\n /* skip unparseable export URLs */\n }\n }\n if (!urls.length) return undefined\n const remainder = reconciliation.unreachedCount - urls.length\n return {\n command: `seo reports run audit-urls --params '${JSON.stringify({ urls })}' --json`,\n why: `Fetch page-level evidence for exported URLs this crawl never reached${remainder > 0 ? ` (first ${urls.length} of ${reconciliation.unreachedCount})` : ''}.${reconciliation.originMismatch ? ' URLs were mapped onto the --url origin by path because the export origin differs.' : ''}`,\n }\n}\n\nexport function reportFollowups(\n report: DiagnoseWorkflowReport,\n input: {\n crawlStartUrl?: string\n projectId?: string\n technicalBaselineStatus?: TechnicalBaseline['status']\n searchDataAvailable?: boolean\n } = {},\n) {\n if (input.searchDataAvailable === false) {\n const commands: Array<{ command: string; why: string }> = []\n if (\n input.crawlStartUrl &&\n input.technicalBaselineStatus !== 'created' &&\n input.technicalBaselineStatus !== 'refreshed' &&\n input.technicalBaselineStatus !== 'reused'\n ) {\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} --health`,\n 'Run the fast sitemap response and access gate before fetching page bodies.',\n )\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} --save`,\n 'Create the technical crawl that this report needs before opening a page-level follow-up.',\n )\n } else if (input.crawlStartUrl) {\n addFollowup(\n commands,\n `seo audit-page --url ${shellArg(input.crawlStartUrl)}`,\n 'Inspect one important page in detail after the site-level crawl.',\n )\n }\n addFollowup(\n commands,\n 'seo start',\n 'Connect Search Console when you want traffic, query, and ranking evidence alongside the crawl.',\n )\n return commands\n }\n\n const identity = input.projectId\n ? `--project ${shellArg(input.projectId)}`\n : `--site ${shellArg(report.site)}`\n const diagnosis = report.output.narrative.diagnosis\n const days = diagnosis.decay.rangeDays\n const commands: Array<{ command: string; why: string }> = []\n const skippedNames = new Set(\n (diagnosis.skippedSections ?? []).map((section) => section.section),\n )\n\n addFollowup(\n commands,\n `seo refresh-priorities ${identity} --days ${days} --verify-content --limit 25`,\n 'Turn the report into a ranked action queue with content checks.',\n )\n\n if (diagnosis.decay.summary.eligibleRows > 0) {\n addFollowup(\n commands,\n `seo decaying ${identity} --days ${days} --limit 25`,\n 'Inspect query/page declines observed in both retained-row windows.',\n )\n }\n\n if (diagnosis.cannibalization.items.length > 0) {\n addFollowup(\n commands,\n `seo cannibal ${identity} --days ${days} --limit 25`,\n 'Find queries split across competing URLs.',\n )\n }\n\n if (diagnosis.quickWins.summary.eligibleRows > 0) {\n addFollowup(\n commands,\n `seo quick-wins ${identity} --days ${days} --verify-content --verify-limit 5`,\n 'Review average-position rows below their heuristic CTR target with optional page evidence.',\n )\n }\n\n if (diagnosis.strikingDistance.summary.eligibleRows > 0) {\n addFollowup(\n commands,\n `seo second-page ${identity} --days ${days} --verify-content --verify-limit 5`,\n 'Work pages sitting just outside page-one rankings.',\n )\n }\n\n if (\n skippedNames.has('traffic anomaly') ||\n skippedNames.has('update correlation')\n ) {\n addFollowup(\n commands,\n `seo quick-wins ${identity} --days ${days} --min-impressions 10 --verify-content --verify-limit 5`,\n 'Sparse GSC data: lower thresholds and look for early content wins.',\n )\n addFollowup(\n commands,\n `seo second-page ${identity} --days ${days} --min-impressions 10 --verify-content --verify-limit 5`,\n 'Sparse GSC data: inspect early second-page opportunities.',\n )\n }\n\n const topMovedPage = diagnosis.segments.page.items.find((item) =>\n item.key.startsWith('http'),\n )\n if (topMovedPage) {\n addFollowup(\n commands,\n `seo audit-page --url ${shellArg(topMovedPage.key)}`,\n 'Audit the biggest moved URL for title, metadata, links, and schema.',\n )\n }\n\n if (\n input.crawlStartUrl &&\n input.technicalBaselineStatus !== 'created' &&\n input.technicalBaselineStatus !== 'refreshed' &&\n input.technicalBaselineStatus !== 'reused'\n ) {\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} --health`,\n 'Run the fast sitemap response and access gate before fetching page bodies.',\n )\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} ${identity} --save`,\n 'Create the first technical crawler baseline with plain-English fixes and JSON-ready issue data.',\n )\n }\n\n addFollowup(\n commands,\n `seo technical-watch ${identity} --limit 50`,\n 'Save a crawl/index baseline so future reports can flag technical drift.',\n )\n\n return commands.slice(0, 6)\n}\n\nfunction printReportFollowups(\n commands: Array<{ command: string; why: string }>,\n): void {\n if (!commands.length) {\n return\n }\n process.stdout.write('\\nRecommended next commands\\n')\n printTable(\n ['Command', 'Why'],\n commands.map((item) => [item.command, item.why]),\n )\n}\n\nfunction printTechnicalOnlyIntro(site: string): void {\n process.stdout.write(`# Technical SEO report: ${site}\\n\\n`)\n}\n\nfunction workflowCommandMeta(input: {\n name: string\n description: string\n workflowName?: string\n printFollowups?: boolean\n}) {\n return defineCommand({\n meta: input,\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n ...(input.printFollowups\n ? {\n url: {\n type: 'string' as const,\n description:\n 'Crawl URL for a technical-only report. Search Console analyses are skipped unless you also pass --site or --project.',\n },\n }\n : {}),\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Search performance window in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum rows per section. Defaults to 10.',\n },\n },\n ),\n ...(input.printFollowups\n ? {\n crawl: defaultTrueBooleanArg(\n 'Create or reuse a bounded technical crawl before the report.',\n 'Skip technical crawl evidence for this report.',\n ),\n 'crawl-max-pages': {\n type: 'string' as const,\n description:\n 'Maximum pages for the report crawl. Defaults to 100.',\n },\n 'crawl-max-depth': {\n type: 'string' as const,\n description:\n 'Maximum link depth for the report crawl. Defaults to 4.',\n },\n full: {\n type: 'boolean' as const,\n default: false,\n description:\n 'Include the full report in JSON output. Default JSON is a compact summary for agents.',\n },\n 'actions-only': {\n type: 'boolean' as const,\n default: false,\n description:\n 'Return findings, verification, and the content inventory without the full report body. JSON only.',\n },\n 'search-console-export': {\n type: 'string' as const,\n description:\n 'Path to a local Search Console export (a directory or CSV with the standard query and page tables). URL mode only; query and page tables stay separate.',\n },\n 'inventory-page': {\n type: 'string' as const,\n default: '1',\n description:\n 'Page of local Search Console export inventory rows to return. URL mode only.',\n },\n ...reportHtmlArgs,\n }\n : {}),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const html = input.printFollowups ? reportHtmlOptions(args) : undefined\n const full = input.printFollowups && booleanArg(args.full)\n const actionsOnly =\n input.printFollowups && booleanArg(args['actions-only'])\n if (actionsOnly && !json) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --actions-only with --json so findings and completion outcomes stay machine-readable.',\n )\n }\n if (actionsOnly && full) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Choose either --actions-only or --full, not both.',\n )\n }\n const project = projectArg(args)\n const explicitSite = stringArg(args.site)\n const directUrl = input.printFollowups ? stringArg(args.url) : undefined\n const useSearchData = Boolean(project || explicitSite || !directUrl)\n const exportPath = input.printFollowups\n ? stringArg(args['search-console-export'])\n : undefined\n const inventoryPage = input.printFollowups\n ? (numberArg(args['inventory-page']) ?? 1)\n : 1\n if (!Number.isSafeInteger(inventoryPage) || inventoryPage < 1) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--inventory-page must be a positive integer.',\n )\n }\n if (inventoryPage !== 1 && !exportPath) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --inventory-page only with --search-console-export.',\n )\n }\n if (exportPath && useSearchData) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --search-console-export only with --url. A connected property already provides query and page evidence, and imported tables must not be blended with it.',\n )\n }\n const selection = useSearchData\n ? await resolveClientSelection({\n client: project,\n site: explicitSite,\n options: { json, refresh: booleanArg(args.refresh) },\n })\n : undefined\n const site = selection?.site ?? siteForDirectUrl(directUrl ?? '')\n const report = await diagnosePropertyWorkflow({\n site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection?.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n refresh: booleanArg(args.refresh),\n skipSearchData: !useSearchData,\n })\n const outputReport = input.workflowName\n ? { ...report, workflow: input.workflowName }\n : report\n const technicalBaseline = input.printFollowups\n ? await resolveTechnicalBaseline({\n site,\n searchSite: selection?.site,\n url:\n directUrl ?? selection?.client?.startUrl ?? startUrlForSite(site),\n projectId: selection?.client?.id,\n googleAnalyticsPropertyId:\n selection?.client?.analytics.google?.propertyId,\n analyticsConnection: analyticsConnection(selection?.client),\n crawl: !negatedBooleanArg(args, 'crawl'),\n refresh: booleanArg(args.refresh),\n maxPages: numberArg(args['crawl-max-pages']),\n maxDepth: numberArg(args['crawl-max-depth']),\n })\n : undefined\n const technicalCrawl = technicalBaseline\n ? technicalSection(technicalBaseline)\n : undefined\n const exportEvidence = exportPath\n ? await loadSearchConsoleExport({ path: exportPath })\n : undefined\n const exportReconciliation =\n exportEvidence && technicalBaseline?.report && directUrl\n ? reconcileExportPagesWithCrawl({\n pages: exportEvidence.pages.rows,\n crawledUrls: technicalBaseline.report.pages.flatMap((page) => [\n page.url,\n page.finalUrl,\n ]),\n crawlOrigin: siteForDirectUrl(directUrl),\n })\n : undefined\n const exportSummaryInput = exportEvidence\n ? { evidence: exportEvidence, reconciliation: exportReconciliation }\n : undefined\n // Exported pages the crawl never reached are still part of the site\n // being audited, so fetch a bounded sample in the same run instead of\n // deferring their page-level evidence to a follow-up command.\n const unreachedAudit = await (async () => {\n if (!exportReconciliation || exportReconciliation.unreachedCount === 0)\n return undefined\n const urls = unreachedUrlsOnCrawlOrigin(\n exportReconciliation,\n UNREACHED_AUDIT_LIMIT,\n )\n if (!urls.length) return undefined\n const auditReport = await crawlSite({\n url: urls[0] ?? '',\n urls,\n mode: 'list',\n maxPages: urls.length,\n useSitemap: false,\n refresh: booleanArg(args.refresh),\n })\n saveCrawlReport(auditReport, undefined, { retention: 'baseline' })\n return {\n reportId: auditReport.id,\n auditedUrls: auditReport.summary.totalPages,\n totalUnreached: exportReconciliation.unreachedCount,\n capped: exportReconciliation.unreachedCount > urls.length,\n issueGroupsComplete: true,\n topFixes: completeTopFixes(auditReport),\n reviewObservations: completeReviewObservations(auditReport),\n // Bounded by the audit's own URL cap. Retained so title-based\n // evidence can include pages the main crawl never reached.\n pages: auditReport.pages.map((page) => ({\n url: page.finalUrl || page.url,\n title: page.title ?? null,\n })),\n }\n })()\n const titlePages = technicalBaseline?.report\n ? titleEvidencePages(\n technicalBaseline.report.pages,\n unreachedAudit?.pages,\n )\n : undefined\n // Title-based topic overlap between exported query phrases and crawled\n // page titles. The export has no query-to-page mapping, so this is a\n // labelled heuristic observation, never a cannibalisation verdict.\n const topicOverlap =\n exportEvidence && titlePages\n ? topicOverlapCandidates({\n queries: exportEvidence.queries.rows,\n pages: titlePages,\n })\n : undefined\n // Per-page suggested disposition tiers so a migration or cleanup can\n // be decided page by page instead of from one blanket recommendation.\n const pageInventory =\n exportEvidence && titlePages\n ? exportPageInventory({\n pages: exportEvidence.pages.rows,\n sourceCapped: exportEvidence.pages.capped,\n page: inventoryPage,\n reconciliation: exportReconciliation,\n crawledPages: titlePages,\n overlap: topicOverlap,\n })\n : undefined\n const technicalActions = technicalBaseline?.report\n ? technicalCrawlActions({\n crawlReportId: technicalBaseline.report.id,\n topFixes: completeTopFixes(technicalBaseline.report),\n reviewObservations: completeReviewObservations(\n technicalBaseline.report,\n ),\n reconciliation: exportReconciliation,\n ...(unreachedAudit\n ? {\n unreachedAudit: {\n reportId: unreachedAudit.reportId,\n topFixes: unreachedAudit.topFixes,\n reviewObservations: unreachedAudit.reviewObservations,\n titlePrefix: 'unreached pages:',\n },\n }\n : {}),\n ...(topicOverlap ? { topicOverlap } : {}),\n ...(pageInventory ? { pageInventory } : {}),\n })\n : undefined\n const followups = input.printFollowups\n ? reportFollowups(outputReport, {\n crawlStartUrl:\n directUrl ?? selection?.client?.startUrl ?? startUrlForSite(site),\n projectId: selection?.client?.id,\n technicalBaselineStatus: technicalBaseline?.status,\n searchDataAvailable: useSearchData,\n })\n : undefined\n if (\n followups &&\n exportReconciliation &&\n (!unreachedAudit || unreachedAudit.capped)\n ) {\n const audit = unreachedAuditFollowup(exportReconciliation)\n if (audit) followups.unshift(audit)\n }\n if (json) {\n const jsonReport =\n input.printFollowups && !full\n ? compactMainReportJson(report, input.workflowName)\n : outputReport\n const completeActions = reportActionsWithTechnicalEvidence(\n jsonReport.actions,\n technicalActions,\n )\n const reportWithTechnicalEvidence =\n !useSearchData && technicalCrawl\n ? {\n ...jsonReport,\n summary: technicalFirstSummary(\n technicalCrawl,\n exportSummaryInput,\n unreachedAudit,\n ),\n steps: [\n technicalWorkflowStep(technicalCrawl),\n ...exportWorkflowSteps(exportSummaryInput),\n ...jsonReport.steps,\n ],\n actions: completeActions,\n // The compact URL-mode report replaces the empty narrative\n // shell (every section unavailable) with an explicit skip\n // marker. --full keeps the whole narrative object.\n ...(full\n ? {}\n : {\n output: {\n searchSections: {\n status: 'skipped',\n reason:\n 'No Search Console property was selected. Pass --site or --project, or run seo start to connect one.',\n },\n },\n }),\n }\n : { ...jsonReport, actions: completeActions }\n const completeReport =\n technicalCrawl || followups\n ? {\n ...reportWithTechnicalEvidence,\n ...(input.printFollowups\n ? { detail: full ? 'full' : 'summary' }\n : {}),\n ...(technicalCrawl\n ? {\n technicalCrawl:\n input.printFollowups && !full\n ? compactTechnicalSection(technicalCrawl)\n : technicalCrawl,\n }\n : {}),\n ...(exportEvidence\n ? {\n searchConsoleExport: {\n ...searchConsoleExportSection({\n evidence: exportEvidence,\n reconciliation: exportReconciliation,\n pageInventory,\n }),\n ...(unreachedAudit\n ? { unreachedPagesAudit: unreachedAudit }\n : {}),\n ...(topicOverlap\n ? { topicOverlapCandidates: topicOverlap }\n : {}),\n },\n }\n : {}),\n ...(followups ? { nextCommands: followups } : {}),\n }\n : jsonReport\n const contractOptions = {\n reportId: 'report',\n preferRootActions: true,\n verify:\n 'Rerun seo report with the same inputs and confirm the finding is absent or its evidence now matches the intended state.',\n ...(!useSearchData &&\n technicalCrawl &&\n 'issueGroupsComplete' in technicalCrawl &&\n technicalCrawl.issueGroupsComplete\n ? { coverage: 'complete' as const }\n : {}),\n }\n printJson(\n compactAgentWorkflowOutput(\n actionsOnly\n ? agentActionsView(completeReport, contractOptions)\n : withAgentReportContract(completeReport, contractOptions),\n ),\n )\n return\n }\n if (html) {\n const path = await writeReportHtml({\n report: outputReport.output.narrative,\n reportName: 'report',\n title: useSearchData ? 'SEO report' : 'Technical SEO report',\n options: html,\n projectId: selection?.client?.id,\n additionalSections: mainReportHtmlSections({\n technicalCrawl,\n followups,\n }),\n })\n printReportHtmlPath(path)\n return\n }\n if (useSearchData) {\n process.stdout.write(`${outputReport.output.narrative.markdown}\\n\\n`)\n printWorkflow(outputReport)\n } else {\n printTechnicalOnlyIntro(site)\n }\n if (technicalCrawl) {\n printTechnicalSection(technicalCrawl, { providerFree: !useSearchData })\n if (exportEvidence) {\n printSearchConsoleExportSection({\n evidence: exportEvidence,\n reconciliation: exportReconciliation,\n unreachedAudit,\n topicOverlap,\n pageInventory,\n })\n }\n if (!useSearchData) printSkippedProviderSections(technicalCrawl)\n }\n if (followups) printReportFollowups(followups)\n },\n })\n}\n\nexport const diagnosePropertyWorkflowCommand = workflowCommandMeta({\n name: 'diagnose-property',\n description: 'Find what changed in Google Search and what to inspect next',\n})\n\nexport const mainReportCommand = workflowCommandMeta({\n name: 'report',\n workflowName: 'report',\n printFollowups: true,\n description:\n 'Run the main SEO report and recommend the next best follow-up commands',\n})\n","import { analyticsConnection, refreshPrioritiesWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from '../analytics/connection.js'\nimport { printActionDetails } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { printWorkflow } from './output.js'\n\nexport const refreshPrioritiesCommand = defineCommand({\n meta: {\n name: 'refresh-priorities',\n description: 'Agent workflow for a ranked SEO action queue',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum queue items to print. Defaults to 25.',\n },\n },\n ),\n ...analyticsConnectionArgs,\n 'verify-content': defaultTrueBooleanArg(\n 'Verify top opportunities against page title, meta, and content. Defaults to true.',\n 'Skip page content verification.',\n ),\n 'verify-limit': {\n type: 'string',\n description: 'Maximum opportunity URLs to verify. Defaults to 5.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await refreshPrioritiesWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n googleAnalyticsPropertyId: stringArg(args['google-analytics-property']),\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection.client),\n ),\n verifyContent: booleanArg(args['verify-content']),\n verifyLimit: numberArg(args['verify-limit']),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printWorkflow(report)\n printTable(\n [\n 'Source',\n 'Category',\n 'Score',\n 'Findings',\n 'Template',\n 'Analytics',\n 'Target',\n 'Action',\n ],\n report.output.queue.map((item) => [\n item.source,\n item.category,\n item.score,\n item.grouped?.count ?? 1,\n item.template?.label ?? '-',\n item.analytics?.sessions ?? '-',\n item.target,\n item.action,\n ]),\n )\n printActionDetails(\n 'Queue action details',\n report.output.queue.map((item) => ({\n label: item.target,\n context: `${item.category}, score ${item.score}`,\n action: item.action,\n })),\n )\n },\n})\n","import { technicalWatchWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n listArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport { printMonitoringRun } from '../monitoring/output.js'\nimport { startUrlForSite } from '../shared.js'\n\nexport const technicalWatchCommand = defineCommand({\n meta: {\n name: 'technical-watch',\n description: 'Agent workflow for crawl-diff and index-watch monitoring',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Defaults from the GSC property when possible.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to inspect with URL Inspection.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs for quota-aware index monitoring.',\n },\n properties: {\n type: 'string',\n description:\n 'Comma-separated GSC properties for sitemap index monitoring.',\n },\n limit: {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 50.',\n },\n 'daily-limit': {\n type: 'string',\n description: 'URL Inspection daily limit per property. Defaults to 2000.',\n },\n 'inspect-limit': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to inspect in this run. Defaults to 100.',\n },\n 'max-urls': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to load for monitoring. Defaults to 50000.',\n },\n language: {\n type: 'string',\n description: 'Optional URL Inspection language code.',\n },\n 'recover-links': defaultTrueBooleanArg(\n 'Check search-value GSC pages for broken, blocked, or poorly redirected URLs. Defaults to true.',\n 'Skip link recovery checks.',\n ),\n 'recover-days': {\n type: 'string',\n description: 'GSC lookback window for link recovery. Defaults to 90.',\n },\n 'recover-limit': {\n type: 'string',\n description:\n 'Maximum search-value pages to check for link recovery. Defaults to 10.',\n },\n 'recover-min-clicks': {\n type: 'string',\n description:\n 'Minimum clicks for link recovery candidates. Defaults to 1.',\n },\n 'recover-min-impressions': {\n type: 'string',\n description:\n 'Minimum impressions for link recovery candidates. Defaults to 100.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP/GSC cache where supported.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const watchUrls = listArg(args.urls)\n const sitemaps = listArg(args.sitemaps)\n const startUrl =\n stringArg(args.url) ??\n selection.client?.startUrl ??\n startUrlForSite(selection.site)\n const report = await technicalWatchWorkflow({\n site: selection.site,\n startUrl,\n urls: watchUrls.length ? watchUrls : selection.client?.watchUrls,\n sitemaps: sitemaps.length ? sitemaps : undefined,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n limit: numberArg(args.limit),\n languageCode: stringArg(args.language),\n dailyLimit: numberArg(args['daily-limit']),\n inspectLimit: numberArg(args['inspect-limit']),\n maxUrls: numberArg(args['max-urls']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n recoverLinks: booleanArg(args['recover-links']),\n recoverDays: numberArg(args['recover-days']),\n recoverLimit: numberArg(args['recover-limit']),\n recoverMinClicks: numberArg(args['recover-min-clicks']),\n recoverMinImpressions: numberArg(args['recover-min-impressions']),\n })\n if (json) {\n printJson(report)\n return\n }\n printMonitoringRun(report)\n },\n})\n","import { updatePostmortemWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNextCommand, printNotes, printReportSummary } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\ntype SegmentSplit = Awaited<\n ReturnType<typeof updatePostmortemWorkflow>\n>['output']['segments']['page']\n\nfunction formatNumber(value: number | null): string {\n if (value === null) return '-'\n return value.toLocaleString('en-GB', {\n maximumFractionDigits: value >= 100 ? 0 : 1,\n })\n}\n\nfunction segmentRows(split: SegmentSplit) {\n return [\n ...split.winners.map((item) => ({ direction: 'winner', item })),\n ...split.losers.map((item) => ({ direction: 'loser', item })),\n ]\n}\n\nfunction printSegmentTable(label: string, split: SegmentSplit): void {\n const rows = segmentRows(split)\n if (!rows.length) return\n process.stdout.write(`\\n${label}\\n`)\n printTable(\n ['Direction', 'Key', 'Clicks', 'Impr.', 'Position'],\n rows.map(({ direction, item }) => [\n direction,\n item.key,\n formatNumber(item.clickDelta),\n formatNumber(item.impressionDelta),\n formatNumber(item.positionDelta),\n ]),\n )\n}\n\nfunction printSegmentCoverage(\n segments: Awaited<\n ReturnType<typeof updatePostmortemWorkflow>\n >['output']['segments'],\n): void {\n process.stdout.write('\\nSegment coverage\\n')\n printTable(\n [\n 'Dimension',\n 'Eligible',\n 'Returned',\n 'Limited',\n 'Result cap',\n 'Source cap',\n 'Source capped',\n ],\n (['page', 'query', 'device', 'country'] as const).map((dimension) => {\n const coverage = segments[dimension].coverage\n return [\n dimension,\n coverage.eligibleRows,\n coverage.returnedRows,\n coverage.limitedRows,\n coverage.resultLimit,\n coverage.sourceRowLimit,\n coverage.sourcePossiblyTruncated ? 'yes' : 'no',\n ]\n }),\n )\n}\n\ntype TemplateMovement = Awaited<\n ReturnType<typeof updatePostmortemWorkflow>\n>['output']['templateMovement'][number]\n\nfunction printTemplateMovement(items: TemplateMovement[]): void {\n if (!items.length) return\n process.stdout.write('\\nTemplate movement\\n')\n printTable(\n [\n 'Direction',\n 'Template',\n 'Pattern confidence',\n 'URLs',\n 'Clicks',\n 'Returned share',\n 'Common terms',\n ],\n items.map((item) => [\n item.direction,\n item.signature,\n item.confidence,\n item.urlCount,\n formatNumber(item.clickDelta),\n `${Math.round(item.movementShare * 100)}%`,\n item.commonTerms.join(', ') || '-',\n ]),\n )\n printNotes(\n 'Template actions',\n items.map((item) => item.summary),\n )\n printNotes('Template evidence scope', [\n 'Shares use returned directional page click movement. Pattern confidence applies only to returned matched-retained page segments.',\n ])\n}\n\nexport const updatePostmortemCommand = defineCommand({\n meta: {\n name: 'update-postmortem',\n description: 'Agent workflow for Google update winner/loser analysis',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum winners/losers per segment. Defaults to 20.',\n },\n },\n ),\n 'known-change': {\n type: 'string',\n description:\n 'Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.',\n },\n 'ignore-change-log': {\n type: 'boolean',\n default: false,\n description: 'Do not use saved change-log entries as confounders.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await updatePostmortemWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n knownConfounders: stringArg(args['known-change'])\n ? [stringArg(args['known-change']) ?? '']\n : undefined,\n includeChangeLog: !booleanArg(args['ignore-change-log']),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Update postmortem',\n target: report.site,\n status: 'unknown',\n summary: report.summary,\n metrics: [\n {\n label: 'Attribution',\n value: report.output.update.attribution.replaceAll('-', ' '),\n },\n { label: 'Confidence', value: report.output.update.confidence },\n {\n label: 'Known confounders',\n value: report.output.update.confounders.length,\n },\n ],\n })\n printNotes(\n 'Recommended actions',\n report.actions.map(\n (action) => `${action.title} (${action.confidence}): ${action.action}`,\n ),\n )\n printNotes(\n 'Postmortem findings',\n report.output.insights.map((insight) => insight.summary),\n )\n printNotes(\n 'Segment evidence warnings',\n [\n ...report.output.segments.page.warnings,\n ...report.output.segments.query.warnings,\n ...report.output.segments.device.warnings,\n ...report.output.segments.country.warnings,\n ].filter(\n (warning, index, warnings) => warnings.indexOf(warning) === index,\n ),\n )\n printTemplateMovement(report.output.templateMovement)\n printNotes('Update evidence', report.output.update.evidence)\n printSegmentCoverage(report.output.segments)\n printSegmentTable('Page winners and losers', report.output.segments.page)\n printSegmentTable('Query winners and losers', report.output.segments.query)\n printSegmentTable(\n 'Device winners and losers',\n report.output.segments.device,\n )\n printSegmentTable(\n 'Country winners and losers',\n report.output.segments.country,\n )\n const target = selection.client\n ? `--project ${JSON.stringify(selection.client.id)}`\n : `--site ${JSON.stringify(selection.site)}`\n printNextCommand(`seo export update-postmortem ${target}`)\n },\n})\n","import { arch, platform } from 'node:os'\nimport {\n classifyTelemetryFailure,\n isTelemetryOperation,\n isTelemetryReport,\n SEO_VERSION,\n type TelemetryOperation,\n toSeoError,\n} from '@seo/core'\n\nconst BUG_REPORT_URL = 'https://github.com/iannuttall/seo/issues/new'\nconst ACTIONABLE_CATEGORIES = new Set([\n 'database',\n 'filesystem',\n 'internal',\n 'unknown',\n])\n\ntype ErrorFeedbackOptions = {\n args: string[]\n error: unknown\n nodeVersion?: string\n processArch?: string\n processPlatform?: string\n report?: string\n version?: string\n}\n\nfunction nodeMajor(version: string): string {\n return version.replace(/^v/, '').split('.')[0] || 'unknown'\n}\n\nexport function telemetryOperation(\n args: string[],\n): TelemetryOperation | undefined {\n return isTelemetryOperation(args[0]) ? args[0] : undefined\n}\n\nfunction feedbackSubject(\n report: string | undefined,\n operation: TelemetryOperation | undefined,\n): string {\n if (isTelemetryReport(report)) return `seo ${report}`\n if (operation) return `seo ${operation}`\n return 'seo command'\n}\n\nexport function buildErrorFeedbackUrl(\n options: ErrorFeedbackOptions,\n): string | undefined {\n const failure = classifyTelemetryFailure(options.error)\n if (!ACTIONABLE_CATEGORIES.has(failure.errorCategory)) return undefined\n\n const operation = telemetryOperation(options.args)\n const subject = feedbackSubject(options.report, operation)\n const normalized = toSeoError(options.error)\n const diagnostics = [\n normalized.code,\n failure.errorCategory,\n failure.failureReason,\n failure.failureContext,\n ]\n .filter(Boolean)\n .join(' | ')\n const url = new URL(BUG_REPORT_URL)\n url.searchParams.set('template', 'bug.yml')\n url.searchParams.set('title', `bug: ${subject} failed`)\n url.searchParams.set('version', options.version ?? SEO_VERSION)\n url.searchParams.set(\n 'runtime',\n `Node ${nodeMajor(options.nodeVersion ?? process.version)} on ${\n options.processPlatform ?? platform()\n } (${options.processArch ?? arch()})`,\n )\n url.searchParams.set('diagnostics', diagnostics)\n return url.toString()\n}\n","// Version 0.3.0 moved most reports into eight commands. Old names keep\n// working for this one release and say where they went. Removed commands say\n// so and stop. Both lists go in 0.4.0.\n\nexport const RENAMED: Record<string, string> = {\n 'diagnose-property': 'seo report',\n 'refresh-priorities': 'seo report',\n 'query-cluster': 'seo report',\n 'quick-wins': 'seo report --section quick-wins',\n 'ctr-underperformers': 'seo report --section low-ctr',\n 'striking-distance': 'seo report --section striking-distance',\n 'second-page': 'seo report --section second-page',\n decaying: 'seo report --section content-decay',\n cannibal: 'seo report --section cannibalization',\n 'traffic-anomaly': 'seo report --section traffic-drop',\n 'page-opportunities': 'seo page --url <url>',\n 'audit-page': 'seo page --url <url>',\n 'url-inspect': 'seo page --url <url>',\n 'segment-impact': 'seo compare --date <date>',\n 'update-correlate': 'seo compare --date <date>',\n 'update-postmortem': 'seo compare --date <date>',\n 'link-recover': 'seo index',\n 'gsc-query': 'seo data',\n}\n\n// Removed commands, with the command to use instead when there is one. A key\n// with a space is a subcommand, such as `seo export pseo`, and can have up to\n// three words.\nexport const REMOVED: Record<string, string | null> = {\n 'agent-readiness': null,\n 'ai-readiness': null,\n 'community-intent': null,\n 'entity-readiness': null,\n llms: null,\n 'monthly-report': 'seo report',\n okf: null,\n pseo: null,\n 'report-narrative': 'seo report',\n 'seo-to-ai-query': null,\n 'server-logs': null,\n 'client keyword-sets': null,\n links: 'seo research backlinks --target <domain>',\n 'export knowledge': null,\n 'export monthly': 'seo report --json',\n 'export narrative': 'seo report --json',\n 'export pseo': null,\n indexnow: null,\n 'project keyword-sets': null,\n 'projects keyword-sets': null,\n 'providers bing': null,\n 'providers semrush': 'seo providers',\n 'providers limits': null,\n 'providers spend': null,\n 'providers dataforseo limits': null,\n 'providers dataforseo spend': null,\n 'providers ahrefs limits': null,\n}\n\nconst SPEND_REASON =\n 'Spend is controlled in your provider account. Set limits in DataForSEO, Ahrefs or the other provider.'\n\n// Why a command was removed, when the general reason does not fit.\nconst REMOVED_REASONS: Record<string, string> = {\n 'providers limits': SPEND_REASON,\n 'providers spend': SPEND_REASON,\n 'providers dataforseo limits': SPEND_REASON,\n 'providers dataforseo spend': SPEND_REASON,\n 'providers ahrefs limits': SPEND_REASON,\n}\n\nconst PROJECT_ALIASES = new Set(['client', 'project', 'projects'])\n\n// The removed command an argument list names, if any. Only the leading\n// words before the first flag count, so a flag value never matches.\nexport function removedCommand(args: string[]): string | null {\n const flag = args.findIndex((arg) => arg.startsWith('-'))\n const words = flag === -1 ? args : args.slice(0, flag)\n const start = words[0] === 'help' ? 1 : 0\n for (let length = 3; length >= 1; length -= 1) {\n const key = words.slice(start, start + length).join(' ')\n if (words.length - start >= length && Object.hasOwn(REMOVED, key)) {\n return key\n }\n }\n return null\n}\n\nexport function renamedNotice(command: string): string | null {\n const next = Object.hasOwn(RENAMED, command) ? RENAMED[command] : undefined\n return next\n ? `\\`seo ${command}\\` is now \\`${next}\\`. The old name stops working in 0.4.0.`\n : null\n}\n\nexport function removedNotice(args: string[]): string | null {\n const command = removedCommand(args)\n if (!command) return null\n const replacement = REMOVED[command]\n const group = command.split(' ')[0] ?? ''\n const next = replacement\n ? `Use \\`${replacement}\\` instead.`\n : PROJECT_ALIASES.has(group)\n ? 'Run `seo projects --help` for the project commands.'\n : group === 'providers'\n ? 'Run `seo providers --help` for the provider commands.'\n : 'Run `seo help` for the commands.'\n const reason = Object.hasOwn(REMOVED_REASONS, command)\n ? REMOVED_REASONS[command]\n : 'SEO Skill now focuses on Search Console, analytics and keyword data.'\n return `\\`seo ${command}\\` was removed in 0.3.0. ${reason} ${next}`\n}\n","import { spawnSync } from 'node:child_process'\nimport { realpathSync } from 'node:fs'\nimport { isCancel, log, select } from '@clack/prompts'\nimport updateNotifier from 'update-notifier'\n\ntype PackageInfo = {\n name: string\n version: string\n}\n\ntype UpdateInfo = {\n current: string\n latest: string\n}\n\ntype UpdateNotifier = {\n update?: UpdateInfo\n}\n\nexport type SelfUpdateCommand = {\n args: string[]\n command: string\n}\n\ntype OfferUpdateOptions = {\n argv?: string[]\n cliPath?: string\n createNotifier?: (pkg: PackageInfo) => UpdateNotifier\n env?: NodeJS.ProcessEnv\n platform?: NodeJS.Platform\n prompt?: (input: {\n command: SelfUpdateCommand\n update: UpdateInfo\n }) => Promise<'later' | 'update'>\n run?: (command: SelfUpdateCommand) => number | null\n stdinIsTty?: boolean\n stdoutIsTty?: boolean\n}\n\nfunction normalizedPath(value: string): string {\n return value.replaceAll('\\\\', '/').toLowerCase()\n}\n\nfunction packageManagerCommand(\n manager: 'bun' | 'npm' | 'pnpm' | 'yarn',\n platform: NodeJS.Platform,\n): string {\n if (platform !== 'win32') return manager\n return `${manager}.cmd`\n}\n\nexport function inferSelfUpdateCommand(\n resolvedCliPath: string,\n platform: NodeJS.Platform = process.platform,\n): SelfUpdateCommand | undefined {\n const path = normalizedPath(resolvedCliPath)\n\n if (\n path.includes('/_npx/') ||\n path.includes('/.npm/_npx/') ||\n path.includes('/.cache/pnpm/dlx/') ||\n path.includes('/.volta/')\n ) {\n return undefined\n }\n\n if (path.includes('/.pnpm/') || path.includes('/pnpm/global/')) {\n return {\n command: packageManagerCommand('pnpm', platform),\n args: ['add', '--global', 'seo@latest'],\n }\n }\n\n if (path.includes('/.bun/install/global/')) {\n return {\n command: packageManagerCommand('bun', platform),\n args: ['add', '--global', 'seo@latest'],\n }\n }\n\n if (path.includes('/.config/yarn/global/')) {\n return {\n command: packageManagerCommand('yarn', platform),\n args: ['global', 'add', 'seo@latest'],\n }\n }\n\n if (path.includes('/node_modules/seo/')) {\n return {\n command: packageManagerCommand('npm', platform),\n args: ['install', '--global', 'seo@latest'],\n }\n }\n\n return undefined\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const parse = (value: string) =>\n value\n .replace(/^v/, '')\n .split('-')[0]\n ?.split('.')\n .map((part) => Number.parseInt(part, 10)) ?? []\n const currentParts = parse(current)\n const latestParts = parse(latest)\n\n for (let index = 0; index < 3; index += 1) {\n const currentPart = currentParts[index] ?? 0\n const latestPart = latestParts[index] ?? 0\n if (!Number.isFinite(currentPart) || !Number.isFinite(latestPart)) {\n return false\n }\n if (latestPart > currentPart) return true\n if (latestPart < currentPart) return false\n }\n\n return false\n}\n\nexport function canOfferInteractiveUpdate(input: {\n argv: string[]\n env: NodeJS.ProcessEnv\n stdinIsTty: boolean\n stdoutIsTty: boolean\n}): boolean {\n if (!input.stdinIsTty || !input.stdoutIsTty) return false\n if (\n input.env.CI ||\n input.env.NO_UPDATE_NOTIFIER ||\n input.env.NODE_ENV === 'test' ||\n input.env.npm_lifecycle_event ||\n input.env.npm_execpath ||\n input.env.TERM === 'dumb'\n ) {\n return false\n }\n if (input.argv.includes('--json')) return false\n if (\n input.argv.some((arg) => ['--help', '-h', '--version', '-v'].includes(arg))\n ) {\n return false\n }\n if (['help', 'mcp'].includes(input.argv[0] ?? '')) return false\n return true\n}\n\nfunction resolvedCliPath(cliPath: string | undefined): string | undefined {\n if (!cliPath) return undefined\n try {\n return realpathSync(cliPath)\n } catch {\n return cliPath\n }\n}\n\nasync function promptForUpdate(input: {\n command: SelfUpdateCommand\n update: UpdateInfo\n}): Promise<'later' | 'update'> {\n const choice = await select<'later' | 'update'>({\n message: `seo ${input.update.latest} is available. You have ${input.update.current}.`,\n options: [\n {\n value: 'update',\n label: 'Update now',\n hint: [input.command.command, ...input.command.args].join(' '),\n },\n { value: 'later', label: 'Later' },\n ],\n initialValue: 'later',\n })\n return isCancel(choice) ? 'later' : choice\n}\n\nfunction runUpdate(command: SelfUpdateCommand): number | null {\n return spawnSync(command.command, command.args, { stdio: 'inherit' }).status\n}\n\nexport async function maybeOfferSelfUpdate(\n pkg: PackageInfo,\n options: OfferUpdateOptions = {},\n): Promise<number | undefined> {\n const argv = options.argv ?? process.argv.slice(2)\n const env = options.env ?? process.env\n if (\n !canOfferInteractiveUpdate({\n argv,\n env,\n stdinIsTty: options.stdinIsTty ?? Boolean(process.stdin.isTTY),\n stdoutIsTty: options.stdoutIsTty ?? Boolean(process.stdout.isTTY),\n })\n ) {\n return undefined\n }\n\n const path = resolvedCliPath(options.cliPath ?? process.argv[1])\n const command = path\n ? inferSelfUpdateCommand(path, options.platform ?? process.platform)\n : undefined\n if (!command) return undefined\n\n const notifier = (\n options.createNotifier ??\n ((value) =>\n updateNotifier({\n pkg: value,\n shouldNotifyInNpmScript: false,\n }))\n )(pkg)\n const update = notifier.update\n if (!update || !isNewerVersion(update.current, update.latest)) {\n return undefined\n }\n\n const choice = await (options.prompt ?? promptForUpdate)({ command, update })\n if (choice === 'later') return undefined\n\n const status = (options.run ?? runUpdate)(command)\n if (status === 0) {\n log.success(`Updated seo to ${update.latest}. Run your command again.`)\n return 0\n }\n\n log.error('The update failed. Your current version is unchanged.')\n return 1\n}\n","import {\n detectTelemetryAgent,\n initializeTelemetry,\n SEO_VERSION,\n seoErrorEnvelope,\n toSeoError,\n trackTelemetryCommandFailed,\n trackTelemetryReportComplete,\n trackTelemetryReportFailed,\n trackTelemetryReportStart,\n trackTelemetrySetupComplete,\n} from '@seo/core'\nimport {\n COMMANDS,\n type CommandId,\n telemetryReportFor,\n} from '@seo/core/commands'\nimport { listReports } from '@seo/mcp'\nimport { defineCommand, runCommand, runMain } from 'citty'\nimport { analyticsCommand } from './commands/analytics/index.js'\nimport { authCommand } from './commands/auth.js'\nimport { cacheCommand } from './commands/cache.js'\nimport { clientCommand, projectCommand } from './commands/clients/index.js'\nimport { contentCommand } from './commands/content.js'\nimport {\n compareCommand,\n dataCommand,\n indexCommand,\n pageCommand,\n reportCommand,\n researchCommand,\n} from './commands/core-commands.js'\nimport { crawlCommand } from './commands/crawl.js'\nimport { crawlReportsCommand } from './commands/crawl-reports.js'\nimport { gscQueryCommand, urlInspectCommand } from './commands/data.js'\nimport {\n trafficAnomalyCommand,\n updateCorrelateCommand,\n} from './commands/diagnosis-reports.js'\nimport {\n changeLogCommand,\n contentGroupsCommand,\n testsCommand,\n} from './commands/experiments/index.js'\nimport { exportCommand } from './commands/export/index.js'\nimport { initCommand } from './commands/init.js'\nimport { logsCommand } from './commands/logs.js'\nimport { mcpCommand } from './commands/mcp.js'\nimport {\n crawlDiffCommand,\n indexCoverageCommand,\n indexWatchCommand,\n linkRecoverCommand,\n monitoringCommand,\n redirectTraceCommand,\n} from './commands/monitoring.js'\nimport {\n aiReferralsCommand,\n cannibalCommand,\n ctrUnderperformersCommand,\n decayingCommand,\n internalLinksCommand,\n pageOpportunitiesCommand,\n queryClusterCommand,\n quickWinsCommand,\n secondPageCommand,\n} from './commands/opportunities/index.js'\nimport { auditPageCommand } from './commands/page-audit.js'\nimport { performanceCommand } from './commands/performance.js'\nimport {\n diagnoseCommand,\n doctorCommand,\n segmentImpactCommand,\n strikingDistanceCommand,\n} from './commands/product/index.js'\nimport { providersCommand } from './commands/providers/index.js'\nimport { reportCatalogCommand } from './commands/report-catalog.js'\nimport { explainCommand, rulesCommand } from './commands/rules.js'\nimport { scheduleCommand } from './commands/schedule.js'\nimport { setupCommand, startCommand } from './commands/setup/index.js'\nimport { skillsCommand } from './commands/skills.js'\nimport {\n privacyCommand,\n resetCommand,\n sitesCommand,\n updatesCommand,\n} from './commands/system.js'\nimport { telemetryCommand } from './commands/telemetry.js'\nimport {\n crawlQueueCommand,\n mainReportCommand,\n refreshPrioritiesCommand,\n technicalWatchCommand,\n updatePostmortemCommand,\n} from './commands/workflows/index.js'\nimport { buildErrorFeedbackUrl, telemetryOperation } from './error-feedback.js'\nimport { removedNotice, renamedNotice } from './renames.js'\nimport { maybeOfferSelfUpdate } from './self-update.js'\nimport { printCatalog, printHeading, printSection } from './utils.js'\n\nconst pkg = {\n name: 'seo',\n version: SEO_VERSION,\n}\n\ntype HelpSection = {\n title: string\n commands: Array<[command: string, description: string]>\n}\n\nconst helpSections: HelpSection[] = [\n {\n title: 'Start here',\n commands: [\n ['seo start', 'Connect Search Console and save a project profile'],\n ['seo report', 'The main report: overview and every section'],\n [\n 'seo report --section quick-wins',\n 'One section of the report, with live page checks',\n ],\n ],\n },\n {\n title: 'Commands',\n commands: [\n ['seo page --url <url>', 'One page: live facts, index status, queries'],\n ['seo compare --date <date>', 'Before and after a date'],\n ['seo index', 'Pages that lost most of their clicks'],\n [\n 'seo research <action>',\n 'Keyword, SERP, competitor and backlink data from your key',\n ],\n ['seo data', 'Raw Search Console rows'],\n ['seo crawl', 'Crawl a site and list technical issues'],\n ['seo internal-links', 'Pages that could link to a target page'],\n ],\n },\n {\n title: 'Setup',\n commands: [\n ['seo projects list', 'List saved project profiles'],\n ['seo sites', 'List Search Console properties'],\n ['seo mcp install', 'Add the local MCP server to your agents'],\n ['seo providers', 'Connect DataForSEO or Ahrefs'],\n ['seo doctor', 'Check local auth and config'],\n ],\n },\n]\n\nconst allHelpSections: HelpSection[] = [\n ...helpSections,\n {\n title: 'More commands',\n commands: [\n ['seo crawl-reports', 'List saved crawl reports'],\n ['seo crawl-diff', 'Compare crawl changes'],\n ['seo crawl-queue', 'Run a crawl and rank the fix queue'],\n ['seo rules', 'List crawler rule ids'],\n ['seo explain --rule missing_title', 'Explain a crawler rule'],\n ['seo redirect-trace', 'Trace redirects'],\n ['seo perf audit', 'Run a page performance audit'],\n ['seo index-coverage', 'Choose pages for URL Inspection'],\n ['seo index-watch', 'Check saved URL Inspection snapshots'],\n ['seo ai-referrals', 'AI referral traffic in Google Analytics'],\n ['seo analytics google report', 'Run a Google Analytics report'],\n ['seo updates', 'List official Google ranking updates'],\n ['seo change-log', 'Track SEO changes'],\n ['seo tests', 'Create and report local SEO tests'],\n ['seo content-groups', 'Manage reusable page and query groups'],\n ['seo monitoring', 'Run and review monitoring'],\n ['seo schedule cron', 'Print cron entries'],\n ['seo export', 'Export report data to CSV'],\n ['seo reports list', 'List every structured report'],\n ['seo skill list', 'Show the packaged SEO skill'],\n ['seo auth', 'Manage Google auth'],\n ['seo cache', 'Manage local cache'],\n ['seo privacy', 'Show local storage paths'],\n ['seo telemetry status', 'Check anonymous usage telemetry'],\n ['seo reset', 'Delete saved credentials and all local data'],\n ],\n },\n]\n\nfunction printHelpSections(sections: HelpSection[]): void {\n printHeading(\n `seo v${pkg.version}`,\n 'Run SEO audits, find what needs fixing, and ship the changes with your agent.',\n )\n process.stdout.write('\\n')\n printCatalog(\n sections.flatMap((section) =>\n section.commands.map(([command, description]) => ({\n category: section.title,\n id: command,\n name: description,\n })),\n ),\n {\n noun: 'command',\n categoryLabels: Object.fromEntries(\n sections.map((section) => [section.title, section.title]),\n ),\n },\n )\n process.stdout.write('\\n')\n printSection(\n 'More help',\n 'Use `seo help <command>` or `seo <command> --help` for command help.',\n 'Use `seo help all` for the longer command list.',\n )\n}\n\nconst main = defineCommand({\n meta: {\n name: 'seo',\n version: pkg.version,\n description: 'Local-first SEO CLI and MCP server',\n },\n subCommands: {\n init: initCommand,\n analytics: analyticsCommand,\n auth: authCommand,\n mcp: mcpCommand,\n doctor: doctorCommand,\n privacy: privacyCommand,\n telemetry: telemetryCommand,\n reset: resetCommand,\n cache: cacheCommand,\n logs: logsCommand,\n crawl: crawlCommand,\n 'crawl-queue': crawlQueueCommand,\n 'crawl-reports': crawlReportsCommand,\n client: clientCommand,\n content: contentCommand,\n project: projectCommand,\n projects: projectCommand,\n providers: providersCommand,\n 'change-log': changeLogCommand,\n tests: testsCommand,\n 'content-groups': contentGroupsCommand,\n 'crawl-diff': crawlDiffCommand,\n diagnose: diagnoseCommand,\n // The 0.2 main report, kept under its old name for one release.\n 'diagnose-property': mainReportCommand,\n export: exportCommand,\n 'index-coverage': indexCoverageCommand,\n 'index-watch': indexWatchCommand,\n 'link-recover': linkRecoverCommand,\n monitoring: monitoringCommand,\n rules: rulesCommand,\n explain: explainCommand,\n 'refresh-priorities': refreshPrioritiesCommand,\n 'redirect-trace': redirectTraceCommand,\n schedule: scheduleCommand,\n skill: skillsCommand,\n start: startCommand,\n setup: setupCommand,\n report: reportCommand,\n page: pageCommand,\n compare: compareCommand,\n index: indexCommand,\n data: dataCommand,\n research: researchCommand,\n reports: reportCatalogCommand,\n 'segment-impact': segmentImpactCommand,\n 'striking-distance': strikingDistanceCommand,\n 'technical-watch': technicalWatchCommand,\n 'update-postmortem': updatePostmortemCommand,\n sites: sitesCommand,\n 'gsc-query': gscQueryCommand,\n 'url-inspect': urlInspectCommand,\n updates: updatesCommand,\n 'traffic-anomaly': trafficAnomalyCommand,\n 'update-correlate': updateCorrelateCommand,\n 'ai-referrals': aiReferralsCommand,\n 'audit-page': auditPageCommand,\n 'second-page': secondPageCommand,\n cannibal: cannibalCommand,\n decaying: decayingCommand,\n 'quick-wins': quickWinsCommand,\n 'page-opportunities': pageOpportunitiesCommand,\n perf: performanceCommand,\n 'internal-links': internalLinksCommand,\n 'ctr-underperformers': ctrUnderperformersCommand,\n 'query-cluster': queryClusterCommand,\n },\n run: async () => {\n if (process.argv.slice(2).length === 0) {\n process.stdout.write(\n 'Use `seo start` to set up, then `seo report` for the main report.\\n',\n )\n }\n },\n})\n\nconst reportAliases: Record<string, string> = {\n cannibal: 'cannibalisation',\n crawl: 'site-crawl',\n 'crawl-queue': 'top-fixes',\n decaying: 'decaying-pages',\n 'diagnose-property': 'search-performance-overview',\n doctor: 'setup-check',\n explain: 'explain-crawl-issue',\n 'link-recover': 'link-recovery',\n 'query-cluster': 'query-clusters',\n report: 'search-performance-overview',\n rules: 'crawler-rules',\n 'update-correlate': 'update-correlation',\n}\n\nconst directReportIds = new Set([\n 'ai-referrals',\n 'audit-page',\n 'crawl-diff',\n 'ctr-underperformers',\n 'index-coverage',\n 'index-watch',\n 'internal-links',\n 'page-opportunities',\n 'quick-wins',\n 'redirect-trace',\n 'refresh-priorities',\n 'second-page',\n 'segment-impact',\n 'striking-distance',\n 'technical-watch',\n 'traffic-anomaly',\n 'update-postmortem',\n])\nconst knownReportIds = new Set(listReports().map((report) => report.id))\n\nfunction flagValue(args: string[], flag: string): string | undefined {\n const at = args.indexOf(flag)\n if (at >= 0) return args[at + 1]\n return args.find((arg) => arg.startsWith(`${flag}=`))?.slice(flag.length + 1)\n}\n\nfunction telemetryReportId(args: string[]): string | undefined {\n const [command, subcommand, id] = args\n if (!command) return undefined\n if (command in COMMANDS) {\n return (\n telemetryReportFor(command as CommandId, {\n section: flagValue(args, '--section'),\n action: subcommand,\n }) ?? undefined\n )\n }\n if (command === 'reports' && subcommand === 'run') {\n return id && knownReportIds.has(id) ? id : undefined\n }\n if (command === 'content' && subcommand === 'optimize') {\n return 'content-optimization'\n }\n if (command === 'change-log' && subcommand === 'measure') {\n return 'measure-change'\n }\n if (command === 'monitoring' && subcommand === 'run') {\n return 'technical-watch'\n }\n if (command === 'perf' && subcommand === 'audit') return 'performance-audit'\n if (command === 'tests' && subcommand === 'report') return 'measure-change'\n return (\n reportAliases[command] ??\n (directReportIds.has(command) ? command : undefined)\n )\n}\n\nconst argv = process.argv.slice(2)\nconst removed = removedNotice(argv)\nif (removed) {\n process.stderr.write(`${removed}\\n`)\n process.exit(2)\n}\nconst renamed = renamedNotice(argv[0] ?? '')\nif (renamed && !argv.some((arg) => ['--help', '-h'].includes(arg))) {\n process.stderr.write(`${renamed}\\n`)\n}\nconst telemetryOptions = { agent: detectTelemetryAgent() }\nconst isTelemetryControl = argv[0] === 'telemetry'\nconst isMcpServer = argv[0] === 'mcp' && argv[1] === 'serve'\nif (!isTelemetryControl && !isMcpServer) {\n initializeTelemetry(telemetryOptions)\n}\nconst updateExitCode = await maybeOfferSelfUpdate(pkg, { argv })\nif (updateExitCode !== undefined) {\n process.exit(updateExitCode)\n}\nif (\n argv.length === 0 ||\n (argv.length === 1 && ['help', '--help', '-h'].includes(argv[0] ?? ''))\n) {\n printHelpSections(helpSections)\n process.exit(0)\n}\nif (argv[0] === 'help' && argv[1] === 'all') {\n printHelpSections(allHelpSections)\n process.exit(0)\n}\nconst commandArgs =\n argv[0] === 'help' && argv.length > 1 ? [...argv.slice(1), '--help'] : argv\nif (commandArgs !== argv) {\n process.argv = [\n process.argv[0] ?? 'node',\n process.argv[1] ?? 'seo',\n ...commandArgs,\n ]\n}\nconst helpRequested = commandArgs.some((arg) => ['--help', '-h'].includes(arg))\nconst versionRequested =\n argv.length === 1 && ['--version', '-v'].includes(argv[0] ?? '')\nconst trackedReport =\n helpRequested || versionRequested ? undefined : telemetryReportId(commandArgs)\n\nif (helpRequested || versionRequested) {\n await runMain(main)\n} else {\n if (trackedReport) {\n trackTelemetryReportStart(trackedReport, telemetryOptions)\n }\n try {\n await runCommand(main, { rawArgs: commandArgs })\n if (trackedReport) {\n trackTelemetryReportComplete(trackedReport, telemetryOptions)\n }\n if (\n ['init', 'setup', 'start'].includes(commandArgs[0] ?? '') &&\n !commandArgs.includes('--dry-run')\n ) {\n trackTelemetrySetupComplete(telemetryOptions)\n }\n } catch (error) {\n if (trackedReport) {\n trackTelemetryReportFailed(trackedReport, error, telemetryOptions)\n } else if (!isTelemetryControl) {\n const operation = telemetryOperation(commandArgs)\n if (operation) {\n trackTelemetryCommandFailed(operation, error, telemetryOptions)\n }\n }\n const normalized = toSeoError(error)\n if (argv.includes('--json')) {\n process.stdout.write(\n `${JSON.stringify(seoErrorEnvelope(normalized), null, 2)}\\n`,\n )\n } else {\n process.stderr.write(`Error: ${normalized.message}\\n`)\n const feedbackUrl = buildErrorFeedbackUrl({\n args: commandArgs,\n error,\n report: trackedReport,\n })\n if (feedbackUrl) {\n process.stderr.write(`Report this bug: ${feedbackUrl}\\n`)\n }\n }\n process.exitCode = normalized.exitCode\n }\n}\n"],"mappings":"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EAAM,CACR,EAAU,CAAM,EAChB,MACF,CACA,GAAc,CAAM,EACpB,EACE,CACE,SACA,WACA,QACA,WACA,WACA,YACA,SACA,QACF,EACA,EAAO,OAAO,MAAM,IAAK,GAAS,CAChC,EAAK,OACL,EAAK,SACL,EAAK,MACL,EAAK,SAAS,OAAS,EACvB,EAAK,UAAU,OAAS,IACxB,EAAK,WAAW,UAAY,IAC5B,EAAK,OACL,EAAK,MACP,CAAC,CACH,EACA,EACE,uBACA,EAAO,OAAO,MAAM,IAAK,IAAU,CACjC,MAAO,EAAK,OACZ,QAAS,GAAG,EAAK,SAAS,UAAU,EAAK,QACzC,OAAQ,EAAK,MACf,EAAE,CACJ,CACF,CACF,CAAC,EC3GY,GAAwB,EAAc,CACjD,KAAM,CACJ,KAAM,kBACN,YAAa,0DACf,EACA,KAAM,CACJ,KAAM,CACJ,KAAM,SACN,YAAa,sDACf,EACA,OAAQ,CACN,KAAM,SACN,YAAa,6BACf,EACA,QAAS,CACP,KAAM,SACN,YAAa,2BACf,EACA,IAAK,CACH,KAAM,SACN,YACE,mEACJ,EACA,KAAM,CACJ,KAAM,SACN,YAAa,sDACf,EACA,SAAU,CACR,KAAM,SACN,YACE,oEACJ,EACA,WAAY,CACV,KAAM,SACN,YACE,8DACJ,EACA,MAAO,CACL,KAAM,SACN,YAAa,yCACf,EACA,cAAe,CACb,KAAM,SACN,YAAa,4DACf,EACA,gBAAiB,CACf,KAAM,SACN,YACE,+DACJ,EACA,WAAY,CACV,KAAM,SACN,YACE,iEACJ,EACA,SAAU,CACR,KAAM,SACN,YAAa,wCACf,EACA,gBAAiB,GACf,iGACA,4BACF,EACA,eAAgB,CACd,KAAM,SACN,YAAa,wDACf,EACA,gBAAiB,CACf,KAAM,SACN,YACE,wEACJ,EACA,qBAAsB,CACpB,KAAM,SACN,YACE,6DACJ,EACA,0BAA2B,CACzB,KAAM,SACN,YACE,oEACJ,EACA,KAAM,CACJ,KAAM,UACN,QAAS,GACT,YAAa,8BACf,EACA,QAAS,CACP,KAAM,UACN,QAAS,GACT,YAAa,8CACf,EACA,GAAI,CACF,KAAM,UACN,QAA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"}
1
+ {"version":3,"file":"cli.js","names":["compareText","normalizedPath","statusLabel","readConfig","credentialSourceLabel","connectCommand","statusCommand","reportCommand","disconnectCommand","readConfig","truncate","shellArg","truncate","quote","urlListArgs","crawlUrlArg","crawlModeArg","parseUrlList","truncate","formatNumber","today","changeScope","slug","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","truncate","doctorCommand","truncate","connectCommand","statusCommand","disconnectCommand","connectCommand","statusCommand","disconnectCommand","connectCommand","statusCommand","disconnectCommand","listCommand","describeCommand","installCommand","runCommand","listCommand","runCommand","truncate","truncate","doctorCommand"],"sources":["../packages/core/dist/export/report-html.js","../packages/core/dist/export/update-postmortem.js","../packages/core/dist/ga4/matching.js","../packages/core/dist/gsc/local-export.js","../packages/core/dist/gsc/local-export-reconcile.js","../packages/core/dist/utils/time.js","../packages/cli/src/args.ts","../packages/cli/src/presentation/context.ts","../packages/cli/src/presentation/render.ts","../packages/cli/src/presentation/report.ts","../packages/cli/src/presentation/views.ts","../packages/cli/src/utils.ts","../packages/cli/src/selection.ts","../packages/cli/src/commands/analytics/clicky/index.ts","../packages/cli/src/commands/analytics/google/properties.ts","../packages/cli/src/commands/output.ts","../packages/cli/src/commands/analytics/google/report.ts","../packages/cli/src/commands/analytics/google/index.ts","../packages/cli/src/commands/analytics/index.ts","../packages/cli/src/commands/google-login.ts","../packages/cli/src/commands/auth.ts","../packages/cli/src/commands/cache.ts","../packages/cli/src/commands/shared.ts","../packages/cli/src/commands/setup/project-target.ts","../packages/cli/src/commands/mcp-clients.ts","../packages/cli/src/commands/mcp-config.ts","../packages/cli/src/commands/skill-install.ts","../packages/cli/src/commands/setup/prompts.ts","../packages/cli/src/commands/setup/flow.ts","../packages/cli/src/commands/setup/index.ts","../packages/cli/src/commands/clients/brand.ts","../packages/cli/src/commands/clients/profiles/output.ts","../packages/cli/src/commands/clients/profiles/add.ts","../packages/cli/src/commands/clients/profiles/default.ts","../packages/cli/src/commands/clients/profiles/delete.ts","../packages/cli/src/commands/clients/profiles/list.ts","../packages/cli/src/commands/clients/profiles/show.ts","../packages/cli/src/commands/clients/profiles.ts","../packages/cli/src/commands/clients/index.ts","../packages/cli/src/commands/content.ts","../packages/cli/src/commands/core-commands.ts","../packages/cli/src/json-output.ts","../packages/cli/src/presentation/crawl-report.ts","../packages/cli/src/commands/analytics/connection.ts","../packages/cli/src/commands/crawl.ts","../packages/cli/src/commands/crawl-reports.ts","../packages/cli/src/commands/data.ts","../packages/cli/src/commands/report-options.ts","../packages/cli/src/commands/diagnosis-reports.ts","../packages/cli/src/commands/experiments/change-log.ts","../packages/cli/src/commands/experiments/content-groups.ts","../packages/cli/src/commands/experiments/tests.ts","../packages/cli/src/progress.ts","../packages/cli/src/commands/export/shared.ts","../packages/cli/src/commands/export/diagnose.ts","../packages/cli/src/commands/export/refresh-priorities.ts","../packages/cli/src/commands/export/update-postmortem.ts","../packages/cli/src/commands/export/index.ts","../packages/cli/src/commands/init.ts","../packages/cli/src/commands/logs.ts","../packages/cli/src/commands/mcp.ts","../packages/cli/src/commands/monitoring/crawl-diff.ts","../packages/cli/src/commands/monitoring/args.ts","../packages/cli/src/commands/workflows/output.ts","../packages/cli/src/commands/monitoring/output.ts","../packages/cli/src/commands/monitoring/index.ts","../packages/cli/src/commands/monitoring/index-coverage.ts","../packages/cli/src/commands/monitoring/index-watch.ts","../packages/cli/src/commands/monitoring/link-recover.ts","../packages/cli/src/commands/monitoring/redirect-trace.ts","../packages/cli/src/commands/opportunities/ai-referrals.ts","../packages/cli/src/commands/opportunities/cannibal.ts","../packages/cli/src/commands/opportunities/ctr.ts","../packages/cli/src/commands/opportunities/decaying.ts","../packages/cli/src/commands/opportunities/internal-links.ts","../packages/cli/src/commands/opportunities/page-opportunities.ts","../packages/cli/src/commands/opportunities/query-cluster.ts","../packages/cli/src/commands/opportunities/quick-wins.ts","../packages/cli/src/commands/opportunities/second-page.ts","../packages/cli/src/commands/page-audit.ts","../packages/cli/src/commands/performance.ts","../packages/cli/src/commands/product/diagnose.ts","../packages/cli/src/commands/product/doctor.ts","../packages/cli/src/commands/product/segment-impact.ts","../packages/cli/src/commands/product/striking-distance.ts","../packages/cli/src/commands/providers/shared.ts","../packages/cli/src/commands/providers/ahrefs.ts","../packages/cli/src/commands/providers/bing.ts","../packages/cli/src/commands/providers/dataforseo.ts","../packages/cli/src/commands/providers/extensions.ts","../packages/cli/src/commands/providers/index.ts","../packages/cli/src/commands/report-catalog.ts","../packages/cli/src/commands/rules.ts","../packages/cli/src/commands/schedule.ts","../packages/cli/src/commands/skill-paths.ts","../packages/cli/src/commands/skills-eval.ts","../packages/cli/src/commands/skills.ts","../packages/cli/src/commands/system.ts","../packages/cli/src/commands/telemetry.ts","../packages/cli/src/commands/workflows/crawl-queue.ts","../packages/cli/src/commands/report-html.ts","../packages/cli/src/commands/workflows/main-report-json.ts","../packages/cli/src/commands/workflows/url-report-output.ts","../packages/cli/src/commands/workflows/url-report-evidence.ts","../packages/cli/src/commands/workflows/diagnose-property.ts","../packages/cli/src/commands/workflows/refresh-priorities.ts","../packages/cli/src/commands/workflows/technical-watch.ts","../packages/cli/src/commands/workflows/update-postmortem.ts","../packages/cli/src/error-feedback.ts","../packages/cli/src/renames.ts","../packages/cli/src/self-update.ts","../packages/cli/src/upgrade-notice.ts","../packages/cli/src/index.ts"],"sourcesContent":["function escapeHtml(value) {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&#39;');\n}\nfunction safeHttpUrl(value) {\n try {\n const url = new URL(value);\n return url.protocol === 'http:' || url.protocol === 'https:'\n ? url.toString()\n : undefined;\n }\n catch {\n return undefined;\n }\n}\nfunction siteMarkup(site) {\n const safeUrl = safeHttpUrl(site);\n const label = escapeHtml(site);\n return safeUrl\n ? `<a href=\"${escapeHtml(safeUrl)}\" rel=\"noreferrer\">${label}</a>`\n : label;\n}\nfunction list(items) {\n if (items.length === 0)\n return '<p class=\"empty\">No items to report.</p>';\n return `<ul>${items.map((item) => `<li>${escapeHtml(item)}</li>`).join('')}</ul>`;\n}\nfunction reportSections(report) {\n return report.sections\n .map((section) => `<section class=\"panel\">\n <h2>${escapeHtml(section.title)}</h2>\n ${list(section.bullets)}\n </section>`)\n .join('');\n}\nfunction additionalSections(sections) {\n return sections\n .map((section) => `<section class=\"panel\">\n <h2>${escapeHtml(section.title)}</h2>\n ${section.summary ? `<p>${escapeHtml(section.summary)}</p>` : ''}\n ${list(section.items)}\n </section>`)\n .join('');\n}\nfunction priorities(report) {\n if (report.priorities.length === 0) {\n return '<p class=\"empty\">No evidence-backed priorities were found.</p>';\n }\n return `<ol class=\"priorities\">${report.priorities\n .map((priority) => `<li>\n <div class=\"priority-heading\">\n <strong>${escapeHtml(priority.title)}</strong>\n <span class=\"confidence\">${escapeHtml(priority.confidence)} confidence</span>\n </div>\n <p>${escapeHtml(priority.action)}</p>\n </li>`)\n .join('')}</ol>`;\n}\nfunction analystEvidence(report) {\n const skipped = report.diagnosis.skippedSections ?? [];\n const attempts = report.changeMeasurementAttempts;\n return `<section class=\"panel analyst-only\">\n <h2>Evidence coverage</h2>\n <dl class=\"facts\">\n <div><dt>Data status</dt><dd>${escapeHtml(report.dataStatus)}</dd></div>\n <div><dt>Generated</dt><dd>${escapeHtml(report.generatedAt)}</dd></div>\n <div><dt>Saved changes checked</dt><dd>${attempts.length}</dd></div>\n <div><dt>Unavailable sections</dt><dd>${skipped.length}</dd></div>\n </dl>\n ${skipped.length\n ? `<h3>Unavailable sections</h3>${list(skipped.map((section) => 'reason' in section && typeof section.reason === 'string'\n ? `${section.section}: ${section.reason}`\n : section.section))}`\n : ''}\n </section>`;\n}\nconst styles = `\n :root { color-scheme: light; font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; color: #17211b; background: #f2f4ef; }\n * { box-sizing: border-box; }\n body { margin: 0; line-height: 1.55; }\n a { color: inherit; text-decoration-color: #ff5b35; text-underline-offset: 0.18em; }\n main { width: min(980px, calc(100% - 32px)); margin: 32px auto 64px; }\n header { padding: clamp(28px, 6vw, 64px); color: #f9fbf7; background: #17211b; border-radius: 20px; }\n .eyebrow { margin: 0 0 12px; color: #ff7958; font-size: 0.78rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; }\n h1 { max-width: 760px; margin: 0; font-size: clamp(2rem, 5vw, 4rem); line-height: 1.02; letter-spacing: -0.04em; }\n header .headline { max-width: 760px; margin: 24px 0 0; font-size: clamp(1.05rem, 2vw, 1.3rem); color: #d9e1d9; }\n .meta { display: flex; flex-wrap: wrap; gap: 10px 22px; margin-top: 28px; color: #b9c5ba; font-size: 0.9rem; }\n .status { display: inline-flex; width: fit-content; margin-top: 22px; padding: 6px 10px; border: 1px solid #4f6153; border-radius: 999px; font-size: 0.8rem; font-weight: 700; text-transform: capitalize; }\n .panel { margin-top: 20px; padding: clamp(22px, 4vw, 38px); background: #fff; border: 1px solid #dfe4dc; border-radius: 16px; box-shadow: 0 8px 30px rgba(23, 33, 27, 0.05); }\n h2 { margin: 0 0 16px; font-size: clamp(1.25rem, 3vw, 1.65rem); letter-spacing: -0.02em; }\n h3 { margin: 26px 0 10px; font-size: 1rem; }\n p { margin: 0 0 14px; }\n ul, ol { margin: 0; padding-left: 1.25rem; }\n li + li { margin-top: 10px; }\n .priorities { list-style: none; padding: 0; counter-reset: priority; }\n .priorities > li { counter-increment: priority; padding: 18px 0 18px 52px; position: relative; border-top: 1px solid #e6eae4; }\n .priorities > li:first-child { border-top: 0; padding-top: 4px; }\n .priorities > li::before { content: counter(priority); position: absolute; left: 0; top: 16px; display: grid; width: 34px; height: 34px; place-items: center; border-radius: 50%; color: #17211b; background: #ff7958; font-weight: 800; }\n .priorities > li:first-child::before { top: 2px; }\n .priority-heading { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 8px 20px; }\n .confidence { color: #647067; font-size: 0.82rem; text-transform: capitalize; }\n .priorities p { margin: 8px 0 0; color: #3e4941; }\n .facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin: 0; }\n .facts div { padding: 14px; background: #f5f7f3; border-radius: 10px; }\n dt { color: #647067; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; }\n dd { margin: 4px 0 0; font-weight: 700; }\n details summary { cursor: pointer; font-weight: 750; }\n details ul { margin-top: 14px; }\n .empty { color: #647067; font-style: italic; }\n footer { margin-top: 26px; color: #647067; font-size: 0.8rem; text-align: center; }\n @media print { :root { background: #fff; } main { width: 100%; margin: 0; } header, .panel { break-inside: avoid; box-shadow: none; } header { border-radius: 0; } }\n`;\nexport function renderReportHtml(input) {\n const report = input.report;\n const view = input.view ?? 'client';\n const title = input.title ?? 'SEO report';\n const evidenceNotesOpen = report.dataStatus !== 'complete' ? ' open' : '';\n const analyst = view === 'analyst' ? analystEvidence(report) : '';\n return `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <meta name=\"robots\" content=\"noindex,nofollow\">\n <title>${escapeHtml(title)}: ${escapeHtml(report.site)}</title>\n <style>${styles}</style>\n</head>\n<body>\n <main>\n <header>\n <p class=\"eyebrow\">${escapeHtml(title)}</p>\n <h1>${siteMarkup(report.site)}</h1>\n <p class=\"headline\">${escapeHtml(report.headline)}</p>\n <div class=\"meta\">\n <span>${escapeHtml(report.period.startDate)} to ${escapeHtml(report.period.endDate)}</span>\n <span>Generated ${escapeHtml(report.generatedAt.slice(0, 10))}</span>\n <span>${escapeHtml(view)} view</span>\n </div>\n <span class=\"status\">${escapeHtml(report.dataStatus)} data</span>\n </header>\n\n <section class=\"panel\">\n <h2>Priorities</h2>\n ${priorities(report)}\n </section>\n\n ${reportSections(report)}\n ${additionalSections(input.additionalSections ?? [])}\n ${analyst}\n\n <section class=\"panel\">\n <details${evidenceNotesOpen}>\n <summary>Evidence notes and limitations</summary>\n ${list(report.caveats)}\n </details>\n </section>\n\n <footer>Generated locally from observed report evidence.</footer>\n </main>\n</body>\n</html>`;\n}\n//# sourceMappingURL=report-html.js.map","const HEADERS = {\n summary: [\n 'workflow',\n 'site',\n 'generated_at',\n 'summary',\n 'attribution',\n 'confidence',\n 'classification',\n 'updates_matched',\n 'known_confounders',\n 'page_segment_status',\n 'page_segment_eligible_rows',\n 'page_segment_returned_rows',\n 'page_segment_limited_rows',\n 'page_segment_result_limit',\n 'page_segment_source_row_limit',\n 'page_segment_source_possibly_truncated',\n 'page_segment_warnings',\n 'query_segment_status',\n 'query_segment_eligible_rows',\n 'query_segment_returned_rows',\n 'query_segment_limited_rows',\n 'query_segment_result_limit',\n 'query_segment_source_row_limit',\n 'query_segment_source_possibly_truncated',\n 'query_segment_warnings',\n 'device_segment_status',\n 'device_segment_eligible_rows',\n 'device_segment_returned_rows',\n 'device_segment_limited_rows',\n 'device_segment_result_limit',\n 'device_segment_source_row_limit',\n 'device_segment_source_possibly_truncated',\n 'device_segment_warnings',\n 'country_segment_status',\n 'country_segment_eligible_rows',\n 'country_segment_returned_rows',\n 'country_segment_limited_rows',\n 'country_segment_result_limit',\n 'country_segment_source_row_limit',\n 'country_segment_source_possibly_truncated',\n 'country_segment_warnings',\n ],\n steps: ['rank', 'tool', 'status', 'summary'],\n actions: ['rank', 'title', 'confidence', 'action'],\n findings: [\n 'dimension',\n 'data_status',\n 'eligible_rows',\n 'returned_rows',\n 'limited_rows',\n 'result_limit',\n 'unmatched_rows',\n 'summary',\n 'winner_key',\n 'winner_click_delta',\n 'winner_impression_delta',\n 'winner_position_delta',\n 'loser_key',\n 'loser_click_delta',\n 'loser_impression_delta',\n 'loser_position_delta',\n ],\n templates: [\n 'rank',\n 'direction',\n 'template',\n 'confidence',\n 'url_count',\n 'click_delta',\n 'impression_delta',\n 'movement_share',\n 'movement_share_scope',\n 'confidence_scope',\n 'eligible_rows',\n 'returned_rows',\n 'limited_rows',\n 'result_limit',\n 'source_possibly_truncated',\n 'common_terms',\n 'sample_urls',\n 'summary',\n ],\n evidence: ['rank', 'evidence'],\n confounders: [\n 'rank',\n 'source',\n 'title',\n 'date',\n 'scope',\n 'target',\n 'description',\n ],\n segment: [\n 'rank',\n 'dimension',\n 'data_status',\n 'evidence_scope',\n 'key',\n 'before_clicks',\n 'after_clicks',\n 'click_delta',\n 'before_impressions',\n 'after_impressions',\n 'impression_delta',\n 'before_position',\n 'after_position',\n 'position_delta',\n ],\n unmatchedSegment: [\n 'rank',\n 'dimension',\n 'data_status',\n 'key',\n 'retained_in',\n 'clicks',\n 'impressions',\n 'position',\n 'reason',\n ],\n};\nfunction postmortemSegmentRows(report, dimension) {\n return [\n ...report.output.segments[dimension].winners,\n ...report.output.segments[dimension].losers,\n ].map((item, index) => ({\n rank: index + 1,\n dimension,\n data_status: report.output.segments[dimension].dataStatus,\n evidence_scope: item.evidenceScope,\n key: item.key,\n before_clicks: item.beforeClicks,\n after_clicks: item.afterClicks,\n click_delta: item.clickDelta,\n before_impressions: item.beforeImpressions,\n after_impressions: item.afterImpressions,\n impression_delta: item.impressionDelta,\n before_position: item.beforePosition,\n after_position: item.afterPosition,\n position_delta: item.positionDelta,\n }));\n}\nfunction postmortemUnmatchedSegmentRows(report, dimension) {\n return report.output.segments[dimension].unmatchedSegments.map((item, index) => ({\n rank: index + 1,\n dimension,\n data_status: report.output.segments[dimension].dataStatus,\n key: item.key,\n retained_in: item.retainedIn,\n clicks: item.clicks,\n impressions: item.impressions,\n position: item.position,\n reason: item.reason,\n }));\n}\nexport function updatePostmortemCsvFiles(report) {\n return [\n {\n filename: 'postmortem-summary.csv',\n headers: [...HEADERS.summary],\n rows: [\n {\n workflow: report.workflow,\n site: report.site,\n generated_at: report.generatedAt,\n summary: report.summary,\n attribution: report.output.update.attribution,\n confidence: report.output.update.confidence,\n classification: report.output.update.classification,\n updates_matched: report.output.update.overlappingUpdates.length,\n known_confounders: report.output.update.confounders.length,\n page_segment_status: report.output.segments.page.dataStatus,\n page_segment_eligible_rows: report.output.segments.page.coverage.eligibleRows,\n page_segment_returned_rows: report.output.segments.page.coverage.returnedRows,\n page_segment_limited_rows: report.output.segments.page.coverage.limitedRows,\n page_segment_result_limit: report.output.segments.page.coverage.resultLimit,\n page_segment_source_row_limit: report.output.segments.page.coverage.sourceRowLimit,\n page_segment_source_possibly_truncated: report.output.segments.page.coverage.sourcePossiblyTruncated,\n page_segment_warnings: report.output.segments.page.warnings.join('; '),\n query_segment_status: report.output.segments.query.dataStatus,\n query_segment_eligible_rows: report.output.segments.query.coverage.eligibleRows,\n query_segment_returned_rows: report.output.segments.query.coverage.returnedRows,\n query_segment_limited_rows: report.output.segments.query.coverage.limitedRows,\n query_segment_result_limit: report.output.segments.query.coverage.resultLimit,\n query_segment_source_row_limit: report.output.segments.query.coverage.sourceRowLimit,\n query_segment_source_possibly_truncated: report.output.segments.query.coverage.sourcePossiblyTruncated,\n query_segment_warnings: report.output.segments.query.warnings.join('; '),\n device_segment_status: report.output.segments.device.dataStatus,\n device_segment_eligible_rows: report.output.segments.device.coverage.eligibleRows,\n device_segment_returned_rows: report.output.segments.device.coverage.returnedRows,\n device_segment_limited_rows: report.output.segments.device.coverage.limitedRows,\n device_segment_result_limit: report.output.segments.device.coverage.resultLimit,\n device_segment_source_row_limit: report.output.segments.device.coverage.sourceRowLimit,\n device_segment_source_possibly_truncated: report.output.segments.device.coverage.sourcePossiblyTruncated,\n device_segment_warnings: report.output.segments.device.warnings.join('; '),\n country_segment_status: report.output.segments.country.dataStatus,\n country_segment_eligible_rows: report.output.segments.country.coverage.eligibleRows,\n country_segment_returned_rows: report.output.segments.country.coverage.returnedRows,\n country_segment_limited_rows: report.output.segments.country.coverage.limitedRows,\n country_segment_result_limit: report.output.segments.country.coverage.resultLimit,\n country_segment_source_row_limit: report.output.segments.country.coverage.sourceRowLimit,\n country_segment_source_possibly_truncated: report.output.segments.country.coverage.sourcePossiblyTruncated,\n country_segment_warnings: report.output.segments.country.warnings.join('; '),\n },\n ],\n },\n {\n filename: 'workflow-steps.csv',\n headers: [...HEADERS.steps],\n rows: report.steps.map((step, index) => ({\n rank: index + 1,\n tool: step.tool,\n status: step.status,\n summary: step.summary,\n })),\n },\n {\n filename: 'workflow-actions.csv',\n headers: [...HEADERS.actions],\n rows: report.actions.map((action, index) => ({\n rank: index + 1,\n title: action.title,\n confidence: action.confidence,\n action: action.action,\n })),\n },\n {\n filename: 'postmortem-findings.csv',\n headers: [...HEADERS.findings],\n rows: report.output.insights.map((item) => ({\n dimension: item.dimension,\n data_status: item.dataStatus,\n eligible_rows: item.coverage.eligibleRows,\n returned_rows: item.coverage.returnedRows,\n limited_rows: item.coverage.limitedRows,\n result_limit: item.coverage.resultLimit,\n unmatched_rows: item.unmatchedRows,\n summary: item.summary,\n winner_key: item.winner?.key,\n winner_click_delta: item.winner?.clickDelta,\n winner_impression_delta: item.winner?.impressionDelta,\n winner_position_delta: item.winner?.positionDelta,\n loser_key: item.loser?.key,\n loser_click_delta: item.loser?.clickDelta,\n loser_impression_delta: item.loser?.impressionDelta,\n loser_position_delta: item.loser?.positionDelta,\n })),\n },\n {\n filename: 'postmortem-template-movement.csv',\n headers: [...HEADERS.templates],\n rows: report.output.templateMovement.map((item, index) => ({\n rank: index + 1,\n direction: item.direction,\n template: item.signature,\n confidence: item.confidence,\n url_count: item.urlCount,\n click_delta: item.clickDelta,\n impression_delta: item.impressionDelta,\n movement_share: item.movementShare,\n movement_share_scope: item.movementShareScope,\n confidence_scope: item.confidenceScope,\n eligible_rows: item.segmentCoverage.eligibleRows,\n returned_rows: item.segmentCoverage.returnedRows,\n limited_rows: item.segmentCoverage.limitedRows,\n result_limit: item.segmentCoverage.resultLimit,\n source_possibly_truncated: item.segmentCoverage.sourcePossiblyTruncated,\n common_terms: item.commonTerms.join('; '),\n sample_urls: item.sampleUrls.join('; '),\n summary: item.summary,\n })),\n },\n {\n filename: 'postmortem-update-evidence.csv',\n headers: [...HEADERS.evidence],\n rows: report.output.update.evidence.map((evidence, index) => ({\n rank: index + 1,\n evidence,\n })),\n },\n {\n filename: 'postmortem-confounders.csv',\n headers: [...HEADERS.confounders],\n rows: report.output.update.confounders.map((item, index) => ({\n rank: index + 1,\n source: item.source,\n title: item.title,\n date: item.date,\n scope: item.scope,\n target: item.target,\n description: item.description,\n })),\n },\n ...['page', 'query', 'device', 'country'].map((dimension) => ({\n filename: `postmortem-segment-${dimension}.csv`,\n headers: [...HEADERS.segment],\n rows: postmortemSegmentRows(report, dimension),\n })),\n ...['page', 'query', 'device', 'country'].map((dimension) => ({\n filename: `postmortem-segment-${dimension}-unmatched.csv`,\n headers: [...HEADERS.unmatchedSegment],\n rows: postmortemUnmatchedSegmentRows(report, dimension),\n })),\n ];\n}\n//# sourceMappingURL=update-postmortem.js.map","function hostnameFromUrl(value) {\n try {\n const url = new URL(value);\n if (url.protocol !== 'http:' && url.protocol !== 'https:')\n return undefined;\n return url.hostname.toLowerCase().replace(/\\.$/, '') || undefined;\n }\n catch {\n return undefined;\n }\n}\nfunction domainFromProperty(value) {\n if (!value.startsWith('sc-domain:'))\n return undefined;\n const domain = value.slice('sc-domain:'.length).trim().toLowerCase();\n if (!domain || /[/:]/.test(domain))\n return undefined;\n return domain.replace(/\\.$/, '') || undefined;\n}\nfunction matchForSite(site, streamHostname) {\n const domain = domainFromProperty(site);\n if (domain) {\n return streamHostname === domain || streamHostname.endsWith(`.${domain}`)\n ? 'domain'\n : undefined;\n }\n return hostnameFromUrl(site) === streamHostname ? 'hostname' : undefined;\n}\nexport function matchGa4WebStreams(site, candidates) {\n return candidates.flatMap((candidate) => {\n const defaultUri = candidate.stream.webStreamData?.defaultUri;\n if (!defaultUri)\n return [];\n const hostname = hostnameFromUrl(defaultUri);\n if (!hostname)\n return [];\n const match = matchForSite(site, hostname);\n if (!match)\n return [];\n return [{ ...candidate, defaultUri, hostname, match }];\n });\n}\nexport function ga4MatchReason(match, site) {\n const stream = match.stream.displayName ?? match.defaultUri;\n const location = match.match === 'domain' ? 'is inside' : 'matches';\n return `Matched Google Analytics web stream ${stream} (${match.defaultUri}): its hostname ${location} ${site}.`;\n}\n//# sourceMappingURL=matching.js.map","import { createHash } from 'node:crypto';\nimport { readdir, stat } from 'node:fs/promises';\nimport { extname, join, resolve } from 'node:path';\nimport { SeoError } from '../errors.js';\nimport { csvRecords, DEFAULT_IMPORT_STREAM_BYTES, importFile, } from '../imports/records.js';\nexport const DEFAULT_SEARCH_CONSOLE_EXPORT_ROW_LIMIT = 5_000;\nexport const MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT = 100_000;\nexport const MAX_SEARCH_CONSOLE_EXPORT_FILES = 20;\nconst IMPORT_LABEL = 'Search Console export';\nconst QUERY_TABLE_HEADERS = new Set(['top queries', 'query', 'queries']);\nconst PAGE_TABLE_HEADERS = new Set(['top pages', 'page', 'pages', 'url']);\nconst CLICKS_ALIASES = ['clicks', 'url clicks'];\nconst IMPRESSIONS_ALIASES = ['impressions'];\nconst CTR_ALIASES = ['ctr', 'url ctr', 'site ctr'];\nconst POSITION_ALIASES = [\n 'position',\n 'average position',\n 'avg position',\n 'avg. position',\n];\nconst CAVEATS = [\n 'Query and page tables are separate aggregates from a Search Console export; no query-to-page mapping exists and none was created.',\n 'Search Console exports are partial: anonymised queries are withheld and export row caps apply, so missing rows are not zeros.',\n];\nfunction exportRowLimit(value) {\n const result = value ?? DEFAULT_SEARCH_CONSOLE_EXPORT_ROW_LIMIT;\n if (!Number.isSafeInteger(result) ||\n result < 1 ||\n result > MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT) {\n throw new SeoError('INVALID_INPUT', `Search Console export row limit must be between 1 and ${MAX_SEARCH_CONSOLE_EXPORT_ROW_LIMIT}.`);\n }\n return result;\n}\nasync function exportCsvPaths(input) {\n const path = resolve(input);\n const target = await stat(path).catch(() => undefined);\n if (!target) {\n throw new SeoError('INVALID_INPUT', `Search Console export path was not found: ${path}`);\n }\n if (target.isFile())\n return [path];\n if (!target.isDirectory()) {\n throw new SeoError('INVALID_INPUT', `Search Console export path must be a CSV file or a directory: ${path}`);\n }\n const entries = await readdir(path, { withFileTypes: true });\n const files = entries\n .filter((entry) => {\n if (!entry.isFile())\n return false;\n const extension = extname(entry.name).toLowerCase();\n return extension === '.csv' || extension === '.tsv';\n })\n .map((entry) => join(path, entry.name))\n .sort(compareText);\n if (files.length === 0) {\n throw new SeoError('INVALID_INPUT', `Search Console export directory contains no CSV files: ${path}`);\n }\n if (files.length > MAX_SEARCH_CONSOLE_EXPORT_FILES) {\n throw new SeoError('INVALID_INPUT', `Search Console export directories can contain at most ${MAX_SEARCH_CONSOLE_EXPORT_FILES} CSV files.`);\n }\n return files;\n}\nfunction normalizedHeader(value) {\n return value\n .replace(/^\\uFEFF/u, '')\n .trim()\n .toLowerCase();\n}\nfunction metricIndex(headers, aliases) {\n for (const alias of aliases) {\n const index = headers.indexOf(alias);\n if (index > 0)\n return index;\n }\n return null;\n}\nfunction countValue(cell) {\n const trimmed = (cell ?? '').trim();\n if (!trimmed)\n return null;\n if (!/^\\d+(?:,\\d{3})*$/u.test(trimmed))\n return null;\n const parsed = Number(trimmed.replaceAll(',', ''));\n return Number.isSafeInteger(parsed) ? parsed : null;\n}\nfunction ctrValue(cell) {\n const trimmed = (cell ?? '').trim();\n if (!trimmed)\n return null;\n if (trimmed.endsWith('%')) {\n const parsed = Number(trimmed.slice(0, -1).trim());\n if (!Number.isFinite(parsed))\n return null;\n const fraction = parsed / 100;\n return fraction >= 0 && fraction <= 1 ? fraction : null;\n }\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : null;\n}\nfunction positionValue(cell) {\n const trimmed = (cell ?? '').trim();\n if (!trimmed)\n return null;\n const parsed = Number(trimmed);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : null;\n}\nfunction absoluteHttpUrl(value) {\n let parsed;\n try {\n parsed = new URL(value);\n }\n catch {\n return null;\n }\n return parsed.protocol === 'http:' || parsed.protocol === 'https:'\n ? value\n : null;\n}\nfunction compareText(left, right) {\n return left < right ? -1 : left > right ? 1 : 0;\n}\nfunction keepImportedRow(candidate, existing) {\n if (candidate.impressions !== existing.impressions) {\n return candidate.impressions > existing.impressions;\n }\n return candidate.clicks > existing.clicks;\n}\nfunction compareQueryRows(left, right) {\n return (right.clicks - left.clicks ||\n right.impressions - left.impressions ||\n compareText(left.query, right.query));\n}\nfunction comparePageRows(left, right) {\n return (right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n compareText(left.url, right.url));\n}\nfunction tableOutput(state, compare, rowLimit) {\n const sorted = [...state.byKey.values()].sort(compare);\n const capped = state.capped || sorted.length > rowLimit;\n return {\n rows: sorted.slice(0, rowLimit),\n totalRows: sorted.length,\n capped,\n };\n}\nexport async function loadSearchConsoleExport(input) {\n const rowLimit = exportRowLimit(input.rowLimit);\n const paths = await exportCsvPaths(input.path);\n const files = [];\n const warnings = [];\n const queryState = {\n byKey: new Map(),\n suppliedRows: 0,\n capped: false,\n };\n const pageState = {\n byKey: new Map(),\n suppliedRows: 0,\n capped: false,\n };\n for (const path of paths) {\n const file = await importFile({\n file: path,\n format: 'csv',\n label: IMPORT_LABEL,\n });\n const hash = createHash('sha256');\n const progress = { bytesRead: 0, hash };\n const records = csvRecords({\n path: file.path,\n byteLimit: DEFAULT_IMPORT_STREAM_BYTES,\n progress,\n label: IMPORT_LABEL,\n });\n const first = await records.next();\n const rawHeaders = Array.isArray(first.value) ? first.value : [];\n const headers = rawHeaders.map((value, index) => (index === 0 ? value.replace(/^\\uFEFF/u, '') : value).trim());\n const normalizedHeaders = headers.map(normalizedHeader);\n const firstHeader = normalizedHeaders[0] ?? '';\n const table = QUERY_TABLE_HEADERS.has(firstHeader)\n ? 'queries'\n : PAGE_TABLE_HEADERS.has(firstHeader)\n ? 'pages'\n : 'unrecognized';\n const headerReason = table === 'unrecognized'\n ? headers.length === 0\n ? 'The file has no header row.'\n : `The first header \"${headers[0]}\" is not a recognized Search Console query or page column.`\n : undefined;\n const clicksIndex = metricIndex(normalizedHeaders, CLICKS_ALIASES);\n const impressionsIndex = metricIndex(normalizedHeaders, IMPRESSIONS_ALIASES);\n const ctrIndex = metricIndex(normalizedHeaders, CTR_ALIASES);\n const positionIndex = metricIndex(normalizedHeaders, POSITION_ALIASES);\n const missingRequiredFields = [\n ...(clicksIndex === null ? ['Clicks'] : []),\n ...(impressionsIndex === null ? ['Impressions'] : []),\n ];\n const reason = headerReason ??\n (missingRequiredFields.length\n ? `The recognized ${table} table is missing required ${missingRequiredFields.join(' and ')} columns.`\n : undefined);\n const usable = table !== 'unrecognized' && reason === undefined;\n let fileRows = 0;\n let suppliedRows = 0;\n let validRows = 0;\n let invalidRows = 0;\n let duplicateRows = 0;\n const tableState = table === 'queries' ? queryState : pageState;\n for await (const values of records) {\n fileRows += 1;\n if (!usable)\n continue;\n if (tableState.suppliedRows >= rowLimit)\n continue;\n suppliedRows += 1;\n tableState.suppliedRows += 1;\n if (values.length !== headers.length) {\n invalidRows += 1;\n continue;\n }\n const clicks = countValue(values[clicksIndex ?? -1]);\n const impressions = countValue(values[impressionsIndex ?? -1]);\n if (clicks === null || impressions === null) {\n invalidRows += 1;\n continue;\n }\n const ctrCell = ctrIndex === null ? '' : (values[ctrIndex] ?? '').trim();\n const positionCell = positionIndex === null ? '' : (values[positionIndex] ?? '').trim();\n const ctr = ctrIndex === null ? null : ctrValue(ctrCell);\n const position = positionIndex === null ? null : positionValue(positionCell);\n if ((ctrCell && ctr === null) || (positionCell && position === null)) {\n invalidRows += 1;\n continue;\n }\n const metrics = {\n clicks,\n impressions,\n ctr,\n position,\n };\n const key = (values[0] ?? '').trim();\n if (table === 'queries') {\n if (!key) {\n invalidRows += 1;\n continue;\n }\n const existing = queryState.byKey.get(key);\n if (existing) {\n duplicateRows += 1;\n if (keepImportedRow(metrics, existing)) {\n queryState.byKey.set(key, { query: key, ...metrics });\n }\n continue;\n }\n validRows += 1;\n queryState.byKey.set(key, { query: key, ...metrics });\n continue;\n }\n const url = absoluteHttpUrl(key);\n if (!url) {\n invalidRows += 1;\n continue;\n }\n const existing = pageState.byKey.get(url);\n if (existing) {\n duplicateRows += 1;\n if (keepImportedRow(metrics, existing)) {\n pageState.byKey.set(url, { url, ...metrics });\n }\n continue;\n }\n validRows += 1;\n pageState.byKey.set(url, { url, ...metrics });\n }\n const capped = usable && fileRows > suppliedRows;\n if (capped) {\n if (table === 'queries')\n queryState.capped = true;\n else\n pageState.capped = true;\n warnings.push(`Only ${suppliedRows} of ${fileRows} rows in ${file.path} were processed within the shared ${table} row limit of ${rowLimit}.`);\n }\n if (reason) {\n warnings.push(`Skipped ${file.path}: ${reason ?? 'the file was not recognized.'}`);\n }\n if (invalidRows > 0) {\n warnings.push(`${invalidRows} row${invalidRows === 1 ? '' : 's'} in ${file.path} ${invalidRows === 1 ? 'was' : 'were'} invalid and skipped.`);\n }\n files.push({\n path: file.path,\n table,\n sha256: hash.digest('hex'),\n fileBytes: file.fileBytes,\n bytesRead: progress.bytesRead,\n encoding: progress.encoding ?? 'utf-8',\n delimiter: progress.delimiter ?? null,\n includedFields: [...headers].sort(compareText),\n fileRows,\n suppliedRows,\n validRows,\n invalidRows,\n duplicateRows,\n capped,\n rowLimit,\n ...(reason === undefined ? {} : { reason }),\n });\n }\n if (files.every((file) => file.table === 'unrecognized')) {\n warnings.push('No file matched the Search Console query or page table headers, so no rows were imported.');\n }\n return {\n source: 'search-console-export',\n exportedAt: input.exportedAt?.toISOString() ?? null,\n importedAt: (input.now ?? new Date()).toISOString(),\n files,\n queries: tableOutput(queryState, compareQueryRows, rowLimit),\n pages: tableOutput(pageState, comparePageRows, rowLimit),\n warnings,\n caveats: [\n ...CAVEATS,\n input.exportedAt\n ? 'exportedAt was supplied by the caller and is not verified from the file; importedAt records when the local files were loaded.'\n : 'The export time is unavailable unless supplied separately; importedAt records when the local files were loaded, not when Search Console produced them.',\n ],\n };\n}\n//# sourceMappingURL=local-export.js.map","import { SeoError } from '../errors.js';\nexport const DEFAULT_UNREACHED_PAGE_LIMIT = 100;\nfunction unreachedLimit(value) {\n const result = value ?? DEFAULT_UNREACHED_PAGE_LIMIT;\n if (!Number.isSafeInteger(result) || result < 1) {\n throw new SeoError('INVALID_INPUT', 'Unreached-page limit must be a positive integer.');\n }\n return result;\n}\nfunction normalizedPath(value) {\n let parsed;\n try {\n parsed = new URL(value);\n }\n catch {\n return null;\n }\n const pathname = parsed.pathname !== '/' && parsed.pathname.endsWith('/')\n ? parsed.pathname.slice(0, -1)\n : parsed.pathname;\n return `${pathname}${parsed.search}`;\n}\nfunction compareText(left, right) {\n return left < right ? -1 : left > right ? 1 : 0;\n}\nfunction compareUnreached(left, right) {\n return (right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n compareText(left.url, right.url));\n}\nexport function reconcileExportPagesWithCrawl(input) {\n const limit = unreachedLimit(input.limit);\n const crawledPaths = new Set();\n for (const url of input.crawledUrls) {\n const path = normalizedPath(url);\n if (path !== null)\n crawledPaths.add(path);\n }\n const origins = new Set();\n let matchedPages = 0;\n const unreached = [];\n for (const page of input.pages) {\n let parsed;\n try {\n parsed = new URL(page.url);\n }\n catch {\n continue;\n }\n origins.add(parsed.origin);\n const path = normalizedPath(page.url);\n if (path !== null && crawledPaths.has(path))\n matchedPages += 1;\n else\n unreached.push(page);\n }\n unreached.sort(compareUnreached);\n const exportOrigins = [...origins].sort(compareText);\n return {\n joinBasis: 'path',\n crawlOrigin: input.crawlOrigin,\n exportOrigins,\n originMismatch: exportOrigins.some((origin) => origin !== input.crawlOrigin),\n matchedPages,\n unreachedPages: unreached.slice(0, limit),\n unreachedCount: unreached.length,\n capped: unreached.length > limit,\n };\n}\n//# sourceMappingURL=local-export-reconcile.js.map","export function parseOlderThan(input) {\n if (!input) {\n return undefined;\n }\n const match = input.trim().match(/^(\\d+)([smhdw])$/i);\n if (!match) {\n throw new Error(`Invalid duration \"${input}\". Use values like 7d, 12h, 30m.`);\n }\n const valuePart = match[1];\n const unitPart = match[2];\n if (!valuePart || !unitPart) {\n throw new Error(`Invalid duration \"${input}\".`);\n }\n const value = Number.parseInt(valuePart, 10);\n const unit = unitPart.toLowerCase();\n const multipliers = {\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n w: 604_800_000,\n };\n const multiplier = multipliers[unit];\n if (!multiplier) {\n throw new Error(`Unsupported duration unit in \"${input}\".`);\n }\n return value * multiplier;\n}\nexport function formatRelativeExpiry(expiresAt) {\n const delta = expiresAt - Date.now();\n if (delta <= 0) {\n return 'expired';\n }\n const minutes = Math.round(delta / 60_000);\n if (minutes < 60) {\n return `in ${minutes}m`;\n }\n const hours = Math.floor(minutes / 60);\n const remMinutes = minutes % 60;\n return remMinutes ? `in ${hours}h ${remMinutes}m` : `in ${hours}h`;\n}\nexport function isoDate(daysAgo = 0) {\n const date = new Date();\n date.setUTCDate(date.getUTCDate() - daysAgo);\n return date.toISOString().slice(0, 10);\n}\n//# sourceMappingURL=time.js.map","import { readFile } from 'node:fs/promises'\nimport { type JavaScriptRenderingMode, SeoError } from '@seo/core'\nimport type { BooleanArgDef } from 'citty'\n\nexport function defaultTrueBooleanArg(\n description: string,\n negativeDescription: string,\n): BooleanArgDef {\n return {\n type: 'boolean',\n default: true,\n description,\n negativeDescription,\n }\n}\n\nexport function stringArg(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined\n}\n\nexport function projectArg(args: Record<string, unknown>): string | undefined {\n const project = stringArg(args.project)\n const client = stringArg(args.client)\n if (project && client && project !== client) {\n throw new Error('Use either --project or --client, not both.')\n }\n return project ?? client\n}\n\nexport function booleanArg(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined\n}\n\n/**\n * `--js` remains an alias for `--rendering on` while callers move to the\n * explicit modes. A mode is returned even when neither flag was supplied so\n * commands can pass it straight to the core API.\n */\nexport function renderingModeArg(\n args: Record<string, unknown>,\n): JavaScriptRenderingMode {\n const rendering = stringArg(args.rendering)\n if (\n rendering !== undefined &&\n rendering !== 'auto' &&\n rendering !== 'on' &&\n rendering !== 'off'\n ) {\n throw new SeoError('INVALID_INPUT', '--rendering must be auto, on, or off.')\n }\n if (booleanArg(args.js) === true && rendering && rendering !== 'on') {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --js or --rendering on, not both with different modes.',\n )\n }\n return rendering ?? (booleanArg(args.js) ? 'on' : 'auto')\n}\n\nexport function negatedBooleanArg(\n args: Record<string, unknown>,\n name: string,\n): boolean | undefined {\n const positive = booleanArg(args[name])\n if (positive === false) return true\n if (positive === true) return false\n const camelPositive = booleanArg(args[toCamelCase(name)])\n if (camelPositive === false) return true\n if (camelPositive === true) return false\n const explicitNo = booleanArg(args[`no-${name}`])\n if (explicitNo === true) return true\n const camelNo = booleanArg(args[`no${toPascalCase(name)}`])\n if (camelNo === true) return true\n return undefined\n}\n\nfunction toCamelCase(value: string): string {\n return value.replace(/-([a-z])/g, (_, letter: string) => letter.toUpperCase())\n}\n\nfunction toPascalCase(value: string): string {\n const camel = toCamelCase(value)\n return camel ? `${camel[0]?.toUpperCase()}${camel.slice(1)}` : ''\n}\n\nexport function numberArg(value: unknown): number | undefined {\n if (typeof value === 'number') return value\n if (typeof value !== 'string' || !value.trim()) return undefined\n const parsed = Number(value)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nexport function strictNumberArg(\n value: unknown,\n label: string,\n): number | undefined {\n if (value === undefined || value === '') return undefined\n const parsed = numberArg(value)\n if (parsed === undefined)\n throw new SeoError('INVALID_INPUT', `${label} must be a number.`)\n return parsed\n}\n\nexport function csvArg(value: unknown): string[] | undefined {\n if (typeof value !== 'string') return undefined\n const items = value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean)\n return items.length ? items : undefined\n}\n\nexport function listArg(value: unknown): string[] {\n return csvArg(value) ?? []\n}\n\nexport function fetchRateArg(args: Record<string, unknown>):\n | {\n concurrency?: number\n intervalCap?: number\n intervalMs?: number\n }\n | undefined {\n const rate = {\n concurrency: numberArg(args['fetch-concurrency']),\n intervalCap: numberArg(args['fetch-interval-cap']),\n intervalMs: numberArg(args['fetch-interval-ms']),\n }\n return Object.values(rate).some((value) => value !== undefined)\n ? rate\n : undefined\n}\n\nexport function strictFetchRateArg(args: Record<string, unknown>):\n | {\n concurrency?: number\n intervalCap?: number\n intervalMs?: number\n }\n | undefined {\n const rate = {\n concurrency: strictNumberArg(\n args['fetch-concurrency'],\n '--fetch-concurrency',\n ),\n intervalCap: strictNumberArg(\n args['fetch-interval-cap'],\n '--fetch-interval-cap',\n ),\n intervalMs: strictNumberArg(\n args['fetch-interval-ms'],\n '--fetch-interval-ms',\n ),\n }\n return Object.values(rate).some((value) => value !== undefined)\n ? rate\n : undefined\n}\n\nexport function jsonFlag(args: Record<string, unknown>): boolean {\n return args.json === true\n}\n\nexport async function jsonBodyArg(\n value: unknown,\n fileValue: unknown,\n): Promise<Record<string, unknown> | undefined> {\n const inline = stringArg(value)\n const file = stringArg(fileValue)\n if (inline && file) {\n throw new Error('Use either --body or --body-file, not both.')\n }\n if (!inline && !file) return undefined\n const source = inline ?? (await readFile(file ?? '', 'utf8'))\n const parsed = JSON.parse(source) as unknown\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new Error('JSON body must be an object.')\n }\n return parsed as Record<string, unknown>\n}\n","import { stripVTControlCharacters } from 'node:util'\nimport pc from 'picocolors'\nimport stringWidth from 'string-width'\n\nconst DEFAULT_COLUMNS = 80\nconst MIN_COLUMNS = 40\nconst MAX_COLUMNS = 200\n\nexport type TerminalContext = {\n columns: number\n colors: ReturnType<typeof pc.createColors>\n hasColor: boolean\n isInteractive: boolean\n}\n\nexport type TerminalContextOptions = {\n columns?: number\n color?: boolean\n env?: NodeJS.ProcessEnv\n isTTY?: boolean\n streamColumns?: number\n}\n\nfunction parsedColumns(value: number | string | undefined): number | undefined {\n if (typeof value === 'number') {\n return Number.isFinite(value) ? Math.round(value) : undefined\n }\n if (!value) return undefined\n const parsed = Number.parseInt(value, 10)\n return Number.isFinite(parsed) ? parsed : undefined\n}\n\nexport function resolveTerminalColumns(\n options: TerminalContextOptions = {},\n): number {\n const env = options.env ?? process.env\n const requested =\n parsedColumns(options.columns) ??\n parsedColumns(options.streamColumns) ??\n parsedColumns(env.COLUMNS) ??\n DEFAULT_COLUMNS\n return Math.min(MAX_COLUMNS, Math.max(MIN_COLUMNS, requested))\n}\n\nexport function createTerminalContext(\n options: TerminalContextOptions = {},\n): TerminalContext {\n const env = options.env ?? process.env\n const isTTY = options.isTTY ?? Boolean(process.stdout.isTTY)\n const hasColor = options.color ?? Boolean(isTTY && env.NO_COLOR === undefined)\n return {\n columns: resolveTerminalColumns({\n ...options,\n env,\n streamColumns: options.streamColumns ?? process.stdout.columns,\n }),\n colors: pc.createColors(hasColor),\n hasColor,\n isInteractive: isTTY && !env.CI,\n }\n}\n\nexport function visibleWidth(value: string): number {\n return stringWidth(stripVTControlCharacters(value))\n}\n\nfunction splitToken(token: string, width: number): string[] {\n const chunks: string[] = []\n let chunk = ''\n for (const character of token) {\n if (chunk && visibleWidth(`${chunk}${character}`) > width) {\n chunks.push(chunk)\n chunk = character\n } else {\n chunk += character\n }\n }\n if (chunk) chunks.push(chunk)\n return chunks\n}\n\nfunction wrapLine(value: string, width: number): string[] {\n if (!value) return ['']\n const words = value.trim().split(/\\s+/u)\n const lines: string[] = []\n let line = ''\n\n for (const word of words) {\n const pieces = visibleWidth(word) > width ? splitToken(word, width) : [word]\n for (const piece of pieces) {\n if (!line) {\n line = piece\n } else if (visibleWidth(`${line} ${piece}`) <= width) {\n line += ` ${piece}`\n } else {\n lines.push(line)\n line = piece\n }\n }\n }\n if (line) lines.push(line)\n return lines.length > 0 ? lines : ['']\n}\n\nexport function wrapText(value: string, width: number): string[] {\n const safeWidth = Math.max(1, width)\n return value\n .replaceAll('\\r\\n', '\\n')\n .split('\\n')\n .flatMap((line) => wrapLine(line, safeWidth))\n}\n\nexport function truncateText(value: string, width: number): string {\n if (visibleWidth(value) <= width) return value\n const suffix = '...'\n const available = Math.max(1, width - visibleWidth(suffix))\n let result = ''\n for (const character of value) {\n if (visibleWidth(`${result}${character}`) > available) break\n result += character\n }\n return `${result}${suffix}`\n}\n","import Table from 'cli-table3'\nimport {\n type TerminalContext,\n truncateText,\n visibleWidth,\n wrapText,\n} from './context.js'\n\nexport type TerminalCell = string | number\nexport type TerminalRow = TerminalCell[]\n\ntype TableOptions = {\n layout?: 'auto' | 'records' | 'table'\n rowNumbers?: boolean\n}\n\ntype Callout = {\n body?: string\n command?: string\n title: string\n}\n\nconst borderlessChars = {\n top: '',\n 'top-mid': '',\n 'top-left': '',\n 'top-right': '',\n bottom: '',\n 'bottom-mid': '',\n 'bottom-left': '',\n 'bottom-right': '',\n left: '',\n 'left-mid': '',\n mid: '',\n 'mid-mid': '',\n right: '',\n 'right-mid': '',\n middle: '',\n}\n\nfunction stringCell(value: TerminalCell | undefined): string {\n return value === undefined ? '' : String(value)\n}\n\nfunction naturalColumnWidths(head: string[], rows: TerminalRow[]): number[] {\n return head.map((label, column) => {\n const values = rows.map((row) => stringCell(row[column]))\n return Math.min(\n 42,\n Math.max(visibleWidth(label), ...values.map(visibleWidth), 4),\n )\n })\n}\n\nfunction canRenderTable(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n): boolean {\n if (head.length === 0 || head.length > 4) return false\n const numericColumns = head.map((_, column) =>\n rows.every((row) =>\n /^-?(?:\\d+(?:\\.\\d+)?|\\d+(?:\\.\\d+)?%)$/u.test(\n stringCell(row[column]).trim(),\n ),\n ),\n )\n if (!numericColumns.some(Boolean)) return false\n const widths = naturalColumnWidths(head, rows)\n const tableWidth = widths.reduce((total, width) => total + width + 2, 0)\n return tableWidth <= context.columns\n}\n\nfunction styledValue(\n label: string,\n value: string,\n context: TerminalContext,\n): string {\n if (!/(?:status|state|assessment|data|allowed)/iu.test(label)) return value\n const normalized = value.trim().toLowerCase()\n if (['pass', 'passed', 'completed', 'allowed', 'yes'].includes(normalized)) {\n return context.colors.green(value)\n }\n if (['warn', 'warning', 'review', 'partial'].includes(normalized)) {\n return context.colors.yellow(value)\n }\n if (['fail', 'failed', 'blocked', 'no'].includes(normalized)) {\n return context.colors.red(value)\n }\n if (['unknown', 'unavailable'].includes(normalized)) {\n return context.colors.blue(value)\n }\n return value\n}\n\nfunction renderDenseTable(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n): string {\n const widths = naturalColumnWidths(head, rows).map((width) => width + 2)\n const table = new Table({\n chars: borderlessChars,\n colWidths: widths,\n head: head.map((label) => context.colors.bold(label)),\n style: {\n border: [],\n head: [],\n 'padding-left': 0,\n 'padding-right': 2,\n },\n wordWrap: false,\n })\n for (const row of rows) {\n table.push(\n head.map((label, column) =>\n wrapText(\n styledValue(label, stringCell(row[column]), context),\n Math.max(1, (widths[column] ?? 3) - 2),\n ).join('\\n'),\n ),\n )\n }\n return table.toString()\n}\n\nfunction renderRecordValue(\n label: string,\n value: string,\n labelWidth: number,\n context: TerminalContext,\n): string[] {\n const gap = 2\n const valueWidth = context.columns - labelWidth - gap\n if (valueWidth < 24) {\n return [\n context.colors.dim(label),\n ...wrapText(value, context.columns - 2).map((line) => ` ${line}`),\n ]\n }\n const wrapped = wrapText(value, valueWidth)\n return wrapped.map((line, index) => {\n const prefix =\n index === 0 ? label.padEnd(labelWidth) : ''.padEnd(labelWidth)\n return `${context.colors.dim(prefix)}${' '.repeat(gap)}${line}`\n })\n}\n\nexport function renderRecords(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n options: { rowNumbers?: boolean } = {},\n): string {\n const labelWidth = Math.min(\n 28,\n Math.max(...head.map((label) => visibleWidth(label)), 0),\n )\n const showNumbers = options.rowNumbers ?? false\n const digits = String(rows.length).length\n const blocks = rows.map((row, index) => {\n const lines: string[] = []\n if (showNumbers) {\n lines.push(context.colors.bold(String(index + 1).padStart(digits, '0')))\n }\n for (const [column, label] of head.entries()) {\n lines.push(\n ...renderRecordValue(\n label,\n styledValue(label, stringCell(row[column]), context),\n labelWidth,\n context,\n ),\n )\n }\n return lines.join('\\n')\n })\n return blocks.join('\\n\\n')\n}\n\nexport function renderTable(\n head: string[],\n rows: TerminalRow[],\n context: TerminalContext,\n options: TableOptions = {},\n): string {\n if (rows.length === 0) return context.colors.dim('No results.')\n const useTable =\n options.layout === 'table' ||\n (options.layout !== 'records' && canRenderTable(head, rows, context))\n return useTable\n ? renderDenseTable(head, rows, context)\n : renderRecords(head, rows, context, options)\n}\n\nexport function renderKeyValues(\n rows: Array<[string, string]>,\n context: TerminalContext,\n): string {\n if (rows.length === 0) return ''\n const labelWidth = Math.min(\n 28,\n Math.max(...rows.map(([label]) => visibleWidth(label))),\n )\n return rows\n .flatMap(([label, value]) => {\n const lines = renderRecordValue(label, value, labelWidth, context)\n if (lines.length > 0) {\n const first = lines[0] ?? ''\n lines[0] = first.replace(label, context.colors.bold(label))\n }\n return lines\n })\n .join('\\n')\n}\n\nexport function renderCallout(\n callout: Callout,\n context: TerminalContext,\n): string {\n const lines = [context.colors.bold(callout.title)]\n if (callout.body) lines.push(...wrapText(callout.body, context.columns))\n if (callout.command) {\n lines.push(\n context.colors.cyan(truncateText(callout.command, context.columns)),\n )\n }\n return lines.join('\\n')\n}\n","import { type TerminalContext, wrapText } from './context.js'\n\nexport type SemanticStatus =\n | 'pass'\n | 'warning'\n | 'fail'\n | 'unknown'\n | 'info'\n | 'notApplicable'\n\nexport type SemanticDiagnostic = {\n status: SemanticStatus\n title: string\n explanation: string\n fix?: string\n evidence?: string[]\n}\n\nexport type SemanticReportSection = {\n title: string\n diagnostics: SemanticDiagnostic[]\n}\n\nexport type SemanticReportView = {\n title: string\n target?: string\n status: SemanticStatus\n summary: string\n metrics?: Array<{\n label: string\n value: string | number\n status?: SemanticStatus\n }>\n sections: SemanticReportSection[]\n notes?: string[]\n}\n\nfunction statusStyle(status: SemanticStatus, context: TerminalContext) {\n if (status === 'pass') return context.colors.green\n if (status === 'warning') return context.colors.yellow\n if (status === 'fail') return context.colors.red\n if (status === 'unknown') return context.colors.blue\n if (status === 'info') return context.colors.cyan\n return context.colors.dim\n}\n\nfunction statusLabel(status: SemanticStatus): string {\n if (status === 'warning') return 'WARN'\n if (status === 'notApplicable') return 'N/A'\n return status.toUpperCase()\n}\n\nfunction indent(value: string, spaces: number, width: number): string[] {\n const prefix = ' '.repeat(spaces)\n return wrapText(value, Math.max(1, width - spaces)).map(\n (line) => `${prefix}${line}`,\n )\n}\n\nfunction renderDiagnostic(\n diagnostic: SemanticDiagnostic,\n context: TerminalContext,\n): string {\n const style = statusStyle(diagnostic.status, context)\n const label = style(`[${statusLabel(diagnostic.status)}]`.padEnd(10))\n const titleWidth = Math.max(1, context.columns - 10)\n const titles = wrapText(diagnostic.title, titleWidth)\n const lines = titles.map(\n (line, index) =>\n `${index === 0 ? label : ' '.repeat(10)}${context.colors.bold(line)}`,\n )\n lines.push(...indent(diagnostic.explanation, 10, context.columns))\n for (const item of diagnostic.evidence ?? []) {\n const wrapped = wrapText(item, Math.max(1, context.columns - 20))\n lines.push(\n ...wrapped.map(\n (line, index) =>\n `${' '.repeat(10)}${index === 0 ? `${context.colors.dim('Evidence')} ` : ' '}${line}`,\n ),\n )\n }\n if (diagnostic.fix) {\n const wrapped = wrapText(diagnostic.fix, Math.max(1, context.columns - 15))\n lines.push(\n ...wrapped.map(\n (line, index) =>\n `${' '.repeat(10)}${index === 0 ? `${context.colors.cyan(context.colors.bold('Fix'))} ` : ' '}${line}`,\n ),\n )\n }\n return lines.join('\\n')\n}\n\nfunction renderMetrics(\n metrics: NonNullable<SemanticReportView['metrics']>,\n context: TerminalContext,\n): string {\n const line = metrics\n .map((metric) => {\n const value = String(metric.value)\n const rendered = metric.status\n ? statusStyle(metric.status, context)(value)\n : context.colors.bold(value)\n return `${metric.label} ${rendered}`\n })\n .join(context.colors.dim(' · '))\n return wrapText(line, context.columns).join('\\n')\n}\n\nexport function renderSemanticReport(\n report: SemanticReportView,\n context: TerminalContext,\n): string {\n const style = statusStyle(report.status, context)\n const output = [context.colors.bold(report.title)]\n if (report.target) output.push(context.colors.dim(report.target))\n output.push('')\n output.push(\n `${style(statusLabel(report.status))} ${wrapText(report.summary, Math.max(1, context.columns - 6)).join('\\n ')}`,\n )\n if (report.metrics?.length)\n output.push(renderMetrics(report.metrics, context))\n\n for (const section of report.sections.filter(\n (item) => item.diagnostics.length > 0,\n )) {\n output.push('', context.colors.bold(section.title))\n output.push(\n section.diagnostics\n .map((diagnostic) => renderDiagnostic(diagnostic, context))\n .join('\\n\\n'),\n )\n }\n\n if (report.notes?.length) {\n output.push('', context.colors.bold('Notes'))\n for (const note of report.notes) {\n const lines = wrapText(note, Math.max(1, context.columns - 2))\n output.push(\n ...lines.map((line, index) => `${index === 0 ? '- ' : ' '}${line}`),\n )\n }\n }\n return output.join('\\n')\n}\n","import { type TerminalContext, visibleWidth, wrapText } from './context.js'\n\nexport type CheckView = {\n detail: string\n fix?: string\n label: string\n status: 'pass' | 'warn' | 'fail'\n}\n\nexport type CatalogItemView = {\n category: string\n id: string\n name: string\n}\n\nexport type SummaryItemView = {\n description?: string\n meta?: string[]\n title: string\n}\n\nexport type ParameterView = {\n description?: string\n name: string\n required: boolean\n type: string\n}\n\nfunction plural(count: number, singular: string, multiple = `${singular}s`) {\n return count === 1 ? singular : multiple\n}\n\nfunction indented(value: string, indent: number, width: number): string[] {\n const prefix = ' '.repeat(indent)\n return wrapText(value, Math.max(1, width - indent)).map(\n (line) => `${prefix}${line}`,\n )\n}\n\nexport function renderHeading(\n title: string,\n context: TerminalContext,\n summary?: string,\n): string {\n return [\n context.colors.bold(title),\n ...(summary ? wrapText(summary, context.columns) : []),\n ].join('\\n')\n}\n\nexport function renderChecks(\n checks: CheckView[],\n context: TerminalContext,\n): string {\n const styles = {\n pass: context.colors.green,\n warn: context.colors.yellow,\n fail: context.colors.red,\n }\n return checks\n .map((check) => {\n const status = styles[check.status](check.status.toUpperCase().padEnd(4))\n const lines = [`${status} ${context.colors.bold(check.label)}`]\n lines.push(...indented(check.detail, 6, context.columns))\n if (check.fix) {\n const fixLines = wrapText(check.fix, Math.max(1, context.columns - 11))\n lines.push(\n ...fixLines.map(\n (line, index) =>\n `${' '.repeat(6)}${index === 0 ? `${context.colors.bold('Fix')} ` : ' '}${line}`,\n ),\n )\n }\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\nexport function checkSummary(checks: CheckView[]): string {\n const passed = checks.filter((check) => check.status === 'pass').length\n const warnings = checks.filter((check) => check.status === 'warn').length\n const failed = checks.filter((check) => check.status === 'fail').length\n return `${passed} ${plural(passed, 'check')} passed, ${warnings} ${plural(warnings, 'warning')}, ${failed} failed.`\n}\n\nfunction renderCatalogItem(\n item: CatalogItemView,\n idWidth: number,\n context: TerminalContext,\n): string {\n const gap = 2\n const nameWidth = context.columns - idWidth - gap - 2\n if (nameWidth < 24 || visibleWidth(item.id) > idWidth) {\n return [\n ...indented(item.id, 2, context.columns).map((line) =>\n context.colors.cyan(line),\n ),\n ...indented(item.name, 4, context.columns),\n ].join('\\n')\n }\n const names = wrapText(item.name, nameWidth)\n return names\n .map((name, index) => {\n const id = index === 0 ? item.id.padEnd(idWidth) : ''.padEnd(idWidth)\n return ` ${context.colors.cyan(id)}${' '.repeat(gap)}${name}`\n })\n .join('\\n')\n}\n\nfunction categoryLabel(category: string): string {\n const value = category.replaceAll('-', ' ')\n return value.charAt(0).toUpperCase() + value.slice(1)\n}\n\nexport function renderCatalog(\n items: CatalogItemView[],\n context: TerminalContext,\n options: {\n categoryLabels?: Record<string, string>\n noun: string\n },\n): string {\n const groups = new Map<string, CatalogItemView[]>()\n for (const item of items) {\n const group = groups.get(item.category) ?? []\n group.push(item)\n groups.set(item.category, group)\n }\n const intro = `${items.length} ${plural(items.length, options.noun)} across ${groups.size} ${plural(groups.size, 'category', 'categories')}.`\n const idWidth = Math.min(\n 30,\n Math.max(...items.map((item) => visibleWidth(item.id)), 0),\n )\n const labelledCategories = Object.keys(options.categoryLabels ?? {}).filter(\n (category) => groups.has(category),\n )\n const remainingCategories = [...groups.keys()].filter(\n (category) => !labelledCategories.includes(category),\n )\n const sections = [...labelledCategories, ...remainingCategories].map(\n (category) => {\n const entries = groups.get(category) ?? []\n const label =\n options.categoryLabels?.[category] ?? categoryLabel(category)\n return [\n context.colors.bold(`${label} (${entries.length})`),\n ...entries.map((item) => renderCatalogItem(item, idWidth, context)),\n ].join('\\n')\n },\n )\n return [intro, ...sections].join('\\n\\n')\n}\n\nexport function renderSummaryList(\n items: SummaryItemView[],\n context: TerminalContext,\n options: { empty: string },\n): string {\n if (items.length === 0) return context.colors.dim(options.empty)\n\n return items\n .map((item) => {\n const lines = [context.colors.bold(item.title)]\n if (item.description) {\n lines.push(...indented(item.description, 2, context.columns))\n }\n const meta = item.meta?.filter(Boolean).join(' · ')\n if (meta) {\n lines.push(\n ...indented(meta, 2, context.columns).map((line) =>\n context.colors.dim(line),\n ),\n )\n }\n return lines.join('\\n')\n })\n .join('\\n\\n')\n}\n\nexport function renderSection(\n title: string,\n paragraphs: readonly string[],\n context: TerminalContext,\n): string {\n const body = paragraphs\n .filter((paragraph) => paragraph.trim().length > 0)\n .flatMap((paragraph) => wrapText(paragraph, context.columns))\n return [context.colors.bold(title), ...body].join('\\n')\n}\n\nexport function renderBulletSection(\n title: string,\n items: readonly string[],\n context: TerminalContext,\n): string {\n const body = items.flatMap((item) => {\n const wrapped = wrapText(item, Math.max(1, context.columns - 2))\n return wrapped.map((line, index) => `${index === 0 ? '- ' : ' '}${line}`)\n })\n return [context.colors.bold(title), ...body].join('\\n')\n}\n\nexport function renderParameters(\n parameters: ParameterView[],\n context: TerminalContext,\n): string {\n if (parameters.length === 0) {\n return context.colors.dim('No parameters.')\n }\n\n return renderSummaryList(\n parameters.map((parameter) => ({\n title: parameter.name,\n description: parameter.description,\n meta: [parameter.type, parameter.required ? 'required' : 'optional'],\n })),\n context,\n { empty: 'No parameters.' },\n )\n}\n","import { createTerminalContext } from './presentation/context.js'\nimport {\n renderCallout,\n renderKeyValues,\n renderTable,\n} from './presentation/render.js'\nimport {\n renderSemanticReport,\n type SemanticReportView,\n} from './presentation/report.js'\nimport {\n type CatalogItemView,\n type CheckView,\n type ParameterView,\n renderBulletSection,\n renderCatalog,\n renderChecks,\n renderHeading,\n renderParameters,\n renderSection,\n renderSummaryList,\n type SummaryItemView,\n} from './presentation/views.js'\n\nexport function canPrompt(options: { json?: boolean } = {}): boolean {\n return Boolean(\n !options.json &&\n process.stdin.isTTY &&\n process.stdout.isTTY &&\n !process.env.CI,\n )\n}\n\nexport function printJson(data: unknown): void {\n process.stdout.write(`${JSON.stringify(data, null, 2)}\\n`)\n}\n\nexport function printKeyValue(rows: Array<[string, string]>): void {\n const output = renderKeyValues(rows, createTerminalContext())\n if (output) process.stdout.write(`${output}\\n`)\n}\n\nexport function printTable(\n head: string[],\n rows: Array<Array<string | number>>,\n): void {\n process.stdout.write(`${renderTable(head, rows, createTerminalContext())}\\n`)\n}\n\nexport function printCallout(callout: {\n body?: string\n command?: string\n title: string\n}): void {\n process.stdout.write(`${renderCallout(callout, createTerminalContext())}\\n`)\n}\n\nexport function printHeading(title: string, summary?: string): void {\n process.stdout.write(\n `${renderHeading(title, createTerminalContext(), summary)}\\n`,\n )\n}\n\nexport function printChecks(checks: CheckView[]): void {\n process.stdout.write(`${renderChecks(checks, createTerminalContext())}\\n`)\n}\n\nexport function printSemanticReport(report: SemanticReportView): void {\n process.stdout.write(\n `${renderSemanticReport(report, createTerminalContext())}\\n`,\n )\n}\n\nexport function printCatalog(\n items: CatalogItemView[],\n options: {\n categoryLabels?: Record<string, string>\n noun: string\n },\n): void {\n process.stdout.write(\n `${renderCatalog(items, createTerminalContext(), options)}\\n`,\n )\n}\n\nexport function printSummaryList(\n items: SummaryItemView[],\n options: { empty: string },\n): void {\n process.stdout.write(\n `${renderSummaryList(items, createTerminalContext(), options)}\\n`,\n )\n}\n\nexport function printSection(title: string, ...paragraphs: string[]): void {\n process.stdout.write(\n `${renderSection(title, paragraphs, createTerminalContext())}\\n`,\n )\n}\n\nexport function printBulletSection(\n title: string,\n items: readonly string[],\n): void {\n process.stdout.write(\n `${renderBulletSection(title, items, createTerminalContext())}\\n`,\n )\n}\n\nexport function printParameters(parameters: ParameterView[]): void {\n process.stdout.write(\n `${renderParameters(parameters, createTerminalContext())}\\n`,\n )\n}\n\nexport function formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nexport function maybeExitCancelled<T>(value: T | symbol): T {\n if (typeof value === 'symbol') {\n process.exit(1)\n }\n return value\n}\n","import { type Option, select, text } from '@clack/prompts'\nimport {\n type ClientProfile,\n ga4PropertyIdFromName,\n getClient,\n listClients,\n listGa4AccountSummaries,\n listSites,\n readConfig,\n SeoError,\n selectGoogleAccounts,\n} from '@seo/core'\nimport { canPrompt, maybeExitCancelled } from './utils.js'\n\ntype ResolveOptions = {\n allowDefault?: boolean\n json?: boolean\n refresh?: boolean\n account?: string\n}\n\ntype SiteChoice = {\n siteUrl: string\n permissionLevel?: string\n}\n\ntype GoogleAnalyticsPropertyChoice = {\n property: string\n displayName: string\n account: string\n}\n\nexport type ClientSelection = {\n client?: ClientProfile\n site: string\n}\n\nfunction selectClientGoogleAccounts(client: ClientProfile | undefined): void {\n selectGoogleAccounts(client?.googleAccounts)\n}\n\nfunction includesQuery(values: string[], query: string): boolean {\n const normalized = query.trim().toLowerCase()\n if (!normalized) return true\n return values.some((value) => value.toLowerCase().includes(normalized))\n}\n\nasync function chooseFromSearch<T>(input: {\n message: string\n searchMessage: string\n emptyMessage: string\n choices: T[]\n label: (choice: T) => string\n hint?: (choice: T) => string | undefined\n searchValues: (choice: T) => string[]\n}): Promise<T> {\n let visible = input.choices\n\n if (input.choices.length > 8) {\n const query = maybeExitCancelled(\n await text({\n message: input.searchMessage,\n placeholder: 'Type part of the name or URL, or leave blank',\n }),\n )\n visible = input.choices.filter((choice) =>\n includesQuery(input.searchValues(choice), query),\n )\n\n if (!visible.length) {\n throw new SeoError('INVALID_INPUT', input.emptyMessage)\n }\n }\n\n return maybeExitCancelled(\n await select({\n message: input.message,\n options: visible.map((choice) => {\n const hint = input.hint?.(choice)\n return {\n value: choice,\n label: input.label(choice),\n ...(hint ? { hint } : {}),\n }\n }) as Option<T>[],\n }),\n )\n}\n\nexport async function resolveSite(input: {\n site?: string\n options?: ResolveOptions\n}): Promise<string> {\n if (input.site) return input.site\n\n const config = readConfig()\n const defaultSiteKnown =\n Boolean(config.defaultSite) &&\n (config.clients.some((client) => client.siteUrl === config.defaultSite) ||\n config.sites.some((site) => site.siteUrl === config.defaultSite))\n if (\n input.options?.allowDefault !== false &&\n config.defaultSite &&\n defaultSiteKnown\n ) {\n selectClientGoogleAccounts(\n config.clients.find(\n (client) => client.isDefault && client.siteUrl === config.defaultSite,\n ),\n )\n return config.defaultSite\n }\n\n if (input.options?.json || !canPrompt()) {\n throw new SeoError(\n 'INVALID_INPUT',\n config.defaultSite\n ? `Saved default site ${config.defaultSite} does not match any saved project. Pass --site or --project, or run \\`seo start\\` to save a new default.`\n : 'No site selected. Pass --site, use --project on supported commands, or run `seo start` in a terminal.',\n )\n }\n\n const sites = await listSites(input.options?.refresh, input.options?.account)\n if (!sites.length) {\n throw new SeoError(\n 'PROPERTY_NOT_FOUND',\n 'No Search Console properties found for this Google login.',\n )\n }\n if (sites.length === 1) {\n return sites[0]?.siteUrl ?? ''\n }\n\n const choice = await chooseFromSearch<SiteChoice>({\n message: 'Choose a Search Console property',\n searchMessage: 'Search Search Console properties',\n emptyMessage: 'No Search Console properties matched that search.',\n choices: sites,\n label: (site) => site.siteUrl,\n hint: (site) => site.permissionLevel,\n searchValues: (site) => [site.siteUrl, site.permissionLevel ?? ''],\n })\n\n return choice.siteUrl\n}\n\nexport async function resolveClientSelection(input: {\n client?: string\n project?: string\n site?: string\n options?: ResolveOptions\n}): Promise<ClientSelection> {\n if (input.client && input.project && input.client !== input.project) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --project or --client, not both.',\n )\n }\n const project = input.project ?? input.client\n if (project) {\n const client = getClient(project)\n if (!client) {\n throw new SeoError('INVALID_INPUT', `Project not found: ${project}`)\n }\n selectClientGoogleAccounts(client)\n return { client, site: client.siteUrl }\n }\n\n const defaultClient = getClient()\n if (!input.site && defaultClient) {\n selectClientGoogleAccounts(defaultClient)\n return { client: defaultClient, site: defaultClient.siteUrl }\n }\n\n return {\n site: await resolveSite({ site: input.site, options: input.options }),\n }\n}\n\nexport async function resolveClient(input: {\n client?: string\n project?: string\n options?: ResolveOptions\n}): Promise<ClientProfile | undefined> {\n if (input.client && input.project && input.client !== input.project) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --project or --client, not both.',\n )\n }\n const project = input.project ?? input.client\n if (project) {\n const client = getClient(project)\n if (!client) {\n throw new SeoError('INVALID_INPUT', `Project not found: ${project}`)\n }\n selectClientGoogleAccounts(client)\n return client\n }\n\n const clients = listClients()\n if (!clients.length) return undefined\n const defaultClient = getClient()\n if (defaultClient) {\n selectClientGoogleAccounts(defaultClient)\n return defaultClient\n }\n\n if (input.options?.json || !canPrompt()) return undefined\n\n const selected = await chooseFromSearch<ClientProfile>({\n message: 'Choose a project',\n searchMessage: 'Search projects',\n emptyMessage: 'No projects matched that search.',\n choices: clients,\n label: (client) => client.name,\n hint: (client) => client.siteUrl,\n searchValues: (client) => [client.id, client.name, client.siteUrl],\n })\n selectClientGoogleAccounts(selected)\n return selected\n}\n\nexport async function resolveGoogleAnalyticsProperty(input: {\n property?: string\n options?: ResolveOptions\n}): Promise<string> {\n if (input.property) return input.property\n\n const config = readConfig()\n if (config.analytics.google.defaultPropertyId) {\n return config.analytics.google.defaultPropertyId\n }\n\n if (input.options?.json || !canPrompt()) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'No Google Analytics property selected. Pass --property or run this command in a terminal to choose one.',\n )\n }\n\n const accountSummaries = await listGa4AccountSummaries(input.options?.account)\n const choices = accountSummaries.flatMap((account) =>\n account.propertySummaries.map((property) => ({\n property: ga4PropertyIdFromName(property.property),\n displayName: property.displayName ?? property.property,\n account: account.displayName ?? account.account,\n })),\n )\n\n if (!choices.length) {\n throw new SeoError(\n 'PROPERTY_NOT_FOUND',\n 'No Google Analytics properties found for this Google login.',\n )\n }\n if (choices.length === 1) {\n return choices[0]?.property ?? ''\n }\n\n const choice = await chooseFromSearch<GoogleAnalyticsPropertyChoice>({\n message: 'Choose a Google Analytics property',\n searchMessage: 'Search Google Analytics properties',\n emptyMessage: 'No Google Analytics properties matched that search.',\n choices,\n label: (property) => `${property.displayName} (${property.property})`,\n hint: (property) => property.account,\n searchValues: (property) => [\n property.property,\n property.displayName,\n property.account,\n ],\n })\n\n return choice.property\n}\n","import { confirm, intro, note, outro, password, text } from '@clack/prompts'\nimport {\n analyticsConnection,\n CLICKY_SITEKEY_ENV,\n deleteClickySiteKey,\n deleteProviderExtensionCredentials,\n inspectProviderPackage,\n installProviderPackage,\n loadInstalledProviderExtensions,\n type RegisteredProviderExtension,\n readClickySiteKey,\n readProviderExtensionCredentials,\n removeClientAnalyticsConnection,\n runProviderExtensionAction,\n SeoError,\n setClientAnalyticsConnection,\n verifyAnalyticsProvider,\n writeClickySiteKey,\n writeProviderExtensionAccount,\n writeProviderExtensionCredentials,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../../args.js'\nimport { resolveClient } from '../../../selection.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n printTable,\n} from '../../../utils.js'\n\nconst CLICKY_PROVIDER_PACKAGE = '@seoskill/clicky-provider'\n\nfunction credentialSourceLabel(source: string | undefined): string {\n if (source === 'keychain') return 'system keychain'\n if (source === 'file') return 'private local file'\n if (source === 'provider-store') return 'provider credential store'\n return source ?? 'missing'\n}\n\nasync function clickyProvider(input: {\n json?: boolean\n}): Promise<RegisteredProviderExtension> {\n let loaded = await loadInstalledProviderExtensions()\n const installed = loaded.registry.get('clicky')\n if (installed) return installed\n const failure = loaded.failures.find((item) => item.id === 'clicky')\n if (failure) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n `The Clicky provider package could not load: ${failure.message}`,\n )\n }\n const interactive = canPrompt({ json: input.json })\n if (!interactive) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n `Clicky is now an optional provider package. Run \\`seo providers install ${CLICKY_PROVIDER_PACKAGE} --yes\\`, then run this command again.`,\n )\n }\n let release: Awaited<ReturnType<typeof inspectProviderPackage>>\n try {\n release = await inspectProviderPackage(CLICKY_PROVIDER_PACKAGE)\n } catch (error) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n error instanceof Error ? error.message : String(error),\n )\n }\n note(\n [\n `${release.package}@${release.version}`,\n `Publisher: ${release.publisher ?? 'not supplied by npm'}`,\n `Repository: ${release.repository ?? 'not supplied by npm'}`,\n `Integrity: ${release.integrity}`,\n ].join('\\n'),\n 'Clicky package',\n )\n note(\n 'This package can read files, use the network, and run with the same local permissions as seo.',\n 'Local permissions',\n )\n const approved = maybeExitCancelled(\n await confirm({\n message: 'Install the Clicky provider package?',\n initialValue: true,\n }),\n )\n if (!approved) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider package is required for this command.',\n )\n }\n await installProviderPackage(release)\n loaded = await loadInstalledProviderExtensions()\n const provider = loaded.registry.get('clicky')\n if (!provider) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider package was installed but could not load. Run `seo providers doctor`.',\n )\n }\n return provider\n}\n\nasync function resolveClickySiteId(input: {\n siteId?: string\n project?: string\n json?: boolean\n}): Promise<string> {\n if (input.siteId) return input.siteId\n const client = await resolveClient({\n client: input.project,\n options: { json: input.json },\n })\n const connection = analyticsConnection(client)\n if (connection?.provider === 'clicky') return connection.siteId\n if (\n connection?.provider === 'extension' &&\n connection.providerId === 'clicky' &&\n connection.account.siteId\n ) {\n return connection.account.siteId\n }\n throw new SeoError(\n 'INVALID_INPUT',\n 'No Clicky site is selected. Pass --site-id or use a project connected to Clicky.',\n )\n}\n\nasync function savedCredentials(\n provider: RegisteredProviderExtension,\n siteId: string,\n): Promise<{ siteKey?: string; source?: string }> {\n const legacy = await readClickySiteKey(siteId)\n if (legacy) return { siteKey: legacy.siteKey, source: legacy.source }\n try {\n const credentials = await readProviderExtensionCredentials({\n providerId: 'clicky',\n account: { siteId },\n fields: provider.connection.fields,\n })\n return credentials.sitekey\n ? { siteKey: credentials.sitekey, source: 'provider-store' }\n : {}\n } catch {\n return {}\n }\n}\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save a Clicky sitekey',\n },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const provider = await clickyProvider({ json })\n const interactive = canPrompt({ json })\n const requestedProject = projectArg(args)\n const project = requestedProject\n ? await resolveClient({ project: requestedProject, options: { json } })\n : undefined\n if (interactive) intro('Connect Clicky')\n const currentConnection = analyticsConnection(project)\n const currentSiteId =\n currentConnection?.provider === 'clicky'\n ? currentConnection.siteId\n : currentConnection?.provider === 'extension' &&\n currentConnection.providerId === 'clicky'\n ? currentConnection.account.siteId\n : undefined\n const siteId =\n stringArg(args['site-id']) ??\n currentSiteId ??\n (interactive\n ? maybeExitCancelled(\n await text({\n message: 'Clicky site ID',\n validate: (value) =>\n /^\\d{1,30}$/u.test(value?.trim() ?? '')\n ? undefined\n : 'Enter the numeric site ID from Clicky',\n }),\n )\n : undefined)\n if (!siteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass --site-id when the selected project is not already connected to Clicky.',\n )\n }\n const existing = await savedCredentials(provider, siteId)\n const siteKey =\n existing.siteKey ??\n (interactive\n ? maybeExitCancelled(\n await password({\n message: 'Clicky sitekey',\n validate: (value) =>\n /^[A-Za-z0-9]{12,64}$/u.test(value?.trim() ?? '')\n ? undefined\n : 'Enter the sitekey from Clicky',\n }),\n )\n : undefined)\n if (!siteKey) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run this command in a terminal or set ${CLICKY_SITEKEY_ENV}.`,\n )\n }\n await verifyAnalyticsProvider({\n providerId: 'clicky',\n account: { siteId },\n credentials: { sitekey: siteKey },\n })\n const source =\n existing.source ?? (await writeClickySiteKey(siteId, siteKey))\n await writeProviderExtensionCredentials({\n providerId: 'clicky',\n account: { siteId },\n credentials: { sitekey: siteKey },\n })\n writeProviderExtensionAccount('clicky', { siteId })\n const savedProject = project\n ? setClientAnalyticsConnection(project.id, {\n provider: 'extension',\n providerId: 'clicky',\n account: { siteId },\n })\n : undefined\n const result = {\n siteId,\n connected: true,\n credentialSource: source,\n project: savedProject\n ? { id: savedProject.id, name: savedProject.name }\n : undefined,\n }\n if (json) {\n printJson(result)\n return\n }\n const message = savedProject\n ? `Connection verified and attached to ${savedProject.name}. Saved in the ${credentialSourceLabel(source)}.`\n : `Connection verified. Saved in the ${credentialSourceLabel(source)}.`\n if (interactive) outro(message)\n else process.stdout.write(`${message}\\n`)\n },\n})\n\nconst statusCommand = defineCommand({\n meta: { name: 'status', description: 'Show the local Clicky connection' },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n check: {\n type: 'boolean',\n default: false,\n description: 'Verify the saved sitekey with Clicky.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const provider = await clickyProvider({ json })\n const siteId = await resolveClickySiteId({\n siteId: stringArg(args['site-id']),\n project: projectArg(args),\n json,\n })\n const credential = await savedCredentials(provider, siteId)\n const check = booleanArg(args.check)\n if (check && credential.siteKey) {\n await verifyAnalyticsProvider({\n providerId: 'clicky',\n account: { siteId },\n credentials: { sitekey: credential.siteKey },\n })\n }\n const result = {\n siteId,\n connected: Boolean(credential.siteKey),\n credentialSource: credential.source,\n liveCheck: check\n ? credential.siteKey\n ? ('passed' as const)\n : ('unavailable' as const)\n : ('not-requested' as const),\n }\n if (json) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Site ID', siteId],\n ['Connected', result.connected ? 'yes' : 'no'],\n ['Credential', credentialSourceLabel(result.credentialSource)],\n ['Live check', result.liveCheck],\n ])\n },\n})\n\nconst reportCommand = defineCommand({\n meta: {\n name: 'report',\n description: 'Run a bounded Clicky analytics report',\n },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n type: {\n type: 'string',\n default: 'pages-entrance',\n description: 'Clicky report type. Defaults to pages-entrance.',\n },\n 'start-date': {\n type: 'string',\n required: true,\n description: 'First site calendar date in YYYY-MM-DD format.',\n },\n 'end-date': {\n type: 'string',\n required: true,\n description: 'Last site calendar date in YYYY-MM-DD format.',\n },\n limit: {\n type: 'string',\n default: '100',\n description: 'Maximum retained rows. Defaults to 100 and caps at 5000.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local Clicky cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const provider = await clickyProvider({ json })\n const siteId = await resolveClickySiteId({\n siteId: stringArg(args['site-id']),\n project: projectArg(args),\n json,\n })\n const credential = await savedCredentials(provider, siteId)\n const action = await runProviderExtensionAction({\n providerId: 'clicky',\n actionId: 'report',\n account: { siteId },\n ...(credential.siteKey\n ? { credentials: { sitekey: credential.siteKey } }\n : {}),\n params: {\n type: stringArg(args.type) ?? 'pages-entrance',\n startDate: stringArg(args['start-date']) ?? '',\n endDate: stringArg(args['end-date']) ?? '',\n limit: numberArg(args.limit) ?? 100,\n },\n refresh: booleanArg(args.refresh),\n })\n if (!action.data || typeof action.data !== 'object') {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider returned an invalid report.',\n )\n }\n const result = {\n ...(action.data as Record<string, unknown>),\n cache: action.cache,\n } as {\n siteId: string\n type: string\n rows: Array<Record<string, unknown>>\n returnedRows: number\n cache: string\n }\n if (json) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Site ID', result.siteId],\n ['Report', result.type],\n ['Rows', String(result.returnedRows)],\n ['Cache', result.cache],\n ])\n printTable(\n ['Value', 'Title', 'URL'],\n result.rows\n .slice(0, 25)\n .map((row) => [\n String(row.value ?? ''),\n String(row.title ?? ''),\n String(row.url ?? ''),\n ]),\n )\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: { name: 'disconnect', description: 'Remove a saved Clicky sitekey' },\n args: {\n 'site-id': { type: 'string', description: 'Numeric Clicky site ID.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n await clickyProvider({ json })\n const siteId = await resolveClickySiteId({\n siteId: stringArg(args['site-id']),\n project: projectArg(args),\n json,\n })\n await deleteClickySiteKey(siteId)\n await deleteProviderExtensionCredentials({\n providerId: 'clicky',\n account: { siteId },\n })\n const environmentCredential = Boolean(process.env[CLICKY_SITEKEY_ENV])\n const result = {\n siteId,\n savedCredentialRemoved: true,\n environmentCredential: environmentCredential ? 'active' : 'missing',\n }\n if (json) printJson(result)\n else\n process.stdout.write(\n environmentCredential\n ? `Saved sitekey removed. ${CLICKY_SITEKEY_ENV} is still active.\\n`\n : 'Clicky is disconnected for this site.\\n',\n )\n },\n})\n\nconst detachCommand = defineCommand({\n meta: {\n name: 'detach',\n description: 'Remove Clicky from one project without deleting its sitekey',\n },\n args: {\n project: {\n type: 'string',\n required: true,\n description: 'Saved project id or name.',\n },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = await resolveClient({\n project: projectArg(args),\n options: { json },\n })\n const selected = analyticsConnection(project)\n const provider =\n selected?.provider === 'extension' && selected.providerId === 'clicky'\n ? ('extension:clicky' as const)\n : selected?.provider === 'clicky'\n ? ('clicky' as const)\n : undefined\n if (!project || !provider) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'The selected project is not attached to Clicky.',\n )\n }\n const updated = removeClientAnalyticsConnection(project.id, provider)\n const result = {\n project: { id: updated.id, name: updated.name },\n detached: true,\n selectedAnalytics: updated.analytics.selected,\n savedSitekey: true,\n }\n if (json) printJson(result)\n else\n process.stdout.write(\n `Clicky detached from ${updated.name}. The saved sitekey was kept.\\n`,\n )\n },\n})\n\nexport const clickyAnalyticsCommand = defineCommand({\n meta: {\n name: 'clicky',\n description: 'Connect Clicky and read bounded analytics reports',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n report: reportCommand,\n detach: detachCommand,\n disconnect: disconnectCommand,\n },\n})\n","import {\n ga4PropertyIdFromName,\n listGa4AccountSummaries,\n readConfig,\n writeConfig,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson, printTable } from '../../../utils.js'\n\nexport const googleAnalyticsPropertiesCommand = defineCommand({\n meta: {\n name: 'properties',\n description: 'List Google Analytics accounts and properties',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n save: {\n type: 'string',\n description:\n 'Save this numeric Google Analytics property ID as the default.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n },\n run: async ({ args }) => {\n const summaries = await listGa4AccountSummaries(stringArg(args.account))\n const rows = summaries.flatMap((account) =>\n account.propertySummaries.map((property) => ({\n account: account.displayName ?? account.account,\n property: ga4PropertyIdFromName(property.property),\n displayName: property.displayName ?? property.property,\n })),\n )\n\n const save = stringArg(args.save)\n if (save) {\n const config = readConfig()\n config.analytics.google.defaultPropertyId = save\n writeConfig(config)\n }\n\n if (jsonFlag(args)) {\n printJson({ accountSummaries: summaries, properties: rows, saved: save })\n return\n }\n if (save) {\n process.stdout.write(`Saved default Google Analytics property ${save}.\\n`)\n }\n printTable(\n ['Property', 'Name', 'Account'],\n rows.map((row) => [row.property, row.displayName, row.account]),\n )\n },\n})\n","import { truncateText } from '../presentation/context.js'\nimport type {\n SemanticDiagnostic,\n SemanticReportView,\n SemanticStatus,\n} from '../presentation/report.js'\nimport { printSemanticReport, printTable } from '../utils.js'\n\nconst HUMAN_ROW_LIMIT = 25\ntype TableRow = Array<string | number>\ntype ActionDetail = {\n label: string\n action: string\n context?: string\n}\n\ntype ReportMetric = {\n label: string\n value: string | number\n status?: SemanticStatus\n}\n\ntype ReportSummary = {\n title: string\n target?: string\n status: SemanticStatus\n summary: string\n metrics?: ReportMetric[]\n diagnostics?: {\n title: string\n items: SemanticDiagnostic[]\n }[]\n notes?: string[]\n}\n\nexport function formatCount(value: number): string {\n return Math.round(value).toLocaleString('en-GB')\n}\n\nexport function formatPosition(value: number): string {\n return value.toFixed(1)\n}\n\nexport function formatPercent(value: number): string {\n return `${(value * 100).toFixed(1)}%`\n}\n\nexport function truncate(value: string, maxLength = 72): string {\n return truncateText(value, maxLength)\n}\n\nexport function verificationSummary(report: {\n verification?: { requested: boolean; verified: number; failed: number }\n}): string {\n if (!report.verification?.requested) return 'off'\n return `${report.verification.verified} checked, ${report.verification.failed} failed`\n}\n\nexport function reportSummaryView(summary: ReportSummary): SemanticReportView {\n return {\n title: summary.title,\n target: summary.target,\n status: summary.status,\n summary: summary.summary,\n metrics: summary.metrics,\n sections: (summary.diagnostics ?? []).map((section) => ({\n title: section.title,\n diagnostics: section.items,\n })),\n notes: summary.notes,\n }\n}\n\nexport function printReportSummary(summary: ReportSummary): void {\n printSemanticReport(reportSummaryView(summary))\n}\n\nexport function printLimitedTable(head: string[], rows: TableRow[]): void {\n printTable(head, rows.slice(0, HUMAN_ROW_LIMIT))\n if (rows.length > HUMAN_ROW_LIMIT) {\n process.stdout.write(\n `Showing ${HUMAN_ROW_LIMIT} of ${rows.length}. Use --json for full data.\\n`,\n )\n }\n}\n\nexport function printActionDetails(\n title: string,\n actions: ActionDetail[],\n limit = 5,\n): void {\n const visible = actions\n .filter((item) => item.action.trim().length > 0)\n .slice(0, limit)\n const report = actionDetailsView(title, visible)\n if (!report) return\n\n process.stdout.write('\\n')\n printSemanticReport(report)\n if (actions.length > visible.length) {\n process.stdout.write(\n `Showing ${visible.length} of ${actions.length}. Use --json for full data.\\n`,\n )\n }\n}\n\nexport function actionDetailsView(\n title: string,\n actions: ActionDetail[],\n): SemanticReportView | undefined {\n if (!actions.length) return undefined\n return {\n title,\n status: 'info',\n summary: `${actions.length} ${actions.length === 1 ? 'action' : 'actions'} shown.`,\n sections: [\n {\n title: 'Actions',\n diagnostics: actions.map((item) => ({\n status: 'info',\n title: item.label,\n explanation:\n item.context ?? 'Review the evidence before making changes.',\n fix: item.action,\n })),\n },\n ],\n }\n}\n\nexport function printNextCommand(command: string): void {\n process.stdout.write(`\\nNext: ${command}\\n`)\n}\n\nexport function printNotes(title: string, notes: string[]): void {\n const visible = notes.filter((note) => note.trim().length > 0)\n if (!visible.length) return\n process.stdout.write(`\\n${title}\\n`)\n for (const note of visible) {\n process.stdout.write(`- ${note}\\n`)\n }\n}\n","import {\n ga4RowsToObjects,\n googleAnalyticsPropertyId,\n runGa4Report,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonBodyArg,\n jsonFlag,\n projectArg,\n stringArg,\n} from '../../../args.js'\nimport {\n resolveClient,\n resolveGoogleAnalyticsProperty,\n} from '../../../selection.js'\nimport { printJson, printTable } from '../../../utils.js'\nimport { printReportSummary } from '../../output.js'\n\ntype GoogleAnalyticsPropertySelectionDependencies = {\n resolveClient: typeof resolveClient\n resolveGoogleAnalyticsProperty: typeof resolveGoogleAnalyticsProperty\n}\n\nexport async function resolveGoogleAnalyticsReportProperty(\n input: {\n property?: string\n project?: string\n options?: { json?: boolean; account?: string }\n },\n dependencies: GoogleAnalyticsPropertySelectionDependencies = {\n resolveClient,\n resolveGoogleAnalyticsProperty,\n },\n): Promise<string> {\n if (input.property) {\n return dependencies.resolveGoogleAnalyticsProperty({\n property: input.property,\n options: input.options,\n })\n }\n\n const client = await dependencies.resolveClient({\n client: input.project,\n options: input.options,\n })\n return dependencies.resolveGoogleAnalyticsProperty({\n property: googleAnalyticsPropertyId(client),\n options: input.options,\n })\n}\n\nexport const googleAnalyticsReportCommand = defineCommand({\n meta: {\n name: 'report',\n description: 'Run a Google Analytics report',\n },\n args: {\n property: {\n type: 'string',\n description:\n 'Google Analytics property ID. If omitted in a terminal, choose one.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description:\n 'Saved project id or name with an optional Google Analytics property.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n 'start-date': { type: 'string', default: '28daysAgo' },\n 'end-date': { type: 'string', default: 'yesterday' },\n dimensions: { type: 'string', default: 'landingPage' },\n metrics: { type: 'string', default: 'sessions,totalUsers,eventCount' },\n limit: { type: 'string', default: '25' },\n body: { type: 'string' },\n 'body-file': { type: 'string' },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local Google Analytics cache.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const property = await resolveGoogleAnalyticsReportProperty({\n property: stringArg(args.property),\n project: projectArg(args),\n options: { json, account: stringArg(args.account) },\n })\n const body =\n (await jsonBodyArg(args.body, args['body-file'])) ??\n ({\n dateRanges: [\n {\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n },\n ],\n dimensions: (csvArg(args.dimensions) ?? []).map((name) => ({ name })),\n metrics: (csvArg(args.metrics) ?? []).map((name) => ({ name })),\n limit: stringArg(args.limit),\n } as Record<string, unknown>)\n const result = await runGa4Report(property, body as never, {\n refresh: booleanArg(args.refresh),\n accountEmail: stringArg(args.account),\n })\n if (json) {\n printJson(result)\n return\n }\n const rows = ga4RowsToObjects(result)\n printReportSummary({\n title: 'Google Analytics report',\n target: property,\n status: 'info',\n summary: `${result.rowCount ?? rows.length} rows returned for the requested dimensions and metrics.`,\n metrics: [\n { label: 'Rows', value: result.rowCount ?? rows.length },\n { label: 'Displayed', value: Math.min(rows.length, 25) },\n ],\n })\n if (rows.length) {\n const headings = Object.keys(rows[0] ?? {})\n printTable(\n headings,\n rows\n .slice(0, 25)\n .map((row) => headings.map((heading) => row[heading] ?? '')),\n )\n }\n },\n})\n","import { defineCommand } from 'citty'\nimport { googleAnalyticsPropertiesCommand } from './properties.js'\nimport { googleAnalyticsReportCommand } from './report.js'\n\nexport const googleAnalyticsCommand = defineCommand({\n meta: {\n name: 'google',\n description: 'Read Google Analytics properties and reports',\n },\n subCommands: {\n properties: googleAnalyticsPropertiesCommand,\n report: googleAnalyticsReportCommand,\n },\n})\n","import { defineCommand } from 'citty'\nimport { clickyAnalyticsCommand } from './clicky/index.js'\nimport { googleAnalyticsCommand } from './google/index.js'\n\nexport const analyticsCommand = defineCommand({\n meta: {\n name: 'analytics',\n description: 'Read analytics data from connected providers',\n },\n subCommands: {\n clicky: clickyAnalyticsCommand,\n google: googleAnalyticsCommand,\n },\n})\n","import { note } from '@clack/prompts'\nimport { loginWithLoopback, type StoredTokens } from '@seo/core'\n\nexport function googleLoginGuidance(): string {\n return 'Your browser will open. Choose your Google account and select all permission boxes for read-only access. Keep this terminal open and finish the browser steps within five minutes.'\n}\n\nexport async function loginWithGuidance(): Promise<StoredTokens> {\n note(googleLoginGuidance(), 'Google sign-in')\n return loginWithLoopback()\n}\n","import { intro, note, outro, password, text } from '@clack/prompts'\nimport {\n authStatus,\n deleteTokens,\n formatRelativeExpiry,\n getSeoCliPaths,\n getTokenStorageStatus,\n listGoogleAccounts,\n readTokens,\n refreshAuthToken,\n SeoError,\n setActiveGoogleAccount,\n setTokenStorageMode,\n writeOauthClient,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n} from '../utils.js'\nimport { loginWithGuidance } from './google-login.js'\n\nfunction serviceAccountSource(source?: string): string {\n if (!source) return 'invalid or conflicting configuration'\n if (source === 'environment-json') {\n return 'SEO_GOOGLE_SERVICE_ACCOUNT_JSON'\n }\n if (source === 'environment-file') {\n return 'SEO_GOOGLE_SERVICE_ACCOUNT_FILE'\n }\n return 'GOOGLE_APPLICATION_CREDENTIALS'\n}\n\nfunction tokenStorageLabel(input: {\n configured: 'keychain' | 'file'\n active: 'keychain' | 'file'\n reason?: string\n}): string {\n if (input.active === 'keychain') return 'system keychain'\n return input.configured === 'keychain'\n ? 'private file fallback'\n : 'private file'\n}\n\nfunction oauthClientLabel(source: 'shared' | 'byo'): string {\n return source === 'shared' ? 'SEO Skill app' : 'Local OAuth config'\n}\n\nfunction oauthIdentityRows(input: {\n accountEmail: string\n clientSource: 'shared' | 'byo'\n expiresAt: number\n scope: string\n}): Array<[string, string]> {\n const rows: Array<[string, string]> = [['Account', input.accountEmail]]\n const scopes = new Set(input.scope.split(/\\s+/u).filter(Boolean))\n\n if (scopes.has('https://www.googleapis.com/auth/webmasters.readonly')) {\n rows.push(['Search Console', 'Read only'])\n } else {\n rows.push(['Search Console', 'Not granted'])\n }\n if (scopes.has('https://www.googleapis.com/auth/analytics.readonly')) {\n rows.push(['Google Analytics', 'Read only'])\n } else {\n rows.push(['Google Analytics', 'Not granted'])\n }\n rows.push(\n ['OAuth app', oauthClientLabel(input.clientSource)],\n ['Expires', formatRelativeExpiry(input.expiresAt)],\n )\n return rows\n}\n\nexport const authCommand = defineCommand({\n meta: {\n name: 'auth',\n description: 'Authentication commands',\n },\n subCommands: {\n login: defineCommand({\n meta: { name: 'login', description: 'Run Google OAuth flow' },\n run: async () => {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n throw new SeoError(\n 'AUTH_CONFIG_REQUIRED',\n 'A service account is active from the environment. Unset its credential variable before running browser OAuth.',\n )\n }\n const tokens = await loginWithGuidance()\n printKeyValue(\n oauthIdentityRows({\n accountEmail: tokens.account_email,\n clientSource: tokens.client_source,\n expiresAt: tokens.expires_at,\n scope: tokens.scope,\n }),\n )\n },\n }),\n logout: defineCommand({\n meta: { name: 'logout', description: 'Delete a local Google login' },\n args: {\n account: {\n type: 'string',\n description: 'Delete the login for this Google account.',\n },\n all: {\n type: 'boolean',\n default: false,\n description: 'Delete every saved Google login.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n const account = stringArg(args.account)\n if (account && args.all) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --account or --all, not both.',\n )\n }\n const targetAccount = args.all\n ? undefined\n : (account ??\n status.accounts.find((savedAccount) => savedAccount.active)\n ?.accountEmail)\n await deleteTokens(targetAccount)\n if (status.activeMode === 'service-account') {\n process.stdout.write(\n `${args.all ? 'Deleted all local Google logins.' : targetAccount ? `Deleted the local login for ${targetAccount}.` : 'No local Google login was found.'} Service account credentials remain available through the environment.\\n`,\n )\n return\n }\n process.stdout.write(\n `${args.all ? 'Deleted all local Google logins.' : targetAccount ? `Deleted the local login for ${targetAccount}.` : 'No local Google login was found.'}\\nRevoke at https://myaccount.google.com/permissions if you also want Google to forget the grant.\\n`,\n )\n },\n }),\n whoami: defineCommand({\n meta: {\n name: 'whoami',\n description: 'Show the signed-in Google account',\n },\n args: {\n account: {\n type: 'string',\n description: 'Show this saved Google account.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n const result = {\n mode: 'service-account',\n account: status.identity ?? null,\n source: serviceAccountSource(status.serviceAccount.source),\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Account type', 'Service account'],\n ['Account', status.identity ?? 'Invalid configuration'],\n ['Credentials', result.source],\n ['Access', 'Search Console and Google Analytics, read only'],\n ])\n return\n }\n const requestedAccount = stringArg(args.account)\n const tokens = requestedAccount\n ? await readTokens(requestedAccount)\n : status.tokens\n if (requestedAccount && !tokens) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${requestedAccount} is not connected.`,\n )\n }\n if (!tokens) {\n if (jsonFlag(args)) {\n printJson({ mode: 'oauth', account: null })\n return\n }\n process.stdout.write('Not logged in.\\n')\n return\n }\n if (jsonFlag(args)) {\n printJson({\n mode: 'oauth',\n account: tokens.account_email,\n scopes: tokens.scope.split(/\\s+/u).filter(Boolean),\n clientSource: tokens.client_source,\n expiresAt: tokens.expires_at,\n })\n return\n }\n printKeyValue(\n oauthIdentityRows({\n accountEmail: tokens.account_email,\n clientSource: tokens.client_source,\n expiresAt: tokens.expires_at,\n scope: tokens.scope,\n }),\n )\n },\n }),\n status: defineCommand({\n meta: {\n name: 'status',\n description: 'Show local Google auth status',\n },\n args: {\n account: {\n type: 'string',\n description: 'Show status for this saved Google account.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n const requestedAccount = stringArg(args.account)\n const selectedTokens = requestedAccount\n ? await readTokens(requestedAccount)\n : status.tokens\n if (\n requestedAccount &&\n !selectedTokens &&\n status.activeMode !== 'service-account'\n ) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${requestedAccount} is not connected.`,\n )\n }\n const storage =\n status.activeMode === 'oauth'\n ? await getTokenStorageStatus()\n : undefined\n if (jsonFlag(args)) {\n printJson({\n authenticated:\n status.activeMode === 'oauth'\n ? Boolean(selectedTokens)\n : status.serviceAccount.configured,\n mode: status.activeMode,\n identity: status.identity,\n account:\n status.activeMode === 'oauth'\n ? selectedTokens?.account_email\n : undefined,\n scopes:\n status.activeMode === 'oauth' ? selectedTokens?.scope : undefined,\n clientSource:\n status.activeMode === 'oauth'\n ? selectedTokens?.client_source\n : undefined,\n expiresAt:\n status.activeMode === 'oauth'\n ? selectedTokens?.expires_at\n : undefined,\n sharedConfigured: status.sharedConfigured,\n byoConfigured: status.byoConfigured,\n serviceAccount: {\n configured: status.serviceAccount.configured,\n identity: status.serviceAccount.identity,\n source: status.serviceAccount.source,\n error: status.serviceAccount.error,\n },\n accounts: status.accounts,\n ...(storage ? { tokenStorage: storage } : {}),\n })\n return\n }\n if (status.activeMode === 'service-account') {\n const rows: Array<[string, string]> = [\n ['Mode', 'service account'],\n ['Identity', status.identity ?? 'unavailable'],\n ['Source', serviceAccountSource(status.serviceAccount.source)],\n ['Scopes', 'Search Console readonly, Google Analytics readonly'],\n ['Storage', 'credentials stay in the environment'],\n ]\n if (status.serviceAccount.error) {\n rows.push(['Status', status.serviceAccount.error])\n }\n printKeyValue(rows)\n return\n }\n if (!selectedTokens) {\n const authMode = status.serviceAccount.error\n ? status.serviceAccount.error\n : status.sharedConfigured\n ? 'Shared seo app available'\n : status.byoConfigured\n ? 'Local OAuth config available'\n : 'No OAuth client configured'\n process.stdout.write(\n `Not logged in. ${authMode}. Run \\`seo auth login\\` to connect Google.\\n`,\n )\n return\n }\n const tokenStorage = storage ?? (await getTokenStorageStatus())\n printKeyValue([\n ['Account', selectedTokens.account_email],\n ['Connected accounts', String(status.accounts.length)],\n ['Scopes', selectedTokens.scope],\n ['Client', oauthClientLabel(selectedTokens.client_source)],\n ['Expires', formatRelativeExpiry(selectedTokens.expires_at)],\n ['Tokens file', getSeoCliPaths().tokensFile],\n ['Token storage', tokenStorageLabel(tokenStorage)],\n ...(tokenStorage.reason\n ? [['Storage note', tokenStorage.reason] as [string, string]]\n : []),\n [\n 'OAuth mode',\n status.sharedConfigured\n ? 'SEO Skill app available'\n : status.byoConfigured\n ? 'Local OAuth config available'\n : 'missing',\n ],\n ['Revoke at', 'https://myaccount.google.com/permissions'],\n ])\n },\n }),\n storage: defineCommand({\n meta: {\n name: 'storage',\n description: 'Show or change local OAuth token storage',\n },\n args: {\n keychain: {\n type: 'boolean',\n default: false,\n description:\n 'Store OAuth tokens in the system keychain when available.',\n },\n file: {\n type: 'boolean',\n default: false,\n description: 'Store OAuth tokens in the private local file.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (args.keychain && args.file) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Choose either --keychain or --file, not both.',\n )\n }\n const storage =\n args.keychain || args.file\n ? await setTokenStorageMode(args.keychain ? 'keychain' : 'file')\n : await getTokenStorageStatus()\n\n if (jsonFlag(args)) {\n printJson(storage)\n return\n }\n\n printKeyValue([\n ['Configured storage', storage.configured],\n ['Active storage', tokenStorageLabel(storage)],\n ...(storage.reason\n ? [['Note', storage.reason] as [string, string]]\n : []),\n ])\n },\n }),\n refresh: defineCommand({\n meta: {\n name: 'refresh',\n description: 'Refresh the Google OAuth token',\n },\n args: {\n account: {\n type: 'string',\n description: 'Refresh this saved Google account.',\n },\n },\n run: async ({ args }) => {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n process.stdout.write(\n 'Service accounts request short-lived Google tokens automatically. No local refresh token is stored.\\n',\n )\n return\n }\n const tokens = await refreshAuthToken(stringArg(args.account))\n process.stdout.write(\n `Refreshed. New expiry ${new Date(tokens.expires_at).toISOString()}.\\n`,\n )\n },\n }),\n accounts: defineCommand({\n meta: {\n name: 'accounts',\n description: 'List saved Google accounts',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const accounts = listGoogleAccounts()\n if (jsonFlag(args)) {\n printJson({ accounts })\n return\n }\n if (accounts.length === 0) {\n process.stdout.write('No Google accounts are connected.\\n')\n return\n }\n printKeyValue(\n accounts.map((account) => [\n account.active ? 'Active account' : 'Account',\n account.accountEmail,\n ]),\n )\n },\n }),\n use: defineCommand({\n meta: {\n name: 'use',\n description: 'Select the default Google account',\n },\n args: {\n account: {\n type: 'positional',\n required: true,\n description: 'Saved Google account email.',\n },\n },\n run: ({ args }) => {\n const account = stringArg(args.account)\n if (!account) {\n throw new SeoError('INVALID_INPUT', 'Google account is required.')\n }\n setActiveGoogleAccount(account)\n process.stdout.write(`Default Google account: ${account}\\n`)\n },\n }),\n 'setup-client': defineCommand({\n meta: {\n name: 'setup-client',\n description: 'Save your own Google Desktop OAuth client',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Return a structured error instead of prompting.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'INVALID_INPUT',\n '`seo auth setup-client` needs an interactive terminal. Run it without --json, or set SEO_GOOGLE_CLIENT_ID and SEO_GOOGLE_CLIENT_SECRET.',\n )\n }\n intro('Local Google OAuth client')\n note(\n [\n 'This is the advanced path.',\n 'Most users should use the shared seo Google app.',\n 'Your actual sensitive data is the local refresh token, not the desktop app client secret.',\n ].join('\\n'),\n 'Advanced',\n )\n const clientId = maybeExitCancelled(\n await text({\n message: 'Google Desktop OAuth client ID',\n validate: (value) => (value ? undefined : 'Client ID is required'),\n }),\n )\n const clientSecret = maybeExitCancelled(\n await password({\n message: 'Google Desktop OAuth client secret',\n validate: (value) =>\n value ? undefined : 'Client secret is required',\n }),\n )\n writeOauthClient({ clientId, clientSecret })\n outro(`Saved local OAuth config to ${getSeoCliPaths().oauthClientFile}`)\n },\n }),\n },\n})\n","import { clearCache, getCacheStats, SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { formatBytes, printKeyValue } from '../utils.js'\n\nconst CACHE_PROVIDERS = [\n 'gsc',\n 'google-analytics',\n 'dataforseo',\n 'ahrefs',\n 'clicky',\n 'http',\n] as const\n\nfunction cacheProvider(\n value: unknown,\n): (typeof CACHE_PROVIDERS)[number] | undefined {\n if (value === undefined) return undefined\n if (\n typeof value === 'string' &&\n CACHE_PROVIDERS.includes(value as (typeof CACHE_PROVIDERS)[number])\n ) {\n return value as (typeof CACHE_PROVIDERS)[number]\n }\n throw new SeoError(\n 'INVALID_INPUT',\n `--provider must be one of: ${CACHE_PROVIDERS.join(', ')}.`,\n )\n}\n\nexport const cacheCommand = defineCommand({\n meta: { name: 'cache', description: 'Cache helpers' },\n subCommands: {\n stats: defineCommand({\n meta: {\n name: 'stats',\n description: 'Show local cache size and row counts',\n },\n run: async () => {\n const stats = getCacheStats()\n printKeyValue([\n ['DB', stats.dbPath],\n ['Size', formatBytes(stats.sizeBytes)],\n [\n 'Cached data',\n `${formatBytes(stats.logicalSizeBytes)} of ${formatBytes(stats.maxSizeBytes)} automatic limit`,\n ],\n ['Sites', String(stats.counts.sites ?? 0)],\n ['Search Console', String(stats.counts.gsc_cache ?? 0)],\n [\n 'Google Analytics',\n String(stats.counts.google_analytics_cache ?? 0),\n ],\n ['DataForSEO', String(stats.counts.provider_cache ?? 0)],\n ['Ahrefs', String(stats.counts.ahrefs_cache ?? 0)],\n ['Clicky', String(stats.counts.clicky_cache ?? 0)],\n ['HTTP', String(stats.counts.http_cache ?? 0)],\n ])\n },\n }),\n clear: defineCommand({\n meta: {\n name: 'clear',\n description: 'Clear cached API and HTTP data',\n },\n args: {\n provider: {\n type: 'string',\n description:\n 'Optional cache provider: gsc, google-analytics, dataforseo, ahrefs, clicky, or http',\n },\n },\n run: async ({ args }) => {\n const removed = clearCache(cacheProvider(args.provider))\n process.stdout.write(`Removed ${removed} cached rows.\\n`)\n },\n }),\n },\n})\n","import type {\n PageFetchDiagnostics,\n QueryContentClassification,\n} from '@seo/core'\nimport { resolveClientSelection } from '../selection.js'\n\nexport async function selectedSiteOrThrow(\n input: {\n client?: string\n project?: string\n site?: string\n },\n options: { json?: boolean; refresh?: boolean; account?: string } = {},\n): Promise<string> {\n return (\n await resolveClientSelection({\n client: input.client,\n project: input.project,\n site: input.site,\n options,\n })\n ).site\n}\n\nexport function startUrlForSite(site: string): string | undefined {\n if (site.startsWith('http://') || site.startsWith('https://')) return site\n if (site.startsWith('sc-domain:')) return `https://${site.slice(10)}/`\n return undefined\n}\n\nexport function suggestedClientName(site: string): string {\n return site.replace(/^sc-domain:/, '').replace(/^https?:\\/\\//, '')\n}\n\nexport function slugId(value: string): string {\n return value\n .toLowerCase()\n .replace(/^https?:\\/\\//, '')\n .replace(/^sc-domain:/, '')\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 60)\n}\n\nexport function formatFetchDiagnostics(\n diagnostics?: PageFetchDiagnostics,\n): string {\n if (!diagnostics) return '-'\n if (diagnostics.backpressure?.status === 'stopped') {\n return `stopped: ${diagnostics.backpressure.reason ?? 'origin cooldown'}`\n }\n if (diagnostics.backpressure?.status === 'slowed') {\n return `slowed ${diagnostics.backpressure.delayMs}ms`\n }\n if (diagnostics.rendering?.status === 'unavailable') {\n return 'raw HTML; rendering unavailable'\n }\n if (diagnostics.rendering?.status === 'failed') {\n return 'raw HTML; rendering failed'\n }\n if (diagnostics.blocked) return 'blocked'\n if (diagnostics.rendered) return 'rendered'\n if (diagnostics.cache === 'hit') return 'cached'\n if (diagnostics.fetched) return 'fetched'\n return diagnostics.source\n}\n\nexport function formatContentCheck(\n classification?: QueryContentClassification,\n): string {\n if (!classification) return '-'\n if (classification === 'serp-framing') return 'wording gap'\n if (classification === 'content-gap') return 'content gap'\n if (classification === 'technical-check') return 'technical check'\n return 'covered'\n}\n","import { select } from '@clack/prompts'\nimport type { ClientProfile } from '@seo/core'\nimport { maybeExitCancelled } from '../../utils.js'\nimport { slugId } from '../shared.js'\n\nconst CREATE_PROJECT = '__create_project__'\nconst SKIP_PROJECT = '__skip_project__'\n\nexport type SetupProjectTarget =\n | { mode: 'create'; requestedId?: string }\n | { mode: 'update'; client: ClientProfile }\n | { mode: 'skip' }\n\nexport type SetupProjectOption = {\n value: string\n label: string\n hint?: string\n}\n\nexport function setupProjectOptions(\n clients: ClientProfile[],\n): SetupProjectOption[] {\n return [\n {\n value: CREATE_PROJECT,\n label: 'Create a new project',\n hint: 'Save a separate site and its data sources',\n },\n ...clients.map((client) => ({\n value: client.id,\n label: `Update ${client.name}`,\n hint: `${client.id}, ${client.siteUrl}`,\n })),\n {\n value: SKIP_PROJECT,\n label: 'Continue without a project profile',\n hint: 'Pass --site or --url when you run reports',\n },\n ]\n}\n\nexport function nextAvailableProjectId(\n name: string,\n clients: ClientProfile[],\n): string {\n const base = slugId(name)\n if (!base) throw new Error('Project id could not be derived.')\n const ids = new Set(clients.map((client) => client.id.toLowerCase()))\n if (!ids.has(base.toLowerCase())) return base\n let suffix = 2\n while (ids.has(`${base}-${suffix}`.toLowerCase())) suffix += 1\n return `${base}-${suffix}`\n}\n\nexport async function chooseSetupProjectTarget(input: {\n clients: ClientProfile[]\n interactive: boolean\n requestedId?: string\n skipProfile?: boolean\n prompt?: (options: SetupProjectOption[]) => Promise<string | symbol>\n}): Promise<SetupProjectTarget> {\n if (input.skipProfile) return { mode: 'skip' }\n if (input.requestedId) {\n const normalized = input.requestedId.toLowerCase()\n const normalizedId = slugId(input.requestedId).toLowerCase()\n const existing = input.clients.find(\n (client) =>\n client.id.toLowerCase() === normalizedId ||\n client.name.toLowerCase() === normalized,\n )\n return existing\n ? { mode: 'update', client: existing }\n : { mode: 'create', requestedId: input.requestedId }\n }\n if (!input.interactive) return { mode: 'create' }\n\n const options = setupProjectOptions(input.clients)\n const choice = maybeExitCancelled(\n await (input.prompt\n ? input.prompt(options)\n : select({\n message: 'Create a project or update an existing one?',\n options,\n })),\n )\n if (choice === CREATE_PROJECT) return { mode: 'create' }\n if (choice === SKIP_PROJECT) return { mode: 'skip' }\n const client = input.clients.find((item) => item.id === choice)\n if (!client) throw new Error(`Project not found: ${choice}`)\n return { mode: 'update', client }\n}\n","import { existsSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { dirname, join, posix, win32 } from 'node:path'\n\nexport type SupportedClient =\n | 'claude-desktop'\n | 'claude-code'\n | 'codex'\n | 'cursor'\n\ninterface BaseClientTarget {\n client: SupportedClient\n label: string\n path: string\n commandNames: string[]\n detectionPaths: string[]\n}\n\nexport interface JsonClientConfigTarget extends BaseClientTarget {\n kind: 'json'\n includeType?: boolean\n}\n\nexport interface NativeClientConfigTarget extends BaseClientTarget {\n kind: 'native'\n executable: 'codex'\n}\n\nexport type ClientConfigTarget =\n | JsonClientConfigTarget\n | NativeClientConfigTarget\n\nfunction platformConfigRoot(input: {\n home: string\n platform: NodeJS.Platform\n env: NodeJS.ProcessEnv\n}): string {\n const path = input.platform === 'win32' ? win32 : posix\n if (input.platform === 'win32') {\n return input.env.APPDATA ?? path.resolve(input.home, 'AppData/Roaming')\n }\n if (input.platform === 'darwin') {\n return path.resolve(input.home, 'Library/Application Support')\n }\n return input.env.XDG_CONFIG_HOME ?? path.resolve(input.home, '.config')\n}\n\nexport function mcpClientTargets(\n input: {\n home?: string\n platform?: NodeJS.Platform\n env?: NodeJS.ProcessEnv\n } = {},\n): ClientConfigTarget[] {\n const home = input.home ?? homedir()\n const platform = input.platform ?? process.platform\n const env = input.env ?? process.env\n const configRoot = platformConfigRoot({ home, platform, env })\n const path = platform === 'win32' ? win32 : posix\n const targets: ClientConfigTarget[] = []\n\n if (platform === 'darwin' || platform === 'win32') {\n const claudeRoot = path.resolve(configRoot, 'Claude')\n targets.push({\n kind: 'json',\n client: 'claude-desktop',\n label: 'Claude Desktop',\n path: path.resolve(claudeRoot, 'claude_desktop_config.json'),\n commandNames: [],\n detectionPaths:\n platform === 'darwin'\n ? [claudeRoot, '/Applications/Claude.app']\n : [claudeRoot],\n })\n }\n\n targets.push(\n {\n kind: 'json',\n client: 'claude-code',\n label: 'Claude Code',\n path: path.resolve(home, '.claude.json'),\n includeType: true,\n commandNames: ['claude'],\n detectionPaths: [path.resolve(home, '.claude')],\n },\n {\n kind: 'native',\n client: 'codex',\n label: 'Codex',\n path: path.resolve(home, '.codex/config.toml'),\n executable: 'codex',\n commandNames: ['codex'],\n detectionPaths: [path.resolve(home, '.codex')],\n },\n {\n kind: 'json',\n client: 'cursor',\n label: 'Cursor',\n path: path.resolve(home, '.cursor/mcp.json'),\n commandNames: ['cursor', 'cursor-agent'],\n detectionPaths: [\n path.resolve(home, '.cursor'),\n ...(platform === 'darwin' ? ['/Applications/Cursor.app'] : []),\n ],\n },\n )\n\n return targets\n}\n\nexport function resolveMcpClientExecutable(\n command: string,\n input: {\n exists?: (path: string) => boolean\n nodePath?: string\n path?: string\n platform?: NodeJS.Platform\n } = {},\n): string {\n const platform = input.platform ?? process.platform\n const exists = input.exists ?? existsSync\n const nodePath = input.nodePath ?? process.execPath\n const names =\n platform === 'win32'\n ? [`${command}.cmd`, `${command}.exe`, command]\n : [command]\n\n const pathEntries = (input.path ?? process.env.PATH ?? '')\n .split(platform === 'win32' ? ';' : ':')\n .filter(Boolean)\n for (const directory of pathEntries) {\n for (const name of names) {\n const candidate = join(directory, name)\n if (exists(candidate)) return candidate\n }\n }\n\n for (const name of names) {\n const candidate = join(dirname(nodePath), name)\n if (exists(candidate)) return candidate\n }\n return command\n}\n\nfunction commandExists(command: string): boolean {\n return resolveMcpClientExecutable(command) !== command\n}\n\nexport function detectMcpClients(\n input: {\n targets?: ClientConfigTarget[]\n hasCommand?: (command: string) => boolean\n hasPath?: (path: string) => boolean\n } = {},\n): ClientConfigTarget[] {\n const targets = input.targets ?? mcpClientTargets()\n const hasCommand = input.hasCommand ?? commandExists\n const hasPath = input.hasPath ?? existsSync\n return targets.filter((target) => {\n if (target.kind === 'native') {\n return target.commandNames.some(hasCommand)\n }\n return (\n hasPath(target.path) ||\n target.detectionPaths.some(hasPath) ||\n target.commandNames.some(hasCommand)\n )\n })\n}\n","import { spawnSync } from 'node:child_process'\nimport {\n constants,\n copyFileSync,\n existsSync,\n mkdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n statSync,\n writeFileSync,\n} from 'node:fs'\nimport { dirname } from 'node:path'\nimport { isDeepStrictEqual } from 'node:util'\nimport { getSeoCliPaths, SEO_VERSION } from '@seo/core'\nimport {\n applyEdits,\n modify,\n type ParseError,\n parse,\n printParseErrorCode,\n} from 'jsonc-parser'\nimport type {\n ClientConfigTarget,\n JsonClientConfigTarget,\n NativeClientConfigTarget,\n SupportedClient,\n} from './mcp-clients.js'\nimport { resolveMcpClientExecutable } from './mcp-clients.js'\n\ninterface CommandResult {\n status: number | null\n stdout: string\n stderr: string\n error?: Error\n}\n\ntype CommandRunner = (command: string, args: string[]) => CommandResult\n\nexport interface McpServerCommand {\n command: string\n args: string[]\n}\n\nexport interface McpConfigOptions {\n runCommand?: CommandRunner\n reinstall?: boolean\n serverCommand?: McpServerCommand\n}\n\nconst formattingOptions = {\n insertSpaces: true,\n tabSize: 2,\n eol: '\\n',\n}\n\nfunction timestamp(): string {\n return new Date().toISOString().replace(/[:.]/g, '-')\n}\n\nfunction writeAtomic(path: string, value: string): void {\n mkdirSync(dirname(path), { recursive: true, mode: 0o700 })\n const tmp = `${path}.${process.pid}.${Date.now()}.tmp`\n const mode = existsSync(path) ? statSync(path).mode & 0o777 : 0o600\n writeFileSync(tmp, value, { encoding: 'utf8', mode })\n renameSync(tmp, path)\n}\n\nfunction backup(path: string): void {\n const base = `${path}.bak-${timestamp()}`\n let candidate = base\n let suffix = 2\n while (existsSync(candidate)) {\n candidate = `${base}-${suffix}`\n suffix += 1\n }\n copyFileSync(path, candidate, constants.COPYFILE_EXCL)\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction readConfig(target: JsonClientConfigTarget): {\n source: string\n config: Record<string, unknown>\n} {\n if (!existsSync(target.path)) return { source: '{}\\n', config: {} }\n\n const source = readFileSync(target.path, 'utf8')\n const errors: ParseError[] = []\n const config = parse(source, errors, { allowTrailingComma: true })\n if (errors.length > 0) {\n const first = errors[0]\n const detail = first\n ? `${printParseErrorCode(first.error)} at offset ${first.offset}`\n : 'unknown parse error'\n throw new Error(`Cannot update ${target.path}: invalid JSONC (${detail}).`)\n }\n if (!isRecord(config)) {\n throw new Error(\n `Cannot update ${target.path}: config root must be an object.`,\n )\n }\n if (config.mcpServers !== undefined && !isRecord(config.mcpServers)) {\n throw new Error(\n `Cannot update ${target.path}: mcpServers must be an object.`,\n )\n }\n return { source, config }\n}\n\nfunction isSeoPackageCommand(args: string[]): boolean {\n return (\n args.includes('mcp') &&\n args.includes('serve') &&\n args.some(\n (item) =>\n item === 'seo' || item.startsWith('seo@') || item === '@seo/cli',\n )\n )\n}\n\nfunction isManagedNodeCommand(\n value: Record<string, unknown>,\n args: string[],\n): boolean {\n if (\n typeof value.command !== 'string' ||\n args.length !== 3 ||\n args[1] !== 'mcp' ||\n args[2] !== 'serve' ||\n !isRecord(value.env)\n ) {\n return false\n }\n return value.env.SEO_MCP_CONFIGURED_BY === 'seo'\n}\n\nfunction managedServer(value: unknown): boolean {\n if (!isRecord(value) || !Array.isArray(value.args)) return false\n const args = value.args.filter(\n (item): item is string => typeof item === 'string',\n )\n return isSeoPackageCommand(args) || isManagedNodeCommand(value, args)\n}\n\nfunction writeConfigEdit(input: {\n target: JsonClientConfigTarget\n source: string\n value: unknown\n}): void {\n const next = applyEdits(\n input.source,\n modify(input.source, ['mcpServers', 'seo'], input.value, {\n formattingOptions,\n }),\n )\n if (existsSync(input.target.path)) backup(input.target.path)\n writeAtomic(input.target.path, next)\n}\n\nfunction defaultCommandRunner(command: string, args: string[]): CommandResult {\n const result = spawnSync(command, args, { encoding: 'utf8' })\n return {\n status: result.status,\n stdout: result.stdout ?? '',\n stderr: result.stderr ?? '',\n error: result.error,\n }\n}\n\nfunction isTemporaryNpxPath(path: string): boolean {\n const normalized = path.replaceAll('\\\\', '/').toLowerCase()\n return (\n normalized.includes('/_npx/') ||\n normalized.includes('/.npm/_npx/') ||\n normalized.includes('/.cache/pnpm/dlx/')\n )\n}\n\nfunction installedCliPath(cliPath: string | undefined): string | undefined {\n if (!cliPath || !existsSync(cliPath)) return undefined\n const resolved = realpathSync(cliPath)\n return isTemporaryNpxPath(resolved) ? undefined : resolved\n}\n\nexport function resolveMcpServerCommand(\n input: {\n cliPath?: string\n nodePath?: string\n platform?: NodeJS.Platform\n version?: string\n } = {},\n): McpServerCommand {\n const cliPath = installedCliPath(input.cliPath ?? process.argv[1])\n if (cliPath) {\n return {\n command: input.nodePath ?? process.execPath,\n args: [cliPath, 'mcp', 'serve'],\n }\n }\n\n const packageName = `seo@${input.version ?? SEO_VERSION}`\n if ((input.platform ?? process.platform) === 'win32') {\n return {\n command: 'cmd',\n args: ['/c', 'npx', '-y', packageName, 'mcp', 'serve'],\n }\n }\n return { command: 'npx', args: ['-y', packageName, 'mcp', 'serve'] }\n}\n\nfunction serverConfig(\n includeType = false,\n command = resolveMcpServerCommand(),\n): Record<string, unknown> {\n const paths = getSeoCliPaths()\n const config: Record<string, unknown> = {\n command: command.command,\n args: command.args,\n env: {\n SEO_CONFIG_DIR: paths.configDir,\n SEO_MCP_CONFIGURED_BY: 'seo',\n },\n }\n if (includeType) config.type = 'stdio'\n return config\n}\n\nfunction codexManaged(output: string): boolean {\n return (\n output.includes('SEO_MCP_CONFIGURED_BY') ||\n /args:\\s+-y\\s+(?:seo(?:@\\S+)?|@seo\\/cli)\\s+mcp\\s+serve\\b/.test(output)\n )\n}\n\nfunction codexCommand(\n target: NativeClientConfigTarget,\n operation: 'install' | 'uninstall',\n options: Required<\n Pick<McpConfigOptions, 'runCommand' | 'reinstall' | 'serverCommand'>\n >,\n): { client: SupportedClient; path: string; changed: boolean } {\n const executable = resolveMcpClientExecutable(target.executable)\n const current = options.runCommand(executable, ['mcp', 'get', 'seo'])\n if ((current.error as NodeJS.ErrnoException | undefined)?.code === 'ENOENT') {\n throw new Error(\n 'Cannot install SEO MCP for Codex: the `codex` command is not available on PATH. Install Codex CLI or choose another MCP client.',\n )\n }\n const exists = current.status === 0\n if (exists && !codexManaged(current.stdout)) {\n throw new Error(\n `Cannot ${operation} SEO MCP: ${target.path} already has an unmanaged mcp_servers.seo entry.`,\n )\n }\n if (operation === 'install' && exists && !options.reinstall) {\n return { client: target.client, path: target.path, changed: false }\n }\n if (operation === 'uninstall' && !exists) {\n return { client: target.client, path: target.path, changed: false }\n }\n\n if (operation === 'install' && exists) {\n const removed = options.runCommand(executable, ['mcp', 'remove', 'seo'])\n if (removed.error || removed.status !== 0) {\n const detail =\n removed.error?.message ?? removed.stderr.trim() ?? 'unknown error'\n throw new Error(`Cannot reinstall SEO MCP for Codex: ${detail}`)\n }\n }\n\n const paths = getSeoCliPaths()\n const args =\n operation === 'install'\n ? [\n 'mcp',\n 'add',\n 'seo',\n '--env',\n `SEO_CONFIG_DIR=${paths.configDir}`,\n '--env',\n 'SEO_MCP_CONFIGURED_BY=seo',\n '--',\n options.serverCommand.command,\n ...options.serverCommand.args,\n ]\n : ['mcp', 'remove', 'seo']\n const result = options.runCommand(executable, args)\n if (result.error || result.status !== 0) {\n const detail =\n result.error?.message ?? result.stderr.trim() ?? 'unknown error'\n throw new Error(`Cannot ${operation} SEO MCP for Codex: ${detail}`)\n }\n return { client: target.client, path: target.path, changed: true }\n}\n\nexport function installMcpConfig(\n target: ClientConfigTarget,\n options: McpConfigOptions = {},\n): { client: SupportedClient; path: string; changed: boolean } {\n const resolved = {\n runCommand: options.runCommand ?? defaultCommandRunner,\n reinstall: options.reinstall ?? false,\n serverCommand: options.serverCommand ?? resolveMcpServerCommand(),\n }\n if (target.kind === 'native') {\n return codexCommand(target, 'install', resolved)\n }\n\n const { source, config } = readConfig(target)\n const servers = config.mcpServers as Record<string, unknown> | undefined\n const current = servers?.seo\n const desired = serverConfig(target.includeType, resolved.serverCommand)\n if (isDeepStrictEqual(current, desired) && !resolved.reinstall) {\n return { client: target.client, path: target.path, changed: false }\n }\n if (current !== undefined && !managedServer(current)) {\n throw new Error(\n `Cannot install SEO MCP: ${target.path} already has an unmanaged mcpServers.seo entry.`,\n )\n }\n\n writeConfigEdit({ target, source, value: desired })\n return { client: target.client, path: target.path, changed: true }\n}\n\nexport function uninstallMcpConfig(\n target: ClientConfigTarget,\n options: Pick<McpConfigOptions, 'runCommand'> = {},\n): { client: SupportedClient; path: string; changed: boolean } {\n if (target.kind === 'native') {\n return codexCommand(target, 'uninstall', {\n runCommand: options.runCommand ?? defaultCommandRunner,\n reinstall: false,\n serverCommand: resolveMcpServerCommand(),\n })\n }\n if (!existsSync(target.path)) {\n return { client: target.client, path: target.path, changed: false }\n }\n\n const { source, config } = readConfig(target)\n const servers = config.mcpServers as Record<string, unknown> | undefined\n if (servers?.seo === undefined) {\n return { client: target.client, path: target.path, changed: false }\n }\n if (!managedServer(servers.seo)) {\n throw new Error(\n `Cannot uninstall SEO MCP: ${target.path} has an unmanaged mcpServers.seo entry.`,\n )\n }\n\n writeConfigEdit({ target, source, value: undefined })\n return { client: target.client, path: target.path, changed: true }\n}\n","import { spawnSync } from 'node:child_process'\n\nexport type SkillInstallOutcome =\n | { status: 'installed' }\n | { status: 'failed'; error: string }\n\n/**\n * Install the packaged router skill for coding agents through the skills\n * ecosystem. Used by guided setup and by `seo skill install`.\n */\nexport function installSeoSkill(\n options: { quiet?: boolean } = {},\n): SkillInstallOutcome {\n const result = spawnSync('npx', ['-y', 'skills', 'add', 'iannuttall/seo'], {\n stdio: options.quiet ? 'ignore' : 'inherit',\n })\n if (result.error) {\n return { status: 'failed', error: result.error.message }\n }\n if (result.status !== 0) {\n return {\n status: 'failed',\n error: `npx skills add exited with status ${result.status ?? 'unknown'}.`,\n }\n }\n return { status: 'installed' }\n}\n","import {\n confirm,\n multiselect,\n note,\n password,\n select,\n text,\n} from '@clack/prompts'\nimport {\n type AnalyticsConnection,\n analyticsConnectionLabel,\n authStatus,\n type Ga4WebStreamCandidate,\n type Ga4WebStreamMatch,\n ga4MatchReason,\n ga4PropertyIdFromName,\n listGa4AccountSummaries,\n listGa4DataStreams,\n listGoogleAccounts,\n loadProviderExtensions,\n matchGa4WebStreams,\n type RegisteredProviderExtension,\n readClickySiteKey,\n readProviderExtensionCredentials,\n SeoError,\n setActiveGoogleAccount,\n verifyAnalyticsProvider,\n writeOauthClient,\n writeProviderExtensionCredentials,\n} from '@seo/core'\nimport { canPrompt, maybeExitCancelled } from '../../utils.js'\nimport { loginWithGuidance } from '../google-login.js'\nimport { detectMcpClients } from '../mcp-clients.js'\nimport { installMcpConfig } from '../mcp-config.js'\nimport { installSeoSkill } from '../skill-install.js'\n\nexport type SetupAuthStatus =\n | 'connected'\n | 'already-connected'\n | 'service-account'\n | 'skipped'\nexport type SetupAuthResult = {\n status: SetupAuthStatus\n accountEmail?: string\n}\nexport type SetupMcpInstall = {\n client: string\n path: string\n changed: boolean\n error?: string\n}\nexport type SetupGoogleAnalyticsSelection = {\n propertyId: string\n accountEmail?: string\n selection: 'explicit' | 'matched' | 'manual'\n reason: string\n}\nexport type SetupAnalyticsSelection =\n | { provider: 'google'; google: SetupGoogleAnalyticsSelection }\n | {\n provider: 'extension'\n extension: { providerId: string; account: Record<string, string> }\n }\n | { provider: 'none' }\nexport type SetupSkillInstall = {\n status: 'installed' | 'declined' | 'skipped' | 'failed'\n error?: string\n}\n\ntype GoogleAnalyticsPropertyChoice = {\n property: string\n label: string\n account: string\n}\n\ntype GoogleAnalyticsSetupChoice = GoogleAnalyticsPropertyChoice & {\n match?: Ga4WebStreamMatch\n}\n\ntype AuthSetupChoice = 'login' | 'setup' | 'skip'\ntype SavedGoogleAccountChoice =\n | { type: 'account'; accountEmail: string }\n | { type: 'connect' }\n | { type: 'skip' }\ntype AnalyticsSetupChoice =\n | 'keep'\n | 'google'\n | 'remove'\n | 'skip'\n | `extension:${string}`\n\nexport function analyticsSetupOptions(\n current?: AnalyticsConnection,\n installedProviders: readonly RegisteredProviderExtension[] = [],\n): Array<{\n value: AnalyticsSetupChoice\n label: string\n hint?: string\n}> {\n const providers: Array<{\n value: AnalyticsSetupChoice\n label: string\n hint?: string\n }> = [\n {\n value: 'google',\n label: 'Google Analytics',\n hint: 'Use a property available to your Google login',\n },\n ...installedProviders\n .filter(\n (provider) =>\n provider.capabilities.some(\n (capability) => capability.id === 'landing-page-visits',\n ) && provider.id !== 'google',\n )\n .map((provider) => ({\n value: `extension:${provider.id}` as const,\n label: provider.displayName,\n hint: `Installed provider from ${provider.package}`,\n })),\n ]\n if (!current) {\n return [...providers, { value: 'skip', label: 'Skip traffic analytics' }]\n }\n const currentLabel = analyticsConnectionLabel(current)\n return [\n {\n value: 'keep' as const,\n label: `Keep ${currentLabel}`,\n hint: 'Leave this project connection unchanged',\n },\n ...providers,\n { value: 'remove', label: 'Remove traffic analytics' },\n ]\n}\n\nasync function connectAnalyticsExtension(\n provider: RegisteredProviderExtension,\n initialAccount: Readonly<Record<string, string>> = {},\n interactive = true,\n): Promise<Extract<SetupAnalyticsSelection, { provider: 'extension' }>> {\n if (\n !provider.capabilities.some(\n (capability) => capability.id === 'landing-page-visits',\n )\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Provider ${provider.id} does not supply landing-page visits.`,\n )\n }\n const account: Record<string, string> = { ...initialAccount }\n const credentials: Record<string, string> = {}\n for (const field of provider.connection.fields.filter(\n (item) => item.kind === 'account',\n )) {\n if (account[field.id]?.trim()) continue\n if (!interactive) {\n if (field.required !== false) {\n throw new SeoError('INVALID_INPUT', `${field.label} is required.`)\n }\n continue\n }\n const value = maybeExitCancelled(\n await text({\n message: field.label,\n validate: (input) =>\n field.required !== false && !input?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n ).trim()\n if (value) account[field.id] = value\n }\n const normalizedAccount = provider.connection.normalizeAccount\n ? provider.connection.normalizeAccount(account)\n : account\n try {\n Object.assign(\n credentials,\n await readProviderExtensionCredentials({\n providerId: provider.id,\n account: normalizedAccount,\n fields: provider.connection.fields,\n }),\n )\n } catch {\n // Missing values are requested below or reported in non-interactive mode.\n }\n if (provider.id === 'clicky' && !credentials.sitekey) {\n const saved = await readClickySiteKey(normalizedAccount.siteId ?? '')\n if (saved) credentials.sitekey = saved.siteKey\n }\n for (const field of provider.connection.fields.filter(\n (item) => item.kind === 'secret',\n )) {\n const environmentValue = field.envVar\n ? process.env[field.envVar]?.trim()\n : undefined\n if (environmentValue) credentials[field.id] = environmentValue\n if (credentials[field.id]) continue\n if (!interactive) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n field.envVar\n ? `Set ${field.envVar} to connect ${provider.displayName}.`\n : `${field.label} is required to connect ${provider.displayName}.`,\n )\n }\n const value = maybeExitCancelled(\n await password({\n message: field.label,\n validate: (input) =>\n field.required !== false && !input?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n ).trim()\n if (value) credentials[field.id] = value\n }\n if (provider.connection.verificationNotice) {\n note(provider.connection.verificationNotice, 'Connection check')\n }\n await verifyAnalyticsProvider({\n providerId: provider.id,\n account: normalizedAccount,\n credentials,\n })\n if (Object.keys(credentials).length > 0) {\n await writeProviderExtensionCredentials({\n providerId: provider.id,\n account: normalizedAccount,\n credentials,\n })\n }\n return {\n provider: 'extension',\n extension: { providerId: provider.id, account: normalizedAccount },\n }\n}\n\nexport function authSetupOptions(input: {\n sharedConfigured: boolean\n byoConfigured: boolean\n canSkip: boolean\n}): Array<{\n value: AuthSetupChoice\n label: string\n hint?: string\n}> {\n const skipOption = input.canSkip\n ? [{ value: 'skip' as const, label: 'Skip for now' }]\n : []\n const hasOauthClient = input.sharedConfigured || input.byoConfigured\n\n return hasOauthClient\n ? [\n {\n value: 'login',\n label: 'Connect Google',\n hint: 'Opens your browser for read-only Search Console and Google Analytics access',\n },\n ...skipOption,\n ]\n : [\n {\n value: 'setup',\n label: 'Set up Google login for local development',\n hint: 'This source checkout does not include the public app credentials',\n },\n ...skipOption,\n ]\n}\n\nasync function findGoogleAnalyticsWebStreamCandidates(\n properties: GoogleAnalyticsPropertyChoice[],\n accountEmail?: string,\n): Promise<{ candidates: Ga4WebStreamCandidate[]; complete: boolean }> {\n const candidates: Ga4WebStreamCandidate[] = []\n let complete = true\n let nextIndex = 0\n\n async function worker(): Promise<void> {\n while (nextIndex < properties.length) {\n const property = properties[nextIndex]\n nextIndex += 1\n if (!property) continue\n\n try {\n const streams = await listGa4DataStreams(\n property.property,\n accountEmail,\n )\n candidates.push(\n ...streams\n .filter((stream) => stream.webStreamData)\n .map((stream) => ({\n account: property.account,\n property: property.property,\n propertyName: property.label,\n stream,\n })),\n )\n } catch {\n complete = false\n }\n }\n }\n\n await Promise.all(\n Array.from({ length: Math.min(properties.length, 4) }, () => worker()),\n )\n return { candidates, complete }\n}\n\nexport async function maybeConnectAuth(\n args: Record<string, unknown>,\n): Promise<SetupAuthResult> {\n const status = await authStatus()\n if (status.activeMode === 'service-account') {\n return { status: 'service-account', accountEmail: status.identity }\n }\n const requestedAccount =\n typeof args['search-console-account'] === 'string'\n ? args['search-console-account']\n : undefined\n const connectedAccounts = listGoogleAccounts()\n if (requestedAccount) {\n const selected = connectedAccounts.find(\n (account) =>\n account.accountEmail.toLowerCase() === requestedAccount.toLowerCase(),\n )\n if (!selected) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${requestedAccount} is not connected. Run \\`seo auth login\\` first.`,\n )\n }\n return { status: 'already-connected', accountEmail: selected.accountEmail }\n }\n if (args['skip-auth']) return { status: 'skipped' }\n if (!canPrompt({ json: args.json === true })) {\n if (status.tokens) {\n return {\n status: 'already-connected',\n accountEmail: status.tokens.account_email,\n }\n }\n throw new SeoError(\n 'AUTH_REQUIRED',\n 'Not logged in. Run `seo auth login`, or pass --skip-auth to save a project profile without connecting Google.',\n )\n }\n\n if (connectedAccounts.length > 0) {\n const choice = maybeExitCancelled(\n await select<SavedGoogleAccountChoice>({\n message: 'Google account for Search Console',\n options: [\n ...connectedAccounts.map((account) => ({\n value: {\n type: 'account' as const,\n accountEmail: account.accountEmail,\n },\n label: account.accountEmail,\n hint: account.active ? 'Current default' : undefined,\n })),\n {\n value: { type: 'connect' as const },\n label: 'Connect another Google account',\n },\n ...(typeof args.site === 'string'\n ? [\n {\n value: { type: 'skip' as const },\n label: 'Skip for now',\n },\n ]\n : []),\n ],\n }),\n )\n if (choice.type === 'account') {\n setActiveGoogleAccount(choice.accountEmail)\n return {\n status: 'already-connected',\n accountEmail: choice.accountEmail,\n }\n }\n if (choice.type === 'skip') return { status: 'skipped' }\n if (status.sharedConfigured || status.byoConfigured) {\n const tokens = await loginWithGuidance()\n note(\n `Connected as ${tokens.account_email}. seo has read-only access and cannot change your site.`,\n 'Google connected',\n )\n return { status: 'connected', accountEmail: tokens.account_email }\n }\n }\n\n const choice = maybeExitCancelled(\n await select<AuthSetupChoice>({\n message: 'Connect Google now?',\n options: authSetupOptions({\n sharedConfigured: status.sharedConfigured,\n byoConfigured: status.byoConfigured,\n canSkip: typeof args.site === 'string' && args.site.length > 0,\n }),\n }),\n )\n\n if (choice === 'skip') return { status: 'skipped' }\n if (choice === 'setup') {\n const clientId = maybeExitCancelled(\n await text({\n message: 'Google Desktop OAuth client ID',\n validate: (value) => (value ? undefined : 'Client ID is required'),\n }),\n )\n const clientSecret = maybeExitCancelled(\n await password({\n message: 'Google Desktop OAuth client secret',\n validate: (value) => (value ? undefined : 'Client secret is required'),\n }),\n )\n writeOauthClient({ clientId, clientSecret })\n }\n\n const tokens = await loginWithGuidance()\n note(\n `Connected as ${tokens.account_email}. seo has read-only access and cannot change your site.`,\n 'Google connected',\n )\n return { status: 'connected', accountEmail: tokens.account_email }\n}\n\nexport async function chooseGoogleAnalyticsProperty(input: {\n property?: string\n accountEmail?: string\n site: string\n interactive?: boolean\n}): Promise<SetupGoogleAnalyticsSelection | undefined> {\n if (input.property) {\n return {\n propertyId: input.property,\n accountEmail: input.accountEmail,\n selection: 'explicit',\n reason: 'Set with --google-analytics-property.',\n }\n }\n const interactive = input.interactive ?? canPrompt()\n if (!interactive) return undefined\n\n const summaries = await listGa4AccountSummaries(input.accountEmail).catch(\n () => [],\n )\n const properties: GoogleAnalyticsPropertyChoice[] = summaries.flatMap(\n (account) =>\n account.propertySummaries.map((property) => ({\n property: ga4PropertyIdFromName(property.property),\n label: property.displayName ?? property.property,\n account: account.displayName ?? account.account,\n })),\n )\n if (!properties.length) return undefined\n\n const { candidates, complete: streamsComplete } =\n await findGoogleAnalyticsWebStreamCandidates(properties, input.accountEmail)\n const matches = streamsComplete\n ? matchGa4WebStreams(input.site, candidates)\n : []\n const matchesByProperty = new Map<string, Ga4WebStreamMatch>()\n for (const match of matches) {\n matchesByProperty.set(match.property, match)\n }\n const matchedProperties = [...matchesByProperty.values()]\n\n if (matchedProperties.length === 1) {\n const match = matchedProperties[0]\n if (!match) return undefined\n return {\n propertyId: match.property,\n accountEmail: input.accountEmail,\n selection: 'matched',\n reason: ga4MatchReason(match, input.site),\n }\n }\n\n const choices: GoogleAnalyticsSetupChoice[] = matchedProperties.length\n ? matchedProperties.map((match) => ({\n property: match.property,\n label: match.propertyName,\n account: match.account,\n match,\n }))\n : properties\n\n const choice = maybeExitCancelled(\n await select<GoogleAnalyticsSetupChoice | ''>({\n message: matchedProperties.length\n ? 'Several Google Analytics properties match this site. Which property should seo use?'\n : streamsComplete\n ? 'No Google Analytics web stream clearly matches this site. Attach a property?'\n : 'Some Google Analytics web streams could not be read. Attach a property?',\n options: [\n { value: '', label: 'Skip Google Analytics for now' },\n ...choices.map((property) => ({\n value: property,\n label: `${property.label} (${property.property})`,\n hint: property.match\n ? ga4MatchReason(property.match, input.site)\n : property.account,\n })),\n ],\n }),\n )\n if (!choice) return undefined\n\n return {\n propertyId: choice.property,\n accountEmail: input.accountEmail,\n selection: 'manual',\n reason: choice.match\n ? ga4MatchReason(choice.match, input.site)\n : streamsComplete\n ? `Selected ${choice.label} during setup. Its web stream did not clearly match ${input.site}.`\n : `Selected ${choice.label} during setup. seo could not read every Google Analytics web stream, so it did not guess a match.`,\n }\n}\n\nexport async function chooseAnalyticsForSetup(input: {\n googleProperty?: string\n googleAccount?: string\n clickySiteId?: string\n current?: AnalyticsConnection\n site: string\n interactive?: boolean\n}): Promise<SetupAnalyticsSelection | undefined> {\n if (input.googleProperty && input.clickySiteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass either --google-analytics-property or --clicky-site-id, not both.',\n )\n }\n const interactive = input.interactive ?? canPrompt()\n if (input.clickySiteId) {\n const loaded = await loadProviderExtensions()\n const provider = loaded.registry.get('clicky')\n if (!provider) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n 'The Clicky provider package is not installed. Run `seo providers install @seoskill/clicky-provider`.',\n )\n }\n return connectAnalyticsExtension(\n provider,\n { siteId: input.clickySiteId },\n interactive,\n )\n }\n if (input.googleProperty) {\n const accountEmail = await chooseGoogleAnalyticsAccount({\n requested: input.googleAccount,\n interactive,\n })\n const google = await chooseGoogleAnalyticsProperty({\n property: input.googleProperty,\n accountEmail,\n site: input.site,\n interactive,\n })\n return google ? { provider: 'google', google } : undefined\n }\n if (!interactive) return undefined\n\n const loadedProviders = await loadProviderExtensions()\n\n const choice = maybeExitCancelled(\n await select<AnalyticsSetupChoice>({\n message: 'Traffic analytics',\n options: analyticsSetupOptions(\n input.current,\n loadedProviders.registry.list(),\n ),\n }),\n )\n if (choice === 'keep') return undefined\n if (choice === 'remove') return { provider: 'none' }\n if (choice === 'skip') return undefined\n if (choice.startsWith('extension:')) {\n const id = choice.slice('extension:'.length)\n const provider = loadedProviders.registry.get(id)\n if (!provider) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Provider ${id} is installed but could not be loaded. Run \\`seo providers doctor\\`.`,\n )\n }\n return connectAnalyticsExtension(provider)\n }\n const accountEmail = await chooseGoogleAnalyticsAccount({ interactive })\n const google = await chooseGoogleAnalyticsProperty({\n accountEmail,\n site: input.site,\n interactive,\n })\n if (!google) {\n note(\n 'No Google Analytics property was available for this Google login. You can connect one later.',\n 'Traffic analytics skipped',\n )\n }\n return google ? { provider: 'google', google } : undefined\n}\n\nasync function chooseGoogleAnalyticsAccount(input: {\n requested?: string\n interactive: boolean\n}): Promise<string | undefined> {\n const status = await authStatus()\n if (status.activeMode === 'service-account') return status.identity\n const accounts = listGoogleAccounts()\n if (input.requested) {\n const selected = accounts.find(\n (account) =>\n account.accountEmail.toLowerCase() === input.requested?.toLowerCase(),\n )\n if (!selected) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Google account ${input.requested} is not connected. Run \\`seo auth login\\` first.`,\n )\n }\n return selected.accountEmail\n }\n if (!input.interactive) {\n return accounts.find((account) => account.active)?.accountEmail\n }\n if (accounts.length === 0) {\n const tokens = await loginWithGuidance()\n return tokens.account_email\n }\n const choice = maybeExitCancelled(\n await select<SavedGoogleAccountChoice>({\n message: 'Google account for Google Analytics',\n options: [\n ...accounts.map((account) => ({\n value: {\n type: 'account' as const,\n accountEmail: account.accountEmail,\n },\n label: account.accountEmail,\n hint: account.active ? 'Current default' : undefined,\n })),\n {\n value: { type: 'connect' as const },\n label: 'Connect another Google account',\n },\n ],\n }),\n )\n if (choice.type === 'account') return choice.accountEmail\n const tokens = await loginWithGuidance()\n note(\n `Connected as ${tokens.account_email}. seo has read-only access and cannot change your site.`,\n 'Google connected',\n )\n return tokens.account_email\n}\n\nexport async function maybeInstallSkill(\n args: Record<string, unknown>,\n): Promise<SetupSkillInstall> {\n if (args['skip-skill'] || !canPrompt({ json: args.json === true })) {\n return { status: 'skipped' }\n }\n const shouldInstall = maybeExitCancelled(\n await confirm({\n message:\n 'Install the SEO skill so coding agents know how to run reports?',\n initialValue: true,\n }),\n )\n if (!shouldInstall) return { status: 'declined' }\n\n return installSeoSkill()\n}\n\nexport async function maybeInstallMcp(\n args: Record<string, unknown>,\n): Promise<SetupMcpInstall[]> {\n if (args['skip-mcp'] || !canPrompt({ json: args.json === true })) return []\n const detected = detectMcpClients()\n if (detected.length === 0) return []\n const shouldInstall = maybeExitCancelled(\n await confirm({\n message: 'Install seo as an MCP server too?',\n initialValue: true,\n }),\n )\n if (!shouldInstall) return []\n\n const selected = maybeExitCancelled(\n await multiselect({\n message: 'Which MCP clients?',\n options: detected.map((target) => ({\n value: target.client,\n label: target.label,\n hint: target.path,\n })),\n initialValues: detected.map((target) => target.client),\n }),\n )\n\n return detected\n .filter((target) => selected.includes(target.client))\n .map((target) => {\n try {\n return installMcpConfig(target)\n } catch (error) {\n return {\n client: target.client,\n path: target.path,\n changed: false,\n error: error instanceof Error ? error.message : String(error),\n }\n }\n })\n}\n","import { intro, note, outro, text } from '@clack/prompts'\nimport {\n analyticsConnection,\n analyticsConnectionLabel,\n type ClientProfile,\n deriveBrandTerms,\n ensureSeoCliDirs,\n listClients,\n saveClient,\n updateClient,\n} from '@seo/core'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printCallout,\n printJson,\n printKeyValue,\n} from '../../utils.js'\nimport { slugId, startUrlForSite, suggestedClientName } from '../shared.js'\nimport {\n chooseSetupProjectTarget,\n nextAvailableProjectId,\n} from './project-target.js'\nimport {\n chooseAnalyticsForSetup,\n maybeConnectAuth,\n maybeInstallMcp,\n maybeInstallSkill,\n type SetupAuthStatus,\n type SetupGoogleAnalyticsSelection,\n type SetupMcpInstall,\n type SetupSkillInstall,\n} from './prompts.js'\n\ntype SetupResult = {\n client?: ClientProfile\n site: string\n auth: SetupAuthStatus\n googleAnalytics?: SetupGoogleAnalyticsSelection\n extension?: { providerId: string; account: Record<string, string> }\n mcp: SetupMcpInstall[]\n skill?: SetupSkillInstall\n next: string[]\n}\n\nfunction skillInstallLabel(skill: SetupSkillInstall): string {\n if (skill.status === 'installed') return 'installed'\n if (skill.status === 'failed') return 'install failed'\n return 'not installed'\n}\n\nfunction shellArg(value: string): string {\n if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {\n return value\n }\n return `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n}\n\nfunction printStarAsk(): void {\n process.stdout.write('\\n')\n printCallout({\n title: 'Help other people find SEO Skill',\n body: 'If SEO Skill saved you time, a GitHub star helps other people find it.',\n command: 'https://github.com/iannuttall/seo',\n })\n}\n\nfunction mcpInstallLabel(installs: SetupMcpInstall[]): string {\n const failed = installs.filter((install) => install.error).length\n const installed = installs.length - failed\n if (installs.length === 0) return 'not installed'\n if (failed === 0) return `${installed} installed`\n if (installed === 0) return `${failed} skipped`\n return `${installed} installed, ${failed} skipped`\n}\n\nfunction mcpFailureMessage(installs: SetupMcpInstall[]): string | undefined {\n const failures = installs.filter(\n (install): install is SetupMcpInstall & { error: string } =>\n Boolean(install.error),\n )\n if (failures.length === 0) return undefined\n return failures\n .map((install) => `${install.client}: ${install.error}`)\n .join('\\n')\n}\n\nexport async function runGuidedSetup(\n args: Record<string, unknown>,\n): Promise<void> {\n const json = jsonFlag(args)\n if (!json) intro(process.argv[2] === 'start' ? 'seo start' : 'seo setup')\n\n if (args['dry-run']) {\n const next = [\n 'seo auth login',\n 'seo start',\n 'seo report --project acme',\n 'seo refresh-priorities --project acme --verify-content',\n 'seo technical-watch --project acme',\n ]\n if (json) {\n printJson({ dryRun: true, next })\n } else {\n note(next.join('\\n'), 'This setup will guide you through')\n outro('Dry run complete.')\n }\n return\n }\n\n ensureSeoCliDirs()\n const interactive = canPrompt({ json })\n if (interactive) {\n note(\n 'A project profile remembers one site and its report defaults so future commands stay short.',\n 'Project profiles',\n )\n }\n const clients = listClients()\n const projectTarget = await chooseSetupProjectTarget({\n clients,\n interactive,\n requestedId: stringArg(args.id),\n skipProfile: booleanArg(args['skip-profile']),\n })\n const existingProject =\n projectTarget.mode === 'update' ? projectTarget.client : undefined\n const selectedProjectSite = stringArg(args.site) ?? existingProject?.siteUrl\n const siteInput = {\n site: selectedProjectSite,\n options: {\n allowDefault: projectTarget.mode === 'update',\n json,\n refresh: booleanArg(args.refresh),\n },\n }\n const resolvedNonInteractiveSite = interactive\n ? undefined\n : await resolveSite(siteInput)\n const authSelection = await maybeConnectAuth(\n selectedProjectSite ? { ...args, site: selectedProjectSite } : args,\n )\n const auth = authSelection.status\n const site =\n resolvedNonInteractiveSite ??\n (await resolveSite({\n ...siteInput,\n options: {\n ...siteInput.options,\n account: authSelection.accountEmail,\n },\n }))\n const defaultName = suggestedClientName(site)\n\n if (projectTarget.mode === 'skip') {\n const mcp = await maybeInstallMcp(args)\n const skill = await maybeInstallSkill(args)\n const siteArg = `--site ${shellArg(site)}`\n const next = [\n `seo report ${siteArg}`,\n `seo refresh-priorities ${siteArg} --verify-content`,\n `seo technical-watch ${siteArg}`,\n ]\n const result: SetupResult = { site, auth, mcp, skill, next }\n\n if (json) {\n printJson(result)\n return\n }\n\n printKeyValue([\n ['Project profile', 'not saved'],\n ['GSC property', site],\n ['Auth', auth],\n ['MCP', mcpInstallLabel(mcp)],\n ['SEO skill', skillInstallLabel(skill)],\n ])\n const mcpFailure = mcpFailureMessage(mcp)\n if (mcpFailure) note(mcpFailure, 'MCP setup skipped')\n if (skill.error) note(skill.error, 'SEO skill install failed')\n note(next.join('\\n'), 'Try next')\n outro('Setup complete.')\n printStarAsk()\n return\n }\n\n const name =\n stringArg(args.name) ??\n (interactive\n ? maybeExitCancelled(\n await text({\n message: 'Project name',\n placeholder: existingProject?.name ?? defaultName,\n defaultValue: existingProject?.name ?? defaultName,\n }),\n )\n : (existingProject?.name ?? defaultName))\n const id =\n existingProject?.id ??\n (projectTarget.mode === 'create' && projectTarget.requestedId\n ? slugId(projectTarget.requestedId)\n : nextAvailableProjectId(name, clients))\n const defaultStartUrl =\n existingProject?.startUrl ?? startUrlForSite(site) ?? ''\n const startUrl =\n stringArg(args.url) ??\n (interactive\n ? maybeExitCancelled(\n await text({\n message: 'Website URL to crawl',\n placeholder: defaultStartUrl || 'https://example.com',\n defaultValue: defaultStartUrl,\n }),\n )\n : defaultStartUrl || undefined)\n const watchUrls =\n args.urls === undefined\n ? (existingProject?.watchUrls ?? [])\n : listArg(args.urls)\n const analyticsSelection = await chooseAnalyticsForSetup({\n googleProperty: stringArg(args['google-analytics-property']),\n googleAccount: stringArg(args['google-analytics-account']),\n clickySiteId: stringArg(args['clicky-site-id']),\n current: analyticsConnection(existingProject),\n site,\n interactive,\n })\n const googleAnalytics =\n analyticsSelection?.provider === 'google'\n ? analyticsSelection.google\n : undefined\n const extension =\n analyticsSelection?.provider === 'extension'\n ? analyticsSelection.extension\n : undefined\n const derivedBrandTerms =\n existingProject?.brandTerms ?? deriveBrandTerms({ id, name, siteUrl: site })\n const brandTerms =\n args.brand === undefined ? derivedBrandTerms : listArg(args.brand)\n const technicalWeekday =\n numberArg(args.weekday) ?? existingProject?.technicalWeekday ?? 1\n const isDefault =\n booleanArg(args.default) ?? existingProject?.isDefault ?? true\n\n const analytics =\n analyticsSelection === undefined\n ? undefined\n : analyticsSelection.provider === 'google'\n ? {\n ...existingProject?.analytics,\n selected: 'google' as const,\n google: { propertyId: analyticsSelection.google.propertyId },\n }\n : analyticsSelection.provider === 'extension'\n ? {\n ...existingProject?.analytics,\n selected:\n `extension:${analyticsSelection.extension.providerId}` as const,\n extensions: {\n ...existingProject?.analytics.extensions,\n [analyticsSelection.extension.providerId]: {\n account: analyticsSelection.extension.account,\n },\n },\n }\n : {}\n\n const profile = {\n name,\n siteUrl: site,\n startUrl,\n watchUrls,\n brandTerms,\n analytics,\n googleAccounts: {\n ...existingProject?.googleAccounts,\n ...(authSelection.accountEmail\n ? { searchConsole: authSelection.accountEmail }\n : {}),\n ...(googleAnalytics?.accountEmail\n ? { googleAnalytics: googleAnalytics.accountEmail }\n : {}),\n },\n technicalWeekday,\n isDefault,\n }\n const client = existingProject\n ? updateClient(existingProject.id, profile)\n : saveClient({ id, ...profile })\n const mcp = await maybeInstallMcp(args)\n const skill = await maybeInstallSkill(args)\n const next = [\n `seo report --project ${client.id}`,\n `seo refresh-priorities --project ${client.id} --verify-content`,\n `seo technical-watch --project ${client.id}`,\n ]\n const result: SetupResult = {\n client,\n site,\n auth,\n googleAnalytics,\n extension,\n mcp,\n skill,\n next,\n }\n\n if (json) {\n printJson(result)\n return\n }\n\n const selectedAnalytics = analyticsConnection(client)\n\n printKeyValue([\n ['Project profile', `${client.name} (${client.id})`],\n ['GSC property', client.siteUrl],\n [\n 'Search Console account',\n client.googleAccounts?.searchConsole ?? 'default Google account',\n ],\n ['Crawl URL', client.startUrl ?? 'not set'],\n ['Watch URLs', String(client.watchUrls.length)],\n ['Brand terms', client.brandTerms.join(', ') || 'not set'],\n [\n 'Traffic analytics',\n selectedAnalytics\n ? analyticsConnectionLabel(selectedAnalytics)\n : 'not connected (optional)',\n ],\n ...(googleAnalytics\n ? [\n ['Google Analytics selection', googleAnalytics.reason] as [\n string,\n string,\n ],\n ]\n : []),\n ...(client.googleAccounts?.googleAnalytics\n ? [\n [\n 'Google Analytics account',\n client.googleAccounts.googleAnalytics,\n ] as [string, string],\n ]\n : []),\n ['Auth', auth],\n ['MCP', mcpInstallLabel(mcp)],\n ['SEO skill', skillInstallLabel(skill)],\n ])\n const mcpFailure = mcpFailureMessage(mcp)\n if (mcpFailure) note(mcpFailure, 'MCP setup skipped')\n if (skill.error) note(skill.error, 'SEO skill install failed')\n note(next.join('\\n'), 'Try next')\n outro('Setup complete.')\n printStarAsk()\n}\n","import { defineCommand } from 'citty'\nimport { runGuidedSetup } from './flow.js'\n\nexport const setupCommand = defineCommand({\n meta: {\n name: 'setup',\n description:\n 'Guided setup for auth, one project profile, MCP, and next commands',\n },\n args: {\n id: { type: 'string', description: 'Short stable project id.' },\n name: { type: 'string', description: 'Human project name.' },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n 'search-console-account': {\n type: 'string',\n description: 'Saved Google account email for Search Console.',\n },\n url: { type: 'string', description: 'Default technical crawl start URL.' },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to watch with URL Inspection.',\n },\n 'google-analytics-property': {\n type: 'string',\n description: 'Optional Google Analytics property ID.',\n },\n 'google-analytics-account': {\n type: 'string',\n description: 'Saved Google account email for Google Analytics.',\n },\n 'clicky-site-id': {\n type: 'string',\n description:\n 'Optional Clicky site ID. Set SEO_CLICKY_SITEKEY outside a terminal.',\n },\n brand: {\n type: 'string',\n description: 'Comma-separated branded query terms to exclude by default.',\n },\n weekday: {\n type: 'string',\n description: 'Preferred technical-watch weekday. Defaults to Monday.',\n },\n default: {\n type: 'boolean',\n description: 'Make this the default project.',\n },\n 'skip-profile': {\n type: 'boolean',\n default: false,\n description: 'Do not save a project profile during setup.',\n },\n 'skip-auth': {\n type: 'boolean',\n default: false,\n description: 'Skip Google sign-in during setup.',\n },\n 'skip-mcp': {\n type: 'boolean',\n default: false,\n description: 'Skip MCP install prompts.',\n },\n 'skip-skill': {\n type: 'boolean',\n default: false,\n description: 'Skip the SEO skill install prompt.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Refresh GSC property discovery.',\n },\n 'dry-run': {\n type: 'boolean',\n default: false,\n description: 'Show what setup does without changing files.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => runGuidedSetup(args),\n})\n\nexport const startCommand = defineCommand({\n ...setupCommand,\n meta: {\n name: 'start',\n description:\n 'Start here: connect first-party data, save a profile, and get the first report commands',\n },\n})\n\nexport const clientSetupCommand = defineCommand({\n ...setupCommand,\n meta: {\n name: 'setup',\n description: 'Guided setup for one saved project profile',\n },\n})\n","import { detectBrandTerms, getClient, saveClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\n\nexport const clientBrandCommand = defineCommand({\n meta: {\n name: 'brand',\n description: 'Detect and manage project brand query terms',\n },\n subCommands: {\n detect: defineCommand({\n meta: {\n name: 'detect',\n description:\n 'Suggest branded query terms from GSC navigational queries',\n },\n args: {\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name. Defaults to default.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n days: {\n type: 'string',\n description: 'Detection window length in days. Defaults to 28.',\n },\n limit: {\n type: 'string',\n description: 'Maximum candidate terms. Defaults to 10.',\n },\n 'min-impressions': {\n type: 'string',\n description: 'Minimum query impressions. Defaults to 10.',\n },\n save: {\n type: 'boolean',\n default: false,\n description: 'Save suggested terms to the selected project.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local GSC cache.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const client = getClient(projectArg(args))\n const siteUrl = await resolveSite({\n site: stringArg(args.site) ?? client?.siteUrl,\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const detection = await detectBrandTerms({\n site: siteUrl,\n id: client?.id,\n name: client?.name,\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n refresh: booleanArg(args.refresh),\n })\n const saved =\n booleanArg(args.save) && client\n ? saveClient({\n id: client.id,\n name: client.name,\n siteUrl: client.siteUrl,\n startUrl: client.startUrl,\n watchUrls: client.watchUrls,\n analytics: client.analytics,\n brandTerms: detection.suggestedTerms,\n technicalWeekday: client.technicalWeekday,\n isDefault: client.isDefault,\n })\n : undefined\n\n if (booleanArg(args.save) && !client) {\n throw new Error('Pass --project to save detected brand terms.')\n }\n if (json) {\n printJson({ ...detection, saved })\n return\n }\n\n printKeyValue([\n ['Property', detection.site],\n ['Derived terms', detection.derivedTerms.join(', ')],\n ['Suggested terms', detection.suggestedTerms.join(', ')],\n ['Saved', saved ? saved.id : 'no'],\n ])\n printTable(\n ['Term', 'Score', 'Evidence'],\n detection.candidates.map((candidate) => [\n candidate.term,\n candidate.score,\n candidate.evidence\n .map(\n (item) => `${item.query} (${Math.round(item.clicks)} clicks)`,\n )\n .join(', '),\n ]),\n )\n },\n }),\n },\n})\n","import type { ClientProfile } from '@seo/core'\nimport { printKeyValue, printSummaryList } from '../../../utils.js'\n\nexport function printClientList(clients: ClientProfile[]): void {\n printSummaryList(\n clients.map((client) => ({\n title: `${client.name}${client.isDefault ? ' (default)' : ''}`,\n description: client.siteUrl,\n meta: [\n client.id,\n client.startUrl ? `crawl ${client.startUrl}` : '',\n client.watchUrls.length\n ? `${client.watchUrls.length} watched URL${client.watchUrls.length === 1 ? '' : 's'}`\n : '',\n client.brandTerms.length\n ? `${client.brandTerms.length} brand term${client.brandTerms.length === 1 ? '' : 's'}`\n : '',\n ],\n })),\n { empty: 'No saved projects.' },\n )\n}\n\nexport function printClientProfile(client: ClientProfile): void {\n printKeyValue([\n ['ID', client.id],\n ['Name', client.name],\n ['GSC property', client.siteUrl],\n [\n 'Search Console account',\n client.googleAccounts?.searchConsole ?? 'default Google account',\n ],\n ['Crawl URL', client.startUrl ?? 'not set'],\n ['Watch URLs', client.watchUrls.join(', ') || 'not set'],\n ['Brand terms', client.brandTerms.join(', ') || 'not set'],\n [\n 'Google Analytics property',\n client.analytics.google?.propertyId ?? 'not set',\n ],\n [\n 'Google Analytics account',\n client.googleAccounts?.googleAnalytics ?? 'default Google account',\n ],\n ['Clicky site', client.analytics.clicky?.siteId ?? 'not set'],\n ['Selected analytics', client.analytics.selected ?? 'not set'],\n [\n 'Technical weekday',\n client.technicalWeekday === undefined\n ? 'not set'\n : String(client.technicalWeekday),\n ],\n ['Default', client.isDefault ? 'yes' : 'no'],\n ])\n}\n","import { getClient, SeoError, saveClient, updateClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n stringArg,\n} from '../../../args.js'\nimport { resolveSite } from '../../../selection.js'\nimport { printJson } from '../../../utils.js'\nimport { slugId } from '../../shared.js'\nimport { printClientProfile } from './output.js'\n\nexport const clientAddCommand = defineCommand({\n meta: {\n name: 'add',\n description: 'Create or update a project profile',\n },\n args: {\n id: {\n type: 'string',\n description: 'Short stable project id, for example acme.',\n },\n name: {\n type: 'string',\n description: 'Human project name.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n 'search-console-account': {\n type: 'string',\n description: 'Saved Google account email for Search Console.',\n },\n url: {\n type: 'string',\n description: 'Default technical crawl start URL.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to watch with URL Inspection.',\n },\n 'google-analytics-property': {\n type: 'string',\n description: 'Optional Google Analytics property ID for this project.',\n },\n 'google-analytics-account': {\n type: 'string',\n description: 'Saved Google account email for Google Analytics.',\n },\n 'clicky-site-id': {\n type: 'string',\n description:\n 'Optional legacy Clicky site ID. New connections use seo start.',\n },\n brand: {\n type: 'string',\n description: 'Comma-separated branded query terms to exclude by default.',\n },\n weekday: {\n type: 'string',\n description: 'Preferred technical-watch weekday, 0-7.',\n },\n default: {\n type: 'boolean',\n description: 'Make this the default project.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const requestedId = stringArg(args.id)\n const existing = requestedId\n ? (getClient(requestedId) ?? getClient(slugId(requestedId)))\n : undefined\n const googleAnalyticsProperty = stringArg(args['google-analytics-property'])\n const googleAnalyticsAccount = stringArg(args['google-analytics-account'])\n const searchConsoleAccount = stringArg(args['search-console-account'])\n const clickySiteId = stringArg(args['clicky-site-id'])\n if (googleAnalyticsProperty && clickySiteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass either --google-analytics-property or --clicky-site-id, not both.',\n )\n }\n if (\n googleAnalyticsAccount &&\n !googleAnalyticsProperty &&\n !existing?.analytics.google?.propertyId\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--google-analytics-account needs a Google Analytics property.',\n )\n }\n const siteUrl = await resolveSite({\n site: stringArg(args.site) ?? existing?.siteUrl,\n options: { json, account: searchConsoleAccount },\n })\n const profile = {\n name: stringArg(args.name),\n siteUrl,\n startUrl: stringArg(args.url),\n watchUrls: args.urls === undefined ? undefined : listArg(args.urls),\n brandTerms: args.brand === undefined ? undefined : listArg(args.brand),\n analytics:\n googleAnalyticsProperty || googleAnalyticsAccount\n ? {\n ...existing?.analytics,\n selected: 'google' as const,\n google: {\n propertyId:\n googleAnalyticsProperty ??\n existing?.analytics.google?.propertyId ??\n '',\n },\n }\n : clickySiteId\n ? {\n ...existing?.analytics,\n selected: 'clicky' as const,\n clicky: { siteId: clickySiteId },\n }\n : undefined,\n googleAccounts:\n searchConsoleAccount || googleAnalyticsAccount\n ? {\n ...existing?.googleAccounts,\n ...(searchConsoleAccount\n ? { searchConsole: searchConsoleAccount }\n : {}),\n ...(googleAnalyticsAccount\n ? { googleAnalytics: googleAnalyticsAccount }\n : {}),\n }\n : undefined,\n technicalWeekday: numberArg(args.weekday),\n isDefault: booleanArg(args.default),\n }\n const client = existing\n ? updateClient(existing.id, profile)\n : saveClient({ id: requestedId, ...profile })\n if (json) {\n printJson(client)\n return\n }\n printClientProfile(client)\n },\n})\n","import { setDefaultClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\n\nexport const clientDefaultCommand = defineCommand({\n meta: {\n name: 'default',\n description: 'Set the default project',\n },\n args: {\n id: {\n type: 'string',\n required: true,\n description: 'Project id or name.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const client = setDefaultClient(stringArg(args.id) ?? '')\n if (jsonFlag(args)) {\n printJson(client)\n return\n }\n process.stdout.write(`Default project set to ${client.id}.\\n`)\n },\n})\n","import { deleteClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\n\nexport const clientDeleteCommand = defineCommand({\n meta: {\n name: 'delete',\n description: 'Delete a project profile',\n },\n args: {\n id: {\n type: 'string',\n required: true,\n description: 'Project id or name.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const deleted = deleteClient(id)\n if (jsonFlag(args)) {\n printJson({ id, deleted })\n return\n }\n process.stdout.write(`${deleted ? 'Deleted' : 'Not found'} ${id}.\\n`)\n },\n})\n","import { listClients } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\nimport { printClientList } from './output.js'\n\nexport const clientListCommand = defineCommand({\n meta: {\n name: 'list',\n description: 'List saved project profiles',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const clients = listClients()\n if (jsonFlag(args)) {\n printJson({ clients })\n return\n }\n printClientList(clients)\n },\n})\n","import { getClient } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../../args.js'\nimport { printJson } from '../../../utils.js'\nimport { printClientProfile } from './output.js'\n\nexport const clientShowCommand = defineCommand({\n meta: {\n name: 'show',\n description: 'Show one project profile',\n },\n args: {\n id: {\n type: 'string',\n description: 'Project id or name. Defaults to the default project.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const client = getClient(stringArg(args.id))\n if (!client) throw new Error('Project not found.')\n if (jsonFlag(args)) {\n printJson(client)\n return\n }\n printClientProfile(client)\n },\n})\n","import { clientAddCommand } from './profiles/add.js'\nimport { clientDefaultCommand } from './profiles/default.js'\nimport { clientDeleteCommand } from './profiles/delete.js'\nimport { clientListCommand } from './profiles/list.js'\nimport { clientShowCommand } from './profiles/show.js'\n\nexport const clientProfileCommands = {\n list: clientListCommand,\n add: clientAddCommand,\n show: clientShowCommand,\n default: clientDefaultCommand,\n delete: clientDeleteCommand,\n}\n","import { defineCommand } from 'citty'\nimport { clientSetupCommand } from '../setup/index.js'\nimport { clientBrandCommand } from './brand.js'\nimport { clientProfileCommands } from './profiles.js'\n\nexport const clientCommand = defineCommand({\n meta: {\n name: 'client',\n description: 'Manage saved project profiles',\n },\n subCommands: {\n setup: clientSetupCommand,\n brand: clientBrandCommand,\n ...clientProfileCommands,\n },\n})\n\nexport const projectCommand = defineCommand({\n ...clientCommand,\n meta: {\n name: 'projects',\n description: 'Manage saved project profiles',\n },\n})\n","import { contentOptimizationReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printJson } from '../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from './output.js'\n\nexport const contentCommand = defineCommand({\n meta: {\n name: 'content',\n description: 'Optimize page content from real GSC queries',\n },\n subCommands: {\n optimize: defineCommand({\n meta: {\n name: 'optimize',\n description: 'Build a content optimization report for one URL',\n },\n args: {\n site: { type: 'string' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n url: { type: 'string', required: true },\n days: {\n type: 'string',\n description: 'GSC lookback days. Defaults to 28.',\n },\n limit: {\n type: 'string',\n description: 'Maximum GSC queries to inspect. Defaults to 25.',\n },\n 'min-impressions': {\n type: 'string',\n description: 'Minimum query impressions. Defaults to 10.',\n },\n 'include-brand': {\n type: 'boolean',\n default: false,\n description: 'Include branded queries.',\n },\n 'verify-content': defaultTrueBooleanArg(\n 'Fetch the page for content checks. Defaults to true.',\n 'Skip fetching the page for content checks.',\n ),\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for page extraction.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local GSC and HTTP cache.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await contentOptimizationReport({\n site: selection.site,\n url: stringArg(args.url) ?? '',\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent: booleanArg(args['verify-content']) !== false,\n js: booleanArg(args.js) ? true : 'auto',\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Content optimization',\n target: report.url,\n status: 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Score', value: `${report.summary.score}/100` },\n { label: 'Primary intent', value: report.summary.primaryIntent },\n {\n label: 'Primary query',\n value: report.summary.primaryQuery ?? 'None',\n },\n { label: 'Queries', value: formatCount(report.summary.queries) },\n {\n label: 'Opportunities',\n value: formatCount(report.summary.opportunities),\n },\n {\n label: 'Estimated lift',\n value: formatCount(report.summary.estimatedClickLift),\n },\n ],\n })\n\n printActionDetails(\n 'Top actions',\n report.topActions.map((action) => ({\n label: action.title,\n action: action.action,\n context: action.plainEnglish,\n })),\n )\n\n if (report.brief.sections.length) {\n process.stdout.write('\\nSuggested sections\\n')\n printLimitedTable(\n ['Heading', 'Queries'],\n report.brief.sections.map((section) => [\n truncate(section.heading, 48),\n truncate(section.queries.join(', '), 80),\n ]),\n )\n }\n\n if (report.intentMix.length) {\n process.stdout.write('\\nIntent mix\\n')\n printLimitedTable(\n ['Intent', 'Queries', 'Impressions', 'Clicks'],\n report.intentMix.map((intent) => [\n intent.intent,\n formatCount(intent.queries),\n formatCount(intent.impressions),\n formatCount(intent.clicks),\n ]),\n )\n }\n\n printNotes('Caveats', report.caveats)\n },\n }),\n },\n})\n","import {\n listSites,\n localError,\n localResearchKeys,\n nodeCommandDeps,\n SeoError,\n} from '@seo/core'\nimport {\n type Caller,\n type CommandResult,\n DIMENSIONS,\n type Dimension,\n matchProperty,\n RESEARCH_ACTIONS,\n RESEARCH_PROVIDERS,\n type ResearchAction,\n type ResearchProvider,\n runBingRows,\n runCompare,\n runLostPages,\n runPage,\n runReport,\n runResearch,\n runRows,\n SECTION_IDS,\n type SectionId,\n} from '@seo/core/commands'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printJson } from '../utils.js'\nimport { selectedSiteOrThrow } from './shared.js'\n\n// The shared commands: the same core code and text as the hosted MCP, with\n// this machine's Google sign-in. Each takes a target, optional dates and\n// progressive detail, nothing more.\n\nconst FLAGS: Record<string, string> = {\n site: '--site',\n url: '--url',\n section: '--section',\n date: '--date',\n pages: '--pages',\n dimensions: '--dimensions',\n detail: '--detail',\n offset: '--offset',\n}\n\nconst quote = (value: string | number) =>\n /^[\\w:/.,<>@#?=&%+-]+$/.test(String(value)) ? String(value) : `\"${value}\"`\n\nexport const cliCall: Caller = (command, args) =>\n [\n `seo ${command}`,\n ...Object.entries(args ?? {})\n .filter(([, value]) => value !== undefined)\n .map(\n ([key, value]) => `${FLAGS[key] ?? `--${key}`} ${quote(value ?? '')}`,\n ),\n ].join(' ')\n\nconst common = {\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n account: { type: 'string', description: 'Saved Google account email.' },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local cache and fetch fresh data.',\n },\n} as const\n\nconst dates = {\n 'start-date': { type: 'string', description: 'Optional YYYY-MM-DD.' },\n 'end-date': { type: 'string', description: 'Optional YYYY-MM-DD.' },\n} as const\n\nconst detail = {\n detail: {\n type: 'string',\n description: 'summary (default), rows for the next page, or full.',\n },\n offset: { type: 'string', description: 'rows only: the first row.' },\n} as const\n\ntype Args = Record<string, unknown>\n\nfunction detailArg(args: Args) {\n const value = stringArg(args.detail) ?? 'summary'\n if (!['summary', 'rows', 'full'].includes(value)) {\n throw new SeoError('INVALID_INPUT', '--detail is summary, rows or full.')\n }\n return value as 'summary' | 'rows' | 'full'\n}\n\n// A saved project, or the property that covers --site or --url.\nasync function property(args: Args, target?: string): Promise<string> {\n const options = {\n json: jsonFlag(args),\n refresh: booleanArg(args.refresh),\n account: stringArg(args.account),\n }\n if (!target || projectArg(args)) {\n return selectedSiteOrThrow({ client: projectArg(args) }, options)\n }\n const names = (await listSites(options.refresh, options.account)).map(\n (site) => site.siteUrl,\n )\n const found = matchProperty(names, target)\n if (!found) {\n throw new SeoError(\n 'PROPERTY_NOT_FOUND',\n `This Google login has no Search Console property for ${target}. Run \\`seo sites\\` to list the properties it can read.`,\n )\n }\n return found\n}\n\nasync function run(\n args: Args,\n task: (deps: ReturnType<typeof nodeCommandDeps>) => Promise<CommandResult>,\n) {\n try {\n const result = await task(\n nodeCommandDeps({\n call: cliCall,\n account: stringArg(args.account),\n refresh: booleanArg(args.refresh),\n }),\n )\n if (jsonFlag(args)) printJson(result.data)\n else process.stdout.write(`${result.text}\\n`)\n } catch (error) {\n throw localError(error)\n }\n}\n\nexport const reportCommand = defineCommand({\n meta: {\n name: 'report',\n description:\n 'The main Search Console report: overview and every section, then one section on request',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n section: {\n type: 'string',\n description: `Optional. One of ${SECTION_IDS.join(', ')}.`,\n },\n ...dates,\n ...detail,\n ...common,\n },\n run: async ({ args }) => {\n const section = stringArg(args.section)\n if (section && !SECTION_IDS.includes(section as SectionId)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `--section is one of ${SECTION_IDS.join(', ')}.`,\n )\n }\n const site = await property(args, stringArg(args.site))\n await run(args, (deps) =>\n runReport(\n {\n site,\n section: section as SectionId | undefined,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n },\n})\n\nexport const pageCommand = defineCommand({\n meta: {\n name: 'page',\n description:\n 'One URL: live page facts, Google index status and its queries',\n },\n args: {\n url: { type: 'string', description: 'The page URL.', required: true },\n ...dates,\n ...detail,\n ...common,\n },\n run: async ({ args }) => {\n const url = stringArg(args.url) ?? ''\n if (!/^https?:\\/\\/\\S+$/.test(url)) {\n throw new SeoError('INVALID_INPUT', '--url must be a full http(s) URL.')\n }\n const site = await property(args, url)\n await run(args, (deps) =>\n runPage(\n {\n site,\n url,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n },\n})\n\nexport const compareCommand = defineCommand({\n meta: {\n name: 'compare',\n description:\n 'Equal periods before and after a date, with the pages and queries that moved',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n date: {\n type: 'string',\n description: 'YYYY-MM-DD: the first day after the change.',\n required: true,\n },\n pages: {\n type: 'string',\n description: 'Optional URL text, such as /blog/.',\n },\n ...common,\n },\n run: async ({ args }) => {\n const site = await property(args, stringArg(args.site))\n await run(args, (deps) =>\n runCompare(\n {\n site,\n date: stringArg(args.date) ?? '',\n pages: stringArg(args.pages),\n },\n deps,\n ),\n )\n },\n})\n\nexport const indexCommand = defineCommand({\n meta: {\n name: 'index',\n description:\n 'Pages that lost most of their clicks, checked live and with URL Inspection',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n ...dates,\n ...common,\n },\n run: async ({ args }) => {\n const site = await property(args, stringArg(args.site))\n await run(args, (deps) =>\n runLostPages(\n {\n site,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n },\n deps,\n ),\n )\n },\n})\n\nexport const dataCommand = defineCommand({\n meta: {\n name: 'data',\n description:\n 'Raw Search Console or Bing rows for any dimensions, beside the previous period',\n },\n args: {\n site: {\n type: 'string',\n description: 'Site, URL or Search Console property.',\n },\n source: {\n type: 'string',\n description:\n 'search_console (default) or bing. Bing takes the first dimension, query or page.',\n },\n dimensions: {\n type: 'string',\n description: `Comma-separated: ${DIMENSIONS.join(', ')}. Default query.`,\n },\n page: {\n type: 'string',\n description: 'Optional: only rows for pages whose URL contains this.',\n },\n query: {\n type: 'string',\n description: 'Optional: only rows for queries that contain this.',\n },\n ...dates,\n ...detail,\n ...common,\n },\n run: async ({ args }) => {\n const dimensions = csvArg(args.dimensions) ?? ['query']\n const unknown = dimensions.filter(\n (dimension) => !DIMENSIONS.includes(dimension as Dimension),\n )\n if (unknown.length) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Unknown dimensions: ${unknown.join(', ')}. Use ${DIMENSIONS.join(', ')}.`,\n )\n }\n const source = stringArg(args.source) ?? 'search_console'\n if (!['search_console', 'bing'].includes(source)) {\n throw new SeoError('INVALID_INPUT', '--source is search_console or bing.')\n }\n const site = await property(args, stringArg(args.site))\n if (source === 'bing') {\n await run(args, (deps) =>\n runBingRows(\n {\n site,\n dimension: dimensions[0] === 'page' ? 'page' : 'query',\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n return\n }\n const page = stringArg(args.page)\n const query = stringArg(args.query)\n await run(args, (deps) =>\n runRows(\n {\n site,\n dimensions: dimensions as Dimension[],\n filters: [\n ...(page\n ? [\n {\n dimension: 'page' as const,\n operator: 'contains' as const,\n expression: page,\n },\n ]\n : []),\n ...(query\n ? [\n {\n dimension: 'query' as const,\n operator: 'contains' as const,\n expression: query,\n },\n ]\n : []),\n ],\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n deps,\n ),\n )\n },\n})\n\nexport const researchCommand = defineCommand({\n meta: {\n name: 'research',\n description:\n 'Keyword, SERP, competitor and backlink data from your DataForSEO or Ahrefs key',\n },\n args: {\n action: {\n type: 'positional',\n required: true,\n description: RESEARCH_ACTIONS.join(', '),\n },\n provider: {\n type: 'string',\n description: `${RESEARCH_PROVIDERS.join(', ')}. Default: the first one with a saved key.`,\n },\n keywords: { type: 'string', description: 'Comma-separated keywords.' },\n target: { type: 'string', description: 'Domain or URL.' },\n country: {\n type: 'string',\n description: 'Two-letter country code. Default us.',\n },\n ...detail,\n json: common.json,\n },\n run: async ({ args }) => {\n const action = stringArg(args.action) as ResearchAction\n if (!RESEARCH_ACTIONS.includes(action)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `The action is one of ${RESEARCH_ACTIONS.join(', ')}.`,\n )\n }\n const keys = await localResearchKeys()\n const header: Record<ResearchProvider, string> = {\n dataforseo: 'x-dataforseo-login',\n ahrefs: 'x-ahrefs-key',\n }\n const chosen = stringArg(args.provider)\n const provider = (chosen ??\n RESEARCH_PROVIDERS.find((name) => keys.has(header[name])) ??\n 'dataforseo') as ResearchProvider\n if (!RESEARCH_PROVIDERS.includes(provider)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `--provider is one of ${RESEARCH_PROVIDERS.join(', ')}.`,\n )\n }\n if (!keys.has(header[provider])) {\n throw new SeoError(\n 'AUTH_CONFIG_REQUIRED',\n `No ${provider} key saved. Run \\`seo providers ${provider} connect\\` first.`,\n )\n }\n const keywords = csvArg(args.keywords) ?? []\n const target = stringArg(args.target)\n const country = stringArg(args.country)\n await run(args, () =>\n runResearch(\n {\n provider,\n action,\n keywords,\n target,\n country,\n detail: detailArg(args),\n offset: numberArg(args.offset),\n },\n keys,\n {\n call: (offset) =>\n cliCall('research', {\n action,\n provider,\n keywords: keywords.join(',') || undefined,\n target,\n country,\n detail: 'rows',\n offset,\n }).replace('--action ', ''),\n },\n ),\n )\n },\n})\n","import { createWriteStream } from 'node:fs'\nimport { mkdir } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport type { Writable } from 'node:stream'\nimport { finished } from 'node:stream/promises'\n\nconst BUFFER_SIZE = 64 * 1024\n\nclass BufferedWriter {\n private buffer = ''\n\n constructor(private readonly stream: Writable) {}\n\n async write(value: string): Promise<void> {\n this.buffer += value\n if (this.buffer.length >= BUFFER_SIZE) await this.flush()\n }\n\n async flush(): Promise<void> {\n if (!this.buffer) return\n const chunk = this.buffer\n this.buffer = ''\n if (!this.stream.write(chunk)) {\n await new Promise<void>((resolve, reject) => {\n const onDrain = () => {\n cleanup()\n resolve()\n }\n const onError = (error: Error) => {\n cleanup()\n reject(error)\n }\n const cleanup = () => {\n this.stream.off('drain', onDrain)\n this.stream.off('error', onError)\n }\n this.stream.once('drain', onDrain)\n this.stream.once('error', onError)\n })\n }\n }\n}\n\nfunction indentation(depth: number): string {\n return ' '.repeat(depth)\n}\n\nfunction jsonValue(value: unknown): unknown {\n if (\n value &&\n typeof value === 'object' &&\n 'toJSON' in value &&\n typeof value.toJSON === 'function'\n ) {\n return value.toJSON()\n }\n return value\n}\n\nasync function writeValue(\n writer: BufferedWriter,\n input: unknown,\n depth: number,\n ancestors: Set<object>,\n arrayItem = false,\n): Promise<boolean> {\n const value = jsonValue(input)\n if (value === null) {\n await writer.write('null')\n return true\n }\n if (typeof value === 'string' || typeof value === 'boolean') {\n await writer.write(JSON.stringify(value))\n return true\n }\n if (typeof value === 'number') {\n await writer.write(Number.isFinite(value) ? String(value) : 'null')\n return true\n }\n if (typeof value === 'bigint') {\n JSON.stringify(value)\n }\n if (\n value === undefined ||\n typeof value === 'function' ||\n typeof value === 'symbol'\n ) {\n if (arrayItem) await writer.write('null')\n return arrayItem\n }\n if (!value || typeof value !== 'object') return false\n if (ancestors.has(value)) {\n throw new TypeError('Converting circular structure to JSON')\n }\n ancestors.add(value)\n try {\n if (Array.isArray(value)) {\n if (value.length === 0) {\n await writer.write('[]')\n return true\n }\n await writer.write('[\\n')\n for (let index = 0; index < value.length; index += 1) {\n if (index > 0) await writer.write(',\\n')\n await writer.write(indentation(depth + 1))\n await writeValue(writer, value[index], depth + 1, ancestors, true)\n }\n await writer.write(`\\n${indentation(depth)}]`)\n return true\n }\n\n const entries = Object.entries(value).filter(([, item]) => {\n const normalized = jsonValue(item)\n return !['undefined', 'function', 'symbol'].includes(typeof normalized)\n })\n if (entries.length === 0) {\n await writer.write('{}')\n return true\n }\n await writer.write('{\\n')\n for (let index = 0; index < entries.length; index += 1) {\n const [key, item] = entries[index] as [string, unknown]\n if (index > 0) await writer.write(',\\n')\n await writer.write(`${indentation(depth + 1)}${JSON.stringify(key)}: `)\n await writeValue(writer, item, depth + 1, ancestors)\n }\n await writer.write(`\\n${indentation(depth)}}`)\n return true\n } finally {\n ancestors.delete(value)\n }\n}\n\nexport async function writeJsonStream(\n stream: Writable,\n value: unknown,\n): Promise<void> {\n const writer = new BufferedWriter(stream)\n const written = await writeValue(writer, value, 0, new Set())\n if (!written) await writer.write('undefined')\n await writer.write('\\n')\n await writer.flush()\n}\n\nexport async function writeJsonOutput(\n path: string | undefined,\n value: unknown,\n): Promise<void> {\n if (!path) {\n await writeJsonStream(process.stdout, value)\n return\n }\n await mkdir(dirname(path), { recursive: true })\n const stream = createWriteStream(path)\n try {\n await writeJsonStream(stream, value)\n stream.end()\n await finished(stream)\n } catch (error) {\n stream.destroy()\n throw error\n }\n process.stdout.write(`Wrote ${path}\\n`)\n}\n","import {\n type CrawlReport,\n explainRule,\n reviewObservations,\n type TopFix,\n topFixes,\n} from '@seo/core'\nimport { printSemanticReport } from '../utils.js'\n\nfunction issueStatus(severity: TopFix['severity']): 'fail' | 'warning' {\n return severity === 'high' ? 'fail' : 'warning'\n}\n\nexport function printCrawlHuman(\n report: CrawlReport,\n fixes: TopFix[] = topFixes(report),\n): void {\n const reviews = reviewObservations(report)\n const status =\n report.status === 'failed' || report.summary.highIssues > 0\n ? 'fail'\n : report.status === 'partial'\n ? 'unknown'\n : report.summary.mediumIssues > 0 || report.summary.lowIssues > 0\n ? 'warning'\n : 'pass'\n const accessDiagnostics = report.access.samples.slice(0, 5).map((sample) => ({\n status: 'fail' as const,\n title: sample.evidence.guidance.summary,\n explanation: `${sample.evidence.provider} returned ${sample.evidence.kind} evidence for the crawler request.`,\n evidence: [sample.url],\n fix: sample.evidence.guidance.recommendedAction,\n }))\n const fixDiagnostics = fixes.slice(0, 10).map((fix) => ({\n status: issueStatus(fix.severity),\n title: `${fix.title} on ${fix.count} ${fix.count === 1 ? 'URL' : 'URLs'}`,\n explanation: explainRule(fix.ruleId)?.whyItMatters ?? fix.whyThisRanks,\n evidence: fix.sampleUrls.slice(0, 5),\n fix: fix.howToFix,\n }))\n const reviewDiagnostics = reviews.slice(0, 10).map((review) => ({\n status: 'warning' as const,\n title: `${review.title} on ${review.count} ${review.count === 1 ? 'URL' : 'URLs'}`,\n explanation:\n explainRule(review.ruleId)?.whyItMatters ?? review.whyThisRanks,\n evidence: review.sampleUrls.slice(0, 5),\n fix: review.howToFix,\n }))\n\n printSemanticReport({\n title:\n report.config.strategy === 'health'\n ? 'Sitemap health pass'\n : 'Site crawl',\n target: report.config.url,\n status,\n summary:\n report.status === 'partial'\n ? `Partial evidence from ${report.summary.totalPages} retained pages. Review the caveats before treating missing findings as an all-clear.`\n : `${report.summary.totalPages} pages retained with ${report.issues.length} findings.`,\n metrics: [\n { label: 'Pages', value: report.summary.totalPages },\n {\n label: 'High',\n value: report.summary.highIssues,\n status: 'fail',\n },\n {\n label: 'Medium',\n value: report.summary.mediumIssues,\n status: 'warning',\n },\n { label: 'Low', value: report.summary.lowIssues, status: 'info' },\n { label: 'Failed fetches', value: report.summary.failedUrls },\n ],\n sections: [\n { title: 'Access diagnostics', diagnostics: accessDiagnostics },\n { title: 'Prioritised fixes', diagnostics: fixDiagnostics },\n {\n title: 'Review before changing anything',\n diagnostics: reviewDiagnostics,\n },\n ...(!accessDiagnostics.length &&\n !fixDiagnostics.length &&\n !reviewDiagnostics.length\n ? [\n {\n title: 'Checks',\n diagnostics: [\n {\n status: 'pass' as const,\n title: 'No prioritised findings were observed',\n explanation:\n 'The evaluated crawl evidence did not produce a prioritised fix or review item.',\n },\n ],\n },\n ]\n : []),\n ],\n notes: [\n `Strategy: ${report.config.strategy}. Data: ${report.status}. Report: ${report.id}.`,\n ...report.warnings,\n ...report.caveats,\n ],\n })\n}\n","import {\n type AnalyticsConnection,\n normalizeClickySiteId,\n SeoError,\n} from '@seo/core'\nimport { stringArg } from '../../args.js'\n\nexport const analyticsConnectionArgs = {\n 'google-analytics-property': {\n type: 'string' as const,\n description:\n 'Google Analytics property ID for landing-page sessions. Defaults from --project when saved.',\n },\n 'clicky-site-id': {\n type: 'string' as const,\n description:\n 'Clicky site ID for landing-page visits. Defaults from --project when saved.',\n },\n}\n\nexport function analyticsConnectionFromArgs(\n args: Record<string, unknown>,\n fallback?: AnalyticsConnection,\n): AnalyticsConnection | undefined {\n const googlePropertyId = stringArg(args['google-analytics-property'])\n const clickySiteId = stringArg(args['clicky-site-id'])\n if (googlePropertyId && clickySiteId) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass either --google-analytics-property or --clicky-site-id, not both.',\n )\n }\n if (googlePropertyId) {\n return { provider: 'google', propertyId: googlePropertyId }\n }\n if (clickySiteId) {\n return { provider: 'clicky', siteId: normalizeClickySiteId(clickySiteId) }\n }\n return fallback\n}\n","import { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport {\n analyticsConnection,\n type CrawlOutputFormat,\n crawlSite,\n renderCrawlCsv,\n renderCrawlHtml,\n renderCrawlJunit,\n renderCrawlMarkdownTickets,\n renderCrawlPagesCsv,\n renderCrawlPretty,\n reviewObservations,\n saveCrawlReport,\n topFixes,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n fetchRateArg,\n jsonFlag,\n negatedBooleanArg,\n numberArg,\n projectArg,\n renderingModeArg,\n stringArg,\n} from '../args.js'\nimport { writeJsonOutput } from '../json-output.js'\nimport { printCrawlHuman } from '../presentation/crawl-report.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printKeyValue } from '../utils.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from './analytics/connection.js'\nimport { startUrlForSite } from './shared.js'\n\ntype Severity = 'low' | 'medium' | 'high'\n\nconst severityRank: Record<Severity, number> = {\n high: 3,\n medium: 2,\n low: 1,\n}\n\nexport const crawlCommand = defineCommand({\n meta: {\n name: 'crawl',\n description: 'Run a fast sitemap health pass or a full technical crawl',\n },\n args: {\n crawlUrl: {\n type: 'positional',\n required: false,\n description: 'Site start URL. Optional with --sitemap-url.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Optional when --project has a saved crawl URL.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL for joining page metrics.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...analyticsConnectionArgs,\n mode: {\n type: 'string',\n description:\n 'Crawl mode: site, page, list, or sitemap. Start with sitemap --health for large sites.',\n },\n health: {\n type: 'boolean',\n default: false,\n description:\n 'Run the uncached sitemap status and redirect pass before a full audit. No page-body analysis.',\n },\n 'sitemap-url': {\n type: 'string',\n description:\n 'Explicit sitemap URL. Selects sitemap mode when --mode is omitted.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs for list mode.',\n },\n 'urls-file': {\n type: 'string',\n description: 'File with one URL per line for list mode.',\n },\n 'max-pages': {\n type: 'string',\n description: 'Maximum pages to crawl, up to 10,000. Defaults to 500.',\n },\n 'max-depth': {\n type: 'string',\n description: 'Maximum click depth, up to 64. Defaults to 16.',\n },\n concurrency: {\n type: 'string',\n description:\n 'Parallel page fetches, up to 16. Defaults to 8, or progressively up to 4 with --health.',\n },\n 'fetch-interval-cap': {\n type: 'string',\n description: 'Maximum page fetches per interval per host.',\n },\n 'fetch-interval-ms': {\n type: 'string',\n description: 'Fetch rate interval in milliseconds.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache and fetch fresh pages.',\n },\n include: {\n type: 'string',\n description: 'Comma-separated URL patterns to include.',\n },\n exclude: {\n type: 'string',\n description: 'Comma-separated URL patterns to exclude.',\n },\n 'no-sitemap': {\n type: 'boolean',\n default: false,\n description: 'Do not seed URLs from sitemap.xml.',\n },\n 'no-robots': {\n type: 'boolean',\n default: false,\n description: 'Do not skip URLs disallowed by robots.txt.',\n },\n 'no-external': {\n type: 'boolean',\n default: false,\n description:\n 'Do not check external links. Reserved for full link checks.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Legacy alias for --rendering on.',\n },\n rendering: {\n type: 'string',\n description:\n 'JavaScript rendering mode: auto, on, or off. Defaults to auto.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON. Alias for --format json.',\n },\n format: {\n type: 'string',\n description:\n 'Output format: pretty, json, csv, html, markdown, or junit. JUnit requires --health.',\n },\n output: {\n type: 'string',\n description: 'Write output to this path instead of stdout.',\n },\n csv: {\n type: 'string',\n description: 'CSV table to render: issues or pages. Defaults to issues.',\n },\n save: {\n type: 'boolean',\n default: false,\n description: 'Save the crawl report locally.',\n },\n severity: {\n type: 'string',\n description: 'Only show top fixes at this severity.',\n },\n 'fail-on': {\n type: 'string',\n description: 'Exit non-zero when issues exist at this severity or above.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const format = crawlFormatArg(args.format, json)\n const output = stringArg(args.output)\n const csv = crawlCsvArg(args.csv)\n const severity = severityArg(args.severity)\n const failOn = severityArg(args['fail-on'])\n const project = projectArg(args)\n const urls = await urlListArgs(args)\n const explicitUrl = crawlUrlArg(args)\n const sitemapUrl = stringArg(args['sitemap-url'])\n const health = booleanArg(args.health)\n const explicitMode = crawlModeArg(args.mode)\n if (format === 'junit' && !health) {\n throw new Error('--format junit requires --health.')\n }\n if ((health || sitemapUrl) && explicitMode && explicitMode !== 'sitemap') {\n throw new Error('--health and --sitemap-url require sitemap mode.')\n }\n if (health && negatedBooleanArg(args, 'sitemap')) {\n throw new Error('--health cannot be combined with --no-sitemap.')\n }\n if ((health || sitemapUrl) && urls.length) {\n throw new Error(\n '--health and --sitemap-url cannot be combined with URL list input.',\n )\n }\n const selection =\n stringArg(args.site) ||\n project ||\n (!explicitUrl && !urls.length && !sitemapUrl)\n ? await resolveClientSelection({\n client: project,\n site: stringArg(args.site),\n options: { json },\n })\n : undefined\n const crawlUrl =\n explicitUrl ??\n selection?.client?.startUrl ??\n (selection?.site ? startUrlForSite(selection.site) : undefined) ??\n (sitemapUrl ? new URL('/', sitemapUrl).toString() : undefined) ??\n urls[0]\n if (!crawlUrl) {\n throw new Error(\n 'No crawl URL selected. Pass a URL, --url, or use --project with a saved crawl URL.',\n )\n }\n\n const report = await crawlSite({\n url: crawlUrl,\n projectId: selection?.client?.id,\n site: selection?.site,\n mode:\n explicitMode ??\n (health || sitemapUrl ? 'sitemap' : urls.length ? 'list' : undefined),\n strategy: health ? 'health' : 'full',\n sitemapUrl,\n urls,\n maxPages: numberArg(args['max-pages']),\n maxDepth: numberArg(args['max-depth']),\n concurrency: numberArg(args.concurrency),\n refresh: booleanArg(args.refresh),\n fetchRate: fetchRateArg({\n ...args,\n 'fetch-concurrency': args.concurrency,\n }),\n include: csvArg(args.include),\n exclude: csvArg(args.exclude),\n googleAnalyticsPropertyId: stringArg(args['google-analytics-property']),\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection?.client),\n ),\n useSitemap: !negatedBooleanArg(args, 'sitemap'),\n respectRobots: !negatedBooleanArg(args, 'robots'),\n checkExternal: !negatedBooleanArg(args, 'external'),\n js: renderingModeArg(args),\n })\n const saved = booleanArg(args.save) ? saveCrawlReport(report) : undefined\n const rankedFixes = topFixes(report, { severity })\n const failedThreshold = failOn\n ? report.issues.some(\n (issue) => severityRank[issue.severity] >= severityRank[failOn],\n )\n : false\n const failedRun = report.status === 'failed'\n\n const payload = {\n ...report,\n topFixes: rankedFixes,\n reviewObservations: reviewObservations(report, { severity }),\n ...(failOn ? { failOn, failedThreshold } : {}),\n ...(saved ? { saved } : {}),\n }\n\n if (format === 'json') {\n await writeJsonOutput(output, payload)\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'csv') {\n await writeOrPrint(\n output,\n csv === 'pages' ? renderCrawlPagesCsv(report) : renderCrawlCsv(report),\n )\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'html') {\n await writeOrPrint(output, renderCrawlHtml(report, rankedFixes))\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'junit') {\n await writeOrPrint(output, renderCrawlJunit(report))\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (format === 'markdown') {\n await writeOrPrint(\n output,\n renderCrawlMarkdownTickets(report, rankedFixes),\n )\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n if (output) {\n await writeOrPrint(output, renderCrawlPretty(report, rankedFixes))\n if (failedRun || failedThreshold) process.exitCode = 1\n return\n }\n\n printCrawlHuman(report, rankedFixes)\n if (saved || failOn) {\n process.stdout.write('\\nRun metadata\\n')\n printKeyValue([\n ['Saved report', saved?.id ?? 'no'],\n ['Fail threshold', failOn ?? 'off'],\n ])\n }\n if (failedRun || failedThreshold) {\n process.exitCode = 1\n }\n },\n})\n\nfunction crawlModeArg(value: unknown) {\n const mode = stringArg(value)\n if (!mode) return undefined\n if (['site', 'page', 'list', 'sitemap'].includes(mode)) {\n return mode as 'site' | 'page' | 'list' | 'sitemap'\n }\n throw new Error('Mode must be one of: site, page, list, sitemap.')\n}\n\nfunction severityArg(value: unknown): Severity | undefined {\n const severity = stringArg(value)\n if (!severity) return undefined\n if (['low', 'medium', 'high'].includes(severity)) {\n return severity as Severity\n }\n throw new Error('Severity must be one of: low, medium, high.')\n}\n\nfunction crawlUrlArg(args: Record<string, unknown>): string | undefined {\n const positional = stringArg(args.crawlUrl)\n const flag = stringArg(args.url)\n if (positional && flag && positional !== flag) {\n throw new Error('Use either a URL argument or --url, not both.')\n }\n return positional ?? flag\n}\n\nfunction crawlFormatArg(value: unknown, json: boolean): CrawlOutputFormat {\n const format = stringArg(value)\n if (json && format && format !== 'json') {\n throw new Error('Use either --json or --format, not both.')\n }\n if (!format) return json ? 'json' : 'pretty'\n if (['pretty', 'json', 'csv', 'html', 'markdown', 'junit'].includes(format)) {\n return format as CrawlOutputFormat\n }\n throw new Error(\n 'Format must be one of: pretty, json, csv, html, markdown, junit.',\n )\n}\n\nfunction crawlCsvArg(value: unknown): 'issues' | 'pages' {\n const csv = stringArg(value)\n if (!csv) return 'issues'\n if (['issues', 'pages'].includes(csv)) return csv as 'issues' | 'pages'\n throw new Error('CSV table must be one of: issues, pages.')\n}\n\nasync function urlListArgs(args: Record<string, unknown>): Promise<string[]> {\n const urls = csvArg(args.urls) ?? []\n const file = stringArg(args['urls-file'])\n if (file) {\n urls.push(...parseUrlList(await readFile(file, 'utf8')))\n }\n return [...new Set(urls)]\n}\n\nfunction parseUrlList(value: string): string[] {\n return value\n .split(/[\\n,]/)\n .map((item) => item.trim())\n .filter((item) => item && !item.startsWith('#'))\n}\n\nasync function writeOrPrint(path: string | undefined, content: string) {\n if (!path) {\n process.stdout.write(content)\n return\n }\n await mkdir(dirname(path), { recursive: true })\n await writeFile(path, content)\n process.stdout.write(`Wrote ${path}\\n`)\n}\n","import {\n type CrawlReport,\n type CrawlReportMeta,\n compareCrawlReports,\n crawlSite,\n deleteCrawlReport,\n latestCrawlReport,\n listCrawlReports,\n loadCrawlReport,\n reviewObservations,\n saveCrawlReport,\n topFixes,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printCrawlHuman } from '../presentation/crawl-report.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printJson, printSummaryList, printTable } from '../utils.js'\nimport {\n printActionDetails,\n printNotes,\n printReportSummary,\n truncate,\n} from './output.js'\n\nasync function reportSiteFilter(args: Record<string, unknown>, json: boolean) {\n const project = projectArg(args)\n const site = stringArg(args.site)\n if (!project && !site) return undefined\n return (\n await resolveClientSelection({\n client: project,\n site,\n options: { json },\n })\n ).site\n}\n\nfunction printReportList(reports: CrawlReportMeta[]): void {\n printSummaryList(\n reports.map((report) => ({\n title: report.id,\n description: report.site ?? report.url,\n meta: [\n report.status,\n `${report.totalPages} page${report.totalPages === 1 ? '' : 's'}`,\n `${report.issueCount} issue${report.issueCount === 1 ? '' : 's'}`,\n report.createdAt,\n ],\n })),\n { empty: 'No saved crawl reports.' },\n )\n}\n\nfunction printReport(report: CrawlReport): void {\n printCrawlHuman(report)\n}\n\nfunction printReportDiff(report: ReturnType<typeof compareCrawlReports>): void {\n printReportSummary({\n title: 'Crawl report comparison',\n target: report.after.url,\n status:\n report.comparability.status !== 'comparable' ||\n report.completeness.status !== 'complete'\n ? 'unknown'\n : report.summary.newStatusErrors > 0 ||\n report.summary.issueGroupsWorse > 0\n ? 'warning'\n : 'pass',\n summary: report.headline,\n metrics: [\n {\n label: 'Before',\n value: `${report.before.id} (${report.before.generatedAt})`,\n },\n {\n label: 'After',\n value: `${report.after.id} (${report.after.generatedAt})`,\n },\n { label: 'Comparability', value: report.comparability.status },\n { label: 'Completeness', value: report.completeness.status },\n {\n label: 'Pages',\n value: `${report.after.summary.totalPages} (${report.summary.pageDelta >= 0 ? '+' : ''}${report.summary.pageDelta})`,\n },\n {\n label: 'Issues',\n value: `${report.after.summary.highIssues + report.after.summary.mediumIssues + report.after.summary.lowIssues} (${report.summary.issueDelta >= 0 ? '+' : ''}${report.summary.issueDelta})`,\n },\n { label: 'New status errors', value: report.summary.newStatusErrors },\n { label: 'Fixed status errors', value: report.summary.fixedStatusErrors },\n { label: 'Issue groups worse', value: report.summary.issueGroupsWorse },\n { label: 'Issue groups better', value: report.summary.issueGroupsBetter },\n { label: 'Changed pages', value: report.summary.changedPages },\n { label: 'Added pages', value: report.summary.addedPages },\n { label: 'Removed pages', value: report.summary.removedPages },\n ],\n })\n\n printActionDetails(\n 'Top actions',\n report.topActions.map((action) => ({\n label: action.title,\n context: action.plainEnglish,\n action: action.action,\n })),\n report.topActions.length,\n )\n\n if (report.pageChanges.length) {\n process.stdout.write('\\nChanged pages\\n')\n printTable(\n ['Kind', 'Changes', 'URL'],\n report.pageChanges\n .slice(0, 15)\n .map((item) => [\n item.kind,\n item.changes.join(', '),\n truncate(item.url, 80),\n ]),\n )\n if (report.pageChanges.length > 15) {\n process.stdout.write(\n `Showing 15 of ${report.pageChanges.length}. Use --json for all changes.\\n`,\n )\n }\n }\n\n if (report.issueChanges.length) {\n process.stdout.write('\\nIssue movement\\n')\n printTable(\n ['Rule', 'Before', 'After', 'Delta'],\n report.issueChanges\n .slice(0, 10)\n .map((item) => [\n item.ruleId,\n String(item.before),\n String(item.after),\n `${item.delta >= 0 ? '+' : ''}${item.delta}`,\n ]),\n )\n }\n\n printNotes('Caveats', report.caveats)\n}\n\nfunction selectReportAliasMeta(\n reports: CrawlReportMeta[],\n input: {\n value: 'latest' | 'previous'\n skipId?: string\n },\n): CrawlReportMeta | undefined {\n if (input.value === 'latest') {\n return reports.find((item) => item.id !== input.skipId)\n }\n\n if (input.skipId) {\n const skippedIndex = reports.findIndex((item) => item.id === input.skipId)\n const older = skippedIndex >= 0 ? reports.slice(skippedIndex + 1) : reports\n return older.find((item) => item.id !== input.skipId)\n }\n\n return reports[1]\n}\n\nfunction resolveReportAlias(input: {\n value: string\n site?: string\n skipId?: string\n}): CrawlReport | undefined {\n if (input.value !== 'latest' && input.value !== 'previous') {\n return loadCrawlReport(input.value)\n }\n const reports = listCrawlReports({ site: input.site, limit: 20 })\n const meta = selectReportAliasMeta(reports, {\n value: input.value,\n skipId: input.skipId,\n })\n return meta ? loadCrawlReport(meta.id) : undefined\n}\n\nexport const crawlReportsCommand = defineCommand({\n meta: {\n name: 'crawl-reports',\n description: 'List, show, or delete saved crawl reports',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL for filtering reports.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n id: {\n type: 'string',\n description: 'Saved crawl report id to show.',\n },\n latest: {\n type: 'boolean',\n default: false,\n description: 'Show the latest saved crawl report.',\n },\n delete: {\n type: 'string',\n description: 'Delete a saved crawl report by id.',\n },\n rerun: {\n type: 'string',\n description: 'Rerun a saved crawl report by id, or pass latest.',\n },\n compare: {\n type: 'string',\n description: 'Compare a saved report id, latest, or previous.',\n },\n against: {\n type: 'string',\n description: 'Baseline report id. Defaults to previous.',\n },\n limit: {\n type: 'string',\n description: 'Maximum reports to list. Defaults to 20.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const site = await reportSiteFilter(args, json)\n const deleteId = stringArg(args.delete)\n const rerunId = stringArg(args.rerun)\n const compareId = stringArg(args.compare)\n const id = stringArg(args.id)\n\n if (deleteId) {\n const deleted = deleteCrawlReport(deleteId)\n if (json) {\n printJson({ id: deleteId, deleted })\n return\n }\n process.stdout.write(\n deleted\n ? `Deleted crawl report ${deleteId}.\\n`\n : `No saved crawl report found for ${deleteId}.\\n`,\n )\n return\n }\n\n if (rerunId) {\n const previous =\n rerunId === 'latest'\n ? latestCrawlReport(site)\n : loadCrawlReport(rerunId)\n if (!previous) {\n throw new Error(\n rerunId === 'latest'\n ? 'No saved crawl reports found.'\n : `No saved crawl report found for ${rerunId}.`,\n )\n }\n const report = await crawlSite({\n ...previous.config,\n projectId: previous.projectId,\n site: previous.site,\n googleAnalyticsPropertyId: previous.googleAnalyticsPropertyId,\n })\n const saved = saveCrawlReport(report)\n if (json) {\n printJson({\n ...report,\n rerunOf: previous.id,\n saved,\n topFixes: topFixes(report),\n reviewObservations: reviewObservations(report),\n })\n return\n }\n process.stdout.write(`Reran crawl report ${previous.id}.\\n\\n`)\n printReport(report)\n return\n }\n\n if (compareId) {\n const after = resolveReportAlias({ value: compareId, site })\n if (!after) {\n throw new Error(`No saved crawl report found for ${compareId}.`)\n }\n const beforeAlias = stringArg(args.against) ?? 'previous'\n const before = resolveReportAlias({\n value: beforeAlias,\n site: after.site ?? site,\n skipId: after.id,\n })\n if (!before) {\n throw new Error(\n `No baseline crawl report found for ${beforeAlias}. Save at least two reports or pass --against <id>.`,\n )\n }\n const diff = compareCrawlReports({ before, after })\n if (json) {\n printJson(diff)\n return\n }\n printReportDiff(diff)\n return\n }\n\n if (id || booleanArg(args.latest)) {\n const report = id ? loadCrawlReport(id) : latestCrawlReport(site)\n if (!report) {\n throw new Error(\n id\n ? `No saved crawl report found for ${id}.`\n : 'No saved crawl reports found.',\n )\n }\n if (json) {\n printJson(report)\n return\n }\n printReport(report)\n return\n }\n\n const reports = listCrawlReports({\n site,\n limit: numberArg(args.limit),\n })\n if (json) {\n printJson({ reports })\n return\n }\n printReportList(reports)\n },\n})\n","import { inspectUrl, querySearchAnalytics } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonBodyArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printJson, printTable } from '../utils.js'\nimport { printReportSummary } from './output.js'\nimport { selectedSiteOrThrow } from './shared.js'\n\nexport const gscQueryCommand = defineCommand({\n meta: {\n name: 'gsc-query',\n description: 'Run a raw Search Console Search Analytics query',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n 'start-date': { type: 'string', description: 'Start date YYYY-MM-DD.' },\n 'end-date': { type: 'string', description: 'End date YYYY-MM-DD.' },\n dimensions: {\n type: 'string',\n description: 'Comma-separated GSC dimensions, for example query,page.',\n },\n type: { type: 'string', description: 'Search type. Defaults to web.' },\n limit: {\n type: 'string',\n description: 'Maximum rows to request and print.',\n },\n body: { type: 'string', description: 'Raw Search Analytics JSON body.' },\n 'body-file': {\n type: 'string',\n description: 'Path to a Search Analytics JSON body file.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n },\n run: async ({ args }) => {\n const body =\n (await jsonBodyArg(args.body, args['body-file'])) ??\n ({\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n dimensions: csvArg(args.dimensions) ?? ['query', 'page'],\n type: stringArg(args.type) ?? 'web',\n rowLimit: numberArg(args.limit),\n dataState: 'final',\n } as Record<string, unknown>)\n const json = jsonFlag(args)\n const site = await selectedSiteOrThrow(\n {\n client: projectArg(args),\n site: stringArg(args.site) ?? stringArg(body.siteUrl),\n },\n {\n json,\n refresh: booleanArg(args.refresh),\n account: stringArg(args.account),\n },\n )\n delete body.siteUrl\n const result = await querySearchAnalytics(site, body as never, {\n refresh: booleanArg(args.refresh),\n accountEmail: stringArg(args.account),\n })\n const limit = numberArg(args.limit)\n const rows = limit ? result.rows.slice(0, limit) : result.rows\n if (json) {\n printJson({\n site,\n request: body,\n ...result,\n rows,\n rowsReturned: rows.length,\n })\n return\n }\n printReportSummary({\n title: 'Search Console query',\n target: site,\n status: result.rowsFetched > rows.length ? 'unknown' : 'info',\n summary: `${rows.length} rows returned from ${result.rowsFetched} fetched rows.`,\n metrics: [\n { label: 'Rows returned', value: rows.length },\n { label: 'Rows fetched', value: result.rowsFetched },\n { label: 'API calls', value: result.calls },\n ],\n })\n printTable(\n ['Keys', 'Clicks', 'Impr', 'CTR', 'Pos'],\n rows\n .slice(0, 25)\n .map((row) => [\n row.keys.join(' | '),\n Math.round(row.clicks),\n Math.round(row.impressions),\n row.ctr.toFixed(3),\n row.position.toFixed(1),\n ]),\n )\n },\n})\n\nexport const urlInspectCommand = defineCommand({\n meta: {\n name: 'url-inspect',\n description: 'Inspect a URL with the Search Console URL Inspection API',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n url: { type: 'string', description: 'URL to inspect.' },\n language: {\n type: 'string',\n description: 'Optional inspection language code.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const siteUrl = await selectedSiteOrThrow(\n { client: projectArg(args), site: stringArg(args.site) },\n { json, account: stringArg(args.account) },\n )\n const inspectionUrl = stringArg(args.url)\n if (!inspectionUrl) throw new Error('Pass --url.')\n const result = await inspectUrl({\n siteUrl,\n inspectionUrl,\n accountEmail: stringArg(args.account),\n languageCode: stringArg(args.language),\n })\n if (json) {\n printJson(result)\n return\n }\n const indexStatus = result.inspectionResult?.indexStatusResult\n printReportSummary({\n title: 'URL Inspection',\n target: inspectionUrl,\n status:\n indexStatus === undefined\n ? 'unknown'\n : indexStatus.verdict === 'PASS'\n ? 'pass'\n : 'warning',\n summary:\n indexStatus === undefined\n ? 'Google did not return index status evidence for this URL.'\n : `${indexStatus.verdict ?? 'Unknown'}: ${indexStatus.coverageState ?? 'Coverage state unavailable'}.`,\n metrics: [\n { label: 'Property', value: siteUrl },\n { label: 'Robots', value: indexStatus?.robotsTxtState ?? 'Unknown' },\n { label: 'Last crawl', value: indexStatus?.lastCrawlTime ?? 'Unknown' },\n {\n label: 'Google canonical',\n value: indexStatus?.googleCanonical ?? 'Unknown',\n },\n ],\n })\n },\n})\n","import type { ArgDef } from 'citty'\n\n// Shared report option metadata used by CLI commands. The parity check keeps\n// this aligned with scripts/report-surface-catalog.mjs.\ntype CliReportOption = {\n cli: string\n arg: ArgDef\n}\n\nconst REPORT_OPTIONS = {\n days: {\n cli: 'days',\n arg: {\n type: 'string',\n description: 'GSC lookback window. Defaults to 28.',\n },\n },\n recentDays: {\n cli: 'recent',\n arg: {\n type: 'string',\n description: 'Recent anomaly window in days. Defaults to 14.',\n },\n },\n range: {\n cli: 'days',\n arg: {\n type: 'string',\n description: 'GSC lookback window. Defaults to 28.',\n },\n },\n limit: {\n cli: 'limit',\n arg: {\n type: 'string',\n description: 'Maximum rows to return.',\n },\n },\n checkLimit: {\n cli: 'check-limit',\n arg: {\n type: 'string',\n description: 'Maximum candidate pages to fetch and check.',\n },\n },\n minImpressions: {\n cli: 'min-impressions',\n arg: {\n type: 'string',\n description: 'Minimum query impressions.',\n },\n },\n includeBrand: {\n cli: 'include-brand',\n arg: {\n type: 'boolean',\n default: false,\n description: 'Include branded queries in opportunity reports.',\n },\n },\n verifyContent: {\n cli: 'verify-content',\n arg: {\n type: 'boolean',\n default: false,\n description:\n 'Verify top opportunities against page title, meta, and content.',\n },\n },\n verifyLimit: {\n cli: 'verify-limit',\n arg: {\n type: 'string',\n description: 'Maximum opportunity URLs to verify.',\n },\n },\n js: {\n cli: 'js',\n arg: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for verified pages.',\n },\n },\n fetchConcurrency: {\n cli: 'fetch-concurrency',\n arg: {\n type: 'string',\n description:\n 'Maximum concurrent page fetches per host, up to 16. Defaults to 4.',\n },\n },\n fetchIntervalCap: {\n cli: 'fetch-interval-cap',\n arg: {\n type: 'string',\n description: 'Maximum page fetches per interval per host. Defaults to 4.',\n },\n },\n fetchIntervalMs: {\n cli: 'fetch-interval-ms',\n arg: {\n type: 'string',\n description: 'Fetch rate interval in milliseconds. Defaults to 1000.',\n },\n },\n refresh: {\n cli: 'refresh',\n arg: {\n type: 'boolean',\n default: false,\n description: 'Bypass local cache and fetch fresh data.',\n },\n },\n} as const satisfies Record<string, CliReportOption>\n\ntype ReportOptionKey = keyof typeof REPORT_OPTIONS\n\nexport function cliReportArgs<const T extends readonly ReportOptionKey[]>(\n keys: T,\n overrides: Partial<Record<ReportOptionKey, Partial<ArgDef>>> = {},\n): Record<(typeof REPORT_OPTIONS)[T[number]]['cli'], ArgDef> {\n return Object.fromEntries(\n keys.map((key) => {\n const option = REPORT_OPTIONS[key]\n return [option.cli, { ...option.arg, ...overrides[key] }]\n }),\n ) as Record<(typeof REPORT_OPTIONS)[T[number]]['cli'], ArgDef>\n}\n","import { trafficAnomaly, updateCorrelation } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../args.js'\nimport { printJson, printTable } from '../utils.js'\nimport {\n printLimitedTable,\n printNextCommand,\n printNotes,\n printReportSummary,\n} from './output.js'\nimport { cliReportArgs } from './report-options.js'\nimport { selectedSiteOrThrow } from './shared.js'\n\nfunction formatNumber(value: number): string {\n return value.toLocaleString('en-GB', {\n maximumFractionDigits: value >= 100 ? 0 : 1,\n })\n}\n\nfunction formatChange(value: number | null): string {\n if (value === null) return 'n/a'\n const rounded = Math.abs(value) >= 10 ? value.toFixed(0) : value.toFixed(1)\n return `${value > 0 ? '+' : ''}${rounded}%`\n}\n\nexport const trafficAnomalyCommand = defineCommand({\n meta: {\n name: 'traffic-anomaly',\n description: 'Detect unusual recent GSC traffic movement',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'recentDays', 'refresh'], {\n days: { description: 'Baseline window length in days. Defaults to 90.' },\n recentDays: {\n description: 'Recent anomaly window in days. Defaults to 7.',\n },\n refresh: {\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n }),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const report = await trafficAnomaly({\n site: await selectedSiteOrThrow(\n { client: projectArg(args), site: stringArg(args.site) },\n {\n json,\n refresh: booleanArg(args.refresh),\n },\n ),\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Traffic anomaly report',\n target: report.site,\n status:\n report.coverage?.status !== 'complete'\n ? 'unknown'\n : report.anomalies.some((anomaly) => anomaly.significant)\n ? 'warning'\n : 'pass',\n summary: report.anomalies.some((anomaly) => anomaly.significant)\n ? 'At least one recent metric moved beyond the report threshold.'\n : 'No significant recent movement was found in the retained evidence.',\n metrics: [\n { label: 'Metrics checked', value: report.anomalies.length },\n {\n label: 'Significant',\n value: report.anomalies.filter((anomaly) => anomaly.significant)\n .length,\n },\n {\n label: 'Observed days',\n value: report.coverage?.observedDays ?? 'Unavailable',\n },\n {\n label: 'Expected days',\n value: report.coverage?.expectedDays ?? 'Unavailable',\n },\n ],\n })\n printLimitedTable(\n [\n 'Metric',\n 'Direction',\n 'Baseline/day',\n 'Recent/day',\n 'Change',\n 'z',\n 'Significant',\n ],\n report.anomalies.map((anomaly) => [\n anomaly.metric,\n anomaly.direction,\n formatNumber(anomaly.baselineMean),\n formatNumber(anomaly.comparisonMean),\n formatChange(anomaly.percentChange),\n anomaly.zScore ?? 'n/a',\n anomaly.significant ? 'yes' : 'no',\n ]),\n )\n if (report.coverage) {\n printNotes('Evidence coverage', [\n `${report.coverage.observedDays} of ${report.coverage.expectedDays} requested calendar days returned date aggregates.`,\n ...report.coverage.caveats,\n ])\n }\n },\n})\n\nexport const updateCorrelateCommand = defineCommand({\n meta: {\n name: 'update-correlate',\n description: 'Compare traffic movement with official Google update windows',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'recentDays', 'refresh'], {\n days: { description: 'Baseline window length in days. Defaults to 90.' },\n recentDays: {\n description: 'Recent anomaly window in days. Defaults to 7.',\n },\n refresh: {\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n }),\n 'padding-days': {\n type: 'string',\n description: 'Days around update windows to count as overlap.',\n },\n 'known-change': {\n type: 'string',\n description:\n 'Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.',\n },\n 'ignore-change-log': {\n type: 'boolean',\n default: false,\n description: 'Do not use saved change-log entries as confounders.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const client = projectArg(args)\n const site = await selectedSiteOrThrow(\n { client, site: stringArg(args.site) },\n {\n json,\n refresh: booleanArg(args.refresh),\n },\n )\n const report = await updateCorrelation({\n site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n paddingDays: numberArg(args['padding-days']),\n knownConfounders: stringArg(args['known-change'])\n ? [stringArg(args['known-change']) ?? '']\n : undefined,\n includeChangeLog: !booleanArg(args['ignore-change-log']),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Google update correlation',\n target: report.site,\n status: 'unknown',\n summary: report.summary,\n metrics: [\n {\n label: 'Classification',\n value: report.classification.replaceAll('-', ' '),\n },\n {\n label: 'Attribution',\n value: report.attribution.replaceAll('-', ' '),\n },\n { label: 'Confidence', value: report.confidence },\n { label: 'Updates matched', value: report.overlappingUpdates.length },\n { label: 'Known confounders', value: report.confounders.length },\n { label: 'Source', value: report.source.name },\n ],\n })\n printNotes('Evidence', report.evidence)\n printNotes('Report caveats', report.caveats)\n printNotes('Recommended next checks', report.actions)\n printLimitedTable(\n ['Metric', 'Direction', 'Baseline/day', 'Recent/day', 'Change', 'z'],\n report.anomalies.map((anomaly) => [\n anomaly.metric,\n anomaly.direction,\n formatNumber(anomaly.baselineMean),\n formatNumber(anomaly.comparisonMean),\n formatChange(anomaly.percentChange),\n anomaly.zScore ?? 'n/a',\n ]),\n )\n if (report.overlappingUpdates.length) {\n process.stdout.write('\\nUpdates\\n')\n printTable(\n ['Start', 'End', 'Type', 'Name'],\n report.overlappingUpdates.map((update) => [\n update.start.slice(0, 10),\n update.end?.slice(0, 10) ?? 'open',\n update.type,\n update.name,\n ]),\n )\n }\n const target = client\n ? `--project ${JSON.stringify(client)}`\n : `--site ${JSON.stringify(site)}`\n printNextCommand(`seo segment-impact ${target} --dimension page`)\n },\n})\n","import {\n type ChangeScope,\n deleteChange,\n listChanges,\n measureChange,\n recordChange,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary } from '../output.js'\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction changeScope(value: unknown): ChangeScope {\n const scope = stringArg(value) ?? 'page'\n if (\n scope !== 'site' &&\n scope !== 'page' &&\n scope !== 'query' &&\n scope !== 'group'\n ) {\n throw new Error('Invalid --scope. Use site, page, query, or group.')\n }\n return scope\n}\n\nexport const changeLogCommand = defineCommand({\n meta: {\n name: 'change-log',\n description: 'Annotate SEO changes and measure before/after impact',\n },\n subCommands: {\n list: defineCommand({\n meta: {\n name: 'list',\n description: 'List recorded SEO changes',\n },\n args: {\n site: { type: 'string' },\n limit: { type: 'string' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const changes = listChanges({\n site: stringArg(args.site),\n limit: numberArg(args.limit),\n })\n if (jsonFlag(args)) {\n printJson({ changes })\n return\n }\n printTable(\n ['ID', 'Date', 'Site', 'Scope', 'Target', 'Title'],\n changes.map((change) => [\n change.id,\n change.changedAt,\n change.site,\n change.scope,\n change.target,\n change.title,\n ]),\n )\n },\n }),\n add: defineCommand({\n meta: {\n name: 'add',\n description: 'Record an SEO change',\n },\n args: {\n site: { type: 'string' },\n scope: { type: 'string', default: 'page' },\n target: { type: 'string', required: true },\n title: { type: 'string', required: true },\n description: { type: 'string' },\n date: { type: 'string' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const change = recordChange({\n site: await resolveSite({\n site: stringArg(args.site),\n options: { json },\n }),\n scope: changeScope(args.scope),\n target: stringArg(args.target) ?? '',\n title: stringArg(args.title) ?? '',\n description: stringArg(args.description),\n changedAt: stringArg(args.date) ?? today(),\n })\n if (json) {\n printJson(change)\n return\n }\n printKeyValue([\n ['ID', change.id],\n ['Date', change.changedAt],\n ['Site', change.site],\n ['Scope', change.scope],\n ['Target', change.target],\n ['Title', change.title],\n ])\n },\n }),\n delete: defineCommand({\n meta: {\n name: 'delete',\n description: 'Delete a recorded SEO change',\n },\n args: {\n id: { type: 'string', required: true },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const deleted = deleteChange(id)\n if (jsonFlag(args)) {\n printJson({ id, deleted })\n return\n }\n process.stdout.write(`${deleted ? 'Deleted' : 'Not found'} ${id}.\\n`)\n },\n }),\n measure: defineCommand({\n meta: {\n name: 'measure',\n description:\n 'Measure a change with equal finalized before/after windows',\n },\n args: {\n id: { type: 'string' },\n site: { type: 'string' },\n scope: { type: 'string' },\n target: { type: 'string' },\n title: { type: 'string' },\n date: { type: 'string' },\n before: { type: 'string' },\n after: { type: 'string' },\n json: { type: 'boolean', default: false },\n refresh: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const id = stringArg(args.id)\n if (\n !id &&\n (!stringArg(args.site) ||\n !stringArg(args.scope) ||\n !stringArg(args.target) ||\n !stringArg(args.date))\n ) {\n throw new Error(\n 'Pass --id, or pass --site, --scope, --target, and --date for an ad hoc measurement.',\n )\n }\n const report = await measureChange({\n id,\n site: id\n ? undefined\n : await resolveSite({\n site: stringArg(args.site),\n options: { json },\n }),\n scope: id ? undefined : changeScope(args.scope),\n target: id ? undefined : stringArg(args.target),\n title: stringArg(args.title),\n changedAt: id ? undefined : stringArg(args.date),\n beforeDays: strictNumberArg(args.before, '--before'),\n afterDays: strictNumberArg(args.after, '--after'),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Change measurement',\n target: report.change.title,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.note,\n metrics: [\n { label: 'Verdict', value: report.verdict },\n { label: 'Confidence', value: report.confidence },\n {\n label: 'Before',\n value: `${report.before.startDate} to ${report.before.endDate}`,\n },\n {\n label: 'After',\n value: `${report.after.startDate} to ${report.after.endDate}`,\n },\n {\n label: 'Window',\n value: `${report.window.effectiveDays}/${report.window.requestedDays} finalized days`,\n },\n ],\n })\n printTable(\n ['Metric', 'Before', 'After', 'Delta'],\n [\n [\n 'Clicks',\n report.before.metrics?.clicks ?? 'unavailable',\n report.after.metrics?.clicks ?? 'unavailable',\n report.delta.clicks === null\n ? 'unavailable'\n : report.delta.clickPct === null\n ? `${report.delta.clicks}`\n : `${report.delta.clicks} (${report.delta.clickPct}%)`,\n ],\n [\n 'Impressions',\n report.before.metrics?.impressions ?? 'unavailable',\n report.after.metrics?.impressions ?? 'unavailable',\n report.delta.impressions === null\n ? 'unavailable'\n : report.delta.impressionPct === null\n ? `${report.delta.impressions}`\n : `${report.delta.impressions} (${report.delta.impressionPct}%)`,\n ],\n [\n 'CTR',\n report.before.metrics?.ctr ?? 'unavailable',\n report.after.metrics?.ctr ?? 'unavailable',\n report.delta.ctr ?? 'unavailable',\n ],\n [\n 'Position',\n report.before.metrics?.position ?? 'unavailable',\n report.after.metrics?.position ?? 'unavailable',\n report.delta.position ?? 'unavailable',\n ],\n ],\n )\n printNotes('Warnings', report.warnings)\n printNotes('Caveats', report.caveats)\n },\n }),\n },\n})\n","import {\n type ContentGroupDimension,\n type ContentGroupMatchType,\n createContentGroup,\n deleteContentGroup,\n listContentGroups,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\n\nfunction groupDimension(value: unknown): ContentGroupDimension {\n const dimension = stringArg(value) ?? 'page'\n if (dimension !== 'page' && dimension !== 'query') {\n throw new Error('Invalid --dimension. Use page or query.')\n }\n return dimension\n}\n\nfunction matchType(value: unknown): ContentGroupMatchType {\n const type = stringArg(value) ?? 'contains'\n if (type !== 'equals' && type !== 'contains' && type !== 'regex') {\n throw new Error('Invalid --match. Use equals, contains, or regex.')\n }\n return type\n}\n\nexport const contentGroupsCommand = defineCommand({\n meta: {\n name: 'content-groups',\n description: 'Create and manage reusable page/query groups',\n },\n subCommands: {\n list: defineCommand({\n meta: {\n name: 'list',\n description: 'List saved content groups',\n },\n args: {\n site: { type: 'string' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const groups = listContentGroups(stringArg(args.site))\n if (jsonFlag(args)) {\n printJson({ groups })\n return\n }\n printTable(\n ['ID', 'Site', 'Name', 'Dimension', 'Match', 'Pattern'],\n groups.map((group) => [\n group.id,\n group.site,\n group.name,\n group.dimension,\n group.matchType,\n group.pattern,\n ]),\n )\n },\n }),\n add: defineCommand({\n meta: {\n name: 'add',\n description: 'Create a reusable page or query group',\n },\n args: {\n site: { type: 'string' },\n name: { type: 'string', required: true },\n dimension: { type: 'string', default: 'page' },\n match: { type: 'string', default: 'contains' },\n pattern: { type: 'string', required: true },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const group = createContentGroup({\n site: await resolveSite({\n site: stringArg(args.site),\n options: { json },\n }),\n name: stringArg(args.name) ?? '',\n dimension: groupDimension(args.dimension),\n matchType: matchType(args.match),\n pattern: stringArg(args.pattern) ?? '',\n })\n if (json) {\n printJson(group)\n return\n }\n printKeyValue([\n ['ID', group.id],\n ['Site', group.site],\n ['Name', group.name],\n ['Filter', `${group.dimension} ${group.matchType} ${group.pattern}`],\n ])\n },\n }),\n delete: defineCommand({\n meta: {\n name: 'delete',\n description: 'Delete a content group',\n },\n args: {\n id: { type: 'string', required: true },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const deleted = deleteContentGroup(id)\n if (jsonFlag(args)) {\n printJson({ id, deleted })\n return\n }\n process.stdout.write(`${deleted ? 'Deleted' : 'Not found'} ${id}.\\n`)\n },\n }),\n },\n})\n","import {\n type ChangeMeasurement,\n type ChangeScope,\n listChanges,\n measureChange,\n recordChange,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\nimport { formatCount, printNotes, printReportSummary } from '../output.js'\n\nfunction today(): string {\n return new Date().toISOString().slice(0, 10)\n}\n\nfunction changeScope(value: unknown): ChangeScope {\n const scope = stringArg(value) ?? 'page'\n if (\n scope !== 'site' &&\n scope !== 'page' &&\n scope !== 'query' &&\n scope !== 'group'\n ) {\n throw new Error('Invalid --scope. Use site, page, query, or group.')\n }\n return scope\n}\n\nfunction maybeScope(value: unknown): ChangeScope | undefined {\n return value ? changeScope(value) : undefined\n}\n\nfunction pct(value: number | null): string {\n return value === null ? 'n/a' : `${value.toFixed(1)}%`\n}\n\nfunction countMetric(value: number | null | undefined): string {\n return value === null || value === undefined\n ? 'unavailable'\n : formatCount(value)\n}\n\nfunction countDelta(value: number | null, percentage: number | null): string {\n return value === null\n ? 'unavailable'\n : `${formatCount(value)} (${pct(percentage)})`\n}\n\nfunction decimalMetric(value: number | null | undefined, digits = 1): string {\n return value === null || value === undefined\n ? 'unavailable'\n : value.toFixed(digits)\n}\n\nfunction printMeasurement(report: ChangeMeasurement): void {\n printReportSummary({\n title: 'SEO test report',\n target: report.change.title,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.note,\n metrics: [\n { label: 'Verdict', value: report.verdict },\n { label: 'Confidence', value: report.confidence },\n {\n label: 'Before',\n value: `${report.before.startDate} to ${report.before.endDate}`,\n },\n {\n label: 'After',\n value: `${report.after.startDate} to ${report.after.endDate}`,\n },\n {\n label: 'Window',\n value: `${report.window.effectiveDays}/${report.window.requestedDays} finalized days`,\n },\n ],\n })\n printTable(\n ['Metric', 'Before', 'After', 'Delta'],\n [\n [\n 'GSC clicks',\n countMetric(report.before.metrics?.clicks),\n countMetric(report.after.metrics?.clicks),\n countDelta(report.delta.clicks, report.delta.clickPct),\n ],\n [\n 'GSC impressions',\n countMetric(report.before.metrics?.impressions),\n countMetric(report.after.metrics?.impressions),\n countDelta(report.delta.impressions, report.delta.impressionPct),\n ],\n [\n 'GSC CTR',\n report.before.metrics\n ? `${(report.before.metrics.ctr * 100).toFixed(1)}%`\n : 'unavailable',\n report.after.metrics\n ? `${(report.after.metrics.ctr * 100).toFixed(1)}%`\n : 'unavailable',\n report.delta.ctr === null\n ? 'unavailable'\n : `${(report.delta.ctr * 100).toFixed(1)} pts`,\n ],\n [\n 'GSC position',\n decimalMetric(report.before.metrics?.position),\n decimalMetric(report.after.metrics?.position),\n decimalMetric(report.delta.position),\n ],\n ],\n )\n\n if (report.analytics) {\n process.stdout.write('\\nGoogle Analytics impact\\n')\n printTable(\n ['Metric', 'Before', 'After', 'Delta'],\n [\n [\n 'Sessions',\n formatCount(report.analytics.before.metrics.sessions),\n formatCount(report.analytics.after.metrics.sessions),\n `${formatCount(report.analytics.delta.sessions)} (${pct(report.analytics.delta.sessionPct)})`,\n ],\n [\n 'Conversions',\n formatCount(report.analytics.before.metrics.conversions),\n formatCount(report.analytics.after.metrics.conversions),\n `${formatCount(report.analytics.delta.conversions)} (${pct(report.analytics.delta.conversionPct)})`,\n ],\n [\n 'Revenue',\n report.analytics.before.metrics.totalRevenue.toFixed(2),\n report.analytics.after.metrics.totalRevenue.toFixed(2),\n `${report.analytics.delta.totalRevenue.toFixed(2)} (${pct(report.analytics.delta.revenuePct)})`,\n ],\n ],\n )\n }\n\n if (report.control) {\n process.stdout.write('\\nControl comparison\\n')\n printKeyValue([\n ['Control', report.control.change.title],\n [\n 'Adjusted clicks',\n report.control.adjusted.clickDelta === null\n ? 'n/a'\n : formatCount(report.control.adjusted.clickDelta),\n ],\n [\n 'Adjusted click %',\n report.control.adjusted.clickPctPoints === null\n ? 'n/a'\n : `${report.control.adjusted.clickPctPoints.toFixed(1)} pts`,\n ],\n ['Note', report.control.note],\n ])\n }\n printNotes('Warnings', report.warnings)\n printNotes('Caveats', report.caveats)\n}\n\nexport const testsCommand = defineCommand({\n meta: {\n name: 'tests',\n description:\n 'Create and report local SEO tests from Search Console and Google Analytics data',\n },\n subCommands: {\n list: defineCommand({\n meta: { name: 'list', description: 'List saved SEO tests' },\n args: {\n site: { type: 'string', description: 'GSC property URL.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n limit: {\n type: 'string',\n description: 'Maximum tests to list. Defaults to 20.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = projectArg(args)\n const selection =\n project || stringArg(args.site)\n ? await resolveClientSelection({\n client: project,\n site: stringArg(args.site),\n options: { json },\n })\n : undefined\n const changes = listChanges({\n site: selection?.site,\n limit: numberArg(args.limit),\n })\n if (json) {\n printJson({ tests: changes })\n return\n }\n printTable(\n ['ID', 'Date', 'Scope', 'Target', 'Title'],\n changes.map((change) => [\n change.id,\n change.changedAt,\n change.scope,\n change.target,\n change.title,\n ]),\n )\n },\n }),\n create: defineCommand({\n meta: { name: 'create', description: 'Create a local SEO test' },\n args: {\n site: { type: 'string', description: 'GSC property URL.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n scope: {\n type: 'string',\n default: 'page',\n description: 'Change scope: site, page, query, or group.',\n },\n target: {\n type: 'string',\n required: true,\n description: 'Changed URL, query, group pattern, or site marker.',\n },\n title: {\n type: 'string',\n required: true,\n description: 'Plain-English name for the test.',\n },\n description: {\n type: 'string',\n description: 'Optional note about what changed.',\n },\n date: {\n type: 'string',\n description: 'Change date in YYYY-MM-DD. Defaults to today.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const change = recordChange({\n site: selection.site,\n scope: changeScope(args.scope),\n target: stringArg(args.target) ?? '',\n title: stringArg(args.title) ?? '',\n description: stringArg(args.description),\n changedAt: stringArg(args.date) ?? today(),\n })\n if (json) {\n printJson(change)\n return\n }\n printKeyValue([\n ['ID', change.id],\n ['Date', change.changedAt],\n ['Project', selection.client?.name ?? selection.site],\n ['Scope', change.scope],\n ['Target', change.target],\n ['Title', change.title],\n ])\n },\n }),\n report: defineCommand({\n meta: {\n name: 'report',\n description:\n 'Report an SEO test with equal finalized before/after windows',\n },\n args: {\n id: { type: 'string', description: 'Saved SEO test id.' },\n site: { type: 'string', description: 'GSC property URL.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n scope: {\n type: 'string',\n description: 'Ad-hoc change scope: site, page, query, or group.',\n },\n target: {\n type: 'string',\n description:\n 'Ad-hoc changed URL, query, group pattern, or site marker.',\n },\n title: { type: 'string', description: 'Ad-hoc test title.' },\n date: {\n type: 'string',\n description: 'Ad-hoc change date in YYYY-MM-DD.',\n },\n property: {\n type: 'string',\n description: 'Google Analytics property ID.',\n },\n 'control-scope': {\n type: 'string',\n description: 'Control scope: site, page, query, or group.',\n },\n 'control-target': {\n type: 'string',\n description: 'Control URL, query, group pattern, or site marker.',\n },\n 'control-title': {\n type: 'string',\n description: 'Plain-English name for the control group.',\n },\n before: {\n type: 'string',\n description: 'Days before the change date. Defaults to 28.',\n },\n after: {\n type: 'string',\n description: 'Days after the change date. Defaults to 28.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description:\n 'Bypass the local Search Console and Google Analytics cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const id = stringArg(args.id)\n const needsSelection =\n !id || Boolean(projectArg(args) || stringArg(args.site))\n const selection = needsSelection\n ? await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n : undefined\n const report = await measureChange({\n id,\n site: id ? undefined : selection?.site,\n scope: id ? undefined : maybeScope(args.scope),\n target: id ? undefined : stringArg(args.target),\n title: stringArg(args.title),\n changedAt: id ? undefined : stringArg(args.date),\n googleAnalyticsPropertyId:\n stringArg(args.property) ??\n selection?.client?.analytics.google?.propertyId,\n controlScope: maybeScope(args['control-scope']),\n controlTarget: stringArg(args['control-target']),\n controlTitle: stringArg(args['control-title']),\n beforeDays: strictNumberArg(args.before, '--before'),\n afterDays: strictNumberArg(args.after, '--after'),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printMeasurement(report)\n },\n }),\n },\n})\n","import type { ProgressReporter } from '@seo/core'\n\nexport function createProgressReporter(\n enabled: boolean,\n): ProgressReporter | undefined {\n if (!enabled) return undefined\n const startedAt = Date.now()\n return (message) => {\n const elapsed = ((Date.now() - startedAt) / 1000).toFixed(1)\n process.stderr.write(`[seo ${elapsed}s] ${message}\\n`)\n }\n}\n","import { mkdir, writeFile } from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport { type CsvFile, countLabel, renderCsv } from '@seo/core'\nexport const exportSelectionArgs = {\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description:\n 'Saved project id or name. Defaults to the configured default.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL/id when not using a saved project.',\n },\n} as const\n\nexport function outArg(report: string) {\n return {\n type: 'string',\n description: `Output folder. Defaults to ./seo-export/<project>-${report}-YYYY-MM-DD.`,\n } as const\n}\n\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/^sc-domain:/, '')\n .replace(/^https?:\\/\\//, '')\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n}\n\nexport function defaultOutDir(input: {\n report: string\n clientId?: string\n site: string\n}) {\n const day = new Date().toISOString().slice(0, 10)\n const id = slug(input.clientId ?? input.site)\n return resolve(process.cwd(), 'seo-export', `${id}-${input.report}-${day}`)\n}\n\nexport async function writeCsvFiles(outDir: string, files: CsvFile[]) {\n await mkdir(outDir, { recursive: true })\n const written: string[] = []\n for (const file of files) {\n const path = resolve(outDir, file.filename)\n await writeFile(path, renderCsv(file.rows, file.headers), 'utf8')\n written.push(path)\n }\n return written\n}\n\nexport function printWritten(outDir: string, files: string[]) {\n process.stdout.write(\n `Wrote ${countLabel(files.length, 'CSV file')} to ${outDir}\\n`,\n )\n for (const file of files) {\n process.stdout.write(`- ${file}\\n`)\n }\n}\n","import { diagnoseCsvFiles, diagnoseProperty } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n fetchRateArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { createProgressReporter } from '../../progress.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport {\n defaultOutDir,\n exportSelectionArgs,\n outArg,\n printWritten,\n writeCsvFiles,\n} from './shared.js'\n\nexport const exportDiagnoseCommand = defineCommand({\n meta: {\n name: 'diagnose',\n description:\n 'Export diagnosis tables: priorities, anomalies, movement, decay, cannibalisation, striking-distance, and quick wins.',\n },\n args: {\n ...exportSelectionArgs,\n out: outArg('diagnose'),\n days: {\n type: 'string',\n description: 'GSC lookback window. Defaults to 90.',\n },\n recent: {\n type: 'string',\n description: 'Recent anomaly window in days.',\n },\n limit: {\n type: 'string',\n description: 'Maximum rows per movement/opportunity table.',\n },\n 'include-brand': {\n type: 'boolean',\n default: false,\n description: 'Include branded queries in opportunity reports.',\n },\n 'verify-content': {\n type: 'boolean',\n default: false,\n description:\n 'Verify top opportunities against page title, meta, and content.',\n },\n 'verify-limit': {\n type: 'string',\n description: 'Maximum opportunity URLs to verify.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for verified pages.',\n },\n 'fetch-concurrency': {\n type: 'string',\n description: 'Maximum concurrent page fetches per host. Defaults to 4.',\n },\n 'fetch-interval-cap': {\n type: 'string',\n description: 'Maximum page fetches per interval per host. Defaults to 4.',\n },\n 'fetch-interval-ms': {\n type: 'string',\n description: 'Fetch rate interval in milliseconds. Defaults to 1000.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local cache and fetch fresh data.',\n },\n },\n run: async ({ args }) => {\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n })\n const report = await diagnoseProperty({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent: booleanArg(args['verify-content']),\n verifyLimit: numberArg(args['verify-limit']),\n js: booleanArg(args.js) ? true : 'auto',\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n progress: createProgressReporter(true),\n })\n const outDir =\n stringArg(args.out) ??\n defaultOutDir({\n report: 'diagnose',\n clientId: selection.client?.id,\n site: selection.site,\n })\n const written = await writeCsvFiles(outDir, diagnoseCsvFiles(report))\n printWritten(outDir, written)\n },\n})\n","import {\n analyticsConnection,\n refreshPrioritiesCsvFiles,\n refreshPrioritiesWorkflow,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from '../analytics/connection.js'\nimport { cliReportArgs } from '../report-options.js'\nimport {\n defaultOutDir,\n exportSelectionArgs,\n outArg,\n printWritten,\n writeCsvFiles,\n} from './shared.js'\n\nexport const exportRefreshPrioritiesCommand = defineCommand({\n meta: {\n name: 'refresh-priorities',\n description:\n 'Export the ranked SEO priority queue, score breakdowns, grouped findings, and diagnosis detail CSVs.',\n },\n args: {\n ...exportSelectionArgs,\n out: outArg('refresh-priorities'),\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum queue items to export. Defaults to 25.',\n },\n },\n ),\n ...analyticsConnectionArgs,\n 'verify-content': defaultTrueBooleanArg(\n 'Verify top opportunities against page title, meta, and content. Defaults to true.',\n 'Skip page content verification.',\n ),\n 'verify-limit': {\n type: 'string',\n description: 'Maximum opportunity URLs to verify. Defaults to 5.',\n },\n },\n run: async ({ args }) => {\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { refresh: booleanArg(args.refresh) },\n })\n const report = await refreshPrioritiesWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n googleAnalyticsPropertyId:\n stringArg(args['google-analytics-property']) ??\n selection.client?.analytics.google?.propertyId,\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection.client),\n ),\n verifyContent: booleanArg(args['verify-content']),\n verifyLimit: numberArg(args['verify-limit']),\n refresh: booleanArg(args.refresh),\n })\n const outDir =\n stringArg(args.out) ??\n defaultOutDir({\n report: 'refresh-priorities',\n clientId: selection.client?.id,\n site: selection.site,\n })\n const written = await writeCsvFiles(\n outDir,\n refreshPrioritiesCsvFiles(report),\n )\n printWritten(outDir, written)\n },\n})\n","import { updatePostmortemCsvFiles, updatePostmortemWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, numberArg, projectArg, stringArg } from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { cliReportArgs } from '../report-options.js'\nimport {\n defaultOutDir,\n exportSelectionArgs,\n outArg,\n printWritten,\n writeCsvFiles,\n} from './shared.js'\n\nexport const exportUpdatePostmortemCommand = defineCommand({\n meta: {\n name: 'update-postmortem',\n description:\n 'Export update postmortem attribution, findings, template movement, and segment movers.',\n },\n args: {\n ...exportSelectionArgs,\n out: outArg('update-postmortem'),\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum winners/losers per segment. Defaults to 20.',\n },\n },\n ),\n 'known-change': {\n type: 'string',\n description:\n 'Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.',\n },\n 'ignore-change-log': {\n type: 'boolean',\n default: false,\n description: 'Do not use saved change-log entries as confounders.',\n },\n },\n run: async ({ args }) => {\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { refresh: booleanArg(args.refresh) },\n })\n const report = await updatePostmortemWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n knownConfounders: stringArg(args['known-change'])\n ? [stringArg(args['known-change']) ?? '']\n : undefined,\n includeChangeLog: !booleanArg(args['ignore-change-log']),\n refresh: booleanArg(args.refresh),\n })\n const outDir =\n stringArg(args.out) ??\n defaultOutDir({\n report: 'update-postmortem',\n clientId: selection.client?.id,\n site: selection.site,\n })\n const written = await writeCsvFiles(\n outDir,\n updatePostmortemCsvFiles(report),\n )\n printWritten(outDir, written)\n },\n})\n","import { defineCommand } from 'citty'\nimport { exportDiagnoseCommand } from './diagnose.js'\nimport { exportRefreshPrioritiesCommand } from './refresh-priorities.js'\nimport { exportUpdatePostmortemCommand } from './update-postmortem.js'\n\nexport const exportCommand = defineCommand({\n meta: {\n name: 'export',\n description: 'Export full report data to CSV files',\n },\n subCommands: {\n diagnose: exportDiagnoseCommand,\n 'update-postmortem': exportUpdatePostmortemCommand,\n 'refresh-priorities': exportRefreshPrioritiesCommand,\n },\n})\n","import { defineCommand } from 'citty'\nimport { startCommand } from './setup/index.js'\n\n/**\n * Kept for existing scripts. New users should start with `seo start`.\n *\n * Do not let this become a second onboarding flow. A person should see the\n * same calm Google, project-profile, and MCP setup whichever entry they use.\n */\nexport const initCommand = defineCommand({\n ...startCommand,\n meta: {\n name: 'init',\n description: 'Legacy alias for `seo start`.',\n },\n})\n","import { pruneLogs } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../args.js'\nimport { formatBytes, printJson } from '../utils.js'\n\nexport const logsCommand = defineCommand({\n meta: { name: 'logs', description: 'Manage local log retention' },\n subCommands: {\n prune: defineCommand({\n meta: {\n name: 'prune',\n description: 'Rotate large logs and remove old local logs',\n },\n args: {\n quiet: {\n type: 'boolean',\n default: false,\n description: 'Do not print a result.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const result = pruneLogs()\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n if (!args.quiet) {\n process.stdout.write(\n `Rotated ${result.rotated} and removed ${result.removed} log files. ${formatBytes(result.sizeBytes)} retained.\\n`,\n )\n }\n },\n }),\n },\n})\n","import { multiselect } from '@clack/prompts'\nimport { SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag } from '../args.js'\nimport { canPrompt, maybeExitCancelled, printJson } from '../utils.js'\nimport {\n detectMcpClients,\n mcpClientTargets,\n type SupportedClient,\n} from './mcp-clients.js'\nimport { installMcpConfig, uninstallMcpConfig } from './mcp-config.js'\n\nconst targetFlags: Array<{\n client: SupportedClient\n flag: 'claude-desktop' | 'claude-code' | 'codex' | 'cursor'\n}> = [\n {\n client: 'claude-desktop',\n flag: 'claude-desktop',\n },\n { client: 'claude-code', flag: 'claude-code' },\n { client: 'codex', flag: 'codex' },\n { client: 'cursor', flag: 'cursor' },\n]\n\nfunction selectedClients(\n args: Record<string, unknown>,\n available: SupportedClient[],\n): SupportedClient[] {\n if (booleanArg(args.all)) return available\n return targetFlags\n .filter(({ flag }) => booleanArg(args[flag]))\n .map(({ client }) => client)\n}\n\nexport const mcpCommand = defineCommand({\n meta: { name: 'mcp', description: 'MCP server helpers' },\n subCommands: {\n serve: defineCommand({\n meta: {\n name: 'serve',\n description: 'Run the SEO MCP server',\n },\n args: {\n test: {\n type: 'boolean',\n default: false,\n description: 'Start in test mode',\n },\n },\n run: async ({ args }) => {\n const { startMcpServer } = await import('@seo/mcp')\n await startMcpServer({ test: booleanArg(args.test) })\n },\n }),\n install: defineCommand({\n meta: {\n name: 'install',\n description: 'Install or remove SEO MCP config for local clients',\n },\n args: {\n uninstall: {\n type: 'boolean',\n default: false,\n description: 'Remove the SEO MCP config instead of adding it',\n },\n reinstall: {\n type: 'boolean',\n default: false,\n description: 'Rewrite an existing managed SEO MCP config',\n },\n 'claude-desktop': {\n type: 'boolean',\n default: false,\n description: 'Update Claude Desktop',\n },\n 'claude-code': {\n type: 'boolean',\n default: false,\n description: 'Update Claude Code',\n },\n codex: {\n type: 'boolean',\n default: false,\n description: 'Update Codex CLI, app, and IDE extension',\n },\n cursor: {\n type: 'boolean',\n default: false,\n description: 'Update Cursor',\n },\n all: {\n type: 'boolean',\n default: false,\n description: 'Update every detected MCP client',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print structured JSON output',\n },\n },\n run: async ({ args }) => {\n if (booleanArg(args.uninstall) && booleanArg(args.reinstall)) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --uninstall or --reinstall, not both.',\n )\n }\n const targets = mcpClientTargets()\n const detected = detectMcpClients({ targets })\n const json = jsonFlag(args)\n let selected = selectedClients(\n args,\n detected.map((target) => target.client),\n )\n\n if (selected.length === 0) {\n if (!canPrompt({ json })) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Choose an MCP client with --claude-desktop, --claude-code, --codex, --cursor, or --all.',\n )\n }\n const choices = detected.length > 0 ? detected : targets\n selected = maybeExitCancelled(\n await multiselect({\n message: args.uninstall\n ? 'Remove seo from which MCP clients?'\n : 'Install seo into which MCP clients?',\n options: choices.map((target) => ({\n value: target.client,\n label: target.label,\n hint: target.path,\n })),\n initialValues: detected.map((target) => target.client),\n required: true,\n }),\n )\n }\n\n const unavailable = selected.filter(\n (client) => !targets.some((target) => target.client === client),\n )\n if (unavailable.length > 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `MCP setup is not supported for ${unavailable.join(', ')} on ${process.platform}.`,\n )\n }\n\n const results = targets\n .filter((entry) => selected.includes(entry.client))\n .map((target) =>\n booleanArg(args.uninstall)\n ? uninstallMcpConfig(target)\n : installMcpConfig(target, {\n reinstall: booleanArg(args.reinstall),\n }),\n )\n\n if (json) {\n printJson({\n operation: booleanArg(args.uninstall) ? 'uninstall' : 'install',\n results,\n })\n return\n }\n\n for (const result of results) {\n process.stdout.write(\n `${result.changed ? 'updated' : 'skipped'} ${result.client} · ${result.path}\\n`,\n )\n }\n },\n }),\n },\n})\n","import { crawlDiff } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, numberArg, stringArg } from '../../args.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printActionDetails, printReportSummary, truncate } from '../output.js'\n\nexport const crawlDiffCommand = defineCommand({\n meta: {\n name: 'crawl-diff',\n description: 'Crawl a site and diff technical/page changes vs last run',\n },\n args: {\n url: {\n type: 'string',\n required: true,\n description: 'Start URL to crawl.',\n },\n site: {\n type: 'string',\n description: 'Optional GSC property to associate with the crawl.',\n },\n limit: {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 50.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n },\n run: async ({ args }) => {\n const report = await crawlDiff({\n startUrl: stringArg(args.url) ?? '',\n site: stringArg(args.site),\n limit: numberArg(args.limit),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n })\n if (jsonFlag(args)) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Crawl history comparison',\n target: report.run.startUrl,\n status:\n report.previousRun === undefined\n ? 'unknown'\n : report.summary.newErrors > 0 || report.summary.indexabilityFlips > 0\n ? 'warning'\n : 'pass',\n summary:\n report.previousRun === undefined\n ? 'No previous crawl was available for comparison.'\n : `${report.summary.changed} changed, ${report.summary.added} added, and ${report.summary.removed} removed URLs.`,\n metrics: [\n { label: 'Run', value: report.run.id },\n { label: 'Crawled', value: report.summary.crawled },\n { label: 'Previous run', value: report.previousRun?.id ?? 'None' },\n { label: 'Added', value: report.summary.added },\n { label: 'Removed', value: report.summary.removed },\n { label: 'Changed', value: report.summary.changed },\n { label: 'New errors', value: report.summary.newErrors },\n {\n label: 'Indexability flips',\n value: report.summary.indexabilityFlips,\n },\n {\n label: 'High priority',\n value: report.summary.highPriorityRecommendations,\n },\n ],\n })\n if (report.recommendations.length) {\n process.stdout.write('\\nRecommended actions\\n')\n printTable(\n ['Severity', 'Category', 'URL', 'Action'],\n report.recommendations\n .slice(0, 10)\n .map((item) => [\n item.severity,\n item.category,\n truncate(item.url, 56),\n truncate(item.action, 72),\n ]),\n )\n printActionDetails(\n 'Top crawl actions',\n report.recommendations.map((item) => ({\n label: item.category,\n context: `${item.severity}, ${truncate(item.url, 96)}`,\n action: item.action,\n })),\n )\n }\n if (report.items.length) {\n process.stdout.write('\\nChanged URLs\\n')\n printTable(\n ['Kind', 'URL', 'Changes', 'Recommendation'],\n report.items\n .slice(0, 50)\n .map((item) => [\n item.kind,\n truncate(item.url, 56),\n item.changes.join(', '),\n item.recommendation?.title ?? '-',\n ]),\n )\n }\n if (report.warnings.length) {\n process.stdout.write('\\nWarnings\\n')\n for (const warning of report.warnings.slice(0, 10)) {\n process.stdout.write(`- ${warning}\\n`)\n }\n }\n },\n})\n","import { defaultTrueBooleanArg } from '../../args.js'\n\nexport function monitoringRunArgs() {\n return {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Defaults from the project or GSC property.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to inspect with URL Inspection.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs for quota-aware index monitoring.',\n },\n properties: {\n type: 'string',\n description:\n 'Comma-separated GSC properties for sitemap index monitoring.',\n },\n limit: {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 50.',\n },\n 'daily-limit': {\n type: 'string',\n description: 'URL Inspection daily limit per property. Defaults to 2000.',\n },\n 'inspect-limit': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to inspect in this run. Defaults to 100.',\n },\n 'max-urls': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to load for monitoring. Defaults to 50000.',\n },\n language: {\n type: 'string',\n description: 'Optional URL Inspection language code.',\n },\n 'recover-links': defaultTrueBooleanArg(\n 'Check search-value GSC pages for broken, blocked, or poorly redirected URLs.',\n 'Skip link recovery checks.',\n ),\n 'recover-days': {\n type: 'string',\n description: 'GSC lookback window for link recovery. Defaults to 90.',\n },\n 'recover-limit': {\n type: 'string',\n description:\n 'Maximum search-value pages to check for link recovery. Defaults to 10.',\n },\n 'recover-min-clicks': {\n type: 'string',\n description:\n 'Minimum clicks for link recovery candidates. Defaults to 1.',\n },\n 'recover-min-impressions': {\n type: 'string',\n description:\n 'Minimum impressions for link recovery candidates. Defaults to 100.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP/GSC cache where supported.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n } as const\n}\n\nexport function monitoringStatusArgs() {\n return {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n 'stale-days': {\n type: 'string',\n description: 'Mark checks stale after this many days. Defaults to 8.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Refresh property selection data when prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n } as const\n}\n","import { printSemanticReport } from '../../utils.js'\n\nfunction stepStatus(\n value: string,\n): 'pass' | 'warning' | 'fail' | 'unknown' | 'info' {\n const status = value.toLowerCase()\n if (['pass', 'passed', 'complete', 'completed', 'joined'].includes(status)) {\n return 'pass'\n }\n if (['warn', 'warning', 'partial', 'review'].includes(status)) {\n return 'warning'\n }\n if (['fail', 'failed', 'error'].includes(status)) return 'fail'\n if (['unknown', 'unavailable'].includes(status)) return 'unknown'\n return 'info'\n}\n\nexport function printWorkflow(report: {\n workflow: string\n site: string\n summary: string\n steps: Array<{ tool: string; status: string; summary: string }>\n actions: Array<{ title: string; confidence: string; action: string }>\n}): void {\n const statuses = report.steps.map((step) => stepStatus(step.status))\n const status = statuses.includes('fail')\n ? 'fail'\n : statuses.includes('warning')\n ? 'warning'\n : statuses.includes('unknown')\n ? 'unknown'\n : 'pass'\n printSemanticReport({\n title: report.workflow,\n target: report.site,\n status,\n summary: report.summary,\n metrics: [\n {\n label: 'Completed',\n value: statuses.filter((value) => value === 'pass').length,\n status: 'pass',\n },\n {\n label: 'Review',\n value: statuses.filter((value) => value === 'warning').length,\n status: 'warning',\n },\n {\n label: 'Unknown',\n value: statuses.filter((value) => value === 'unknown').length,\n status: 'unknown',\n },\n ],\n sections: [\n {\n title: 'Evidence collection',\n diagnostics: report.steps.map((step) => ({\n status: stepStatus(step.status),\n title: step.tool,\n explanation: step.summary,\n evidence: [`Status: ${step.status}`],\n })),\n },\n {\n title: 'Priority actions',\n diagnostics: report.actions.map((action) => ({\n status: 'warning' as const,\n title: action.title,\n explanation: `Confidence: ${action.confidence}.`,\n fix: action.action,\n })),\n },\n ],\n })\n}\n","import type { MonitoringStatusReport, technicalWatchWorkflow } from '@seo/core'\nimport { printTable } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { printWorkflow } from '../workflows/output.js'\n\ntype TechnicalWatchReport = Awaited<ReturnType<typeof technicalWatchWorkflow>>\n\nexport function printMonitoringRun(report: TechnicalWatchReport): void {\n printWorkflow(report)\n\n if (report.output.crawl?.recommendations.length) {\n process.stdout.write('\\nCrawl actions\\n')\n printTable(\n ['Severity', 'URL', 'Action'],\n report.output.crawl.recommendations\n .slice(0, 10)\n .map((item) => [\n item.severity,\n truncate(item.url, 56),\n truncate(item.action, 72),\n ]),\n )\n printActionDetails(\n 'Top crawl actions',\n report.output.crawl.recommendations.map((item) => ({\n label: item.severity,\n context: truncate(item.url, 96),\n action: item.action,\n })),\n )\n }\n\n if (report.output.index?.items.length) {\n const items = report.output.index.items\n .filter(\n (item) =>\n item.currentIssue ||\n item.changed ||\n item.inspectionStatus !== 'succeeded',\n )\n .slice(0, 25)\n if (items.length) {\n process.stdout.write('\\nIndex reviews, changes, and failed checks\\n')\n printTable(\n ['Check', 'Change', 'Index state', 'Evidence', 'URL'],\n items.map((item) => [\n item.inspectionStatus,\n item.changeKind,\n item.indexStatus,\n truncate(\n (item.errorCode ?? item.issueCodes.join(', ')) || 'none',\n 40,\n ),\n truncate(item.url, 64),\n ]),\n )\n }\n }\n\n if (report.output.recovery?.items.length) {\n process.stdout.write('\\nRecoverable URLs\\n')\n printTable(\n ['Severity', 'Issue', 'Clicks', 'Impr', 'URL', 'Action'],\n report.output.recovery.items\n .slice(0, 10)\n .map((item) => [\n item.severity,\n item.issue,\n formatCount(item.clicks),\n formatCount(item.impressions),\n truncate(item.url, 56),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top recovery actions',\n report.output.recovery.items.map((item) => ({\n label: truncate(item.url, 96),\n context: `${item.severity}, ${formatCount(item.clicks)} clicks at risk`,\n action: item.recommendation.action,\n })),\n )\n }\n}\n\nexport function printMonitoringStatus(report: MonitoringStatusReport): void {\n printReportSummary({\n title: 'Technical monitoring status',\n target: report.site,\n status:\n report.health === 'clear'\n ? 'pass'\n : report.health === 'attention'\n ? 'warning'\n : 'unknown',\n summary:\n report.summary.attention > 0\n ? `${report.summary.attention} checks need attention.`\n : report.summary.stale > 0 || report.summary.notRun > 0\n ? `${report.summary.stale} checks are stale and ${report.summary.notRun} have not run.`\n : 'No monitoring checks currently need attention.',\n metrics: [\n { label: 'Health', value: report.health },\n { label: 'Attention', value: report.summary.attention },\n { label: 'Stale', value: report.summary.stale },\n { label: 'Not run', value: report.summary.notRun },\n ],\n })\n\n printTable(\n ['Check', 'Status', 'Last run', 'Summary'],\n report.checks.map((check) => [\n check.name,\n check.status,\n check.lastRunAt ?? '-',\n check.summary,\n ]),\n )\n\n const actions = report.checks.filter((check) => check.action)\n if (actions.length) {\n process.stdout.write('\\nNext actions\\n')\n printTable(\n ['Check', 'Action'],\n actions.map((check) => [check.name, truncate(check.action ?? '', 96)]),\n )\n printActionDetails(\n 'Next action details',\n actions.map((check) => ({\n label: check.name,\n action: check.action ?? '',\n })),\n )\n }\n}\n","import { monitoringStatus, technicalWatchWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printKeyValue } from '../../utils.js'\nimport { startUrlForSite } from '../shared.js'\nimport { monitoringRunArgs, monitoringStatusArgs } from './args.js'\nimport { printMonitoringRun, printMonitoringStatus } from './output.js'\n\nfunction quotedFlag(name: string, value: unknown): string | undefined {\n const text = stringArg(value)\n return text ? `--${name} ${JSON.stringify(text)}` : undefined\n}\n\nfunction booleanFlag(name: string, value: unknown): string | undefined {\n return booleanArg(value) ? `--${name}` : undefined\n}\n\nfunction recoverLinksFlag(value: unknown): string | undefined {\n return booleanArg(value) === false ? '--recover-links=false' : undefined\n}\n\nexport const monitoringCommand = defineCommand({\n meta: {\n name: 'monitoring',\n description: 'Run and review recurring technical SEO monitoring',\n },\n subCommands: {\n run: defineCommand({\n meta: {\n name: 'run',\n description:\n 'Run crawl, index, and link recovery monitoring for a property',\n },\n args: monitoringRunArgs(),\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const urls = listArg(args.urls)\n const sitemaps = listArg(args.sitemaps)\n const startUrl =\n stringArg(args.url) ??\n selection.client?.startUrl ??\n startUrlForSite(selection.site)\n const report = await technicalWatchWorkflow({\n site: selection.site,\n startUrl,\n urls: urls.length ? urls : selection.client?.watchUrls,\n sitemaps: sitemaps.length ? sitemaps : undefined,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n limit: numberArg(args.limit),\n languageCode: stringArg(args.language),\n dailyLimit: numberArg(args['daily-limit']),\n inspectLimit: numberArg(args['inspect-limit']),\n maxUrls: numberArg(args['max-urls']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n recoverLinks: booleanArg(args['recover-links']),\n recoverDays: numberArg(args['recover-days']),\n recoverLimit: numberArg(args['recover-limit']),\n recoverMinClicks: numberArg(args['recover-min-clicks']),\n recoverMinImpressions: numberArg(args['recover-min-impressions']),\n })\n\n if (json) {\n printJson(report)\n return\n }\n printMonitoringRun(report)\n },\n }),\n status: defineCommand({\n meta: {\n name: 'status',\n description: 'Show the latest saved monitoring state for a property',\n },\n args: monitoringStatusArgs(),\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = monitoringStatus({\n site: selection.site,\n staleAfterDays: numberArg(args['stale-days']),\n })\n if (json) {\n printJson(report)\n return\n }\n printMonitoringStatus(report)\n },\n }),\n cron: defineCommand({\n meta: {\n name: 'cron',\n description: 'Print a local cron line for recurring monitoring',\n },\n args: {\n ...monitoringRunArgs(),\n hour: {\n type: 'string',\n default: '9',\n description: 'Hour in local cron time. Defaults to 9.',\n },\n minute: {\n type: 'string',\n default: '0',\n description: 'Minute in local cron time. Defaults to 0.',\n },\n weekday: {\n type: 'string',\n description:\n 'Weekly monitoring day. Defaults to client setting, then Monday.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const hour = numberArg(args.hour) ?? 9\n const minute = numberArg(args.minute) ?? 0\n const weekday =\n numberArg(args.weekday) ?? selection.client?.technicalWeekday ?? 1\n const identityArg = selection.client\n ? `--project ${JSON.stringify(selection.client.id)}`\n : `--site ${JSON.stringify(selection.site)}`\n const command = [\n 'seo monitoring run',\n identityArg,\n quotedFlag('url', args.url),\n quotedFlag('urls', args.urls),\n quotedFlag('sitemaps', args.sitemaps),\n quotedFlag('properties', args.properties),\n quotedFlag('limit', args.limit),\n quotedFlag('daily-limit', args['daily-limit']),\n quotedFlag('inspect-limit', args['inspect-limit']),\n quotedFlag('max-urls', args['max-urls']),\n quotedFlag('language', args.language),\n quotedFlag('recover-days', args['recover-days']),\n quotedFlag('recover-limit', args['recover-limit']),\n quotedFlag('recover-min-clicks', args['recover-min-clicks']),\n quotedFlag(\n 'recover-min-impressions',\n args['recover-min-impressions'],\n ),\n recoverLinksFlag(args['recover-links']),\n booleanFlag('refresh', args.refresh),\n booleanFlag('js', args.js),\n '--json',\n ]\n .filter(Boolean)\n .join(' ')\n const line = {\n name: 'monitoring',\n cron: `${minute} ${hour} * * ${weekday}`,\n command,\n }\n\n if (json) {\n printJson({ site: selection.site, line })\n return\n }\n printKeyValue([\n ['Property', selection.site],\n ['Install', 'crontab -e'],\n ])\n process.stdout.write(`${line.cron} ${line.command}\\n`)\n },\n }),\n },\n})\n","import { indexCoverageSignals } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary, truncate } from '../output.js'\n\nexport const indexCoverageCommand = defineCommand({\n meta: {\n name: 'index-coverage',\n description:\n 'Find crawlable pages that deserve a closer Google index check',\n },\n args: {\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n 'crawl-report-id': {\n type: 'string',\n description:\n 'Saved crawl report id. Defaults to the latest for the site.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs. Defaults to declarations captured by the crawl.',\n },\n days: {\n type: 'string',\n description: 'Finalized Search Console date range. Defaults to 90 days.',\n },\n 'row-limit': {\n type: 'string',\n description: 'Maximum Search Console page rows. Defaults to 100000.',\n },\n 'max-sitemap-urls': {\n type: 'string',\n description: 'Maximum sitemap inventory URLs. Defaults to 100000.',\n },\n limit: {\n type: 'string',\n description:\n 'Maximum URLs returned in each evidence group. Defaults to 100.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local Search Console cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const sitemapValues = listArg(args.sitemaps)\n const report = await indexCoverageSignals({\n site: selection.site,\n crawlReportId: stringArg(args['crawl-report-id']),\n sitemaps: sitemapValues.length ? sitemapValues : undefined,\n days: numberArg(args.days),\n rowLimit: numberArg(args['row-limit']),\n maxSitemapUrls: numberArg(args['max-sitemap-urls']),\n itemsPerSection: numberArg(args.limit),\n refresh: booleanArg(args.refresh),\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Index coverage',\n target: report.site,\n status:\n report.sources.crawl.completeness === 'complete' &&\n report.sources.searchConsole.completeness === 'complete'\n ? report.summary.crawlableCandidatesWithoutRetainedSearchVisibility >\n 0\n ? 'warning'\n : 'pass'\n : 'unknown',\n summary: `${report.summary.crawlableCandidatesWithoutRetainedSearchVisibility} crawlable pages need URL Inspection review.`,\n metrics: [\n { label: 'Crawl report', value: report.input.crawlReport.id },\n { label: 'Crawl evidence', value: report.sources.crawl.completeness },\n {\n label: 'Sitemap evidence',\n value: report.sources.sitemap.completeness,\n },\n {\n label: 'Search evidence',\n value: report.sources.searchConsole.completeness,\n },\n {\n label: 'Search window',\n value: `${report.sources.searchConsole.startDate} to ${report.sources.searchConsole.endDate}`,\n },\n {\n label: 'Search-visible pages',\n value: report.summary.retainedSearchVisibleUrls,\n },\n {\n label: 'Blocked/non-indexable',\n value: report.summary.blockedOrNonIndexableCrawlUrls,\n },\n { label: 'Sitemap only', value: report.summary.sitemapOnlyUrls },\n {\n label: 'Search Console only',\n value: report.summary.searchConsoleOnlyUrls,\n },\n ],\n })\n\n if (report.crawlableWithoutRetainedSearchVisibility.items.length) {\n process.stdout.write('\\nRepresentative URL Inspection candidates\\n')\n printTable(\n ['URL', 'Status', 'In sitemap'],\n report.crawlableWithoutRetainedSearchVisibility.items.map((item) => [\n truncate(item.url, 80),\n item.status,\n item.inSitemap ? 'yes' : 'no',\n ]),\n )\n }\n\n printNotes('How to read this report', report.caveats)\n },\n})\n","import {\n countLabel,\n indexCoveragePlan,\n indexMonitor,\n indexWatch,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n listArg,\n numberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveSite } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary } from '../output.js'\n\nexport const indexWatchCommand = defineCommand({\n meta: {\n name: 'index-watch',\n description: 'Inspect URLs with GSC and alert on index status changes',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to inspect.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs to plan quota-aware monitoring.',\n },\n plan: {\n type: 'boolean',\n default: false,\n description:\n 'Plan sitemap URL allocation across GSC properties without inspecting URLs.',\n },\n properties: {\n type: 'string',\n description:\n 'Comma-separated GSC properties to use for planning. Defaults to account properties.',\n },\n 'daily-limit': {\n type: 'string',\n description: 'URL Inspection daily limit per property. Defaults to 2000.',\n },\n 'target-days': {\n type: 'string',\n description:\n 'Target number of days to inspect all monitored URLs. Defaults to 1.',\n },\n 'max-urls': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to load for planning. Defaults to 50000.',\n },\n 'inspect-limit': {\n type: 'string',\n description:\n 'Maximum URLs to inspect in this run from sitemap mode. Defaults to 100.',\n },\n language: {\n type: 'string',\n description: 'Optional URL Inspection language code.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const urls = listArg(args.urls)\n const site = await resolveSite({\n site: stringArg(args.site),\n options: { json },\n })\n\n const sitemaps = listArg(args.sitemaps)\n\n if (booleanArg(args.plan)) {\n if (!sitemaps.length) {\n throw new Error('Pass at least one sitemap with --sitemaps.')\n }\n const report = await indexCoveragePlan({\n site,\n sitemaps,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n dailyLimit: numberArg(args['daily-limit']),\n targetCycleDays: numberArg(args['target-days']),\n maxUrls: numberArg(args['max-urls']),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Index monitoring plan',\n target: report.site,\n status: report.warnings.length > 0 ? 'warning' : 'info',\n summary: `${report.summary.urlCount} sitemap URLs can be checked in an estimated ${countLabel(report.summary.estimatedCycleDays, 'day')}.`,\n metrics: [\n { label: 'Sitemap URLs', value: report.summary.urlCount },\n { label: 'Properties', value: report.summary.properties },\n { label: 'Daily capacity', value: report.summary.dailyCapacity },\n {\n label: 'Target cycle',\n value: countLabel(report.summary.targetCycleDays, 'day'),\n },\n {\n label: 'Suggested properties',\n value: report.summary.suggestedProperties,\n },\n ],\n })\n if (report.properties.length) {\n printTable(\n ['Property', 'URLs', 'Cycle', 'Sample URL'],\n report.properties.map((property) => [\n property.property,\n property.urlCount,\n countLabel(property.cycleDays, 'day'),\n property.sampleUrls[0] ?? '-',\n ]),\n )\n }\n if (report.suggestions.length) {\n process.stdout.write('\\nSuggested URL-prefix properties\\n')\n printTable(\n ['Property', 'URLs', 'Current property', 'Cycle', 'Reason'],\n report.suggestions.map((suggestion) => [\n suggestion.property,\n suggestion.urlCount,\n suggestion.currentProperty,\n countLabel(suggestion.estimatedCycleDays, 'day'),\n suggestion.reason,\n ]),\n )\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n return\n }\n\n if (sitemaps.length) {\n const report = await indexMonitor({\n site,\n sitemaps,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n dailyLimit: numberArg(args['daily-limit']),\n inspectLimit: numberArg(args['inspect-limit']),\n maxUrls: numberArg(args['max-urls']),\n languageCode: stringArg(args.language),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Index monitoring run',\n target: report.site,\n status:\n report.summary.failed > 0 || report.summary.quotaBlocked > 0\n ? 'unknown'\n : report.summary.alerts > 0 || report.summary.regressions > 0\n ? 'warning'\n : report.summary.attempted > 0\n ? 'pass'\n : 'info',\n summary: `${report.summary.inspected} URLs inspected, with ${report.summary.alerts} new alerts and ${report.summary.regressions} regressions.`,\n metrics: [\n { label: 'Inventory URLs', value: report.summary.inventoryUrls },\n { label: 'Selected', value: report.summary.selected },\n { label: 'Inspected', value: report.summary.inspected },\n { label: 'Failed', value: report.summary.failed },\n { label: 'Quota blocked', value: report.summary.quotaBlocked },\n { label: 'Current reviews', value: report.summary.currentIssues },\n { label: 'Regressions', value: report.summary.regressions },\n { label: 'Recoveries', value: report.summary.recoveries },\n { label: 'New alerts', value: report.summary.alerts },\n ],\n })\n if (report.properties.length) {\n printTable(\n [\n 'Property',\n 'Inventory',\n 'Selected',\n 'Inspected',\n 'Failed',\n 'Current',\n 'Alerts',\n ],\n report.properties.map((property) => [\n property.property,\n property.inventoryUrls,\n property.selectedUrls,\n property.inspected,\n property.failed + property.quotaBlocked,\n property.currentIssues,\n property.alerts,\n ]),\n )\n }\n const issueItems = report.items\n .filter(\n (item) =>\n item.currentIssue ||\n item.changed ||\n item.inspectionStatus !== 'succeeded',\n )\n .slice(0, 50)\n if (issueItems.length) {\n process.stdout.write('\\nIndex reviews, changes, and failed checks\\n')\n printTable(\n ['Check', 'Change', 'Index state', 'Evidence', 'URL'],\n issueItems.map((item) => [\n item.inspectionStatus,\n item.changeKind,\n item.indexStatus,\n (item.errorCode ?? item.issueCodes.join(', ')) || 'none',\n item.url,\n ]),\n )\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n return\n }\n\n if (!urls.length) throw new Error('Pass at least one URL with --urls.')\n\n const report = await indexWatch({\n site,\n urls,\n languageCode: stringArg(args.language),\n dailyLimit: numberArg(args['daily-limit']),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Index watch',\n target: report.site,\n status:\n report.summary.failed > 0 || report.summary.quotaBlocked > 0\n ? 'unknown'\n : report.summary.alerts > 0 || report.summary.regressions > 0\n ? 'warning'\n : report.summary.attempted > 0\n ? 'pass'\n : 'info',\n summary: `${report.summary.inspected} URLs inspected, with ${report.summary.alerts} new alerts.`,\n metrics: [\n { label: 'Property', value: report.source.property },\n { label: 'Attempted', value: report.summary.attempted },\n { label: 'Inspected', value: report.summary.inspected },\n { label: 'Failed', value: report.summary.failed },\n { label: 'Quota blocked', value: report.summary.quotaBlocked },\n { label: 'Current reviews', value: report.summary.currentIssues },\n { label: 'Regressions', value: report.summary.regressions },\n { label: 'Recoveries', value: report.summary.recoveries },\n { label: 'New alerts', value: report.summary.alerts },\n ],\n })\n printTable(\n ['Check', 'Change', 'Index state', 'Evidence', 'URL'],\n report.items.map((item) => [\n item.inspectionStatus,\n item.changeKind,\n item.indexStatus,\n (item.errorCode ?? item.issueCodes.join(', ')) || 'none',\n item.url,\n ]),\n )\n },\n})\n","import { linkRecover } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { selectedSiteOrThrow } from '../shared.js'\n\nexport const linkRecoverCommand = defineCommand({\n meta: {\n name: 'link-recover',\n description:\n 'Find search-value URLs that are now broken, blocked, or poorly redirected',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'limit', 'minImpressions', 'refresh', 'js'], {\n days: {\n description: 'GSC lookback window. Defaults to 90.',\n },\n limit: {\n description: 'Maximum GSC pages to check. Defaults to 50.',\n },\n minImpressions: {\n description: 'Minimum impressions to check a page. Defaults to 100.',\n },\n refresh: {\n description: 'Bypass local GSC and HTTP caches.',\n },\n js: {\n description: 'Force JavaScript rendering for final page extraction.',\n },\n }),\n 'min-clicks': {\n type: 'string',\n description: 'Minimum clicks to check a page. Defaults to 1.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const report = await linkRecover({\n site: await selectedSiteOrThrow(\n { client: projectArg(args), site: stringArg(args.site) },\n { json },\n ),\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minClicks: numberArg(args['min-clicks']),\n minImpressions: numberArg(args['min-impressions']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n })\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Link recovery',\n target: report.site,\n status:\n report.warnings.length > 0\n ? 'unknown'\n : report.summary.recoverable > 0\n ? 'warning'\n : 'pass',\n summary:\n report.summary.recoverable > 0\n ? `${formatCount(report.summary.recoverable)} previously visible URLs need recovery review.`\n : 'No recoverable URLs were found in the retained evidence.',\n metrics: [\n {\n label: 'Range',\n value: `${report.range.startDate} to ${report.range.endDate}`,\n },\n { label: 'Checked', value: formatCount(report.summary.checked) },\n {\n label: 'Recoverable',\n value: formatCount(report.summary.recoverable),\n },\n { label: 'High severity', value: formatCount(report.summary.high) },\n {\n label: 'Clicks at risk',\n value: formatCount(report.summary.clicksAtRisk),\n },\n {\n label: 'Impressions at risk',\n value: formatCount(report.summary.impressionsAtRisk),\n },\n ],\n })\n if (report.items.length) {\n printLimitedTable(\n ['Severity', 'Issue', 'Clicks', 'Impr', 'URL', 'Action'],\n report.items.map((item) => [\n item.severity,\n item.issue,\n formatCount(item.clicks),\n formatCount(item.impressions),\n truncate(item.url, 56),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top recovery actions',\n report.items.map((item) => ({\n label: truncate(item.url, 96),\n context: `${item.severity}, ${formatCount(item.clicks)} clicks at risk`,\n action: item.recommendation.action,\n })),\n )\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n },\n})\n","import { redirectTrace } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, numberArg, stringArg } from '../../args.js'\nimport { printJson, printKeyValue, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary, truncate } from '../output.js'\n\nexport const redirectTraceCommand = defineCommand({\n meta: {\n name: 'redirect-trace',\n description:\n 'Trace redirects and report final indexability/canonical issues',\n },\n args: {\n url: {\n type: 'string',\n required: true,\n description: 'URL to trace.',\n },\n 'max-hops': {\n type: 'string',\n description: 'Maximum redirect hops to follow. Defaults to 10.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache for final page extraction.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for final page extraction.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const report = await redirectTrace({\n url: stringArg(args.url) ?? '',\n maxHops: numberArg(args['max-hops']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n })\n if (jsonFlag(args)) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Redirect trace',\n target: report.url,\n status:\n report.summary.issues.length > 0\n ? 'warning'\n : report.summary.finalIndexable === undefined\n ? 'unknown'\n : 'pass',\n summary:\n report.summary.issues.length > 0\n ? report.summary.issues.join(', ')\n : `${report.summary.hops} redirect hops ended at HTTP ${report.summary.finalStatus}.`,\n metrics: [\n { label: 'Final URL', value: report.finalUrl },\n { label: 'Final status', value: report.summary.finalStatus },\n {\n label: 'Indexable',\n value:\n report.summary.finalIndexable === undefined\n ? 'Unknown'\n : report.summary.finalIndexable\n ? 'Yes'\n : 'No',\n },\n { label: 'Hops', value: report.summary.hops },\n ],\n })\n printTable(\n ['#', 'Status', 'URL', 'Next'],\n report.chain.map((step, index) => [\n index + 1,\n step.status,\n truncate(step.url, 72),\n truncate(step.nextUrl ?? '-', 72),\n ]),\n )\n if (report.finalPage) {\n process.stdout.write('\\nFinal page\\n')\n printKeyValue([\n ['Title', report.finalPage.title ?? '-'],\n ['Canonical', report.finalPage.canonical ?? '-'],\n ['Meta robots', report.finalPage.metaRobots ?? '-'],\n ])\n }\n printNotes('Warnings', report.warnings.slice(0, 10))\n },\n})\n","import { aiReferralsReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, projectArg, strictNumberArg, stringArg } from '../../args.js'\nimport {\n resolveClient,\n resolveGoogleAnalyticsProperty,\n} from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n printLimitedTable,\n printReportSummary,\n truncate,\n} from '../output.js'\n\nexport const aiReferralsCommand = defineCommand({\n meta: {\n name: 'ai-referrals',\n description: 'Find AI referral traffic detected in Google Analytics',\n },\n args: {\n property: {\n type: 'string',\n description:\n 'Google Analytics property ID. If omitted in a terminal, choose one.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description:\n 'Saved project id or name with an optional Google Analytics property.',\n },\n 'start-date': { type: 'string', default: '28daysAgo' },\n 'end-date': { type: 'string', default: 'yesterday' },\n 'max-rows': {\n type: 'string',\n description:\n 'Maximum Google Analytics rows per query. Defaults to 100000.',\n },\n 'result-limit': {\n type: 'string',\n description: 'Maximum ranked landing pages returned. Defaults to 25.',\n },\n limit: {\n type: 'string',\n description: 'Legacy alias for --max-rows.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass cached Google Analytics responses.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const client = await resolveClient({\n client: projectArg(args),\n options: { json },\n })\n const property = await resolveGoogleAnalyticsProperty({\n property:\n stringArg(args.property) ?? client?.analytics.google?.propertyId,\n options: { json },\n })\n const report = await aiReferralsReport({\n property,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n maxRows: strictNumberArg(args['max-rows'], '--max-rows'),\n resultLimit: strictNumberArg(args['result-limit'], '--result-limit'),\n limit: strictNumberArg(args.limit, '--limit'),\n refresh: args.refresh === true,\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'AI referral report',\n target: report.property,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Evidence',\n value: report.dataStatus === 'complete' ? 'Complete' : 'Partial',\n status: report.dataStatus === 'complete' ? 'pass' : 'unknown',\n },\n { label: 'AI sessions', value: formatCount(report.summary.sessions) },\n {\n label: 'AI users',\n value:\n report.summary.totalUsers === null\n ? 'Unavailable'\n : formatCount(report.summary.totalUsers),\n },\n { label: 'Sources', value: formatCount(report.summary.sources) },\n {\n label: 'Landing pages',\n value: formatCount(report.summary.landingPages),\n },\n {\n label: 'Landing-page output',\n value: `${formatCount(report.selection.landingPages.returnedRows)} returned / ${formatCount(report.selection.landingPages.retainedRows)} retained`,\n },\n {\n label: 'Source rows',\n value: formatCount(report.dataSource.sourceDiscovery.returnedRows),\n },\n ],\n })\n\n if (report.sources.length) {\n process.stdout.write('\\nAI sources\\n')\n printLimitedTable(\n ['Source', 'Sessions', 'Events', 'Share of AI sessions'],\n report.sources.map((source) => [\n source.label,\n formatCount(source.sessions),\n formatCount(source.eventCount),\n formatPercent(source.shareOfAiSessions),\n ]),\n )\n }\n\n if (report.landingPages.length) {\n process.stdout.write('\\nLanding pages\\n')\n printLimitedTable(\n ['Landing page', 'Sessions', 'Events', 'Top source'],\n report.landingPages.map((page) => [\n truncate(page.landingPage, 64),\n formatCount(page.sessions),\n formatCount(page.eventCount),\n page.topSourceDetails.label,\n ]),\n )\n }\n\n if (report.dataSource.partialReasons.length) {\n process.stdout.write('\\nEvidence warnings\\n')\n for (const warning of report.dataSource.partialReasons) {\n process.stdout.write(`- ${warning}\\n`)\n }\n }\n\n process.stdout.write(`\\nNote: ${report.summary.caveat}\\n`)\n },\n})\n","import { cannibalReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const cannibalCommand = defineCommand({\n meta: {\n name: 'cannibal',\n description: 'Find queries with material exposure across multiple URLs',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(\n ['days', 'limit', 'includeBrand', 'minImpressions', 'refresh'],\n {\n minImpressions: {\n description: 'Minimum query impressions. Defaults to 50.',\n },\n },\n ),\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const refresh = booleanArg(args.refresh)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh },\n })\n const report = await cannibalReport({\n site: selection.site,\n days: strictNumberArg(args.days, '--days'),\n limit: strictNumberArg(args.limit, '--limit'),\n minImpressions: strictNumberArg(\n args['min-impressions'],\n '--min-impressions',\n ),\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n refresh,\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Cannibalisation report',\n target: report.site,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'Range',\n value: `${report.range.startDate} to ${report.range.endDate}`,\n },\n {\n label: 'Eligible',\n value: formatCount(report.summary.eligibleClusters),\n },\n {\n label: 'Returned',\n value: formatCount(report.summary.returnedClusters),\n },\n {\n label: 'Suppressed brand queries',\n value: formatCount(report.summary.suppressedQueries),\n },\n { label: 'GSC completeness', value: report.source.completeness },\n {\n label: 'Brand queries',\n value: booleanArg(args['include-brand']) ? 'included' : 'excluded',\n },\n ],\n })\n printLimitedTable(\n ['Query', 'URLs', 'Property impr', 'Exposure', 'HHI', 'Review first'],\n report.items.map((item) => [\n truncate(item.query, 42),\n item.pages.length,\n item.propertyImpressions === undefined\n ? 'n/a'\n : formatCount(item.propertyImpressions),\n formatCount(item.pageExposureImpressions),\n item.hhi.toFixed(2),\n truncate(item.suggestedOwnerUrl, 56),\n ]),\n )\n printActionDetails(\n 'Top cannibalisation actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.pages.length} material URLs; first review ${truncate(item.suggestedOwnerUrl, 64)}`,\n action: item.recommendation.action,\n })),\n )\n printNotes('Report caveats', report.caveats)\n printNotes('Provider usage', [report.ledgerSummary])\n },\n})\n","import { ctrUnderperformersReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const ctrUnderperformersCommand = defineCommand({\n meta: {\n name: 'ctr-underperformers',\n description:\n 'Find high-impression queries with weak CTR for their position',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['includeBrand', 'minImpressions'], {\n minImpressions: {\n description:\n 'Minimum query impressions. Defaults to 1 per 5,000 retained impressions, from 30 to 200.',\n },\n }),\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const report = await ctrUnderperformersReport({\n site: selection.site,\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'CTR underperformers',\n target: report.site,\n status: report.dataStatus === 'partial' ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Underperformers',\n value: formatCount(report.summary.underperformers),\n },\n {\n label: 'Estimated click gap',\n value: formatCount(report.summary.estimatedClickShortfall),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Evidence', value: report.dataStatus },\n { label: 'GSC completeness', value: report.source.completeness },\n ],\n })\n printNotes('Why this matters', [\n 'These queries already have visibility; the fastest win is usually better SERP framing, not new content.',\n 'Start with high-impression rows where actual CTR is far below the expected CTR for that ranking position.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n printLimitedTable(\n ['Query', 'URL', 'Pos', 'Impr', 'CTR', 'Expected', 'Gap', 'Action'],\n report.items.map((item) => [\n truncate(item.query, 36),\n truncate(item.url, 48),\n formatPosition(item.position),\n formatCount(item.impressions),\n formatPercent(item.actualCtr),\n formatPercent(item.expectedCtr),\n formatCount(item.clickShortfall),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top CTR actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${formatCount(item.clickShortfall)} click gap, ${formatPercent(item.actualCtr)} CTR`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","import { decayingReport, SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nfunction formatMaybePosition(value: number): string {\n return value > 0 ? formatPosition(value) : 'n/a'\n}\n\nexport const decayingCommand = defineCommand({\n meta: {\n name: 'decaying',\n description: 'Find query/page rows losing clicks between two GSC windows',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs(['days', 'limit', 'includeBrand', 'refresh']),\n comparison: {\n type: 'string',\n description: 'Comparison: previous-period or year-over-year.',\n },\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n 'min-drop-pct': {\n type: 'string',\n description: 'Minimum click drop percentage. Defaults to 20.',\n },\n 'min-previous-clicks': {\n type: 'string',\n description:\n 'Minimum previous-window clicks for a query/page row. Defaults to 2.',\n },\n 'min-click-loss': {\n type: 'string',\n description: 'Minimum absolute click loss. Defaults to 1.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const refresh = booleanArg(args.refresh)\n const comparison = stringArg(args.comparison)\n const days = strictNumberArg(args.days, '--days')\n const limit = strictNumberArg(args.limit, '--limit')\n const minDropPct = strictNumberArg(args['min-drop-pct'], '--min-drop-pct')\n const minPreviousClicks = strictNumberArg(\n args['min-previous-clicks'],\n '--min-previous-clicks',\n )\n const minClickLoss = strictNumberArg(\n args['min-click-loss'],\n '--min-click-loss',\n )\n if (\n comparison !== undefined &&\n comparison !== 'previous-period' &&\n comparison !== 'year-over-year'\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--comparison must be previous-period or year-over-year.',\n )\n }\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh },\n })\n const report = await decayingReport({\n site: selection.site,\n days,\n limit,\n comparison,\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n minDropPct,\n minPreviousClicks,\n minClickLoss,\n refresh,\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Decaying pages',\n target: report.site,\n status:\n report.dataStatus === 'complete'\n ? report.summary.returnedRows > 0\n ? 'warning'\n : 'pass'\n : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Evidence', value: report.dataStatus },\n { label: 'Comparison', value: report.comparison },\n {\n label: 'Observed declines',\n value: formatCount(report.summary.returnedRows),\n },\n {\n label: 'Eligible declines',\n value: formatCount(report.summary.eligibleRows),\n },\n { label: 'Decay clusters', value: formatCount(report.summary.groups) },\n {\n label: 'Observed click decline',\n value: formatCount(\n report.summary.returnedObservedRetainedQueryClickLoss,\n ),\n },\n {\n label: 'Eligible click decline',\n value: formatCount(report.summary.observedRetainedQueryClickLoss),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Minimum drop', value: `${report.filters.minDropPct}%` },\n {\n label: 'Minimum previous clicks',\n value: formatCount(report.filters.minPreviousClicks),\n },\n { label: 'GSC completeness', value: report.source.completeness },\n ],\n })\n printNotes('Why this matters', [\n 'This report compares retained query/page rows and only counts declines observed in both windows.',\n 'Position, CTR, and impression movements are signals for investigation, not proof of cause.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n printNotes('Warnings', report.warnings)\n\n if (!report.items.length) {\n return\n }\n\n if (report.groups.length) {\n printLimitedTable(\n ['Cluster', 'Rows', 'Observed loss', 'Drop', 'Sample query', 'Action'],\n report.groups.map((group) => [\n truncate(group.label, 42),\n formatCount(group.count),\n formatCount(group.totalClickLoss),\n `${group.averageDropPct.toFixed(1)}%`,\n truncate(group.sampleQueries[0] ?? '-', 40),\n truncate(group.recommendation, 72),\n ]),\n )\n printActionDetails(\n 'Top decay cluster actions',\n report.groups.map((group) => ({\n label: group.label,\n context: `${formatCount(group.count)} retained rows, ${formatCount(group.totalClickLoss)} observed click decline`,\n action: group.recommendation,\n })),\n )\n }\n\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'URL',\n 'Signals',\n 'Decline',\n 'Clicks',\n 'Impr',\n 'CTR',\n 'Pos',\n 'Action',\n ],\n report.items.map((item) => [\n truncate(item.query, 32),\n truncate(item.template.label, 26),\n truncate(item.url, 44),\n item.signals.join(', '),\n formatCount(item.clickLoss),\n `${formatCount(item.previous.clicks)} -> ${formatCount(item.current.clicks)}`,\n `${formatCount(item.previous.impressions)} -> ${formatCount(item.current.impressions)}`,\n `${formatPercent(item.previous.ctr)} -> ${formatPercent(item.current.ctr)}`,\n `${formatMaybePosition(item.previous.position)} -> ${formatMaybePosition(item.current.position)}`,\n truncate(item.recommendation.action, 64),\n ]),\n )\n printActionDetails(\n 'Top decay actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.template.label}, ${formatCount(item.clickLoss)} fewer observed clicks`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","import { internalLinksReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n jsonFlag,\n projectArg,\n strictFetchRateArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const internalLinksCommand = defineCommand({\n meta: {\n name: 'internal-links',\n description: 'Find verified internal-link review candidates for one URL',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n url: {\n type: 'string',\n required: true,\n description: 'Target page that should receive relevant internal links.',\n },\n ...cliReportArgs([\n 'days',\n 'limit',\n 'checkLimit',\n 'minImpressions',\n 'includeBrand',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const refresh = booleanArg(args.refresh)\n const days = strictNumberArg(args.days, '--days')\n const limit = strictNumberArg(args.limit, '--limit')\n const checkLimit = strictNumberArg(args['check-limit'], '--check-limit')\n const minImpressions = strictNumberArg(\n args['min-impressions'],\n '--min-impressions',\n )\n const rate = strictFetchRateArg(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh },\n })\n const report = await internalLinksReport({\n site: selection.site,\n targetUrl: stringArg(args.url) ?? '',\n days,\n limit,\n checkLimit,\n minImpressions,\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n js: booleanArg(args.js) ? true : undefined,\n rate,\n refresh,\n })\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Internal link opportunities',\n target: report.targetUrl,\n status:\n report.summary.failedChecks > 0 ||\n report.summary.uncheckedCandidates > 0\n ? 'unknown'\n : 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Target state', value: report.target.verification },\n { label: 'Preferred target', value: report.target.preferredUrl },\n {\n label: 'Target queries',\n value: formatCount(report.summary.targetQueries),\n },\n {\n label: 'Matched sources',\n value: formatCount(report.summary.candidateSources),\n },\n {\n label: 'Checked sources',\n value: formatCount(report.summary.checkedSources),\n },\n {\n label: 'Attempted sources',\n value: formatCount(report.summary.attemptedSources),\n },\n {\n label: 'Review candidates',\n value: formatCount(report.summary.returnedSources),\n },\n {\n label: 'Technical exclusions',\n value: formatCount(report.summary.technicalExclusions),\n },\n {\n label: 'Existing links',\n value: formatCount(report.summary.existingLinksObserved),\n },\n {\n label: 'Failed checks',\n value: formatCount(report.summary.failedChecks),\n },\n {\n label: 'Unchecked sources',\n value: formatCount(report.summary.uncheckedCandidates),\n },\n { label: 'GSC completeness', value: report.source.completeness },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n ],\n })\n printNotes('Why this matters', [\n 'Exact-query overlap is useful affinity evidence; precision lexical matches are review evidence only.',\n 'Source and target pages are checked for redirects, indexability, canonicals, and existing link placement before an action is returned.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n if (!report.items.length) return\n\n printLimitedTable(\n ['Source URL', 'Matched impr', 'Match', 'Link evidence', 'Action'],\n report.items.map((item) => [\n truncate(item.sourceUrl, 52),\n formatCount(item.matchedQueryImpressions),\n item.bestMatchKind,\n item.linkEvidence.status,\n item.actionType,\n ]),\n )\n printActionDetails(\n 'Top internal-link reviews',\n report.items.map((item) => ({\n label: truncate(item.sourceUrl, 96),\n context: `${formatCount(item.matchedQueryImpressions)} matched-query impressions; ${item.bestMatchKind}`,\n action: item.recommendation.action,\n })),\n )\n printNotes('Provider usage', [report.ledgerSummary])\n },\n})\n","import { pageOpportunitiesReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatFetchDiagnostics } from '../shared.js'\n\nexport const pageOpportunitiesCommand = defineCommand({\n meta: {\n name: 'page-opportunities',\n description: 'Find first-party traffic growth opportunities for one URL',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n url: { type: 'string', required: true },\n ...cliReportArgs(\n ['days', 'limit', 'minImpressions', 'includeBrand', 'js', 'refresh'],\n {\n limit: {\n description: 'Maximum page queries to inspect. Defaults to 25.',\n },\n minImpressions: {\n description: 'Minimum query impressions. Defaults to 10.',\n },\n includeBrand: {\n description: 'Include branded queries in page opportunity reports.',\n },\n js: {\n description: 'Force JavaScript rendering for page extraction.',\n },\n refresh: {\n description: 'Bypass local GSC and HTTP cache.',\n },\n },\n ),\n 'verify-content': defaultTrueBooleanArg(\n 'Fetch the page for title/H1/body checks. Defaults to true.',\n 'Skip fetching the page for title/H1/body checks.',\n ),\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await pageOpportunitiesReport({\n site: selection.site,\n url: stringArg(args.url) ?? '',\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent: booleanArg(args['verify-content']) !== false,\n js: booleanArg(args.js) ? true : 'auto',\n refresh: booleanArg(args.refresh),\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printReportSummary({\n title: 'Page opportunities',\n target: report.url,\n status: report.verification.status === 'failed' ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Title', value: report.page?.title ?? 'Not fetched' },\n {\n label: 'Fetch',\n value: formatFetchDiagnostics(report.page?.fetchDiagnostics),\n },\n { label: 'Verification', value: report.verification.status },\n {\n label: 'Rows',\n value: `${formatCount(report.selection.returnedRows)} returned / ${formatCount(report.selection.eligibleRows)} eligible / ${formatCount(report.selection.sourceRows)} source`,\n },\n { label: 'Queries', value: formatCount(report.summary.queries) },\n {\n label: 'Impressions',\n value: formatCount(report.summary.impressions),\n },\n {\n label: 'Opportunities',\n value: formatCount(report.summary.opportunities),\n },\n {\n label: 'CTR shortfall',\n value: formatCount(report.summary.estimatedCtrClickShortfall),\n },\n { label: 'Focus', value: report.summary.focus },\n { label: 'Evidence', value: report.dataStatus },\n ],\n })\n printNotes('Why this matters', [\n 'This report starts from queries where this exact URL already has impressions, so recommendations stay tied to first-party demand.',\n 'Content verification separates body gaps from title/meta framing issues, which helps avoid adding copy when the page already covers the query.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n\n if (!report.items.length) {\n process.stdout.write(\n report.dataStatus === 'empty'\n ? 'No GSC query rows found for this exact URL.\\n'\n : 'GSC rows were found, but none met the report criteria.\\n',\n )\n return\n }\n\n printLimitedTable(\n [\n 'Type',\n 'Query',\n 'Evidence',\n 'Pos',\n 'CTR',\n 'Expected',\n 'Impr',\n 'Shortfall',\n 'Action',\n ],\n report.items.map((item) => [\n item.opportunityType,\n truncate(item.query, 38),\n item.verification.signals.length\n ? item.verification.signals.join(', ')\n : item.verification.status,\n item.position.toFixed(1),\n formatPercent(item.ctr),\n item.expectedCtr === undefined\n ? 'n/a'\n : formatPercent(item.expectedCtr),\n formatCount(item.impressions),\n item.estimatedCtrClickShortfall === undefined\n ? 'n/a'\n : formatCount(item.estimatedCtrClickShortfall),\n truncate(item.recommendation, 72),\n ]),\n )\n printActionDetails(\n 'Top page actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.opportunityType}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation,\n })),\n )\n },\n})\n","import { queryClusterReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const queryClusterCommand = defineCommand({\n meta: {\n name: 'query-cluster',\n description: 'Cluster GSC queries into repeated demand themes',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n scope: { type: 'string' },\n ...cliReportArgs(['includeBrand', 'minImpressions', 'limit'], {\n includeBrand: {\n description: 'Include branded queries in query clustering.',\n },\n minImpressions: {\n description: 'Minimum impressions per query. Defaults to 25.',\n },\n limit: {\n description: 'Maximum clusters to return. Defaults to 25; max 100.',\n },\n }),\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const report = await queryClusterReport({\n site: selection.site,\n scope: stringArg(args.scope),\n brand: selection.client?.brandTerms?.[0],\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n minImpressions: numberArg(args['min-impressions']),\n limit: numberArg(args.limit),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Query clusters',\n target: report.site,\n status: 'info',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Scope', value: report.scope ?? 'All pages' },\n { label: 'Clusters', value: formatCount(report.summary.clusters) },\n { label: 'Queries', value: formatCount(report.summary.queries) },\n {\n label: 'Impressions',\n value: formatCount(report.summary.impressions),\n },\n { label: 'Clicks', value: formatCount(report.summary.clicks) },\n {\n label: 'Minimum impressions',\n value: formatCount(report.summary.minImpressions),\n },\n { label: 'Result limit', value: formatCount(report.summary.limit) },\n {\n label: 'High opportunity',\n value: formatCount(report.summary.highOpportunityClusters),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n ],\n })\n printNotes('Why this matters', [\n 'Clusters show repeated demand themes, so they are better inputs for page sections, hubs, and templates than one-off query exports.',\n 'Prioritise clusters with high impressions and low clicks; they usually reveal unclear intent coverage or weak SERP framing.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n printLimitedTable(\n [\n 'Cluster',\n 'Intent',\n 'Queries',\n 'Impr',\n 'CTR',\n 'Expected',\n 'Lift',\n 'Action',\n ],\n report.clusters.map((cluster) => {\n return [\n truncate(cluster.label, 32),\n cluster.intent,\n cluster.queries.length,\n formatCount(cluster.totals?.impressions ?? 0),\n formatPercent(cluster.totals?.ctr ?? 0),\n formatPercent(cluster.benchmark?.expectedCtr ?? 0),\n cluster.estimatedClickLift === undefined\n ? '-'\n : formatCount(cluster.estimatedClickLift),\n truncate(cluster.recommendation ?? '', 72),\n ]\n }),\n )\n printActionDetails(\n 'Top cluster actions',\n report.clusters.map((cluster) => ({\n label: cluster.label,\n context: `${formatCount(cluster.totals?.impressions ?? 0)} impressions, ${cluster.estimatedClickLift === undefined ? 'ranking opportunity' : `${formatCount(cluster.estimatedClickLift)} estimated click lift`}`,\n action: cluster.recommendation ?? '',\n })),\n )\n },\n})\n","import { quickWinsReport } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n fetchRateArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n verificationSummary,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatContentCheck, formatFetchDiagnostics } from '../shared.js'\n\nexport const quickWinsCommand = defineCommand({\n meta: {\n name: 'quick-wins',\n description: 'Find high-ranking low-CTR query/page opportunities',\n },\n args: {\n site: { type: 'string' },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs([\n 'days',\n 'limit',\n 'includeBrand',\n 'minImpressions',\n 'verifyContent',\n 'verifyLimit',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n 'brand-terms': {\n type: 'string',\n description: 'Comma-separated brand terms to exclude.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const verifyLimit = numberArg(args['verify-limit'])\n const verifyContent =\n booleanArg(args['verify-content']) === true || verifyLimit !== undefined\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const report = await quickWinsReport({\n site: selection.site,\n days: numberArg(args.days),\n limit: numberArg(args.limit),\n minImpressions: numberArg(args['min-impressions']),\n brandTerms: [\n ...(selection.client?.brandTerms ?? []),\n ...(csvArg(args['brand-terms']) ?? []),\n ],\n includeBrand: booleanArg(args['include-brand']),\n verifyContent,\n verifyLimit,\n js: booleanArg(args.js) ? true : undefined,\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Quick wins',\n target: report.site,\n status: report.source.possiblyTruncated ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Eligible rows',\n value: formatCount(report.summary.eligibleRows),\n },\n {\n label: 'Returned rows',\n value: formatCount(report.summary.returnedRows),\n },\n {\n label: 'Query clusters',\n value: formatCount(report.summary.repeatedQueryGroups),\n },\n {\n label: 'Template patterns',\n value: formatCount(report.summary.templatePatterns),\n },\n {\n label: 'CTR click shortfall',\n value: formatCount(report.summary.returnedEstimatedCtrClickShortfall),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Evidence', value: report.dataStatus },\n { label: 'Verification', value: verificationSummary(report) },\n ],\n })\n printNotes('Why this matters', [\n 'These rows have GSC average positions from 4 to 10 and observed CTR below a site-peer or versioned fallback target.',\n 'Page evidence is needed before treating a CTR shortfall as a title, content, or technical finding.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n\n if (!report.items.length) {\n return\n }\n\n if (report.templateRecommendations.length) {\n printLimitedTable(\n ['Template', 'URLs', 'Rows', 'Shortfall', 'Impr', 'Action'],\n report.templateRecommendations.map((template) => [\n truncate(template.templateLabel, 34),\n formatCount(template.urlCount),\n formatCount(template.rowCount),\n formatCount(template.totalEstimatedCtrClickShortfall),\n formatCount(template.totalImpressions),\n truncate(template.action, 72),\n ]),\n )\n printActionDetails(\n 'Top template actions',\n report.templateRecommendations.map((template) => ({\n label: template.templateLabel,\n context: `${formatCount(template.urlCount)} URLs, ${formatCount(template.totalEstimatedCtrClickShortfall)} heuristic CTR click shortfall`,\n action: `${template.action} ${template.evidence}`,\n })),\n )\n }\n\n if (report.groups.length) {\n printLimitedTable(\n [\n 'Cluster',\n 'URLs',\n 'Rows',\n 'Shortfall',\n 'Impr',\n 'Sample URL',\n 'Action',\n ],\n report.groups.map((group) => [\n truncate(group.label, 44),\n formatCount(group.urlCount),\n formatCount(group.rowCount),\n formatCount(group.totalEstimatedCtrClickShortfall),\n formatCount(group.totalImpressions),\n truncate(group.sampleUrls[0] ?? '-', 46),\n truncate(group.recommendation, 72),\n ]),\n )\n printActionDetails(\n 'Top cluster actions',\n report.groups.map((group) => ({\n label: group.label,\n context: `${formatCount(group.urlCount)} URLs, ${formatCount(group.totalEstimatedCtrClickShortfall)} heuristic CTR click shortfall`,\n action: group.recommendation,\n })),\n )\n }\n\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'URL',\n 'Pos',\n 'Impr',\n 'CTR / target',\n 'Shortfall',\n 'Fetch',\n 'Check',\n 'Action',\n ],\n report.items.map((item) => [\n truncate(item.query, 36),\n truncate(item.template.label, 24),\n truncate(item.url, 48),\n formatPosition(item.position),\n formatCount(item.impressions),\n `${formatPercent(item.ctr)} / ${formatPercent(item.targetCtr)}`,\n formatCount(item.estimatedCtrClickShortfall),\n formatFetchDiagnostics(item.contentVerification?.fetchDiagnostics),\n formatContentCheck(item.contentVerification?.classification),\n truncate(item.recommendation.action, 64),\n ]),\n )\n printActionDetails(\n 'Top opportunity actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.template.label}, pos ${formatPosition(item.position)}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","import { secondPage } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n fetchRateArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n verificationSummary,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatContentCheck, formatFetchDiagnostics } from '../shared.js'\n\nexport const secondPageCommand = defineCommand({\n meta: {\n name: 'second-page',\n description: 'Find URLs averaging positions above 10 through 20 in GSC',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n project: { type: 'string', description: 'Saved project id or name.' },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n ...cliReportArgs([\n 'range',\n 'minImpressions',\n 'limit',\n 'includeBrand',\n 'verifyContent',\n 'verifyLimit',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const verifyLimit = numberArg(args['verify-limit'])\n const verifyContent =\n booleanArg(args['verify-content']) === true || verifyLimit !== undefined\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await secondPage({\n site: selection.site,\n range: numberArg(args.days),\n minImpressions: numberArg(args['min-impressions']),\n limit: stringArg(args.limit) ? Number(stringArg(args.limit)) : 10,\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent,\n verifyLimit,\n js: booleanArg(args.js) ? true : undefined,\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Second-page opportunities',\n target: report.site,\n status:\n report.source.possiblyTruncated || report.summary.fetchFailures > 0\n ? 'unknown'\n : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Eligible pages',\n value: formatCount(report.summary.eligiblePages),\n },\n {\n label: 'Returned pages',\n value: formatCount(report.summary.returnedPages),\n },\n {\n label: 'Eligible queries',\n value: formatCount(report.summary.eligibleQueries),\n },\n {\n label: 'Impressions',\n value: formatCount(report.summary.eligibleImpressions),\n },\n {\n label: 'Content issues',\n value: formatCount(report.summary.contentIssues),\n },\n {\n label: 'Technical issues',\n value: formatCount(report.summary.technicalIssues),\n },\n {\n label: 'Fetch failures',\n value: formatCount(report.summary.fetchFailures),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n { label: 'Evidence', value: report.dataStatus },\n { label: 'Verification', value: verificationSummary(report) },\n ],\n })\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n if (!report.items.length) {\n process.stdout.write(\n 'No average-position candidates matched this report.\\n',\n )\n process.stdout.write(`${report.ledgerSummary}\\n`)\n return\n }\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'Pos',\n 'Impr',\n 'CTR',\n 'Queries',\n 'Fetch',\n 'Check',\n 'Action',\n ],\n report.items.map((item) => [\n item.primaryQuery,\n item.template.label,\n item.position.toFixed(1),\n Math.round(item.impressions),\n item.ctr.toFixed(3),\n formatCount(item.queryCount),\n formatFetchDiagnostics(item.fetchDiagnostics),\n formatContentCheck(item.contentVerification?.classification),\n item.recommendation.action,\n ]),\n )\n printActionDetails(\n 'Top second-page actions',\n report.items.map((item) => ({\n label: item.primaryQuery,\n context: `${item.template.label}, pos ${formatPosition(item.position)}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation.action,\n })),\n )\n process.stdout.write(`${report.ledgerSummary}\\n`)\n },\n})\n","import { auditPage } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, projectArg, stringArg } from '../args.js'\nimport { resolveClient } from '../selection.js'\nimport { printJson } from '../utils.js'\nimport { printReportSummary } from './output.js'\nimport { formatFetchDiagnostics } from './shared.js'\n\nexport const auditPageCommand = defineCommand({\n meta: {\n name: 'audit-page',\n description:\n 'Fetch one page and audit title, metadata, content, links, and schema',\n },\n args: {\n url: { type: 'string', required: true, description: 'URL to audit.' },\n site: {\n type: 'string',\n description:\n 'Optional GSC property for page search metrics, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering for extraction.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache.',\n },\n },\n run: async ({ args }) => {\n const project = projectArg(args)\n const explicitSite = stringArg(args.site)\n const selectedProject = project\n ? await resolveClient({ project, options: { json: jsonFlag(args) } })\n : undefined\n const defaultProject =\n project || explicitSite\n ? undefined\n : await resolveClient({ options: { json: jsonFlag(args) } })\n const report = await auditPage({\n url: stringArg(args.url) ?? '',\n site: selectedProject?.siteUrl ?? explicitSite ?? defaultProject?.siteUrl,\n js: booleanArg(args.js) ? true : 'auto',\n refresh: booleanArg(args.refresh),\n })\n if (jsonFlag(args)) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Page audit',\n target: report.url,\n status: report.issues.some((issue) => issue.severity === 'high')\n ? 'fail'\n : report.issues.length > 0\n ? 'warning'\n : 'pass',\n summary:\n report.issues.length > 0\n ? `${report.issues.length} ${report.issues.length === 1 ? 'issue needs' : 'issues need'} review.`\n : 'No page issues were found by the available checks.',\n metrics: [\n { label: 'Final URL', value: report.page.finalUrl },\n { label: 'Title', value: report.page.title ?? 'Missing' },\n {\n label: 'Meta description',\n value: report.page.metaDescription ?? 'Missing',\n },\n { label: 'Words', value: report.page.wordCount },\n {\n label: 'Fetch',\n value: formatFetchDiagnostics(report.fetchDiagnostics),\n },\n ],\n diagnostics: [\n {\n title: 'Issues',\n items: report.issues.map((issue) => ({\n status: issue.severity === 'high' ? 'fail' : 'warning',\n title: `${issue.code}: ${issue.principle}`,\n explanation: issue.detail,\n })),\n },\n ],\n })\n },\n})\n","import { performanceAudit, SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, projectArg, stringArg } from '../args.js'\nimport { resolveClient } from '../selection.js'\nimport { printJson } from '../utils.js'\nimport { printActionDetails, printNotes, printReportSummary } from './output.js'\n\nfunction strategy(value: unknown): 'mobile' | 'desktop' {\n const selected = stringArg(value) ?? 'mobile'\n if (selected !== 'mobile' && selected !== 'desktop') {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Invalid --strategy. Use mobile or desktop.',\n )\n }\n return selected\n}\n\nfunction metric(value?: { displayValue?: string; value?: number }): string {\n if (!value) return 'not measured'\n return value.displayValue ?? String(value.value ?? 'not measured')\n}\n\nfunction fieldMetric(value?: {\n p75: number\n rating: string\n unit: 'milliseconds' | 'score'\n}): string {\n if (!value) return 'not available'\n const suffix = value.unit === 'milliseconds' ? 'ms' : ''\n return `${value.p75}${suffix} (${value.rating})`\n}\n\nexport const performanceCommand = defineCommand({\n meta: {\n name: 'perf',\n description: 'Audit lab performance and field Core Web Vitals',\n },\n subCommands: {\n audit: defineCommand({\n meta: {\n name: 'audit',\n description: 'Run a Lighthouse/Core Web Vitals performance audit',\n },\n args: {\n url: {\n type: 'string',\n description:\n 'URL to audit. Defaults to the selected project crawl URL.',\n },\n client: { type: 'string', description: 'Legacy alias for --project.' },\n project: { type: 'string', description: 'Saved project id or name.' },\n strategy: {\n type: 'string',\n default: 'mobile',\n description: 'Audit strategy: mobile or desktop.',\n },\n 'lighthouse-bin': {\n type: 'string',\n description:\n 'Custom Lighthouse binary path. Defaults to the bundled version.',\n },\n 'crux-key': {\n type: 'string',\n description:\n 'CrUX API key. Prefer SEO_CRUX_API_KEY to avoid shell history.',\n },\n raw: {\n type: 'boolean',\n default: false,\n description: 'Include the full Lighthouse JSON in JSON output.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local performance report cache.',\n },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = await resolveClient({\n client: projectArg(args),\n options: { json },\n })\n const url = stringArg(args.url) ?? project?.startUrl\n if (!url) {\n throw new Error(\n 'No URL selected. Pass --url or use --project with a crawl URL.',\n )\n }\n const report = await performanceAudit({\n url,\n strategy: strategy(args.strategy),\n lighthouseBin: stringArg(args['lighthouse-bin']),\n cruxApiKey: stringArg(args['crux-key']),\n refresh: booleanArg(args.refresh),\n includeRaw: json && booleanArg(args.raw),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Performance report',\n target: report.url,\n status:\n report.dataStatus === 'partial'\n ? 'unknown'\n : report.grade === 'good'\n ? 'pass'\n : 'warning',\n summary: report.headline,\n metrics: [\n { label: 'Source', value: report.source },\n { label: 'Strategy', value: report.strategy },\n {\n label: 'Lab score',\n value:\n report.score === undefined ? 'Unknown' : `${report.score}/100`,\n },\n { label: 'Lab grade', value: report.grade },\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'FCP',\n value: metric(report.metrics.firstContentfulPaint),\n },\n {\n label: 'LCP',\n value: metric(report.metrics.largestContentfulPaint),\n },\n { label: 'TBT', value: metric(report.metrics.totalBlockingTime) },\n {\n label: 'CLS',\n value: metric(report.metrics.cumulativeLayoutShift),\n },\n {\n label: 'INP',\n value: metric(report.metrics.interactionToNextPaint),\n },\n {\n label: 'Server response',\n value: metric(report.metrics.serverResponseTime),\n },\n {\n label: 'Fallback fetch',\n value: metric(report.metrics.fallbackFetchDuration),\n },\n {\n label: 'Field data',\n value: report.fieldData\n ? `${report.fieldData.scope} ${report.fieldData.formFactor.toLowerCase()} (${report.fieldData.assessment.status})`\n : report.fieldDataStatus.status,\n },\n {\n label: 'Field LCP p75',\n value: fieldMetric(\n report.fieldData?.metrics.largestContentfulPaint,\n ),\n },\n {\n label: 'Field INP p75',\n value: fieldMetric(\n report.fieldData?.metrics.interactionToNextPaint,\n ),\n },\n {\n label: 'Field CLS p75',\n value: fieldMetric(\n report.fieldData?.metrics.cumulativeLayoutShift,\n ),\n },\n {\n label: 'Field period',\n value:\n report.fieldData?.collectionPeriod?.firstDate &&\n report.fieldData.collectionPeriod.lastDate\n ? `${report.fieldData.collectionPeriod.firstDate} to ${report.fieldData.collectionPeriod.lastDate}`\n : 'Unavailable',\n },\n ],\n })\n printActionDetails(\n 'Top actions',\n report.topActions.map((action) => ({\n label: action.title,\n action: action.action,\n context: action.plainEnglish,\n })),\n )\n printNotes('Caveats', report.caveats)\n },\n }),\n },\n})\n","import { diagnoseProperty } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { createProgressReporter } from '../../progress.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printActionDetails, printReportSummary } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nexport const diagnoseCommand = defineCommand({\n meta: {\n name: 'diagnose',\n description: 'Find where Google Search performance changed',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Baseline window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum rows per diagnostic section. Defaults to 10.',\n },\n },\n ),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await diagnoseProperty({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n refresh: booleanArg(args.refresh),\n progress: createProgressReporter(!json),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'SEO diagnosis',\n target: report.site,\n status:\n report.dataStatus === 'complete'\n ? report.priorities.length > 0\n ? 'warning'\n : 'pass'\n : 'unknown',\n summary:\n report.priorities.length > 0\n ? `${report.priorities.length} priorities need review.`\n : 'No priorities were returned by the available evidence.',\n metrics: [\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'Update overlap',\n value: report.summary.updateAttribution.replaceAll('-', ' '),\n },\n {\n label: 'Significant anomalies',\n value: report.summary.significantAnomalies,\n },\n { label: 'Update matches', value: report.summary.updateMatches },\n { label: 'Decay items', value: report.summary.decayItems },\n { label: 'Cannibal items', value: report.summary.cannibalItems },\n {\n label: 'Striking distance',\n value: report.summary.strikingDistanceItems,\n },\n { label: 'Quick wins', value: report.summary.quickWinItems },\n ],\n })\n printTable(\n ['Priority', 'Confidence', 'Reason', 'Action'],\n report.priorities.map((priority) => [\n priority.label,\n priority.confidence,\n priority.reason,\n priority.action,\n ]),\n )\n if (report.skippedSections?.length) {\n printTable(\n ['Skipped section', 'Reason'],\n report.skippedSections.map((section) => [\n section.section,\n section.reason,\n ]),\n )\n }\n printActionDetails(\n 'Priority action details',\n report.priorities.map((priority) => ({\n label: priority.label,\n context: priority.confidence,\n action: priority.action,\n })),\n )\n },\n})\n","import { runDoctor } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport { checkSummary } from '../../presentation/views.js'\nimport { printChecks, printHeading, printJson } from '../../utils.js'\n\nexport const doctorCommand = defineCommand({\n meta: {\n name: 'doctor',\n description: 'Check local auth, scopes, config, and defaults',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const report = await runDoctor()\n if (jsonFlag(args)) {\n printJson(report)\n if (!report.ok) process.exitCode = 1\n return\n }\n printHeading('SEO doctor', checkSummary(report.checks))\n process.stdout.write('\\n')\n printChecks(report.checks)\n process.stdout.write(`\\nChecked ${report.generatedAt}\\n`)\n if (!report.ok) process.exitCode = 1\n },\n})\n","import { type SegmentDimension, segmentImpact } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n projectArg,\n strictNumberArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNotes, printReportSummary } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\nconst segmentDimension = (value: unknown): SegmentDimension => {\n const dimension = stringArg(value) ?? 'page'\n if (\n dimension !== 'page' &&\n dimension !== 'query' &&\n dimension !== 'country' &&\n dimension !== 'device'\n ) {\n throw new Error('Invalid --dimension. Use page, query, country, or device.')\n }\n return dimension\n}\n\nexport const segmentImpactCommand = defineCommand({\n meta: {\n name: 'segment-impact',\n description: 'Compare GSC movement by page, query, device, or country',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n dimension: {\n type: 'string',\n default: 'page',\n description: 'Segment by page, query, country, or device.',\n },\n ...cliReportArgs(['days', 'limit', 'refresh'], {\n days: {\n description: 'Recent window length from 1 to 240 days. Defaults to 28.',\n },\n limit: {\n description: 'Maximum segment rows to print. Defaults to 25.',\n },\n refresh: {\n description: 'Bypass local cache and fetch fresh GSC data.',\n },\n }),\n compare: {\n type: 'string',\n description:\n 'Legacy 1-240 day comparison length. Must equal the current window.',\n },\n 'start-date': {\n type: 'string',\n description: 'Exact current-window start date in YYYY-MM-DD format.',\n },\n 'end-date': {\n type: 'string',\n description: 'Exact current-window end date in YYYY-MM-DD format.',\n },\n 'max-rows': {\n type: 'string',\n description: 'Maximum retained GSC rows per window. Defaults to 100000.',\n },\n 'unmatched-limit': {\n type: 'string',\n description:\n 'Maximum one-window evidence rows to return. Defaults to 25.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const dimension = segmentDimension(args.dimension)\n const days = strictNumberArg(args.days, '--days')\n const compareDays = strictNumberArg(args.compare, '--compare')\n const limit = strictNumberArg(args.limit, '--limit')\n const unmatchedLimit = strictNumberArg(\n args['unmatched-limit'],\n '--unmatched-limit',\n )\n const maxRows = strictNumberArg(args['max-rows'], '--max-rows')\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await segmentImpact({\n site: selection.site,\n dimension,\n days,\n compareDays,\n startDate: stringArg(args['start-date']),\n endDate: stringArg(args['end-date']),\n limit,\n unmatchedLimit,\n maxRows,\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Segment impact',\n target: report.site,\n status: report.dataStatus === 'complete' ? 'info' : 'unknown',\n summary: report.summary.verdict,\n metrics: [\n { label: 'Dimension', value: report.dimension },\n { label: 'Evidence', value: report.dataStatus },\n {\n label: 'Before',\n value: `${report.before.startDate} to ${report.before.endDate}`,\n },\n {\n label: 'After',\n value: `${report.after.startDate} to ${report.after.endDate}`,\n },\n ],\n })\n printTable(\n ['Segment', 'Clicks before', 'Clicks after', 'Delta', 'Pos delta'],\n report.items.map((item) => [\n item.key,\n item.beforeClicks,\n item.afterClicks,\n item.clickDelta,\n item.positionDelta ?? '-',\n ]),\n )\n if (report.unmatchedSegments.length) {\n process.stdout.write('\\nOne-window evidence (not treated as zero)\\n')\n printTable(\n ['Segment', 'Retained in', 'Clicks', 'Impressions'],\n report.unmatchedSegments.map((item) => [\n item.key,\n item.retainedIn,\n item.clicks,\n item.impressions,\n ]),\n )\n }\n printNotes('Warnings', report.warnings)\n },\n})\n","import { strikingDistance } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n fetchRateArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport {\n formatCount,\n formatPercent,\n formatPosition,\n printActionDetails,\n printLimitedTable,\n printNotes,\n printReportSummary,\n truncate,\n} from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { formatContentCheck, formatFetchDiagnostics } from '../shared.js'\n\nfunction rowCountLabel(count: number): string {\n return `${formatCount(count)} ${count === 1 ? 'row' : 'rows'}`\n}\n\nexport const strikingDistanceCommand = defineCommand({\n meta: {\n name: 'striking-distance',\n description: 'Find query/page rows averaging positions above 10 through 20',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs([\n 'days',\n 'minImpressions',\n 'limit',\n 'includeBrand',\n 'verifyContent',\n 'verifyLimit',\n 'js',\n 'fetchConcurrency',\n 'fetchIntervalCap',\n 'fetchIntervalMs',\n 'refresh',\n ]),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const verifyLimit = numberArg(args['verify-limit'])\n const verifyContent =\n booleanArg(args['verify-content']) === true || verifyLimit !== undefined\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await strikingDistance({\n site: selection.site,\n days: numberArg(args.days),\n minImpressions: numberArg(args['min-impressions']),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n verifyContent,\n verifyLimit,\n js: booleanArg(args.js) ? true : undefined,\n rate: fetchRateArg(args),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Striking-distance opportunities',\n target: report.site,\n status: report.source.possiblyTruncated ? 'unknown' : 'info',\n summary: report.summary.verdict,\n metrics: [\n {\n label: 'Eligible rows',\n value: formatCount(report.summary.eligibleRows),\n },\n {\n label: 'Returned rows',\n value: formatCount(report.summary.returnedRows),\n },\n { label: 'Template groups', value: formatCount(report.summary.groups) },\n {\n label: 'Impressions',\n value: formatCount(report.summary.eligibleImpressions),\n },\n { label: 'Brand queries', value: report.summary.brandFiltering },\n {\n label: 'Verification',\n value: report.verification.requested ? 'Requested' : 'Off',\n },\n { label: 'Evidence', value: report.dataStatus },\n ],\n })\n printNotes('Why this matters', [\n 'These rows have a GSC average position above 10 and at most 20. Treat them as candidates for investigation, not guaranteed page-two rankings.',\n 'Groups use all eligible rows. A shared-template label is only a candidate until recurring evidence is verified across distinct URLs.',\n ])\n printNotes('Recommended actions', report.recommendations)\n printNotes('Report caveats', report.caveats)\n\n if (report.groups.length) {\n printLimitedTable(\n ['Group', 'Rows', 'URLs', 'Impr', 'Avg pos', 'Scope', 'Action'],\n report.groups.map((group) => [\n truncate(group.label, 36),\n formatCount(group.rowCount),\n formatCount(group.uniqueUrls),\n formatCount(group.totalImpressions),\n formatPosition(group.impressionWeightedPosition),\n group.actionScope,\n truncate(group.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top striking-distance group actions',\n report.groups.map((group) => ({\n label: group.label,\n context: `${rowCountLabel(group.rowCount)}, ${formatCount(group.totalImpressions)} impressions`,\n action: group.recommendation.action,\n })),\n )\n }\n\n if (!report.items.length) {\n process.stdout.write(\n 'No striking-distance opportunities matched these filters.\\n',\n )\n return\n }\n\n printLimitedTable(\n [\n 'Query',\n 'Template',\n 'URL',\n 'Impr',\n 'CTR',\n 'Pos',\n 'Score',\n 'Fetch',\n 'Check',\n 'Action',\n ],\n report.items.map((item) => [\n truncate(item.query, 36),\n truncate(item.template.label, 24),\n truncate(item.url, 48),\n formatCount(item.impressions),\n formatPercent(item.ctr),\n formatPosition(item.position),\n item.priority.score,\n formatFetchDiagnostics(item.contentVerification?.fetchDiagnostics),\n formatContentCheck(item.contentVerification?.classification),\n truncate(item.recommendation.action, 72),\n ]),\n )\n printActionDetails(\n 'Top striking-distance actions',\n report.items.map((item) => ({\n label: item.query,\n context: `${item.template.label}, pos ${formatPosition(item.position)}, ${formatCount(item.impressions)} impressions`,\n action: item.recommendation.action,\n })),\n )\n },\n})\n","export function credentialSourceLabel(\n source: 'environment' | 'keychain' | 'file' | undefined,\n): string {\n if (source === 'keychain') return 'system keychain'\n if (source === 'file') return 'private local file'\n return source ?? 'missing'\n}\n\nexport function formatUsd(micros: number | null): string {\n return micros === null ? 'unavailable' : `$${(micros / 1_000_000).toFixed(2)}`\n}\n","import { intro, note, outro, password } from '@clack/prompts'\nimport {\n AHREFS_API_KEY_ENV,\n AhrefsClient,\n deleteAhrefsApiKey,\n readAhrefsApiKey,\n SeoError,\n writeAhrefsApiKey,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n} from '../../utils.js'\nimport { credentialSourceLabel } from './shared.js'\n\nfunction unitUsage(input: {\n limit: number | null\n used: number | null\n remaining: number | null\n}): string {\n if (input.limit === null) {\n return input.used === null\n ? 'not reported'\n : `${input.used.toLocaleString('en-US')} used; no key limit`\n }\n return `${(input.remaining ?? 0).toLocaleString('en-US')} of ${input.limit.toLocaleString('en-US')} remaining`\n}\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save an Ahrefs API v3 key',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run \\`seo providers ahrefs connect\\` in a terminal. Agents and CI can set ${AHREFS_API_KEY_ENV}.`,\n )\n }\n\n intro('Connect Ahrefs')\n note(\n 'Paste an API v3 key from Ahrefs Account settings. The validation check and Domain Rating are free; other research can consume API units.',\n 'API key',\n )\n const apiKey = maybeExitCancelled(\n await password({\n message: 'Ahrefs API v3 key',\n validate: (value) =>\n value?.trim() ? undefined : 'API key is required',\n }),\n )\n const account = await new AhrefsClient({ apiKey }).limitsAndUsage()\n const source = await writeAhrefsApiKey(apiKey)\n\n note(\n `${account.subscription} subscription. API key units: ${unitUsage(account.apiKeyUnits)}.`,\n 'Connection verified',\n )\n outro(\n `Saved in the ${credentialSourceLabel(source)}. Run seo providers ahrefs status --check to verify it again.`,\n )\n },\n})\n\nconst statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show the local Ahrefs connection',\n },\n args: {\n check: {\n type: 'boolean',\n default: false,\n description: 'Verify the API key with the free account endpoint.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const credential = await readAhrefsApiKey()\n const shouldCheck = Boolean(args.check)\n const account =\n shouldCheck && credential\n ? await new AhrefsClient().limitsAndUsage()\n : undefined\n const result = {\n connected: Boolean(credential),\n apiVersion: credential ? 3 : null,\n credentialSource: credential?.source,\n liveCheck: account\n ? {\n status: 'passed' as const,\n subscription: account.subscription,\n apiKeyExpiresAt: account.apiKeyExpiresAt,\n usageResetsAt: account.usageResetsAt,\n apiKeyUnits: account.apiKeyUnits,\n workspaceUnits: account.workspaceUnits,\n observedAt: account.observedAt,\n requestCostUnits: account.requestCostUnits,\n }\n : {\n status: (shouldCheck ? 'unavailable' : 'not-requested') as\n | 'unavailable'\n | 'not-requested',\n },\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Connected', result.connected ? 'yes' : 'no'],\n ['API version', result.apiVersion ? 'Version 3' : 'not connected'],\n ['Credential', credentialSourceLabel(result.credentialSource)],\n [\n 'Live check',\n result.liveCheck.status === 'passed'\n ? `passed at ${result.liveCheck.observedAt}`\n : result.liveCheck.status === 'unavailable'\n ? 'not available without credentials'\n : 'not requested; pass --check to verify',\n ],\n ...(account\n ? ([\n ['Subscription', account.subscription],\n ['API key units', unitUsage(account.apiKeyUnits)],\n ['Workspace units', unitUsage(account.workspaceUnits)],\n ['Usage resets', account.usageResetsAt],\n ['Key expires', account.apiKeyExpiresAt],\n ] satisfies Array<[string, string]>)\n : []),\n ])\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove the saved Ahrefs API v3 key',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n await deleteAhrefsApiKey()\n const environmentCredential = Boolean(\n process.env[AHREFS_API_KEY_ENV]?.trim(),\n )\n const result = {\n savedCredentialRemoved: true,\n environmentCredential: environmentCredential\n ? ('active' as const)\n : ('missing' as const),\n note: environmentCredential\n ? `The environment variable was not changed. Clear ${AHREFS_API_KEY_ENV} to fully disconnect.`\n : 'Ahrefs is disconnected.',\n }\n if (jsonFlag(args)) printJson(result)\n else process.stdout.write(`${result.note}\\n`)\n },\n})\n\nexport const ahrefsProviderCommand = defineCommand({\n meta: {\n name: 'ahrefs',\n description: 'Connect Ahrefs for optional search and link data',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n },\n})\n","import { intro, note, outro, password } from '@clack/prompts'\nimport {\n BING_API_KEY_ENV,\n deleteBingApiKey,\n readBingApiKey,\n SeoError,\n writeBingApiKey,\n} from '@seo/core'\nimport { bingCall, listBingSites } from '@seo/core/commands'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport { canPrompt, maybeExitCancelled, printJson } from '../../utils.js'\nimport { credentialSourceLabel } from './shared.js'\n\nconst signIn = 'Run `seo providers bing connect` with a new API key.'\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Check and save a Bing Webmaster Tools API key',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run \\`seo providers bing connect\\` in a terminal. Agents and CI can set ${BING_API_KEY_ENV}.`,\n )\n }\n intro('Connect Bing Webmaster Tools')\n note(\n 'In Bing Webmaster Tools, open Settings, then API access, and copy the API key. Bing data is free.',\n 'API key',\n )\n const apiKey = maybeExitCancelled(\n await password({\n message: 'Bing Webmaster API key',\n validate: (value) =>\n value?.trim() ? undefined : 'API key is required',\n }),\n )\n const sites = await listBingSites(bingCall({ apiKey }, { signIn }))\n const source = await writeBingApiKey(apiKey)\n note(\n `${sites.filter((site) => site.verified).length} verified sites.`,\n 'Connection verified',\n )\n outro(`Saved in the ${credentialSourceLabel(source)}.`)\n },\n})\n\nconst statusCommand = defineCommand({\n meta: { name: 'status', description: 'Show the Bing Webmaster connection' },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const credential = await readBingApiKey()\n const sites = credential\n ? await listBingSites(bingCall({ apiKey: credential.apiKey }, { signIn }))\n : null\n const result = {\n connected: Boolean(credential),\n credentialSource: credential?.source ?? null,\n sites:\n sites?.filter((site) => site.verified).map((site) => site.url) ?? [],\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n process.stdout.write(\n credential\n ? `Connected (${credentialSourceLabel(credential.source)}). Verified sites: ${result.sites.join(', ') || 'none'}.\\n`\n : 'Not connected. Run `seo providers bing connect`.\\n',\n )\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove the saved Bing Webmaster API key',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n await deleteBingApiKey()\n const environment = Boolean(process.env[BING_API_KEY_ENV]?.trim())\n const message = environment\n ? `The saved key is removed. Clear ${BING_API_KEY_ENV} to fully disconnect.`\n : 'Bing is disconnected.'\n if (jsonFlag(args)) printJson({ removed: true, environment })\n else process.stdout.write(`${message}\\n`)\n },\n})\n\nexport const bingProviderCommand = defineCommand({\n meta: {\n name: 'bing',\n description: 'Connect Bing Webmaster Tools for Bing search data',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n },\n})\n","import { intro, note, outro, password, text } from '@clack/prompts'\nimport {\n DATAFORSEO_LOGIN_ENV,\n DATAFORSEO_PASSWORD_ENV,\n DataForSeoClient,\n deleteDataForSeoCredentials,\n readDataForSeoCredentials,\n SeoError,\n writeDataForSeoCredentials,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n} from '../../utils.js'\nimport { credentialSourceLabel, formatUsd } from './shared.js'\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save DataForSEO API credentials',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n if (!canPrompt({ json: jsonFlag(args) })) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Run \\`seo providers dataforseo connect\\` in a terminal. Agents and CI can set ${DATAFORSEO_LOGIN_ENV} and ${DATAFORSEO_PASSWORD_ENV}.`,\n )\n }\n\n intro('Connect DataForSEO')\n note(\n 'Use the API login and API password from DataForSEO API Access. The validation call is free; later research reports can make charged requests.',\n 'API credentials',\n )\n const login = maybeExitCancelled(\n await text({\n message: 'DataForSEO API login',\n validate: (value) =>\n value?.trim() ? undefined : 'API login is required',\n }),\n )\n const apiPassword = maybeExitCancelled(\n await password({\n message: 'DataForSEO API password',\n validate: (value) => (value ? undefined : 'API password is required'),\n }),\n )\n const credentials = { login: login.trim(), password: apiPassword }\n const account = await new DataForSeoClient({\n credentials: () => credentials,\n }).userData()\n const source = await writeDataForSeoCredentials(credentials)\n\n note(\n `${account.login} is connected with an account balance of ${formatUsd(account.balanceMicros)}.`,\n 'Connection verified',\n )\n outro(\n `Saved in the ${credentialSourceLabel(source)}. Run seo providers dataforseo status --check to verify it again.`,\n )\n },\n})\n\nconst statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show the local DataForSEO connection',\n },\n args: {\n check: {\n type: 'boolean',\n default: false,\n description: 'Verify credentials with the free account endpoint.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const credentials = await readDataForSeoCredentials()\n const shouldCheck = Boolean(args.check)\n const account =\n shouldCheck && credentials\n ? await new DataForSeoClient().userData()\n : undefined\n const result = {\n connected: Boolean(credentials),\n credentialSource: credentials?.source,\n migratedLegacyCredentials: credentials?.migrated ?? false,\n liveCheck: account\n ? {\n status: 'passed' as const,\n account: account.login,\n timezone: account.timezone,\n balanceMicros: account.balanceMicros,\n observedAt: account.observedAt,\n requestCostMicros: account.requestCostMicros,\n }\n : {\n status: (shouldCheck ? 'unavailable' : 'not-requested') as\n | 'unavailable'\n | 'not-requested',\n },\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Connected', result.connected ? 'yes' : 'no'],\n ['Credential', credentialSourceLabel(result.credentialSource)],\n [\n 'Live check',\n result.liveCheck.status === 'passed'\n ? `passed at ${result.liveCheck.observedAt}`\n : result.liveCheck.status === 'unavailable'\n ? 'not available without credentials'\n : 'not requested; pass --check to verify',\n ],\n ...(account\n ? ([\n ['Account', account.login],\n ['Balance', formatUsd(account.balanceMicros)],\n ] satisfies Array<[string, string]>)\n : []),\n ])\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove saved DataForSEO credentials',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n await deleteDataForSeoCredentials()\n const hasEnvironmentLogin = Boolean(\n process.env[DATAFORSEO_LOGIN_ENV]?.trim(),\n )\n const hasEnvironmentPassword = Boolean(process.env[DATAFORSEO_PASSWORD_ENV])\n const result = {\n savedCredentialsRemoved: true,\n environmentCredentials:\n hasEnvironmentLogin && hasEnvironmentPassword\n ? ('active' as const)\n : hasEnvironmentLogin || hasEnvironmentPassword\n ? ('partial' as const)\n : ('missing' as const),\n note:\n hasEnvironmentLogin || hasEnvironmentPassword\n ? `Environment variables were not changed. Clear ${DATAFORSEO_LOGIN_ENV} and ${DATAFORSEO_PASSWORD_ENV} to fully disconnect.`\n : 'DataForSEO is disconnected.',\n }\n if (jsonFlag(args)) printJson(result)\n else process.stdout.write(`${result.note}\\n`)\n },\n})\n\nexport const dataForSeoProviderCommand = defineCommand({\n meta: {\n name: 'dataforseo',\n description: 'Connect DataForSEO for optional search data',\n },\n subCommands: {\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n },\n})\n","import { confirm, intro, note, outro, password, text } from '@clack/prompts'\nimport {\n deleteProviderExtensionAccount,\n deleteProviderExtensionCredentials,\n describeInstalledProviderExtension,\n inspectProviderPackage,\n installProviderPackage,\n listInstalledProviderExtensions,\n loadInstalledProviderExtensions,\n readProviderExtensionAccount,\n readProviderExtensionCredentials,\n runProviderExtensionAction,\n SeoError,\n type SeoProviderJson,\n uninstallProviderExtension,\n verifyProviderExtension,\n writeProviderExtensionAccount,\n writeProviderExtensionCredentials,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, stringArg } from '../../args.js'\nimport {\n canPrompt,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n printTable,\n} from '../../utils.js'\n\nfunction parseAccount(value: string | undefined): Record<string, string> {\n if (!value) return {}\n let parsed: unknown\n try {\n parsed = JSON.parse(value)\n } catch {\n throw new SeoError('INVALID_INPUT', '--account must be a JSON object.')\n }\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new SeoError('INVALID_INPUT', '--account must be a JSON object.')\n }\n const entries = Object.entries(parsed)\n if (\n entries.length > 20 ||\n entries.some(\n ([key, item]) =>\n !key ||\n key.length > 64 ||\n typeof item !== 'string' ||\n item.length > 4_096,\n )\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--account must contain at most 20 bounded string fields.',\n )\n }\n return Object.fromEntries(\n entries.map(([key, item]) => [key, (item as string).trim()]),\n )\n}\n\nfunction parseActionParams(\n value: string | undefined,\n): Record<string, SeoProviderJson> {\n if (!value) return {}\n let parsed: unknown\n try {\n parsed = JSON.parse(value)\n } catch {\n throw new SeoError('INVALID_INPUT', '--params must be a JSON object.')\n }\n if (!parsed || Array.isArray(parsed) || typeof parsed !== 'object') {\n throw new SeoError('INVALID_INPUT', '--params must be a JSON object.')\n }\n const entries = Object.entries(parsed)\n if (\n entries.length > 100 ||\n entries.some(([key]) => !/^[A-Za-z][A-Za-z0-9-]{0,63}$/u.test(key)) ||\n Buffer.byteLength(value) > 64 * 1_024\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--params must be a JSON object smaller than 64 KiB.',\n )\n }\n return Object.fromEntries(entries) as Record<string, SeoProviderJson>\n}\n\nasync function installedProvider(id: string) {\n const loaded = await loadInstalledProviderExtensions()\n const provider = loaded.registry.get(id)\n if (provider) return provider\n const failure = loaded.failures.find((item) => item.id === id)\n if (failure) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Provider ${id} could not load: ${failure.message}`,\n )\n }\n throw new SeoError('INVALID_INPUT', `Provider ${id} is not installed.`)\n}\n\nfunction normalizedAccount(\n provider: Awaited<ReturnType<typeof installedProvider>>,\n account: Readonly<Record<string, string>>,\n): Record<string, string> {\n const allowed = new Set(\n provider.connection.fields\n .filter((field) => field.kind === 'account')\n .map((field) => field.id),\n )\n const unknown = Object.keys(account).find((key) => !allowed.has(key))\n if (unknown) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${unknown} is not an account field for ${provider.displayName}.`,\n )\n }\n const normalized = provider.connection.normalizeAccount\n ? provider.connection.normalizeAccount(account)\n : { ...account }\n const unknownNormalized = Object.keys(normalized).find(\n (key) => !allowed.has(key),\n )\n if (unknownNormalized) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n `${provider.displayName} returned an unknown account field.`,\n )\n }\n for (const field of provider.connection.fields.filter(\n (item) => item.kind === 'account' && item.required !== false,\n )) {\n if (!normalized[field.id]?.trim()) {\n throw new SeoError('INVALID_INPUT', `${field.label} is required.`)\n }\n }\n return normalized\n}\n\nexport async function providerExtensionInventory() {\n return listInstalledProviderExtensions()\n}\n\nconst listCommand = defineCommand({\n meta: {\n name: 'list',\n description: 'List installed provider packages',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const inventory = await providerExtensionInventory()\n if (jsonFlag(args)) {\n printJson(inventory)\n return\n }\n if (inventory.installed.length > 0) {\n printTable(\n ['Installed provider', 'Package', 'Version', 'Status'],\n inventory.installed.map((provider) => [\n provider.id,\n provider.package,\n provider.version,\n provider.loadStatus,\n ]),\n )\n } else {\n process.stdout.write('No provider extensions are installed.\\n')\n }\n },\n})\n\nconst describeCommand = defineCommand({\n meta: {\n name: 'describe',\n description: 'Describe one installed provider for an agent',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const result = await describeInstalledProviderExtension(id)\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printKeyValue([\n ['Provider', result.displayName],\n ['Package', `${result.package}@${result.version}`],\n ['Description', result.description],\n [\n 'Capabilities',\n result.capabilities.map((item) => item.id).join(', ') || 'none',\n ],\n ['Actions', result.actions.map((item) => item.id).join(', ') || 'none'],\n ])\n },\n})\n\nconst installCommand = defineCommand({\n meta: {\n name: 'install',\n description: 'Install one provider package from npm',\n },\n args: {\n package: {\n type: 'positional',\n required: true,\n description: 'npm package name with an optional exact version.',\n },\n yes: {\n type: 'boolean',\n default: false,\n description: 'Approve third-party code installation without prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const packageName = stringArg(args.package) ?? ''\n const json = jsonFlag(args)\n const approved = booleanArg(args.yes)\n const interactive = canPrompt({ json })\n if (!approved && !interactive) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Provider installation runs third-party code. Review the package, then pass --yes to approve it in JSON or CI mode.',\n )\n }\n let release: Awaited<ReturnType<typeof inspectProviderPackage>>\n try {\n release = await inspectProviderPackage(packageName)\n } catch (error) {\n throw new SeoError(\n 'INVALID_INPUT',\n error instanceof Error ? error.message : String(error),\n )\n }\n if (!approved) {\n intro('Install provider package')\n note(\n [\n `${release.package}@${release.version}`,\n `Publisher: ${release.publisher ?? 'not supplied by npm'}`,\n `Repository: ${release.repository ?? 'not supplied by npm'}`,\n `Integrity: ${release.integrity}`,\n ].join('\\n'),\n 'Package',\n )\n note(\n 'This package can read files, use the network, and run with the same local permissions as seo. Installing it is not a security review or endorsement.',\n 'Third-party code',\n )\n const accepted = maybeExitCancelled(\n await confirm({\n message: `Install ${release.package}@${release.version}?`,\n initialValue: false,\n }),\n )\n if (!accepted) {\n outro('Provider was not installed.')\n return\n }\n }\n let installed: Awaited<ReturnType<typeof installProviderPackage>>\n try {\n installed = await installProviderPackage(release)\n } catch (error) {\n throw new SeoError(\n 'PROVIDER_UNAVAILABLE',\n error instanceof Error ? error.message : String(error),\n )\n }\n const result = { installed, package: release }\n if (json) {\n printJson(result)\n return\n }\n outro(\n `Installed provider ${installed.id} from ${installed.package}@${installed.version}.`,\n )\n },\n})\n\nconst removeCommand = defineCommand({\n meta: {\n name: 'remove',\n description: 'Remove one installed provider extension',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n yes: {\n type: 'boolean',\n default: false,\n description: 'Remove the package without prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const json = jsonFlag(args)\n const approved = booleanArg(args.yes)\n const interactive = canPrompt({ json })\n if (!approved && !interactive) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Pass --yes to remove a provider extension in JSON or CI mode.',\n )\n }\n if (!approved) {\n const accepted = maybeExitCancelled(\n await confirm({\n message: `Remove provider ${id}?`,\n initialValue: false,\n }),\n )\n if (!accepted) return\n }\n const removed = await uninstallProviderExtension(id)\n if (!removed) {\n throw new SeoError('INVALID_INPUT', `Provider ${id} is not installed.`)\n }\n if (json) {\n printJson({ removed })\n return\n }\n process.stdout.write(`Removed ${id}.\\n`)\n },\n})\n\nconst connectCommand = defineCommand({\n meta: {\n name: 'connect',\n description: 'Validate and save one installed provider connection',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n account: {\n type: 'string',\n description:\n 'Account fields as JSON. Secret fields must use their environment variables.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const json = jsonFlag(args)\n const interactive = canPrompt({ json })\n const provider = await installedProvider(id)\n let account = {\n ...readProviderExtensionAccount(id),\n ...parseAccount(stringArg(args.account)),\n }\n const enteredCredentials: Record<string, string> = {}\n\n if (interactive) {\n intro(`Connect ${provider.displayName}`)\n if (provider.connection.verificationNotice) {\n note(provider.connection.verificationNotice, 'Connection check')\n }\n for (const field of provider.connection.fields) {\n if (field.kind === 'account') {\n const value = maybeExitCancelled(\n await text({\n message: field.label,\n placeholder: field.description,\n initialValue: account[field.id],\n validate: (item) =>\n field.required !== false && !item?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n )\n if (value?.trim()) account[field.id] = value.trim()\n continue\n }\n if (field.envVar && process.env[field.envVar]?.trim()) continue\n const value = maybeExitCancelled(\n await password({\n message: field.label,\n validate: (item) =>\n field.required !== false && !item?.trim()\n ? `${field.label} is required`\n : undefined,\n }),\n )\n if (value?.trim()) enteredCredentials[field.id] = value.trim()\n }\n }\n\n account = normalizedAccount(provider, account)\n let credentials = { ...enteredCredentials }\n if (Object.keys(credentials).length === 0) {\n credentials = await readProviderExtensionCredentials({\n providerId: id,\n account,\n fields: provider.connection.fields,\n })\n }\n await verifyProviderExtension({ providerId: id, account, credentials })\n if (Object.keys(enteredCredentials).length > 0) {\n await writeProviderExtensionCredentials({\n providerId: id,\n account,\n credentials: enteredCredentials,\n })\n }\n writeProviderExtensionAccount(id, account)\n const result = {\n provider: id,\n connected: true,\n account,\n capabilities: (provider.capabilities ?? []).map((item) => item.id),\n actions: (provider.actions ?? []).map((item) => item.id),\n }\n if (json) printJson(result)\n else\n outro(\n `Connected ${provider.displayName}. Run seo providers describe ${id} to see what it can do.`,\n )\n },\n})\n\nconst statusCommand = defineCommand({\n meta: {\n name: 'status',\n description: 'Show one installed provider connection',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n check: {\n type: 'boolean',\n default: false,\n description: 'Run the provider connection check.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const provider = await installedProvider(id)\n const account = readProviderExtensionAccount(id)\n let credentials: Record<string, string> | undefined\n try {\n credentials = await readProviderExtensionCredentials({\n providerId: id,\n account,\n fields: provider.connection.fields,\n })\n } catch {\n credentials = undefined\n }\n const accountReady = provider.connection.fields\n .filter((field) => field.kind === 'account' && field.required !== false)\n .every((field) => Boolean(account[field.id]?.trim()))\n const connected = accountReady && credentials !== undefined\n const shouldCheck = booleanArg(args.check)\n if (shouldCheck && !connected) {\n throw new SeoError(\n 'AUTH_REQUIRED',\n `Provider ${id} is not connected. Run \\`seo providers connect ${id}\\`.`,\n )\n }\n if (shouldCheck && credentials) {\n await verifyProviderExtension({ providerId: id, account, credentials })\n }\n const result = {\n provider: id,\n installed: true,\n connected,\n account,\n capabilities: (provider.capabilities ?? []).map((item) => item.id),\n actions: (provider.actions ?? []).map((item) => item.id),\n check: shouldCheck ? ('passed' as const) : ('not-requested' as const),\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n printTable(\n ['Provider', 'Connected', 'Capabilities', 'Check'],\n [\n [\n provider.displayName,\n connected ? 'yes' : 'no',\n result.capabilities.join(', '),\n result.check,\n ],\n ],\n )\n },\n})\n\nconst disconnectCommand = defineCommand({\n meta: {\n name: 'disconnect',\n description: 'Remove one saved provider connection',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n await installedProvider(id)\n const account = readProviderExtensionAccount(id)\n await deleteProviderExtensionCredentials({ providerId: id, account })\n deleteProviderExtensionAccount(id)\n const result = {\n provider: id,\n disconnected: true,\n note: 'Environment variables were not changed.',\n }\n if (jsonFlag(args)) printJson(result)\n else process.stdout.write(`Disconnected ${id}. ${result.note}\\n`)\n },\n})\n\nconst runCommand = defineCommand({\n meta: {\n name: 'run',\n description: 'Run one action supplied by an installed provider',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Installed provider id.',\n },\n action: {\n type: 'positional',\n required: true,\n description: 'Provider action id.',\n },\n account: {\n type: 'string',\n description: 'Account fields as JSON. Defaults to the saved connection.',\n },\n params: {\n type: 'string',\n description: 'Action parameters as a JSON object.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass the local provider cache.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const action = stringArg(args.action) ?? ''\n await installedProvider(id)\n const account = {\n ...readProviderExtensionAccount(id),\n ...parseAccount(stringArg(args.account)),\n }\n const result = await runProviderExtensionAction({\n providerId: id,\n actionId: action,\n account,\n params: parseActionParams(stringArg(args.params)),\n refresh: booleanArg(args.refresh),\n })\n printJson(result)\n },\n})\n\nconst doctorCommand = defineCommand({\n meta: {\n name: 'doctor',\n description: 'Validate installed provider packages and entry points',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const inventory = await providerExtensionInventory()\n const result = {\n ok: inventory.installed.every(\n (provider) => provider.loadStatus === 'ready',\n ),\n installed: inventory.installed,\n }\n if (jsonFlag(args)) {\n printJson(result)\n return\n }\n if (result.installed.length === 0) {\n process.stdout.write('No provider extensions are installed.\\n')\n return\n }\n printTable(\n ['Provider', 'Package', 'Version', 'Status'],\n result.installed.map((provider) => [\n provider.id,\n provider.package,\n provider.version,\n provider.error ?? provider.loadStatus,\n ]),\n )\n },\n})\n\nexport const providerExtensionCommands = {\n list: listCommand,\n describe: describeCommand,\n install: installCommand,\n remove: removeCommand,\n connect: connectCommand,\n status: statusCommand,\n disconnect: disconnectCommand,\n run: runCommand,\n doctor: doctorCommand,\n}\n","import { defineCommand } from 'citty'\nimport { ahrefsProviderCommand } from './ahrefs.js'\nimport { bingProviderCommand } from './bing.js'\nimport { dataForSeoProviderCommand } from './dataforseo.js'\nimport { providerExtensionCommands } from './extensions.js'\n\nexport const providersCommand = defineCommand({\n meta: { name: 'providers', description: 'Connect optional data providers' },\n subCommands: {\n ...providerExtensionCommands,\n ahrefs: ahrefsProviderCommand,\n bing: bingProviderCommand,\n dataforseo: dataForSeoProviderCommand,\n },\n})\n","import { readFile } from 'node:fs/promises'\nimport { SeoError, type SeoErrorCode } from '@seo/core'\nimport {\n describeReport,\n executeReport,\n listReports,\n REPORT_CATEGORIES,\n type ReportCategory,\n} from '@seo/mcp'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, stringArg } from '../args.js'\nimport {\n printBulletSection,\n printCallout,\n printCatalog,\n printHeading,\n printJson,\n printKeyValue,\n printParameters,\n printSection,\n} from '../utils.js'\n\nconst CATEGORY_LABELS: Record<ReportCategory, string> = {\n 'ai-search': 'AI search',\n crawl: 'Crawling and technical checks',\n diagnosis: 'Diagnosis',\n experiments: 'Experiments',\n monitoring: 'Monitoring',\n opportunities: 'Opportunities',\n reporting: 'Reporting',\n setup: 'Setup',\n workflows: 'Workflows',\n}\n\nfunction categoryArg(value: unknown): ReportCategory | undefined {\n const category = stringArg(value)\n if (!category) return undefined\n if (!REPORT_CATEGORIES.includes(category as ReportCategory)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Unknown report category: ${category}. Choose ${REPORT_CATEGORIES.join(', ')}.`,\n )\n }\n return category as ReportCategory\n}\n\nasync function paramsArg(\n inlineValue: unknown,\n fileValue: unknown,\n): Promise<Record<string, unknown>> {\n const inline = stringArg(inlineValue)\n const file = stringArg(fileValue)\n if (inline && file) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --params or --params-file, not both.',\n )\n }\n if (!inline && !file) return {}\n\n const source = inline ?? (await readFile(file ?? '', 'utf8'))\n let parsed: unknown\n try {\n parsed = JSON.parse(source)\n } catch {\n throw new SeoError('INVALID_INPUT', 'Report parameters must be valid JSON.')\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n throw new SeoError('INVALID_INPUT', 'Report parameters must be an object.')\n }\n return parsed as Record<string, unknown>\n}\n\nfunction throwToolError(result: {\n isError?: boolean\n structuredContent?: Record<string, unknown>\n}): void {\n if (!result.isError) return\n const envelope = result.structuredContent as\n | { error?: { code?: SeoErrorCode; message?: string } }\n | undefined\n throw new SeoError(\n envelope?.error?.code ?? 'INTERNAL_ERROR',\n envelope?.error?.message ?? 'The report could not be completed.',\n )\n}\n\ntype JsonSchemaProperty = {\n description?: string\n format?: string\n items?: { type?: string }\n type?: string | string[]\n}\n\nfunction reportParameters(inputSchema: unknown) {\n if (!inputSchema || typeof inputSchema !== 'object') return []\n const schema = inputSchema as {\n properties?: Record<string, JsonSchemaProperty>\n required?: string[]\n }\n const required = new Set(schema.required ?? [])\n return Object.entries(schema.properties ?? {}).map(([name, property]) => {\n const rawType = Array.isArray(property.type)\n ? property.type.join(' | ')\n : (property.type ?? 'any')\n const type =\n rawType === 'array' && property.items?.type\n ? `${property.items.type}[]`\n : property.format\n ? `${rawType} (${property.format})`\n : rawType\n return {\n name,\n type,\n required: required.has(name),\n description: property.description,\n }\n })\n}\n\nconst listCommand = defineCommand({\n meta: {\n name: 'list',\n description: 'List report ids available to the CLI and MCP server',\n },\n args: {\n category: {\n type: 'string',\n description: `Filter by category: ${REPORT_CATEGORIES.join(', ')}.`,\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const category = categoryArg(args.category)\n const reports = listReports(category)\n if (jsonFlag(args)) {\n printJson({ reports, categories: REPORT_CATEGORIES })\n return\n }\n printCatalog(reports, {\n noun: 'report',\n categoryLabels: CATEGORY_LABELS,\n })\n process.stdout.write('\\n')\n printCallout({\n title: 'Need the detail?',\n body: 'Describe one report to see when to use it, what it needs, and what the result can prove.',\n command: 'seo reports describe <id>',\n })\n },\n})\n\nconst describeCommand = defineCommand({\n meta: {\n name: 'describe',\n description: 'Show the purpose and parameter schema for one report',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Report id from `seo reports list`.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const report = describeReport(stringArg(args.id) ?? '')\n if (jsonFlag(args)) {\n printJson({ report })\n return\n }\n printHeading(report.name, report.description)\n process.stdout.write('\\n')\n printKeyValue([\n ['ID', report.id],\n ['Category', report.category],\n ['Outcome', report.outcome],\n ])\n process.stdout.write('\\n')\n printBulletSection('Use when', report.useWhen)\n process.stdout.write('\\n')\n printBulletSection('Avoid when', report.avoidWhen)\n process.stdout.write('\\n')\n printBulletSection('Read in order', report.readOrder)\n process.stdout.write('\\n')\n printBulletSection('Do not claim', report.doNotClaim)\n process.stdout.write('\\n')\n printSection('Verify', report.verify)\n process.stdout.write('\\n')\n printCallout({\n title: 'Implement findings',\n body: report.agentWorkflow.completion,\n command: report.agentWorkflow.actionView.cli,\n })\n if (report.related.length > 0) {\n process.stdout.write('\\n')\n printBulletSection(\n 'Related reports',\n report.related.map((item) => `${item.id}: ${item.reason}`),\n )\n }\n process.stdout.write('\\nParameters\\n')\n printParameters(reportParameters(report.inputSchema))\n process.stdout.write('\\n')\n printCallout({\n title: 'Need the exact schema?',\n command: `seo reports describe ${report.id} --json`,\n })\n },\n})\n\nconst runCommand = defineCommand({\n meta: {\n name: 'run',\n description: 'Run one report with JSON parameters',\n },\n args: {\n id: {\n type: 'positional',\n required: true,\n description: 'Report id from `seo reports list`.',\n },\n params: {\n type: 'string',\n description: 'Report parameters as a JSON object.',\n },\n 'params-file': {\n type: 'string',\n description: 'Read report parameters from a JSON file.',\n },\n 'actions-only': {\n type: 'boolean',\n default: false,\n description:\n 'Return findings, verification, and retained inventories without the full report body.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const id = stringArg(args.id) ?? ''\n const params = await paramsArg(args.params, args['params-file'])\n const result = await executeReport(id, params, {\n view: booleanArg(args['actions-only']) ? 'actions' : 'full',\n })\n throwToolError(result)\n\n if (jsonFlag(args)) {\n printJson(result.structuredContent ?? {})\n return\n }\n for (const item of result.content) {\n process.stdout.write(`${item.text}\\n`)\n }\n },\n})\n\nexport const reportCatalogCommand = defineCommand({\n meta: {\n name: 'reports',\n description: 'Discover and run the complete report catalog',\n },\n subCommands: {\n list: listCommand,\n describe: describeCommand,\n run: runCommand,\n },\n})\n","import { explainRule, listRules } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../args.js'\nimport {\n printCatalog,\n printJson,\n printKeyValue,\n printSection,\n} from '../utils.js'\n\nexport const rulesCommand = defineCommand({\n meta: {\n name: 'rules',\n description: 'List crawler rule ids and default guidance',\n },\n args: {\n category: {\n type: 'string',\n description: 'Filter rules by category.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const category = stringArg(args.category)\n const rules = listRules().filter((rule) =>\n category ? rule.category === category : true,\n )\n\n if (jsonFlag(args)) {\n printJson({ rules })\n return\n }\n\n printCatalog(\n rules.map((rule) => ({\n id: rule.id,\n category: rule.category,\n name: `${rule.title} · ${rule.defaultSeverity}`,\n })),\n { noun: 'rule' },\n )\n },\n})\n\nexport const explainCommand = defineCommand({\n meta: {\n name: 'explain',\n description: 'Explain one crawler rule in plain English',\n },\n args: {\n rule: {\n type: 'string',\n required: true,\n description: 'Rule id to explain, for example missing_title.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const ruleId = stringArg(args.rule) ?? ''\n const rule = explainRule(ruleId)\n if (!rule) {\n throw new Error(`Unknown rule: ${ruleId}`)\n }\n\n if (jsonFlag(args)) {\n printJson(rule)\n return\n }\n\n printKeyValue([\n ['Rule', rule.id],\n ['Title', rule.title],\n ['Category', rule.category],\n ['Severity', rule.defaultSeverity],\n ])\n process.stdout.write('\\n')\n printSection('Why it matters', rule.whyItMatters)\n process.stdout.write('\\n')\n printSection('How to fix', rule.howToFix)\n process.stdout.write('\\n')\n printSection('Impact if ignored', rule.impactIfIgnored)\n process.stdout.write('\\n')\n printSection('How to verify', rule.howToVerify)\n },\n})\n","import { ensureSeoCliDirs } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, numberArg, projectArg, stringArg } from '../args.js'\nimport { resolveClientSelection } from '../selection.js'\nimport { printJson, printKeyValue } from '../utils.js'\nimport { startUrlForSite } from './shared.js'\n\nfunction quote(value: string): string {\n return JSON.stringify(value)\n}\n\nexport const scheduleCommand = defineCommand({\n meta: {\n name: 'schedule',\n description: 'Print local cron entries for recurring SEO workflows',\n },\n subCommands: {\n cron: defineCommand({\n meta: {\n name: 'cron',\n description: 'Print crontab lines for local recurring SEO workflows',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL for technical-watch. Defaults from the GSC property when possible.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs for index-watch.',\n },\n hour: {\n type: 'string',\n default: '9',\n description: 'Hour in local cron time. Defaults to 9.',\n },\n minute: {\n type: 'string',\n default: '0',\n description: 'Minute in local cron time. Defaults to 0.',\n },\n weekday: {\n type: 'string',\n description:\n 'Weekly technical-watch day. Defaults to client setting, then Monday.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json },\n })\n const site = selection.site\n const startUrl =\n stringArg(args.url) ??\n selection.client?.startUrl ??\n startUrlForSite(selection.site)\n const hour = numberArg(args.hour) ?? 9\n const minute = numberArg(args.minute) ?? 0\n const weekday =\n numberArg(args.weekday) ?? selection.client?.technicalWeekday ?? 1\n const identityArg = selection.client\n ? `--project ${quote(selection.client.id)}`\n : `--site ${quote(site)}`\n const watchUrls =\n stringArg(args.urls) ?? selection.client?.watchUrls.join(',')\n\n const lines = [\n {\n name: 'technical-watch',\n cron: `${minute} ${hour} * * ${weekday}`,\n command: [\n 'seo technical-watch',\n identityArg,\n startUrl ? `--url ${quote(startUrl)}` : undefined,\n watchUrls ? `--urls ${quote(watchUrls)}` : undefined,\n '--json',\n ]\n .filter(Boolean)\n .join(' '),\n },\n ]\n if (json) {\n printJson({ site, lines })\n return\n }\n\n const paths = ensureSeoCliDirs()\n printKeyValue([\n ['Property', site],\n ['Install', 'crontab -e'],\n ])\n for (const line of lines) {\n process.stdout.write(\n `${line.cron} seo logs prune --quiet; ${line.command} >> ${quote(`${paths.logDir}/${line.name}.log`)} 2>&1\\n`,\n )\n }\n },\n }),\n },\n})\n","import { existsSync, readFileSync } from 'node:fs'\nimport { dirname, join, resolve } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { SeoError } from '@seo/core'\n\n// Skills and evals ship at the package root. Both resolvers honour an explicit\n// override, otherwise walk up from the bundled CLI until the directory and its\n// README appear. Kept in its own module so the skills command and the eval\n// command can share it without importing each other.\nexport function skillsDirectory(): string {\n return resolvePackagedDirectory('skills', process.env.SEO_SKILLS_DIR)\n}\n\nexport function evalsDirectory(): string {\n return resolvePackagedDirectory('evals', process.env.SEO_EVALS_DIR)\n}\n\nfunction resolvePackagedDirectory(name: string, override?: string): string {\n if (override) return resolve(override)\n\n let current = dirname(fileURLToPath(import.meta.url))\n for (let depth = 0; depth < 6; depth += 1) {\n const candidate = join(current, name)\n if (existsSync(join(candidate, 'README.md'))) return candidate\n current = dirname(current)\n }\n\n throw new SeoError(\n 'INTERNAL_ERROR',\n `Packaged ${name} could not be found. Reinstall \\`seo\\` and try again.`,\n )\n}\n\nexport function readSkillDescription(path: string): string {\n const source = readFileSync(join(path, 'SKILL.md'), 'utf8')\n return source.match(/^description:\\s*(.+)$/m)?.[1]?.trim() ?? ''\n}\n","import { spawn } from 'node:child_process'\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { basename, join } from 'node:path'\nimport { SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n stringArg,\n} from '../args.js'\nimport { printJson } from '../utils.js'\nimport { evalsDirectory, skillsDirectory } from './skill-paths.js'\n\nconst SCHEMA_VERSION = 1\nconst DEFAULT_AGENT = 'claude -p'\nconst DEFAULT_TIMEOUT_SECONDS = 300\nconst MAX_CONCURRENCY = 4\nconst ROUTER_SKILL = 'seo'\n\ntype EvalItem = {\n id: number\n prompt: string\n expected_output: string\n assertions: string[]\n files: string[]\n}\n\ntype EvalFile = {\n subject: string\n evals: EvalItem[]\n}\n\ntype AssertionVerdict = {\n assertion: string\n verdict: 'pass' | 'fail' | 'unjudged'\n reason?: string\n source?: 'judge verdict'\n}\n\ntype EvalStatus = 'passed' | 'failed' | 'errored' | 'unjudged'\n\ntype EvalResult = {\n id: number\n prompt: string\n status: EvalStatus\n reply: string\n error?: string\n agentDurationMs: number\n judgeDurationMs?: number\n durationMs: number\n assertions: AssertionVerdict[]\n}\n\ntype SubjectResult = {\n subject: string\n passed: number\n failed: number\n errored: number\n unjudged: number\n evals: EvalResult[]\n}\n\nfunction listSubjectFiles(): Array<{ subject: string; path: string }> {\n const root = evalsDirectory()\n return readdirSync(root, { withFileTypes: true })\n .filter((entry) => entry.isFile() && entry.name.endsWith('.json'))\n .map((entry) => ({\n subject: basename(entry.name, '.json'),\n path: join(root, entry.name),\n }))\n .sort((a, b) =>\n a.subject < b.subject ? -1 : a.subject > b.subject ? 1 : 0,\n )\n}\n\nexport function loadEvalFile(subject: string, path: string): EvalFile {\n let raw: string\n try {\n raw = readFileSync(path, 'utf8')\n } catch {\n throw new SeoError('INVALID_INPUT', `Cannot read eval file for ${subject}.`)\n }\n let doc: unknown\n try {\n doc = JSON.parse(raw)\n } catch {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json is not valid JSON.`,\n )\n }\n if (!doc || typeof doc !== 'object' || Array.isArray(doc)) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json must be an object.`,\n )\n }\n const record = doc as Record<string, unknown>\n if (record.subject !== subject) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json must set subject to \"${subject}\".`,\n )\n }\n if (!Array.isArray(record.evals) || record.evals.length === 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Eval file ${subject}.json must have a non-empty evals array.`,\n )\n }\n const seen = new Set<number>()\n const evals: EvalItem[] = record.evals.map((entry, index) => {\n const item = entry as Record<string, unknown>\n const label = `${subject}.json eval ${index + 1}`\n if (!Number.isInteger(item?.id)) {\n throw new SeoError('INVALID_INPUT', `${label}: id must be an integer.`)\n }\n const id = item.id as number\n if (seen.has(id)) {\n throw new SeoError('INVALID_INPUT', `${label}: duplicate id ${id}.`)\n }\n seen.add(id)\n if (typeof item.prompt !== 'string' || item.prompt.trim().length === 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${label}: prompt must be a non-empty string.`,\n )\n }\n if (\n typeof item.expected_output !== 'string' ||\n item.expected_output.trim().length === 0\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${label}: expected_output must be a non-empty string.`,\n )\n }\n if (\n !Array.isArray(item.assertions) ||\n item.assertions.length === 0 ||\n item.assertions.some(\n (value) => typeof value !== 'string' || value.trim().length === 0,\n )\n ) {\n throw new SeoError(\n 'INVALID_INPUT',\n `${label}: assertions must be a non-empty array of non-empty strings.`,\n )\n }\n if (item.files !== undefined && !Array.isArray(item.files)) {\n throw new SeoError('INVALID_INPUT', `${label}: files must be an array.`)\n }\n return {\n id,\n prompt: item.prompt,\n expected_output: item.expected_output,\n assertions: item.assertions as string[],\n files: (item.files as string[] | undefined) ?? [],\n }\n })\n return { subject, evals }\n}\n\nfunction routerSkillBody(): string {\n const path = join(skillsDirectory(), ROUTER_SKILL, 'SKILL.md')\n if (!existsSync(path)) {\n throw new SeoError(\n 'INTERNAL_ERROR',\n 'The seo router skill could not be found. Reinstall `seo` or use --no-skill.',\n )\n }\n return readFileSync(path, 'utf8')\n}\n\n// Split a command template into argv tokens without a shell. Single quotes,\n// double quotes, and backslash escapes group tokens; nothing is expanded, so a\n// substituted prompt can never break out into extra arguments or shell syntax.\nexport function tokenizeCommand(command: string): string[] {\n const tokens: string[] = []\n let current = ''\n let started = false\n let inSingle = false\n let inDouble = false\n for (let i = 0; i < command.length; i += 1) {\n const ch = command[i] as string\n if (inSingle) {\n if (ch === \"'\") inSingle = false\n else current += ch\n started = true\n continue\n }\n if (inDouble) {\n if (ch === '\"') {\n inDouble = false\n } else if (\n ch === '\\\\' &&\n (command[i + 1] === '\"' || command[i + 1] === '\\\\')\n ) {\n current += command[i + 1]\n i += 1\n } else {\n current += ch\n }\n started = true\n continue\n }\n if (ch === \"'\") {\n inSingle = true\n started = true\n continue\n }\n if (ch === '\"') {\n inDouble = true\n started = true\n continue\n }\n if (ch === '\\\\') {\n if (i + 1 < command.length) {\n current += command[i + 1]\n i += 1\n started = true\n }\n continue\n }\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r') {\n if (started) {\n tokens.push(current)\n current = ''\n started = false\n }\n continue\n }\n current += ch\n started = true\n }\n if (inSingle || inDouble) {\n throw new SeoError('INVALID_INPUT', 'Unbalanced quote in agent command.')\n }\n if (started) tokens.push(current)\n return tokens\n}\n\nexport function buildArgv(\n template: string,\n prompt: string,\n): { argv: string[]; usesPlaceholder: boolean } {\n const tokens = tokenizeCommand(template)\n if (tokens.length === 0) {\n throw new SeoError('INVALID_INPUT', 'Agent command must not be empty.')\n }\n const usesPlaceholder = tokens.some((token) => token.includes('{prompt}'))\n const argv = usesPlaceholder\n ? tokens.map((token) => token.split('{prompt}').join(prompt))\n : tokens\n return { argv, usesPlaceholder }\n}\n\nexport function assembleAgentPrompt(\n skillBody: string | null,\n prompt: string,\n): string {\n if (!skillBody) return prompt\n return `${skillBody.trim()}\\n\\n---\\n\\nUser request:\\n${prompt}`\n}\n\nconst JUDGE_CORRECTION =\n 'Your previous reply could not be parsed as the required JSON with one result per assertion. Reply again with STRICT JSON only, in the exact shape shown, and nothing else.'\n\nexport function buildJudgePrompt(\n prompt: string,\n reply: string,\n assertions: string[],\n corrective = false,\n): string {\n const list = assertions\n .map((entry, index) => `${index + 1}. ${entry}`)\n .join('\\n')\n const base = [\n 'You are judging whether an AI agent response satisfies a list of assertions.',\n 'Judge only against the assertions. Be strict but fair.',\n '',\n 'Original request:',\n prompt,\n '',\n 'Agent response:',\n reply,\n '',\n 'Assertions to evaluate, in this exact order:',\n '<assertions>',\n list,\n '</assertions>',\n '',\n 'Judge outcomes, not narration. An assertion about reading, checking, or',\n 'following fields or steps passes when the reply demonstrably used that',\n 'information or produced the result it protects, even if the reply never',\n 'names the field or step. Fail it only when the reply contradicts it or',\n 'shows the work was not done.',\n '',\n 'Reply with STRICT JSON only. No prose, no markdown, no code fence:',\n '{\"results\":[{\"assertion\":\"<assertion text>\",\"pass\":true,\"reason\":\"<short reason>\"}]}',\n `Return exactly ${assertions.length} result${assertions.length === 1 ? '' : 's'}, one per assertion, in the same order.`,\n ].join('\\n')\n return corrective ? `${base}\\n\\n${JUDGE_CORRECTION}` : base\n}\n\n// Pull the first complete JSON object out of a larger reply. Judges wrap JSON\n// in prose or code fences, so scan for the first balanced `{...}` and parse it.\nexport function extractJsonObject(text: string): unknown | undefined {\n const start = text.indexOf('{')\n if (start === -1) return undefined\n let depth = 0\n let inString = false\n let escaped = false\n for (let i = start; i < text.length; i += 1) {\n const ch = text[i]\n if (inString) {\n if (escaped) escaped = false\n else if (ch === '\\\\') escaped = true\n else if (ch === '\"') inString = false\n continue\n }\n if (ch === '\"') inString = true\n else if (ch === '{') depth += 1\n else if (ch === '}') {\n depth -= 1\n if (depth === 0) {\n try {\n return JSON.parse(text.slice(start, i + 1))\n } catch {\n return undefined\n }\n }\n }\n }\n return undefined\n}\n\ntype ParsedVerdicts = { verdicts: AssertionVerdict[] } | { error: string }\n\nexport function parseJudgeVerdicts(\n output: string,\n assertions: string[],\n): ParsedVerdicts {\n const parsed = extractJsonObject(output)\n if (!parsed || typeof parsed !== 'object') {\n return { error: 'Judge reply did not contain a JSON object.' }\n }\n const results = (parsed as Record<string, unknown>).results\n if (!Array.isArray(results)) {\n return { error: 'Judge reply had no results array.' }\n }\n if (results.length !== assertions.length) {\n return {\n error: `Judge returned ${results.length} results for ${assertions.length} assertions.`,\n }\n }\n const verdicts = assertions.map((assertion, index) => {\n const entry = results[index] as Record<string, unknown>\n return {\n assertion,\n verdict: entry?.pass === true ? 'pass' : 'fail',\n reason:\n typeof entry?.reason === 'string' && entry.reason.trim().length > 0\n ? entry.reason.trim()\n : 'No reason given.',\n source: 'judge verdict' as const,\n } satisfies AssertionVerdict\n })\n return { verdicts }\n}\n\ntype ProcessResult = {\n stdout: string\n stderr: string\n code: number | null\n timedOut: boolean\n spawnError?: string\n durationMs: number\n}\n\nfunction runProcess(\n argv: string[],\n options: { input?: string; timeoutMs: number },\n): Promise<ProcessResult> {\n return new Promise((resolvePromise) => {\n const start = Date.now()\n const [command, ...rest] = argv\n let child: ReturnType<typeof spawn>\n try {\n child = spawn(command as string, rest, {\n stdio: ['pipe', 'pipe', 'pipe'],\n })\n } catch (error) {\n resolvePromise({\n stdout: '',\n stderr: '',\n code: null,\n timedOut: false,\n spawnError: error instanceof Error ? error.message : String(error),\n durationMs: Date.now() - start,\n })\n return\n }\n let stdout = ''\n let stderr = ''\n let settled = false\n let timedOut = false\n let killTimer: NodeJS.Timeout | undefined\n const timer = setTimeout(() => {\n timedOut = true\n child.kill('SIGTERM')\n killTimer = setTimeout(() => {\n try {\n child.kill('SIGKILL')\n } catch {\n // process already gone\n }\n }, 2000)\n killTimer.unref()\n }, options.timeoutMs)\n const finish = (result: Omit<ProcessResult, 'durationMs'>) => {\n if (settled) return\n settled = true\n clearTimeout(timer)\n if (killTimer) clearTimeout(killTimer)\n resolvePromise({ ...result, durationMs: Date.now() - start })\n }\n child.stdout?.on('data', (chunk) => {\n stdout += chunk\n })\n child.stderr?.on('data', (chunk) => {\n stderr += chunk\n })\n child.on('error', (error) => {\n finish({\n stdout,\n stderr,\n code: null,\n timedOut,\n spawnError: error.message,\n })\n })\n child.on('close', (code) => {\n finish({ stdout, stderr, code, timedOut })\n })\n if (child.stdin) {\n if (options.input !== undefined) child.stdin.end(options.input)\n else child.stdin.end()\n }\n })\n}\n\nasync function runCommandTemplate(\n template: string,\n prompt: string,\n timeoutMs: number,\n): Promise<ProcessResult> {\n const { argv, usesPlaceholder } = buildArgv(template, prompt)\n return runProcess(argv, {\n input: usesPlaceholder ? undefined : prompt,\n timeoutMs,\n })\n}\n\ntype RunOptions = {\n agent: string\n judge: string | null\n skillBody: string | null\n timeoutMs: number\n}\n\nasync function runSingleEval(\n item: EvalItem,\n options: RunOptions,\n): Promise<EvalResult> {\n const start = Date.now()\n const agentPrompt = assembleAgentPrompt(options.skillBody, item.prompt)\n const agentRun = await runCommandTemplate(\n options.agent,\n agentPrompt,\n options.timeoutMs,\n )\n const reply = agentRun.stdout.trim()\n\n const base = {\n id: item.id,\n prompt: item.prompt,\n reply,\n agentDurationMs: agentRun.durationMs,\n }\n\n if (agentRun.spawnError) {\n return {\n ...base,\n status: 'errored',\n error: `Agent command failed to start: ${agentRun.spawnError}`,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n if (agentRun.timedOut) {\n return {\n ...base,\n status: 'errored',\n error: `Agent timed out after ${Math.round(options.timeoutMs / 1000)}s.`,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n if (reply.length === 0) {\n return {\n ...base,\n status: 'errored',\n error: 'Agent returned no output on stdout.',\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n\n if (!options.judge) {\n return {\n ...base,\n status: 'unjudged',\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n\n let judgeDurationMs = 0\n let parseError = ''\n for (let attempt = 0; attempt < 2; attempt += 1) {\n const judgePrompt = buildJudgePrompt(\n item.prompt,\n reply,\n item.assertions,\n attempt > 0,\n )\n const judgeRun = await runCommandTemplate(\n options.judge,\n judgePrompt,\n options.timeoutMs,\n )\n judgeDurationMs += judgeRun.durationMs\n if (judgeRun.spawnError) {\n return {\n ...base,\n status: 'errored',\n error: `Judge command failed to start: ${judgeRun.spawnError}`,\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n if (judgeRun.timedOut) {\n return {\n ...base,\n status: 'errored',\n error: `Judge timed out after ${Math.round(options.timeoutMs / 1000)}s.`,\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n }\n const parsed = parseJudgeVerdicts(judgeRun.stdout, item.assertions)\n if ('verdicts' in parsed) {\n const failed = parsed.verdicts.some((entry) => entry.verdict === 'fail')\n return {\n ...base,\n status: failed ? 'failed' : 'passed',\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: parsed.verdicts,\n }\n }\n parseError = parsed.error\n }\n\n return {\n ...base,\n status: 'errored',\n error: `Judge output could not be parsed after a retry: ${parseError}`,\n judgeDurationMs,\n durationMs: Date.now() - start,\n assertions: unjudgedAssertions(item.assertions),\n }\n}\n\nfunction unjudgedAssertions(assertions: string[]): AssertionVerdict[] {\n return assertions.map((assertion) => ({ assertion, verdict: 'unjudged' }))\n}\n\nasync function mapWithConcurrency<T, R>(\n items: T[],\n limit: number,\n fn: (item: T, index: number) => Promise<R>,\n): Promise<R[]> {\n const results = new Array<R>(items.length)\n let next = 0\n const worker = async () => {\n while (true) {\n const index = next\n next += 1\n if (index >= items.length) return\n results[index] = await fn(items[index] as T, index)\n }\n }\n const size = Math.max(1, Math.min(limit, items.length))\n await Promise.all(Array.from({ length: size }, () => worker()))\n return results\n}\n\nfunction tally(evals: EvalResult[]): {\n passed: number\n failed: number\n errored: number\n unjudged: number\n} {\n const counts = { passed: 0, failed: 0, errored: 0, unjudged: 0 }\n for (const item of evals) counts[item.status] += 1\n return counts\n}\n\nfunction collectSubjects(args: Record<string, unknown>): string[] {\n const raw: string[] = []\n const first = stringArg(args.subject)\n if (first) raw.push(first)\n const rest = args._\n if (Array.isArray(rest)) {\n for (const value of rest) {\n if (typeof value === 'string' && value.length > 0) raw.push(value)\n }\n }\n return [...new Set(raw)]\n}\n\nfunction resolveSelectedSubjects(requested: string[]): Array<{\n subject: string\n path: string\n}> {\n const available = listSubjectFiles()\n if (requested.length === 0) return available\n const byName = new Map(available.map((entry) => [entry.subject, entry]))\n return requested.map((subject) => {\n const match = byName.get(subject)\n if (!match) {\n const known = available.map((entry) => entry.subject).join(', ')\n throw new SeoError(\n 'INVALID_INPUT',\n `Unknown eval subject: ${subject}.${known ? ` Known subjects: ${known}.` : ''}`,\n )\n }\n return match\n })\n}\n\nfunction renderList(json: boolean): void {\n const subjects = listSubjectFiles().map((entry) => {\n const doc = loadEvalFile(entry.subject, entry.path)\n return { subject: entry.subject, evals: doc.evals.length }\n })\n if (json) {\n printJson({ schemaVersion: SCHEMA_VERSION, subjects })\n return\n }\n if (subjects.length === 0) {\n process.stdout.write('No eval subjects found.\\n')\n return\n }\n const width = Math.max(...subjects.map((entry) => entry.subject.length))\n process.stdout.write('Eval subjects\\n')\n for (const entry of subjects) {\n const label = entry.evals === 1 ? 'eval' : 'evals'\n process.stdout.write(\n ` ${entry.subject.padEnd(width)} ${entry.evals} ${label}\\n`,\n )\n }\n}\n\nfunction statusLabel(status: EvalStatus): string {\n if (status === 'passed') return 'PASS'\n if (status === 'failed') return 'FAIL'\n if (status === 'errored') return 'ERROR'\n return 'UNJUDGED'\n}\n\nfunction renderHuman(\n subjects: SubjectResult[],\n options: { judged: boolean; agent: string; judge: string | null },\n): void {\n if (options.judged) {\n process.stdout.write(\n 'Assertion verdicts below are judge verdicts, model judgments from the judge agent, not ground truth.\\n\\n',\n )\n } else {\n process.stdout.write(\n 'Judging was skipped. Review each agent reply against the assertion checklist by hand.\\n\\n',\n )\n }\n for (const subject of subjects) {\n process.stdout.write(`# ${subject.subject}\\n`)\n for (const item of subject.evals) {\n process.stdout.write(\n `\\n[${statusLabel(item.status)}] eval ${item.id} (${item.durationMs}ms)\\n`,\n )\n process.stdout.write(` prompt: ${truncate(item.prompt, 100)}\\n`)\n if (item.error) {\n process.stdout.write(` error: ${item.error}\\n`)\n }\n if (!options.judged) {\n process.stdout.write(` reply: ${truncate(item.reply, 200)}\\n`)\n process.stdout.write(' assertions to review:\\n')\n for (const verdict of item.assertions) {\n process.stdout.write(` - [ ] ${verdict.assertion}\\n`)\n }\n continue\n }\n for (const verdict of item.assertions) {\n const mark =\n verdict.verdict === 'pass'\n ? 'pass'\n : verdict.verdict === 'fail'\n ? 'fail'\n : 'unjudged'\n process.stdout.write(` - ${mark}: ${verdict.assertion}\\n`)\n if (verdict.reason) {\n process.stdout.write(` judge verdict: ${verdict.reason}\\n`)\n }\n }\n }\n const counts = tally(subject.evals)\n process.stdout.write(\n `\\nSubject ${subject.subject}: ${counts.passed} passed, ${counts.failed} failed, ${counts.errored} errored${counts.unjudged ? `, ${counts.unjudged} unjudged` : ''}.\\n\\n`,\n )\n }\n const totals = totalCounts(subjects)\n process.stdout.write(\n `Totals: ${totals.passed} passed, ${totals.failed} failed, ${totals.errored} errored${totals.unjudged ? `, ${totals.unjudged} unjudged` : ''} across ${totals.evals} evals.\\n`,\n )\n}\n\nfunction totalCounts(subjects: SubjectResult[]): {\n passed: number\n failed: number\n errored: number\n unjudged: number\n evals: number\n} {\n const totals = { passed: 0, failed: 0, errored: 0, unjudged: 0, evals: 0 }\n for (const subject of subjects) {\n totals.passed += subject.passed\n totals.failed += subject.failed\n totals.errored += subject.errored\n totals.unjudged += subject.unjudged\n totals.evals += subject.evals.length\n }\n return totals\n}\n\nfunction truncate(value: string, max: number): string {\n const collapsed = value.replace(/\\s+/g, ' ').trim()\n return collapsed.length > max ? `${collapsed.slice(0, max - 1)}…` : collapsed\n}\n\nexport const skillsEvalCommand = defineCommand({\n meta: {\n name: 'eval',\n description:\n 'Run behaviour evals for the seo skill against a local agent and judge the results',\n },\n args: {\n subject: {\n type: 'positional',\n required: false,\n description:\n 'Eval subject (report id or job). Omit to run every subject.',\n },\n list: {\n type: 'boolean',\n default: false,\n description: 'List eval subjects with their eval counts and exit.',\n },\n id: {\n type: 'string',\n description: 'Run one eval id within a single subject.',\n },\n agent: {\n type: 'string',\n default: DEFAULT_AGENT,\n description:\n 'Agent command. Use {prompt} to place the prompt in argv, otherwise it is sent on stdin.',\n },\n 'judge-agent': {\n type: 'string',\n description: 'Judge command. Defaults to the same command as --agent.',\n },\n judge: defaultTrueBooleanArg(\n 'Judge assertions with an agent.',\n 'Skip judging and print replies with an assertion checklist.',\n ),\n skill: defaultTrueBooleanArg(\n 'Send the seo router skill as context before the prompt.',\n 'Omit the seo router skill context.',\n ),\n timeout: {\n type: 'string',\n default: String(DEFAULT_TIMEOUT_SECONDS),\n description: 'Timeout in seconds per agent or judge call.',\n },\n concurrency: {\n type: 'string',\n default: '1',\n description: `Evals to run in parallel (max ${MAX_CONCURRENCY}).`,\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n\n if (args.list === true) {\n renderList(json)\n return\n }\n\n const requested = collectSubjects(args)\n const selected = resolveSelectedSubjects(requested)\n\n const idFilter = numberArg(args.id)\n if (idFilter !== undefined && selected.length !== 1) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--id needs exactly one subject. Name the subject to filter.',\n )\n }\n\n const timeoutSeconds = numberArg(args.timeout) ?? DEFAULT_TIMEOUT_SECONDS\n if (!(timeoutSeconds > 0)) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--timeout must be a positive number of seconds.',\n )\n }\n const concurrency = Math.max(\n 1,\n Math.min(MAX_CONCURRENCY, numberArg(args.concurrency) ?? 1),\n )\n\n const agent = stringArg(args.agent) ?? DEFAULT_AGENT\n const judgeEnabled = args.judge !== false\n const judge = judgeEnabled\n ? (stringArg(args['judge-agent']) ?? agent)\n : null\n const skillBody = args.skill === false ? null : routerSkillBody()\n\n const runOptions: RunOptions = {\n agent,\n judge,\n skillBody,\n timeoutMs: timeoutSeconds * 1000,\n }\n\n const subjectResults: SubjectResult[] = []\n for (const entry of selected) {\n const doc = loadEvalFile(entry.subject, entry.path)\n let items = doc.evals\n if (idFilter !== undefined) {\n items = items.filter((item) => item.id === idFilter)\n if (items.length === 0) {\n throw new SeoError(\n 'INVALID_INPUT',\n `No eval with id ${idFilter} in subject ${entry.subject}.`,\n )\n }\n }\n if (!json) {\n process.stderr.write(\n `Running ${items.length} eval${items.length === 1 ? '' : 's'} for ${entry.subject}...\\n`,\n )\n }\n const evals = await mapWithConcurrency(items, concurrency, (item) =>\n runSingleEval(item, runOptions),\n )\n const counts = tally(evals)\n subjectResults.push({ subject: entry.subject, ...counts, evals })\n }\n\n const totals = totalCounts(subjectResults)\n const failed = totals.failed > 0 || totals.errored > 0\n\n if (json) {\n printJson({\n schemaVersion: SCHEMA_VERSION,\n agent,\n judge,\n judged: judge !== null,\n skillContext: skillBody !== null,\n timeoutSeconds,\n concurrency,\n subjects: subjectResults,\n totals,\n })\n } else {\n renderHuman(subjectResults, { judged: judge !== null, agent, judge })\n }\n\n if (failed) process.exitCode = 1\n },\n})\n","import { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { SeoError } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag, stringArg } from '../args.js'\nimport {\n printCallout,\n printHeading,\n printJson,\n printKeyValue,\n} from '../utils.js'\nimport { installSeoSkill } from './skill-install.js'\nimport { readSkillDescription, skillsDirectory } from './skill-paths.js'\nimport { skillsEvalCommand } from './skills-eval.js'\n\ntype SkillInfo = {\n name: string\n description: string\n path: string\n}\n\nfunction listSkills(): SkillInfo[] {\n const root = skillsDirectory()\n return readdirSync(root, { withFileTypes: true })\n .filter(\n (entry) =>\n entry.isDirectory() && existsSync(join(root, entry.name, 'SKILL.md')),\n )\n .map((entry) => ({\n name: entry.name,\n description: readSkillDescription(join(root, entry.name)),\n path: join(root, entry.name),\n }))\n .sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0))\n}\n\nfunction selectedSkill(name?: string): SkillInfo[] {\n const skills = listSkills()\n if (!name) return skills\n const skill = skills.find((entry) => entry.name === name)\n if (!skill) {\n throw new SeoError('INVALID_INPUT', `Unknown skill: ${name}.`)\n }\n return [skill]\n}\n\nconst listCommand = defineCommand({\n meta: { name: 'list', description: 'Show the packaged SEO skill' },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const skills = listSkills()\n if (jsonFlag(args)) {\n printJson({ skills })\n return\n }\n printHeading('SEO skill', 'Packaged with this CLI.')\n process.stdout.write('\\n')\n for (const skill of skills) {\n printKeyValue([\n ['Name', skill.name],\n [\n 'Purpose',\n 'Helps agents choose and run the right SEO audit or report.',\n ],\n ['Path', skill.path],\n ])\n }\n process.stdout.write('\\n')\n printCallout({\n title: 'Add it to an agent',\n body: 'Run setup to install the skill and connect your first site.',\n command: 'seo start',\n })\n },\n})\n\nconst pathCommand = defineCommand({\n meta: { name: 'path', description: 'Print a packaged agent skill path' },\n args: {\n name: {\n type: 'positional',\n description: 'Skill name. Omit it for the skill directory.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const name = stringArg(args.name)\n const path = name ? selectedSkill(name)[0]?.path : skillsDirectory()\n if (jsonFlag(args)) {\n printJson({ name, path })\n } else {\n process.stdout.write(`${path}\\n`)\n }\n },\n})\n\nconst installCommand = defineCommand({\n meta: {\n name: 'install',\n description: 'Install the SEO skill for coding agents',\n },\n args: {\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: ({ args }) => {\n const json = jsonFlag(args)\n const result = installSeoSkill({ quiet: json })\n if (json) {\n printJson(result)\n if (result.status === 'failed') process.exitCode = 1\n return\n }\n if (result.status === 'failed') {\n throw new SeoError(\n 'INTERNAL_ERROR',\n `Skill install failed: ${result.error}`,\n )\n }\n process.stdout.write(\n 'SEO skill installed. Agents that support skills can discover it now.\\n',\n )\n },\n})\n\nexport const skillsCommand = defineCommand({\n meta: {\n name: 'skill',\n description: 'Inspect the packaged SEO skill and run its evals',\n },\n subCommands: {\n list: listCommand,\n path: pathCommand,\n install: installCommand,\n eval: skillsEvalCommand,\n },\n})\n","import { cancel, confirm } from '@clack/prompts'\nimport {\n getCacheStats,\n getPrivacySnapshot,\n listSearchUpdates,\n listSites,\n resetSeoData,\n SeoError,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { booleanArg, jsonFlag, numberArg, stringArg } from '../args.js'\nimport {\n canPrompt,\n formatBytes,\n maybeExitCancelled,\n printJson,\n printKeyValue,\n printSummaryList,\n printTable,\n} from '../utils.js'\n\nexport const privacyCommand = defineCommand({\n meta: {\n name: 'privacy',\n description: 'Show local config, token, cache, and log storage paths',\n },\n run: async () => {\n const snapshot = getPrivacySnapshot()\n const stats = getCacheStats()\n printKeyValue(\n snapshot.map((item) => [\n item.label,\n `${item.path} · ${formatBytes(item.sizeBytes)} · ${item.mode}`,\n ]),\n )\n process.stdout.write('\\n')\n printKeyValue(\n Object.entries(stats.counts).map(([key, value]) => [key, String(value)]),\n )\n },\n})\n\nexport const resetCommand = defineCommand({\n meta: {\n name: 'reset',\n description: 'Delete saved credentials and all local data',\n },\n args: {\n yes: {\n type: 'boolean',\n default: false,\n description: 'Confirm deletion without prompting.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n if (!args.yes && !canPrompt({ json })) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Cannot prompt here. Pass --yes to confirm reset.',\n )\n }\n const approved = args.yes\n ? true\n : maybeExitCancelled(\n await confirm({\n message: 'Delete saved credentials and all local data?',\n initialValue: false,\n }),\n )\n if (!approved) {\n cancel('Reset aborted.')\n return\n }\n await resetSeoData()\n if (json) {\n printJson({ reset: true })\n } else {\n process.stdout.write('Reset complete.\\n')\n }\n },\n})\n\nexport const sitesCommand = defineCommand({\n meta: {\n name: 'sites',\n description:\n 'List Search Console properties available to this Google login',\n },\n args: {\n json: { type: 'boolean', default: false },\n refresh: { type: 'boolean', default: false },\n account: {\n type: 'string',\n description: 'Saved Google account email.',\n },\n },\n run: async ({ args }) => {\n const sites = await listSites(\n booleanArg(args.refresh),\n stringArg(args.account),\n )\n if (jsonFlag(args)) {\n printJson({ sites })\n return\n }\n printTable(\n ['Property', 'Permission'],\n sites.map((site) => [site.siteUrl, site.permissionLevel ?? 'unknown']),\n )\n },\n})\n\nexport const updatesCommand = defineCommand({\n meta: {\n name: 'updates',\n description: 'List official Google Search Status ranking updates',\n },\n args: {\n product: { type: 'string', default: 'Ranking' },\n limit: { type: 'string', default: '10' },\n json: { type: 'boolean', default: false },\n },\n run: async ({ args }) => {\n const updates = await listSearchUpdates({\n product: stringArg(args.product),\n limit: numberArg(args.limit),\n })\n if (jsonFlag(args)) {\n printJson({ updates })\n return\n }\n printSummaryList(\n updates.map((update) => ({\n title: update.name,\n meta: [\n update.type,\n update.status,\n `${update.start.slice(0, 10)} to ${update.end?.slice(0, 10) ?? 'present'}`,\n ],\n })),\n { empty: 'No matching Google Search updates.' },\n )\n },\n})\n","import {\n getTelemetryStatus,\n setTelemetryEnabled,\n type TelemetryDisableReason,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport { jsonFlag } from '../args.js'\nimport { printJson, printKeyValue } from '../utils.js'\n\nconst reasonLabels: Record<TelemetryDisableReason, string> = {\n ci: 'disabled automatically in CI or tests',\n do_not_track: 'disabled by DO_NOT_TRACK',\n environment: 'disabled by a telemetry environment variable',\n local_setting: 'disabled in local settings',\n invalid_state: 'disabled because the local state file is invalid',\n}\n\nfunction statusOutput(status: ReturnType<typeof getTelemetryStatus>) {\n return {\n enabled: status.enabled,\n ...(status.reason ? { reason: status.reason } : {}),\n stateFile: status.stateFile,\n ...(status.state\n ? {\n firstRunAt: status.state.firstRunAt,\n cohort: status.state.cohort,\n sentMilestones: status.state.sentMilestones,\n }\n : {}),\n }\n}\n\nfunction printStatus(\n status: ReturnType<typeof getTelemetryStatus>,\n json: boolean,\n): void {\n const output = statusOutput(status)\n if (json) {\n printJson(output)\n return\n }\n printKeyValue([\n ['Anonymous telemetry', status.enabled ? 'enabled' : 'disabled'],\n ['Reason', status.reason ? reasonLabels[status.reason] : 'local setting'],\n ['State file', status.stateFile],\n ['Install cohort', status.state?.cohort ?? 'not created'],\n ])\n process.stdout.write(\n '\\nOnly tool usage is sent. URLs, report data, Google data, and identifiers are never sent.\\n',\n )\n process.stdout.write('Details: https://seoskill.dev/telemetry\\n')\n}\n\nconst jsonArg = {\n type: 'boolean' as const,\n default: false,\n description: 'Print machine-readable JSON.',\n}\n\nexport const telemetryCommand = defineCommand({\n meta: {\n name: 'telemetry',\n description: 'Check or change anonymous usage telemetry',\n },\n subCommands: {\n status: defineCommand({\n meta: {\n name: 'status',\n description: 'Show whether anonymous usage telemetry is enabled',\n },\n args: { json: jsonArg },\n run: async ({ args }) =>\n printStatus(getTelemetryStatus(), jsonFlag(args)),\n }),\n enable: defineCommand({\n meta: {\n name: 'enable',\n description: 'Enable anonymous usage telemetry in local settings',\n },\n args: { json: jsonArg },\n run: async ({ args }) => {\n printStatus(setTelemetryEnabled(true), jsonFlag(args))\n },\n }),\n disable: defineCommand({\n meta: {\n name: 'disable',\n description: 'Disable anonymous usage telemetry in local settings',\n },\n args: { json: jsonArg },\n run: async ({ args }) => {\n printStatus(setTelemetryEnabled(false), jsonFlag(args))\n },\n }),\n },\n})\n","import { readFile } from 'node:fs/promises'\nimport {\n analyticsConnection,\n crawlImplementationQueueWorkflow,\n} from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n csvArg,\n fetchRateArg,\n jsonFlag,\n negatedBooleanArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from '../analytics/connection.js'\nimport { printActionDetails } from '../output.js'\nimport { startUrlForSite } from '../shared.js'\nimport { printWorkflow } from './output.js'\n\nexport const crawlQueueCommand = defineCommand({\n meta: {\n name: 'crawl-queue',\n description: 'Run a crawl and return a ranked implementation queue',\n },\n args: {\n crawlUrl: {\n type: 'positional',\n required: false,\n description: 'Start URL to crawl.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Optional when --project has a saved crawl URL.',\n },\n site: {\n type: 'string',\n description: 'GSC property URL for joining page metrics.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...analyticsConnectionArgs,\n mode: {\n type: 'string',\n description:\n 'Crawl mode: site, page, list, or sitemap. Defaults to site.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs for list mode.',\n },\n 'urls-file': {\n type: 'string',\n description: 'File with one URL per line for list mode.',\n },\n 'max-pages': {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 500.',\n },\n 'max-depth': {\n type: 'string',\n description: 'Maximum click depth. Defaults to 16.',\n },\n concurrency: {\n type: 'string',\n description: 'Parallel page fetches. Defaults to 8.',\n },\n 'fetch-interval-cap': {\n type: 'string',\n description: 'Maximum page fetches per interval per host.',\n },\n 'fetch-interval-ms': {\n type: 'string',\n description: 'Fetch rate interval in milliseconds.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP cache and fetch fresh pages.',\n },\n include: {\n type: 'string',\n description: 'Comma-separated URL patterns to include.',\n },\n exclude: {\n type: 'string',\n description: 'Comma-separated URL patterns to exclude.',\n },\n limit: {\n type: 'string',\n description: 'Maximum queue items to print. Defaults to 25.',\n },\n 'no-sitemap': {\n type: 'boolean',\n default: false,\n description: 'Do not seed URLs from sitemap.xml.',\n },\n 'no-robots': {\n type: 'boolean',\n default: false,\n description: 'Do not skip URLs disallowed by robots.txt.',\n },\n 'no-external': {\n type: 'boolean',\n default: false,\n description: 'Do not check external links.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const project = projectArg(args)\n const urls = await urlListArgs(args)\n const explicitUrl = crawlUrlArg(args)\n const selection =\n stringArg(args.site) || project || (!explicitUrl && !urls.length)\n ? await resolveClientSelection({\n client: project,\n site: stringArg(args.site),\n options: { json },\n })\n : undefined\n const crawlUrl =\n explicitUrl ??\n selection?.client?.startUrl ??\n (selection?.site ? startUrlForSite(selection.site) : undefined) ??\n urls[0]\n if (!crawlUrl) {\n throw new Error(\n 'No crawl URL selected. Pass a URL, --url, or use --project with a saved crawl URL.',\n )\n }\n\n const report = await crawlImplementationQueueWorkflow({\n url: crawlUrl,\n projectId: selection?.client?.id,\n site: selection?.site,\n mode: crawlModeArg(args.mode) ?? (urls.length ? 'list' : undefined),\n urls,\n maxPages: numberArg(args['max-pages']),\n maxDepth: numberArg(args['max-depth']),\n concurrency: numberArg(args.concurrency),\n refresh: booleanArg(args.refresh),\n fetchRate: fetchRateArg({\n ...args,\n 'fetch-concurrency': args.concurrency,\n }),\n include: csvArg(args.include),\n exclude: csvArg(args.exclude),\n googleAnalyticsPropertyId: stringArg(args['google-analytics-property']),\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection?.client),\n ),\n useSitemap: !negatedBooleanArg(args, 'sitemap'),\n respectRobots: !negatedBooleanArg(args, 'robots'),\n checkExternal: !negatedBooleanArg(args, 'external'),\n js: Boolean(booleanArg(args.js)),\n limit: numberArg(args.limit),\n })\n\n if (json) {\n printJson(report)\n return\n }\n\n printWorkflow(report)\n printTable(\n ['Rank', 'Score', 'Rule', 'Severity', 'Affected', 'Target', 'Action'],\n report.output.queue.map((item, index) => [\n index + 1,\n item.score,\n item.ruleId,\n item.severity,\n item.affectedUrls,\n item.target,\n item.action,\n ]),\n )\n printActionDetails(\n 'Implementation queue details',\n report.output.queue.map((item) => ({\n label: `${item.ruleId} (${item.affectedUrls} URLs)`,\n context: `${item.severity}, score ${item.score}`,\n action: `${item.action} Verify with: ${item.verification.command}`,\n })),\n )\n },\n})\n\nfunction crawlModeArg(value: unknown) {\n const mode = stringArg(value)\n if (!mode) return undefined\n if (['site', 'page', 'list', 'sitemap'].includes(mode)) {\n return mode as 'site' | 'page' | 'list' | 'sitemap'\n }\n throw new Error('Mode must be one of: site, page, list, sitemap.')\n}\n\nfunction crawlUrlArg(args: Record<string, unknown>): string | undefined {\n const positional = stringArg(args.crawlUrl)\n const flag = stringArg(args.url)\n if (positional && flag && positional !== flag) {\n throw new Error('Use either a URL argument or --url, not both.')\n }\n return positional ?? flag\n}\n\nasync function urlListArgs(args: Record<string, unknown>): Promise<string[]> {\n const urls = csvArg(args.urls) ?? []\n const file = stringArg(args['urls-file'])\n if (file) urls.push(...parseUrlList(await readFile(file, 'utf8')))\n return [...new Set(urls)]\n}\n\nfunction parseUrlList(value: string): string[] {\n return value\n .split(/[\\n,]/)\n .map((item) => item.trim())\n .filter((item) => item && !item.startsWith('#'))\n}\n","import { mkdir, writeFile } from 'node:fs/promises'\nimport { dirname, resolve } from 'node:path'\nimport {\n type ReportHtmlSection,\n type ReportHtmlView,\n type ReportNarrative,\n renderReportHtml,\n SeoError,\n} from '@seo/core'\nimport { booleanArg, stringArg } from '../args.js'\n\nexport const reportHtmlArgs = {\n format: {\n type: 'string',\n description: 'Output format: terminal or html. Defaults to terminal.',\n },\n output: {\n type: 'string',\n description: 'HTML output file. A dated filename is used by default.',\n },\n view: {\n type: 'string',\n description: 'HTML detail level: client or analyst. Defaults to client.',\n },\n} as const\n\nexport type ReportHtmlOptions = {\n output?: string\n view: ReportHtmlView\n}\n\nexport function reportHtmlOptions(\n args: Record<string, unknown>,\n): ReportHtmlOptions | undefined {\n const format = stringArg(args.format) ?? 'terminal'\n if (format !== 'terminal' && format !== 'html') {\n throw new SeoError('INVALID_INPUT', 'Choose terminal or html for --format.')\n }\n if (format === 'terminal') {\n if (stringArg(args.output) || stringArg(args.view)) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --output and --view with --format html.',\n )\n }\n return undefined\n }\n if (booleanArg(args.json)) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use either --json or --format html, not both.',\n )\n }\n\n const view = stringArg(args.view) ?? 'client'\n if (view !== 'client' && view !== 'analyst') {\n throw new SeoError('INVALID_INPUT', 'Choose client or analyst for --view.')\n }\n return { output: stringArg(args.output), view }\n}\n\nfunction slug(value: string): string {\n return value\n .toLowerCase()\n .replace(/^sc-domain:/, '')\n .replace(/^https?:\\/\\//, '')\n .replace(/[^a-z0-9._-]+/g, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80)\n}\n\nexport function defaultReportHtmlPath(input: {\n reportName: string\n projectId?: string\n site: string\n date?: Date\n}): string {\n const day = (input.date ?? new Date()).toISOString().slice(0, 10)\n const identity = slug(input.projectId ?? input.site) || 'site'\n return resolve(\n process.cwd(),\n `${identity}-${slug(input.reportName)}-${day}.html`,\n )\n}\n\nexport async function writeReportHtml(input: {\n report: ReportNarrative\n reportName: string\n title: string\n options: ReportHtmlOptions\n projectId?: string\n additionalSections?: ReportHtmlSection[]\n}): Promise<string> {\n const path = resolve(\n input.options.output ??\n defaultReportHtmlPath({\n reportName: input.reportName,\n projectId: input.projectId,\n site: input.report.site,\n }),\n )\n await mkdir(dirname(path), { recursive: true })\n await writeFile(\n path,\n renderReportHtml({\n report: input.report,\n title: input.title,\n view: input.options.view,\n additionalSections: input.additionalSections,\n }),\n 'utf8',\n )\n return path\n}\n\nexport function printReportHtmlPath(path: string): void {\n process.stdout.write(`Wrote HTML report to ${path}\\n`)\n}\n","import { type diagnosePropertyWorkflow, SeoError } from '@seo/core'\n\nexport type DiagnoseWorkflowReport = Awaited<\n ReturnType<typeof diagnosePropertyWorkflow>\n>\n\nexport function compactMainReportJson(\n report: DiagnoseWorkflowReport,\n workflowName?: string,\n) {\n const { narrative } = report.output\n const { diagnosis } = narrative\n\n return {\n ...report,\n ...(workflowName ? { workflow: workflowName } : {}),\n output: {\n narrative: {\n site: narrative.site,\n generatedAt: narrative.generatedAt,\n dataStatus: narrative.dataStatus,\n periodDays: narrative.periodDays,\n period: narrative.period,\n headline: narrative.headline,\n caveats: narrative.caveats,\n sections: narrative.sections,\n priorities: narrative.priorities,\n diagnosis: {\n site: diagnosis.site,\n generatedAt: diagnosis.generatedAt,\n dataStatus: diagnosis.dataStatus,\n summary: diagnosis.summary,\n skippedSections: diagnosis.skippedSections,\n partialReasons: diagnosis.partialReasons,\n priorities: diagnosis.priorities,\n },\n },\n },\n }\n}\n\nexport function shellArg(value: string): string {\n if (/^[A-Za-z0-9_./:@-]+$/.test(value)) {\n return value\n }\n return `'${value.replaceAll(\"'\", \"'\\\\''\")}'`\n}\n\nexport function siteForDirectUrl(url: string): string {\n try {\n return new URL(url).origin\n } catch {\n throw new SeoError('INVALID_INPUT', 'Pass a valid absolute URL with --url.')\n }\n}\n","import type {\n SearchConsoleExportEvidence,\n SearchConsoleExportReconciliation,\n} from '@seo/core'\nimport { printTable } from '../../utils.js'\nimport { truncate } from '../output.js'\nimport type { ExportPageInventory } from './url-report-evidence.js'\n\nexport function searchConsoleExportSection(input: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n pageInventory?: ExportPageInventory\n topRows?: number\n}) {\n const topRows = input.topRows ?? 20\n const { evidence } = input\n return {\n source: evidence.source,\n exportedAt: evidence.exportedAt,\n importedAt: evidence.importedAt,\n files: evidence.files,\n queries: {\n totalRows: evidence.queries.totalRows,\n capped: evidence.queries.capped,\n topRowsShown: Math.min(topRows, evidence.queries.rows.length),\n rows: evidence.queries.rows.slice(0, topRows),\n },\n pages: {\n totalRows: evidence.pages.totalRows,\n capped: evidence.pages.capped,\n topRowsShown: Math.min(topRows, evidence.pages.rows.length),\n rows: evidence.pages.rows.slice(0, topRows),\n },\n ...(input.reconciliation ? { reconciliation: input.reconciliation } : {}),\n ...(input.pageInventory ? { pageInventory: input.pageInventory } : {}),\n warnings: evidence.warnings,\n caveats: evidence.caveats,\n }\n}\n\n/** Terminal table for the export page inventory, capped at 15 printed rows. */\nexport function printExportPageInventory(inventory: ExportPageInventory): void {\n if (!inventory.rows.length) return\n const shown = inventory.rows.slice(0, 15)\n process.stdout.write(\n `\\nContent inventory${inventory.pageCount > 1 ? ` page ${inventory.page} of ${inventory.pageCount}` : ''} (${inventory.rows.length} exported page${inventory.rows.length === 1 ? '' : 's'} with suggested dispositions)\\n`,\n )\n printTable(\n ['Path', 'Clicks', 'Impressions', 'Position', 'Suggested'],\n shown.map((row) => [\n truncate(row.path, 48),\n row.clicks,\n row.impressions,\n row.position ?? '-',\n row.suggestedDisposition,\n ]),\n )\n if (inventory.rows.length > shown.length) {\n process.stdout.write(\n `Showing ${shown.length} of ${inventory.rows.length} tiered rows.\\n`,\n )\n }\n if (inventory.pageCount > 1) {\n process.stdout.write(\n `Showing inventory page ${inventory.page} of ${inventory.pageCount}; ${inventory.totalPages} retained rows are available.\\n`,\n )\n }\n process.stdout.write(`${inventory.note}\\n`)\n}\n\nexport function exportSummarySentence(input: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n}): string {\n const queries = input.evidence.queries.totalRows\n const pages = input.evidence.pages.totalRows\n const base = `Loaded a local Search Console export (${queries} query row${queries === 1 ? '' : 's'}, ${pages} page row${pages === 1 ? '' : 's'}).`\n if (!input.reconciliation) return base\n const unreached = input.reconciliation.unreachedCount\n if (unreached === 0) {\n return `${base} Every exported page URL was reached by the crawl.`\n }\n return `${base} ${unreached} exported page URL${unreached === 1 ? '' : 's'} with impressions were not reached by this crawl.`\n}\n\nexport function issueCountSummarySentence(summary: {\n highIssues: number\n mediumIssues: number\n lowIssues: number\n crawledUrls: number\n}): string {\n const pages = summary.crawledUrls\n return `Found ${summary.highIssues} high, ${summary.mediumIssues} medium, and ${summary.lowIssues} low technical issues across ${pages} crawled ${pages === 1 ? 'page' : 'pages'}.`\n}\n","import {\n type CrawlReport,\n reviewObservations,\n type SearchConsoleExportPageRow,\n type SearchConsoleExportQueryRow,\n type SearchConsoleExportReconciliation,\n SeoError,\n type TopFix,\n topFixes,\n} from '@seo/core'\n\nexport {\n exportSummarySentence,\n issueCountSummarySentence,\n printExportPageInventory,\n searchConsoleExportSection,\n} from './url-report-output.js'\n\nexport type UrlReportAction = {\n id: string\n kind: 'fix' | 'review'\n title: string\n action: string\n confidence: 'high' | 'medium' | 'low'\n severity?: string\n affectedCount?: number\n sampleUrls?: string[]\n affectedUrlsReport?: {\n id: 'affected-urls'\n params: {\n reportId: string\n ruleId: string\n }\n }\n evidence?: Record<string, unknown>\n review?: {\n question: string\n changeOnlyIf: string\n ifConfirmed?: string\n ifNotNeeded: string\n doNot?: string[]\n }\n verification?: {\n command?: string\n expected: string\n }\n}\n\nexport type TopicOverlapCandidate = {\n query: string\n impressions: number\n clicks: number\n pages: Array<{ url: string; title: string }>\n}\n\nexport type TopicOverlapResult = {\n candidates: TopicOverlapCandidate[]\n eligibleQueries: number\n consideredQueries: number\n queryLimitReached: boolean\n candidateLimitReached: boolean\n capped: boolean\n}\n\nexport function completeTopFixes(report: CrawlReport) {\n return topFixes(report, { limit: report.issues.length })\n}\n\nexport function completeReviewObservations(report: CrawlReport) {\n return reviewObservations(report, { limit: report.issues.length })\n}\n\nexport function crawlDataSourceLines(\n dataSources: CrawlReport['dataSources'],\n): string[] {\n if (!dataSources) return []\n\n const sourceLine = (input: {\n label: string\n status: string\n joinedPages: number\n totalPages: number\n window?: { days: number }\n warning?: string\n }): string => {\n const range = input.window ? ` in the last ${input.window.days} days` : ''\n const coverage = `for ${input.joinedPages} of ${input.totalPages} crawled URLs`\n\n if (input.status === 'skipped') return `${input.label}: not connected.`\n if (input.status === 'unavailable') {\n return `${input.label}: unavailable. ${input.warning ?? 'No data was joined.'}`\n }\n if (input.status === 'partial') {\n return `${input.label}: partial data ${coverage}${range}. ${input.warning ?? ''}`.trim()\n }\n if (input.status === 'none') {\n return `${input.label}: no matching crawled URLs${range}.`\n }\n return `${input.label}: joined ${coverage}${range}.`\n }\n\n return [\n sourceLine({\n label: 'Search Console',\n status: dataSources.searchConsole.status,\n joinedPages: Math.max(\n dataSources.searchConsole.joinedMetricPages,\n dataSources.searchConsole.joinedQueryPages,\n ),\n totalPages: dataSources.searchConsole.totalPages,\n window: dataSources.searchConsole.window,\n warning: dataSources.searchConsole.warning,\n }),\n sourceLine({\n label: 'Google Analytics',\n status: dataSources.analytics.status,\n joinedPages: dataSources.analytics.joinedPages,\n totalPages: dataSources.analytics.totalPages,\n window: dataSources.analytics.window,\n warning: dataSources.analytics.warning,\n }),\n ]\n}\n\n// Strict codepoint order (not UTF-16 code-unit order) so tie-breaking is\n// stable regardless of which plane a character lives in.\nfunction codePointCompare(left: string, right: string): number {\n if (left === right) return 0\n const a = [...left]\n const b = [...right]\n const shared = Math.min(a.length, b.length)\n for (let index = 0; index < shared; index += 1) {\n const diff =\n (a[index]?.codePointAt(0) ?? 0) - (b[index]?.codePointAt(0) ?? 0)\n if (diff !== 0) return diff\n }\n return a.length - b.length\n}\n\nfunction normalizeText(value: string): string {\n return value\n .toLowerCase()\n .replace(/[^\\p{L}\\p{N}]+/gu, ' ')\n .trim()\n}\n\n// Distinct-page identity: same origin, path (without a trailing slash), and\n// query string. /guide and /guide/ are one page for overlap counting.\nfunction pageIdentityKey(url: string): string {\n try {\n const parsed = new URL(url)\n const path =\n parsed.pathname.length > 1 && parsed.pathname.endsWith('/')\n ? parsed.pathname.slice(0, -1)\n : parsed.pathname\n return `${parsed.origin}${path}${parsed.search}`\n } catch {\n return url.length > 1 && url.endsWith('/') ? url.slice(0, -1) : url\n }\n}\n\n/**\n * Title evidence for export joins: the main crawl's final URLs plus any\n * bounded unreached-audit fetches from the same run.\n */\nexport function titleEvidencePages(\n crawledPages: Array<{\n url: string\n finalUrl?: string | null\n title?: string | null\n }>,\n auditedPages: Array<{ url: string; title: string | null }> = [],\n): Array<{ url: string; title: string | null | undefined }> {\n return [\n ...crawledPages.map((page) => ({\n url: page.finalUrl || page.url,\n title: page.title,\n })),\n ...auditedPages,\n ]\n}\n\n/** Display path for a page URL, used in action copy and terminal tables. */\nexport function pageDisplayPath(url: string): string {\n try {\n const parsed = new URL(url)\n return `${parsed.pathname}${parsed.search}` || '/'\n } catch {\n return url\n }\n}\n\n// Mirrors the path normalization in @seo/core's reconcileExportPagesWithCrawl\n// (strip one trailing slash except at the root, keep the query string) so the\n// inventory joins agree exactly with the reconciliation's path join basis.\nfunction normalizedJoinPath(value: string): string | null {\n let parsed: URL\n try {\n parsed = new URL(value)\n } catch {\n return null\n }\n const pathname =\n parsed.pathname !== '/' && parsed.pathname.endsWith('/')\n ? parsed.pathname.slice(0, -1)\n : parsed.pathname\n return `${pathname}${parsed.search}`\n}\n\nexport type ExportPageInventoryRow = {\n url: string\n path: string\n clicks: number\n impressions: number\n position: number | null\n reachedByCrawl: boolean | null\n title: string | null\n overlapQuery: string | null\n suggestedDisposition: 'keep' | 'update' | 'review'\n tier: string\n}\n\nexport type ExportPageInventory = {\n rows: ExportPageInventoryRow[]\n totalPages: number\n capped: boolean\n sourceCapped: boolean\n page: number\n pageSize: number\n pageCount: number\n nextPage: number | null\n criteria: string[]\n note: string\n}\n\n// Average positions past this value sit outside the usual two result pages.\n// It is an arbitrary review threshold, not a search engine rule.\nconst WEAK_POSITION_THRESHOLD = 20\n\n// The ordered tier rules; the first matching rule wins. Kept as data so every\n// inventory result carries its own methodology.\nconst EXPORT_PAGE_INVENTORY_CRITERIA: readonly string[] = [\n 'review: shares a search phrase with another page title; confirm query-to-page evidence and intent before consolidating',\n 'keep: has clicks in the export window',\n 'review: has impressions but no crawl path reached it',\n `update: has impressions with a weak average position (average position above ${WEAK_POSITION_THRESHOLD} in the export)`,\n 'review: low observed demand in the export window',\n]\n\nexport const EXPORT_PAGE_INVENTORY_NOTE =\n 'Suggested dispositions are heuristic tiers from the export numbers and crawl reach. Decide each page with the owner.'\n\n/**\n * Per-page inventory of the exported page table with a suggested disposition\n * tier for each page. The tiers are heuristics over the export numbers and\n * crawl reach only; the export is a dated snapshot, missing rows are not\n * zeros, and the owner decides intent page by page.\n */\nexport function exportPageInventory(input: {\n pages: SearchConsoleExportPageRow[]\n reconciliation?: SearchConsoleExportReconciliation\n crawledPages: Array<{ url: string; title: string | null | undefined }>\n overlap?: TopicOverlapResult\n maxRows?: number\n page?: number\n sourceCapped?: boolean\n}): ExportPageInventory {\n const maxRows = input.maxRows ?? 50\n const page = input.page ?? 1\n if (!Number.isSafeInteger(maxRows) || maxRows < 1) {\n throw new SeoError('INVALID_INPUT', 'Inventory page size must be positive.')\n }\n if (!Number.isSafeInteger(page) || page < 1) {\n throw new SeoError('INVALID_INPUT', 'Inventory page must be positive.')\n }\n\n // Without a reconciliation there is no unreached evidence, so the\n // unreached rule cannot fire and no reach claim is made from thin air.\n const unreachedPaths = new Set<string>()\n for (const row of input.reconciliation?.unreachedPages ?? []) {\n const path = normalizedJoinPath(row.url)\n if (path !== null) unreachedPaths.add(path)\n }\n\n // Titles join by the same path basis as the reconciliation. Codepoint order\n // plus first-title-wins keeps identical input yielding identical output.\n const titlesByPath = new Map<string, string>()\n const sortedCrawled = [...input.crawledPages].sort((left, right) =>\n codePointCompare(left.url, right.url),\n )\n for (const page of sortedCrawled) {\n if (typeof page.title !== 'string') continue\n const path = normalizedJoinPath(page.url)\n if (path === null) continue\n if (!titlesByPath.has(path)) titlesByPath.set(path, page.title)\n }\n\n // Overlap candidates arrive ranked by impressions, clicks, then query, so\n // the first candidate naming a path wins deterministically.\n const overlapQueryByPath = new Map<string, string>()\n for (const candidate of input.overlap?.candidates ?? []) {\n for (const page of candidate.pages) {\n const path = normalizedJoinPath(page.url)\n if (path === null) continue\n if (!overlapQueryByPath.has(path)) {\n overlapQueryByPath.set(path, candidate.query)\n }\n }\n }\n\n const sortedPages = [...input.pages].sort(\n (left, right) =>\n right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n codePointCompare(left.url, right.url),\n )\n const pageCount = Math.ceil(sortedPages.length / maxRows)\n if (pageCount > 0 && page > pageCount) {\n throw new SeoError(\n 'INVALID_INPUT',\n `Inventory page ${page} does not exist; choose a page from 1 to ${pageCount}.`,\n )\n }\n const pageStart = (page - 1) * maxRows\n const rows = sortedPages\n .slice(pageStart, pageStart + maxRows)\n .map((page): ExportPageInventoryRow => {\n const joinPath = normalizedJoinPath(page.url)\n const reachedByCrawl =\n joinPath === null || !input.reconciliation\n ? null\n : unreachedPaths.has(joinPath)\n ? false\n : input.reconciliation.capped\n ? null\n : true\n const title =\n joinPath !== null ? (titlesByPath.get(joinPath) ?? null) : null\n const overlapQuery =\n joinPath !== null ? (overlapQueryByPath.get(joinPath) ?? null) : null\n let suggestedDisposition: ExportPageInventoryRow['suggestedDisposition']\n let tier: string\n if (overlapQuery !== null) {\n suggestedDisposition = 'review'\n tier =\n 'shares a search phrase with another page title and needs query-to-page and intent verification'\n } else if (page.clicks > 0) {\n suggestedDisposition = 'keep'\n tier = 'has clicks in the export window'\n } else if (page.impressions > 0 && reachedByCrawl === false) {\n suggestedDisposition = 'review'\n tier = 'has impressions but no crawl path reached it'\n } else if (\n page.impressions > 0 &&\n page.position !== null &&\n page.position > WEAK_POSITION_THRESHOLD\n ) {\n suggestedDisposition = 'update'\n tier = 'has impressions with a weak average position'\n } else {\n suggestedDisposition = 'review'\n tier = 'low observed demand in the export window'\n }\n return {\n url: page.url,\n path: pageDisplayPath(page.url),\n clicks: page.clicks,\n impressions: page.impressions,\n position: page.position,\n reachedByCrawl,\n title,\n overlapQuery,\n suggestedDisposition,\n tier,\n }\n })\n\n const paged = pageCount > 1\n const notes = [EXPORT_PAGE_INVENTORY_NOTE]\n if (paged) {\n notes.push(\n `This is inventory page ${page} of ${pageCount}. Fetch every page before treating the returned inventory as complete.`,\n )\n }\n if (input.sourceCapped === true) {\n notes.push(\n 'The source import was capped, so rows missing from this inventory are unknown.',\n )\n }\n return {\n rows,\n totalPages: input.pages.length,\n capped: input.sourceCapped === true || paged,\n sourceCapped: input.sourceCapped === true,\n page,\n pageSize: maxRows,\n pageCount,\n nextPage: page < pageCount ? page + 1 : null,\n criteria: [...EXPORT_PAGE_INVENTORY_CRITERIA],\n note: notes.join(' '),\n }\n}\n\n/**\n * Title-based topic-overlap heuristic for local exports. The standard Search\n * Console UI export keeps query and page tables separate, so no query-to-page\n * mapping exists. This function only observes that an exported query phrase\n * appears in the titles of two or more distinct crawled pages. That is a\n * candidate for review, never a cannibalisation verdict.\n */\nexport function topicOverlapCandidates(input: {\n queries: SearchConsoleExportQueryRow[]\n pages: Array<{ url: string; title: string | null | undefined }>\n maxQueries?: number\n maxCandidates?: number\n}): TopicOverlapResult {\n const maxQueries = input.maxQueries ?? 50\n const maxCandidates = input.maxCandidates ?? 10\n\n // Aggregate duplicate query rows deterministically before ranking.\n // Single-word queries are skipped because they over-match titles.\n const totalsByQuery = new Map<\n string,\n { impressions: number; clicks: number }\n >()\n for (const row of input.queries) {\n const query = normalizeText(row.query)\n if (query.split(' ').length < 2) continue\n const totals = totalsByQuery.get(query)\n if (totals) {\n totals.impressions += row.impressions\n totals.clicks += row.clicks\n } else {\n totalsByQuery.set(query, {\n impressions: row.impressions,\n clicks: row.clicks,\n })\n }\n }\n const eligibleQueries = totalsByQuery.size\n const considered = [...totalsByQuery.entries()]\n .map(([query, totals]) => ({ query, ...totals }))\n .sort(\n (left, right) =>\n right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n codePointCompare(left.query, right.query),\n )\n .slice(0, maxQueries)\n\n // One entry per distinct page path; the codepoint-smallest URL represents\n // a path so identical input always yields identical output.\n const pagesByKey = new Map<\n string,\n { url: string; title: string; normalizedTitle: string }\n >()\n const sortedPages = [...input.pages].sort((left, right) =>\n codePointCompare(left.url, right.url),\n )\n for (const page of sortedPages) {\n if (typeof page.title !== 'string') continue\n const normalizedTitle = normalizeText(page.title)\n if (!normalizedTitle) continue\n const key = pageIdentityKey(page.url)\n if (!pagesByKey.has(key)) {\n pagesByKey.set(key, { url: page.url, title: page.title, normalizedTitle })\n }\n }\n const pagePool = [...pagesByKey.values()]\n\n const candidates: TopicOverlapCandidate[] = []\n for (const item of considered) {\n const phrase = ` ${item.query} `\n const matches = pagePool.filter((page) =>\n ` ${page.normalizedTitle} `.includes(phrase),\n )\n if (matches.length < 2) continue\n candidates.push({\n query: item.query,\n impressions: item.impressions,\n clicks: item.clicks,\n pages: matches\n .map((page) => ({ url: page.url, title: page.title }))\n .sort((left, right) => codePointCompare(left.url, right.url)),\n })\n }\n candidates.sort(\n (left, right) =>\n right.impressions - left.impressions ||\n right.clicks - left.clicks ||\n codePointCompare(left.query, right.query),\n )\n const queryLimitReached = eligibleQueries > considered.length\n const candidateLimitReached = candidates.length > maxCandidates\n return {\n candidates: candidates.slice(0, maxCandidates),\n eligibleQueries,\n consideredQueries: considered.length,\n queryLimitReached,\n candidateLimitReached,\n capped: queryLimitReached || candidateLimitReached,\n }\n}\n\nconst SEVERITY_ORDER = { high: 0, medium: 1, low: 2 } as const\n\ntype PrefixedFix = {\n fix: TopFix\n prefix: string\n source: 'crawl' | 'unreached'\n}\n\n// One queue, best first: a medium issue affecting twelve pages outranks a\n// low issue on one page regardless of which crawl pass surfaced it.\nfunction byPriority(left: PrefixedFix, right: PrefixedFix): number {\n const severity =\n SEVERITY_ORDER[left.fix.severity as keyof typeof SEVERITY_ORDER] -\n SEVERITY_ORDER[right.fix.severity as keyof typeof SEVERITY_ORDER]\n if (severity !== 0) return severity\n if (right.fix.count !== left.fix.count)\n return right.fix.count - left.fix.count\n if (right.fix.score !== left.fix.score)\n return right.fix.score - left.fix.score\n return left.fix.ruleId < right.fix.ruleId\n ? -1\n : left.fix.ruleId > right.fix.ruleId\n ? 1\n : 0\n}\n\n/**\n * Turn the complete crawl issue inventory into workflow actions so the main\n * report does not return an empty or incomplete action list while the crawl\n * holds findings. Fixes carry high confidence because the state was observed;\n * review observations stay medium because intent is unconfirmed.\n */\nexport function technicalCrawlActions(input: {\n topFixes: TopFix[]\n reviewObservations: TopFix[]\n crawlReportId?: string\n reconciliation?: SearchConsoleExportReconciliation\n unreachedAudit?: {\n reportId?: string\n topFixes: TopFix[]\n reviewObservations: TopFix[]\n titlePrefix: string\n }\n topicOverlap?: TopicOverlapResult\n pageInventory?: ExportPageInventory\n}): UrlReportAction[] {\n const audit = input.unreachedAudit\n const fixes: PrefixedFix[] = [\n ...input.topFixes.map((fix) => ({\n fix,\n prefix: '',\n source: 'crawl' as const,\n })),\n ...(audit?.topFixes ?? []).map((fix) => ({\n fix,\n prefix: `${audit?.titlePrefix} `,\n source: 'unreached' as const,\n })),\n ].sort(byPriority)\n const reviews: PrefixedFix[] = [\n ...input.reviewObservations.map((fix) => ({\n fix,\n prefix: '',\n source: 'crawl' as const,\n })),\n ...(audit?.reviewObservations ?? []).map((fix) => ({\n fix,\n prefix: `${audit?.titlePrefix} `,\n source: 'unreached' as const,\n })),\n ].sort(byPriority)\n const actions: UrlReportAction[] = []\n for (const { fix, prefix, source } of fixes) {\n const reportId =\n source === 'crawl' ? input.crawlReportId : input.unreachedAudit?.reportId\n actions.push({\n id: `${source}:${fix.ruleId}`,\n kind: 'fix',\n title: `${prefix}${fix.ruleId}: ${fix.title} (${fix.count} URL${fix.count === 1 ? '' : 's'})`,\n action: fix.howToFix,\n confidence: 'high',\n severity: fix.severity,\n affectedCount: fix.count,\n sampleUrls: fix.sampleUrls,\n ...(reportId\n ? {\n affectedUrlsReport: {\n id: 'affected-urls' as const,\n params: { reportId, ruleId: fix.ruleId },\n },\n }\n : {}),\n evidence: {\n ruleId: fix.ruleId,\n source,\n whyThisRanks: fix.whyThisRanks,\n },\n verification: fix.verification,\n })\n }\n // Export-demand findings rank directly after the fix queue: they carry\n // observed impressions, which outrank convention observations that have\n // no demand link.\n const unreached = input.reconciliation\n if (unreached && unreached.unreachedCount > 0) {\n const impressions = unreached.unreachedPages.reduce(\n (sum, row) => sum + row.impressions,\n 0,\n )\n actions.push({\n id: 'export:unreached-pages',\n kind: 'review',\n title: `${unreached.unreachedCount} exported page URL${unreached.unreachedCount === 1 ? '' : 's'} with search impressions were not reached by this crawl`,\n action: `These pages carry ${impressions} combined impressions across the ${unreached.unreachedPages.length} retained export rows, but no crawl path reached them. Add internal links or sitemap entries when they should be reachable. The join used URL paths from a local export; treat it as a discovery lead within this crawl bound, not proof of orphan status.`,\n confidence: 'medium',\n affectedCount: unreached.unreachedCount,\n evidence: {\n retainedRows: unreached.unreachedPages.length,\n impressions,\n },\n review: {\n question:\n 'Should each retained exported page be reachable from the current site?',\n changeOnlyIf:\n 'Add a crawl path only for a page that should remain part of the current site and has no intended exclusion.',\n ifNotNeeded:\n 'Record no change for a page that is intentionally retired, excluded, or awaiting an owner decision.',\n doNot: [\n 'Do not call a page orphaned from this path-only join.',\n 'Do not redirect unrelated pages to one generic destination.',\n ],\n },\n verification: {\n expected:\n 'Every retained exported page is reachable in the rerun or explicitly accounted for as deferred or no-change with owner intent.',\n },\n })\n }\n const overlap = input.topicOverlap\n const top = overlap?.candidates[0]\n if (overlap && top) {\n const count = overlap.candidates.length\n const paths = top.pages.map((page) => pageDisplayPath(page.url))\n actions.push({\n id: 'export:topic-overlap',\n kind: 'review',\n title: `topic overlap candidates: ${count} exported ${count === 1 ? 'query appears' : 'queries appear'} in 2+ page titles`,\n action: `Top candidate: \"${top.query}\" (${top.impressions} impressions, ${top.clicks} clicks) appears in the titles of ${paths.join(' and ')}. This is a title-based heuristic built from the export's separate query and page tables. The export contains no query-to-page mapping, so it cannot show which pages Google served for the query. Verify with the cannibalisation report (seo cannibal) after connecting a Search Console property.`,\n confidence: 'medium',\n affectedCount: count,\n evidence: {\n topQuery: top.query,\n topPages: top.pages,\n impressions: top.impressions,\n clicks: top.clicks,\n },\n review: {\n question:\n 'Does query-to-page evidence confirm that these pages compete for the same search intent?',\n changeOnlyIf:\n 'Consolidate or redirect only after query-to-page evidence and page intent confirm real overlap.',\n ifNotNeeded:\n 'Keep the pages separate and record why their intents differ.',\n doNot: [\n 'Do not merge or redirect pages from a title-match heuristic alone.',\n ],\n },\n verification: {\n expected:\n 'Confirm intent with query-to-page evidence before consolidating or redirecting either page.',\n },\n })\n }\n const inventory = input.pageInventory\n const topRow = inventory?.rows[0]\n if (inventory && topRow) {\n const counts = { keep: 0, update: 0, review: 0 }\n for (const row of inventory.rows) counts[row.suggestedDisposition] += 1\n const scope = [\n ...(inventory.pageCount > 1\n ? [\n `page ${inventory.page} of ${inventory.pageCount}; ${inventory.rows.length} of ${inventory.totalPages} retained rows`,\n ]\n : []),\n ...(inventory.sourceCapped ? ['source import capped'] : []),\n ]\n const scopeText = scope.length ? ` (${scope.join('; ')})` : ''\n actions.push({\n id: 'export:content-inventory',\n kind: 'review',\n title: `content inventory: ${inventory.rows.length} exported page${inventory.rows.length === 1 ? '' : 's'} tiered with suggested dispositions`,\n action: `Suggested tiers: keep ${counts.keep}, update ${counts.update}, review ${counts.review}${scopeText}. Example: ${topRow.path} (${topRow.clicks} clicks, ${topRow.impressions} impressions, position ${topRow.position ?? 'not in the export'}) is tiered ${topRow.suggestedDisposition} because it ${topRow.tier}. ${inventory.note} Work the inventory page by page instead of applying one blanket policy.`,\n confidence: 'medium',\n affectedCount: inventory.rows.length,\n evidence: { dispositions: counts, capped: inventory.capped },\n review: {\n question:\n 'Has every returned inventory row received an evidence-backed disposition?',\n changeOnlyIf:\n 'Apply a content change, removal, or redirect only after deciding that row from its own evidence and product relevance.',\n ifConfirmed:\n 'Record one disposition and reason for every returned inventory row.',\n ifNotNeeded:\n 'Keep a page unchanged when its evidence and current product role support keeping it.',\n doNot: [\n 'Do not use one blanket disposition for the inventory.',\n 'Do not redirect unrelated URLs to a generic hub.',\n ],\n },\n verification: {\n expected:\n 'Every returned inventory row has an owner-confirmed keep, update, or review decision; every inventory page has been fetched; redirected rows resolve to the intended destination.',\n },\n })\n }\n for (const { fix, prefix, source } of reviews) {\n const reportId =\n source === 'crawl' ? input.crawlReportId : input.unreachedAudit?.reportId\n actions.push({\n id: `${source}:${fix.ruleId}`,\n kind: 'review',\n title: `${prefix}${fix.ruleId}: ${fix.title} (${fix.count} URL${fix.count === 1 ? '' : 's'})`,\n action: `Observed state that needs intent confirmation before treating it as a defect. ${fix.howToFix}`,\n confidence: 'medium',\n severity: fix.severity,\n affectedCount: fix.count,\n sampleUrls: fix.sampleUrls,\n ...(reportId\n ? {\n affectedUrlsReport: {\n id: 'affected-urls' as const,\n params: { reportId, ruleId: fix.ruleId },\n },\n }\n : {}),\n evidence: {\n ruleId: fix.ruleId,\n source,\n whyThisRanks: fix.whyThisRanks,\n },\n verification: fix.verification,\n })\n }\n return actions\n}\n\n/** Map unreached export URLs onto the crawl origin by path, preserving the\n * reconciliation's join basis, so they can be fetched in this environment. */\nexport function unreachedUrlsOnCrawlOrigin(\n reconciliation: SearchConsoleExportReconciliation,\n limit: number,\n): string[] {\n const urls: string[] = []\n for (const row of reconciliation.unreachedPages.slice(0, limit)) {\n try {\n const parsed = new URL(row.url)\n urls.push(\n `${reconciliation.crawlOrigin}${parsed.pathname}${parsed.search}`,\n )\n } catch {\n /* skip unparseable export URLs */\n }\n }\n return urls\n}\n","import {\n agentActionsView,\n analyticsConnection,\n crawlSite,\n diagnosePropertyWorkflow,\n loadSearchConsoleExport,\n type ReportHtmlSection,\n reconcileExportPagesWithCrawl,\n resolveTechnicalBaseline,\n type SearchConsoleExportEvidence,\n type SearchConsoleExportReconciliation,\n SeoError,\n saveCrawlReport,\n type TechnicalBaseline,\n withAgentReportContract,\n} from '@seo/core'\nimport { compactAgentWorkflowOutput } from '@seo/mcp'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n negatedBooleanArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { truncate } from '../output.js'\nimport {\n printReportHtmlPath,\n reportHtmlArgs,\n reportHtmlOptions,\n writeReportHtml,\n} from '../report-html.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { startUrlForSite } from '../shared.js'\nimport {\n compactMainReportJson,\n type DiagnoseWorkflowReport,\n shellArg,\n siteForDirectUrl,\n} from './main-report-json.js'\nimport { printWorkflow } from './output.js'\nimport {\n completeReviewObservations,\n completeTopFixes,\n crawlDataSourceLines,\n type ExportPageInventory,\n exportPageInventory,\n exportSummarySentence,\n issueCountSummarySentence,\n pageDisplayPath,\n printExportPageInventory,\n searchConsoleExportSection,\n type TopicOverlapResult,\n technicalCrawlActions,\n titleEvidencePages,\n topicOverlapCandidates,\n unreachedUrlsOnCrawlOrigin,\n} from './url-report-evidence.js'\n\n// Bound for the in-run audit of exported page URLs the crawl never reached.\n// Keeps the extra fetch work proportional to one crawl worker window.\nconst UNREACHED_AUDIT_LIMIT = 20\n\nfunction addFollowup(\n commands: Array<{ command: string; why: string }>,\n command: string,\n why: string,\n): void {\n if (commands.some((item) => item.command === command)) {\n return\n }\n commands.push({ command, why })\n}\n\nfunction technicalSection(baseline: TechnicalBaseline) {\n const report = baseline.report\n if (!report) {\n return {\n status: baseline.status,\n ...(baseline.reason ? { reason: baseline.reason } : {}),\n }\n }\n return {\n status: baseline.status,\n ...(baseline.reason ? { reason: baseline.reason } : {}),\n reportId: report.id,\n generatedAt: report.generatedAt,\n crawlStatus: report.status,\n capped: report.summary.pageLimitReached,\n maxPages: report.config.maxPages,\n searchDataJoined:\n (report.dataSources?.searchConsole.joinedMetricPages ?? 0) > 0 ||\n (report.dataSources?.searchConsole.joinedQueryPages ?? 0) > 0,\n dataSources: report.dataSources,\n summary: report.summary,\n topFixes: completeTopFixes(report),\n reviewObservations: completeReviewObservations(report),\n issueGroupsComplete: true,\n }\n}\n\nfunction compactTechnicalFinding(\n finding: ReturnType<typeof completeTopFixes>[number],\n) {\n return {\n ruleId: finding.ruleId,\n title: finding.title,\n category: finding.category,\n severity: finding.severity,\n recommendation: finding.recommendation,\n count: finding.count,\n sampleUrls: finding.sampleUrls.slice(0, 3),\n score: finding.score,\n scoreFactors: finding.scoreFactors,\n whyThisRanks: finding.whyThisRanks,\n detailsCommand: `seo explain --rule ${finding.ruleId}`,\n }\n}\n\nfunction compactTechnicalSection(section: ReturnType<typeof technicalSection>) {\n if (!('topFixes' in section)) return section\n\n // Compact trims per-finding fields, never the group list: dropping groups\n // made real findings invisible to agents reading the compact report.\n return {\n ...section,\n topFixes: section.topFixes.map(compactTechnicalFinding),\n reviewObservations: section.reviewObservations.map(compactTechnicalFinding),\n }\n}\n\nexport function reportActionsWithTechnicalEvidence<T, U>(\n reportActions: readonly T[],\n technicalActions?: readonly U[],\n): Array<T | U> {\n return technicalActions\n ? [...reportActions, ...technicalActions]\n : [...reportActions]\n}\n\nfunction printTechnicalSection(\n section: ReturnType<typeof technicalSection>,\n options: { providerFree?: boolean } = {},\n): void {\n if (!('topFixes' in section)) {\n process.stdout.write(\n `\\nTechnical crawl evidence: ${section.reason ?? section.status}\\n`,\n )\n return\n }\n\n const coverage = section.status === 'reused' ? 'saved' : 'new'\n process.stdout.write(`\\nTechnical crawl evidence (${coverage})\\n`)\n if (section.reason) process.stdout.write(`${section.reason}\\n`)\n if (section.capped) {\n process.stdout.write(\n `Coverage is capped at ${section.maxPages} pages. Run \\`seo crawl\\` for a broader investigation.\\n`,\n )\n }\n if (!options.providerFree) {\n for (const line of crawlDataSourceLines(section.dataSources)) {\n process.stdout.write(`${line}\\n`)\n }\n }\n if (!section.topFixes.length) {\n process.stdout.write('No prioritised technical fixes were found.\\n')\n if (section.reviewObservations.length) {\n process.stdout.write(\n `${section.reviewObservations.length} review observation${section.reviewObservations.length === 1 ? '' : 's'} need confirmation before they become implementation work.\\n`,\n )\n }\n return\n }\n process.stdout.write(\n options.providerFree\n ? '\\nPrioritised technical fixes\\n'\n : section.searchDataJoined\n ? '\\nTechnical fixes with search value\\n'\n : '\\nTechnical fixes (no Search Console data joined)\\n',\n )\n if (!section.searchDataJoined) {\n printTable(\n ['#', 'Rule', 'Severity', 'Affected URLs', 'Verify'],\n section.topFixes.map((fix, index) => [\n index + 1,\n fix.ruleId,\n fix.severity,\n fix.count,\n truncate(fix.howToVerify, 72),\n ]),\n )\n } else {\n printTable(\n ['Score', 'Rule', 'Severity', 'Search value', 'Verify'],\n section.topFixes.map((fix) => [\n fix.score,\n fix.ruleId,\n fix.severity,\n `${fix.scoreFactors.clicks} clicks / ${fix.scoreFactors.sessions} visits${fix.scoreFactors.conversions === undefined ? '' : ` / ${fix.scoreFactors.conversions} conv.`}`,\n truncate(fix.howToVerify, 72),\n ]),\n )\n }\n if (section.reviewObservations.length) {\n if (options.providerFree) {\n process.stdout.write(\n '\\nReview observations (confirm intent before treating as defects)\\n',\n )\n printTable(\n ['Rule', 'Severity', 'Affected URLs', 'Sample'],\n section.reviewObservations.map((observation) => [\n observation.ruleId,\n observation.severity,\n observation.count,\n truncate(observation.sampleUrls[0] ?? '', 60),\n ]),\n )\n } else {\n process.stdout.write(\n `\\n${section.reviewObservations.length} review observation${section.reviewObservations.length === 1 ? '' : 's'} were kept out of this action queue.\\n`,\n )\n }\n }\n}\n\nfunction printSearchConsoleExportSection(input: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n unreachedAudit?: {\n auditedUrls: number\n totalUnreached: number\n topFixes: ReturnType<typeof completeTopFixes>\n reviewObservations: ReturnType<typeof completeTopFixes>\n }\n topicOverlap?: TopicOverlapResult\n pageInventory?: ExportPageInventory\n}): void {\n process.stdout.write('\\nSearch Console export (local file evidence)\\n')\n process.stdout.write(`${exportSummarySentence(input)}\\n`)\n for (const warning of input.evidence.warnings) {\n process.stdout.write(`Warning: ${warning}\\n`)\n }\n const unreached = input.reconciliation?.unreachedPages ?? []\n if (unreached.length) {\n process.stdout.write(\n '\\nExported page URLs not reached by this crawl (by impressions)\\n',\n )\n printTable(\n ['URL', 'Clicks', 'Impressions', 'Position'],\n unreached\n .slice(0, 10)\n .map((row) => [\n truncate(row.url, 64),\n row.clicks,\n row.impressions,\n row.position ?? '-',\n ]),\n )\n }\n if (input.unreachedAudit) {\n const audit = input.unreachedAudit\n process.stdout.write(\n `\\nAudited ${audit.auditedUrls} of the ${audit.totalUnreached} unreached URLs in this run\\n`,\n )\n const groups = [...audit.topFixes, ...audit.reviewObservations]\n if (groups.length) {\n printTable(\n ['Rule', 'Severity', 'Affected URLs', 'Sample'],\n groups.map((group) => [\n group.ruleId,\n group.severity,\n group.count,\n truncate(group.sampleUrls[0] ?? '', 60),\n ]),\n )\n }\n }\n if (input.topicOverlap?.candidates.length) {\n process.stdout.write(\n '\\nTopic overlap candidates (title-based heuristic; the export has no query-to-page mapping)\\n',\n )\n printTable(\n ['Query', 'Impressions', 'Pages'],\n input.topicOverlap.candidates.map((candidate) => [\n truncate(candidate.query, 40),\n candidate.impressions,\n truncate(\n candidate.pages.map((page) => pageDisplayPath(page.url)).join(', '),\n 64,\n ),\n ]),\n )\n }\n if (input.pageInventory) printExportPageInventory(input.pageInventory)\n for (const caveat of input.evidence.caveats) {\n process.stdout.write(`Note: ${caveat}\\n`)\n }\n}\n\nfunction printSkippedProviderSections(\n section: ReturnType<typeof technicalSection>,\n): void {\n process.stdout.write('\\nProvider-backed sections skipped\\n')\n const observedLines =\n 'dataSources' in section ? crawlDataSourceLines(section.dataSources) : []\n const lines = observedLines.length\n ? observedLines\n : ['Search Console: not connected.', 'Google Analytics: not connected.']\n for (const line of lines) {\n process.stdout.write(`${line}\\n`)\n }\n process.stdout.write(\n 'Run `seo start` when you want traffic, query, ranking, and analytics evidence added to the report.\\n',\n )\n}\n\nfunction mainReportHtmlSections(input: {\n technicalCrawl?: ReturnType<typeof technicalSection>\n followups?: Array<{ command: string; why: string }>\n}): ReportHtmlSection[] {\n const sections: ReportHtmlSection[] = []\n const technical = input.technicalCrawl\n if (technical) {\n if ('topFixes' in technical) {\n sections.push({\n title: 'Technical crawl evidence',\n summary: `${technical.summary.crawledUrls} pages were included in the ${technical.status === 'reused' ? 'saved' : 'new'} crawl evidence.`,\n items: [\n ...technical.topFixes.map(\n (fix) =>\n `${fix.ruleId}: ${fix.title}. ${fix.count} affected URLs. ${fix.recommendation}`,\n ),\n ...crawlDataSourceLines(technical.dataSources),\n ],\n })\n } else {\n sections.push({\n title: 'Technical crawl evidence',\n summary:\n technical.reason ?? `Technical evidence was ${technical.status}.`,\n items: [],\n })\n }\n }\n if (input.followups?.length) {\n sections.push({\n title: 'Recommended next commands',\n items: input.followups.map((item) => `${item.command}: ${item.why}`),\n })\n }\n return sections\n}\n\nfunction technicalFirstSummary(\n section: ReturnType<typeof technicalSection>,\n exportEvidence?: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n },\n unreachedAudit?: { auditedUrls: number; totalUnreached: number },\n): string {\n if (!('topFixes' in section)) {\n return `Technical crawl evidence was ${section.status}. Search Console and Google Analytics sections were skipped because they are not connected.`\n }\n\n const parts = [issueCountSummarySentence(section.summary)]\n if (exportEvidence) parts.push(exportSummarySentence(exportEvidence))\n if (unreachedAudit) {\n parts.push(\n `Audited ${unreachedAudit.auditedUrls} of the ${unreachedAudit.totalUnreached} unreached URLs in this run; their findings are in the action list.`,\n )\n }\n parts.push(\n 'Search Console and Google Analytics are not connected; provider-backed sections were skipped.',\n )\n return parts.join(' ')\n}\n\nfunction technicalWorkflowStep(section: ReturnType<typeof technicalSection>): {\n tool: string\n status: 'completed' | 'skipped'\n summary: string\n} {\n if (!('topFixes' in section)) {\n return {\n tool: 'seo_crawl',\n status: 'skipped',\n summary:\n section.reason ?? `Technical crawl evidence was ${section.status}.`,\n }\n }\n\n const pages = section.summary.crawledUrls\n return {\n tool: 'seo_crawl',\n status: 'completed',\n summary: `${section.status === 'reused' ? 'Loaded' : 'Completed'} technical evidence for ${pages} crawled ${pages === 1 ? 'page' : 'pages'}.`,\n }\n}\n\nfunction exportWorkflowSteps(exportSummaryInput?: {\n evidence: SearchConsoleExportEvidence\n reconciliation?: SearchConsoleExportReconciliation\n}): Array<{ tool: string; status: 'completed'; summary: string }> {\n if (!exportSummaryInput) return []\n return [\n {\n tool: 'seo_search_console_export',\n status: 'completed',\n summary: exportSummarySentence(exportSummaryInput),\n },\n ]\n}\n\n/**\n * Turn unreached export pages into one runnable follow-up. URLs are mapped\n * onto the crawl origin by path (the same join basis as the reconciliation)\n * so the command works in the environment the user pointed --url at.\n */\nfunction unreachedAuditFollowup(\n reconciliation: SearchConsoleExportReconciliation,\n): { command: string; why: string } | undefined {\n if (reconciliation.unreachedCount === 0) return undefined\n const urls: string[] = []\n for (const row of reconciliation.unreachedPages.slice(0, 10)) {\n try {\n const parsed = new URL(row.url)\n urls.push(\n `${reconciliation.crawlOrigin}${parsed.pathname}${parsed.search}`,\n )\n } catch {\n /* skip unparseable export URLs */\n }\n }\n if (!urls.length) return undefined\n const remainder = reconciliation.unreachedCount - urls.length\n return {\n command: `seo reports run audit-urls --params '${JSON.stringify({ urls })}' --json`,\n why: `Fetch page-level evidence for exported URLs this crawl never reached${remainder > 0 ? ` (first ${urls.length} of ${reconciliation.unreachedCount})` : ''}.${reconciliation.originMismatch ? ' URLs were mapped onto the --url origin by path because the export origin differs.' : ''}`,\n }\n}\n\nexport function reportFollowups(\n report: DiagnoseWorkflowReport,\n input: {\n crawlStartUrl?: string\n projectId?: string\n technicalBaselineStatus?: TechnicalBaseline['status']\n searchDataAvailable?: boolean\n } = {},\n) {\n if (input.searchDataAvailable === false) {\n const commands: Array<{ command: string; why: string }> = []\n if (\n input.crawlStartUrl &&\n input.technicalBaselineStatus !== 'created' &&\n input.technicalBaselineStatus !== 'refreshed' &&\n input.technicalBaselineStatus !== 'reused'\n ) {\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} --health`,\n 'Run the fast sitemap response and access gate before fetching page bodies.',\n )\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} --save`,\n 'Create the technical crawl that this report needs before opening a page-level follow-up.',\n )\n } else if (input.crawlStartUrl) {\n addFollowup(\n commands,\n `seo audit-page --url ${shellArg(input.crawlStartUrl)}`,\n 'Inspect one important page in detail after the site-level crawl.',\n )\n }\n addFollowup(\n commands,\n 'seo start',\n 'Connect Search Console when you want traffic, query, and ranking evidence alongside the crawl.',\n )\n return commands\n }\n\n const identity = input.projectId\n ? `--project ${shellArg(input.projectId)}`\n : `--site ${shellArg(report.site)}`\n const diagnosis = report.output.narrative.diagnosis\n const days = diagnosis.decay.rangeDays\n const commands: Array<{ command: string; why: string }> = []\n const skippedNames = new Set(\n (diagnosis.skippedSections ?? []).map((section) => section.section),\n )\n\n addFollowup(\n commands,\n `seo refresh-priorities ${identity} --days ${days} --verify-content --limit 25`,\n 'Turn the report into a ranked action queue with content checks.',\n )\n\n if (diagnosis.decay.summary.eligibleRows > 0) {\n addFollowup(\n commands,\n `seo decaying ${identity} --days ${days} --limit 25`,\n 'Inspect query/page declines observed in both retained-row windows.',\n )\n }\n\n if (diagnosis.cannibalization.items.length > 0) {\n addFollowup(\n commands,\n `seo cannibal ${identity} --days ${days} --limit 25`,\n 'Find queries split across competing URLs.',\n )\n }\n\n if (diagnosis.quickWins.summary.eligibleRows > 0) {\n addFollowup(\n commands,\n `seo quick-wins ${identity} --days ${days} --verify-content --verify-limit 5`,\n 'Review average-position rows below their heuristic CTR target with optional page evidence.',\n )\n }\n\n if (diagnosis.strikingDistance.summary.eligibleRows > 0) {\n addFollowup(\n commands,\n `seo second-page ${identity} --days ${days} --verify-content --verify-limit 5`,\n 'Work pages sitting just outside page-one rankings.',\n )\n }\n\n if (\n skippedNames.has('traffic anomaly') ||\n skippedNames.has('update correlation')\n ) {\n addFollowup(\n commands,\n `seo quick-wins ${identity} --days ${days} --min-impressions 10 --verify-content --verify-limit 5`,\n 'Sparse GSC data: lower thresholds and look for early content wins.',\n )\n addFollowup(\n commands,\n `seo second-page ${identity} --days ${days} --min-impressions 10 --verify-content --verify-limit 5`,\n 'Sparse GSC data: inspect early second-page opportunities.',\n )\n }\n\n const topMovedPage = diagnosis.segments.page.items.find((item) =>\n item.key.startsWith('http'),\n )\n if (topMovedPage) {\n addFollowup(\n commands,\n `seo audit-page --url ${shellArg(topMovedPage.key)}`,\n 'Audit the biggest moved URL for title, metadata, links, and schema.',\n )\n }\n\n if (\n input.crawlStartUrl &&\n input.technicalBaselineStatus !== 'created' &&\n input.technicalBaselineStatus !== 'refreshed' &&\n input.technicalBaselineStatus !== 'reused'\n ) {\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} --health`,\n 'Run the fast sitemap response and access gate before fetching page bodies.',\n )\n addFollowup(\n commands,\n `seo crawl --url ${shellArg(input.crawlStartUrl)} ${identity} --save`,\n 'Create the first technical crawler baseline with plain-English fixes and JSON-ready issue data.',\n )\n }\n\n addFollowup(\n commands,\n `seo technical-watch ${identity} --limit 50`,\n 'Save a crawl/index baseline so future reports can flag technical drift.',\n )\n\n return commands.slice(0, 6)\n}\n\nfunction printReportFollowups(\n commands: Array<{ command: string; why: string }>,\n): void {\n if (!commands.length) {\n return\n }\n process.stdout.write('\\nRecommended next commands\\n')\n printTable(\n ['Command', 'Why'],\n commands.map((item) => [item.command, item.why]),\n )\n}\n\nfunction printTechnicalOnlyIntro(site: string): void {\n process.stdout.write(`# Technical SEO report: ${site}\\n\\n`)\n}\n\nfunction workflowCommandMeta(input: {\n name: string\n description: string\n workflowName?: string\n printFollowups?: boolean\n}) {\n return defineCommand({\n meta: input,\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n ...(input.printFollowups\n ? {\n url: {\n type: 'string' as const,\n description:\n 'Crawl URL for a technical-only report. Search Console analyses are skipped unless you also pass --site or --project.',\n },\n }\n : {}),\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Search performance window in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum rows per section. Defaults to 10.',\n },\n },\n ),\n ...(input.printFollowups\n ? {\n crawl: defaultTrueBooleanArg(\n 'Create or reuse a bounded technical crawl before the report.',\n 'Skip technical crawl evidence for this report.',\n ),\n 'crawl-max-pages': {\n type: 'string' as const,\n description:\n 'Maximum pages for the report crawl. Defaults to 100.',\n },\n 'crawl-max-depth': {\n type: 'string' as const,\n description:\n 'Maximum link depth for the report crawl. Defaults to 4.',\n },\n full: {\n type: 'boolean' as const,\n default: false,\n description:\n 'Include the full report in JSON output. Default JSON is a compact summary for agents.',\n },\n 'actions-only': {\n type: 'boolean' as const,\n default: false,\n description:\n 'Return findings, verification, and the content inventory without the full report body. JSON only.',\n },\n 'search-console-export': {\n type: 'string' as const,\n description:\n 'Path to a local Search Console export (a directory or CSV with the standard query and page tables). URL mode only; query and page tables stay separate.',\n },\n 'inventory-page': {\n type: 'string' as const,\n default: '1',\n description:\n 'Page of local Search Console export inventory rows to return. URL mode only.',\n },\n ...reportHtmlArgs,\n }\n : {}),\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const html = input.printFollowups ? reportHtmlOptions(args) : undefined\n const full = input.printFollowups && booleanArg(args.full)\n const actionsOnly =\n input.printFollowups && booleanArg(args['actions-only'])\n if (actionsOnly && !json) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --actions-only with --json so findings and completion outcomes stay machine-readable.',\n )\n }\n if (actionsOnly && full) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Choose either --actions-only or --full, not both.',\n )\n }\n const project = projectArg(args)\n const explicitSite = stringArg(args.site)\n const directUrl = input.printFollowups ? stringArg(args.url) : undefined\n const useSearchData = Boolean(project || explicitSite || !directUrl)\n const exportPath = input.printFollowups\n ? stringArg(args['search-console-export'])\n : undefined\n const inventoryPage = input.printFollowups\n ? (numberArg(args['inventory-page']) ?? 1)\n : 1\n if (!Number.isSafeInteger(inventoryPage) || inventoryPage < 1) {\n throw new SeoError(\n 'INVALID_INPUT',\n '--inventory-page must be a positive integer.',\n )\n }\n if (inventoryPage !== 1 && !exportPath) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --inventory-page only with --search-console-export.',\n )\n }\n if (exportPath && useSearchData) {\n throw new SeoError(\n 'INVALID_INPUT',\n 'Use --search-console-export only with --url. A connected property already provides query and page evidence, and imported tables must not be blended with it.',\n )\n }\n const selection = useSearchData\n ? await resolveClientSelection({\n client: project,\n site: explicitSite,\n options: { json, refresh: booleanArg(args.refresh) },\n })\n : undefined\n const site = selection?.site ?? siteForDirectUrl(directUrl ?? '')\n const report = await diagnosePropertyWorkflow({\n site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection?.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n refresh: booleanArg(args.refresh),\n skipSearchData: !useSearchData,\n })\n const outputReport = input.workflowName\n ? { ...report, workflow: input.workflowName }\n : report\n const technicalBaseline = input.printFollowups\n ? await resolveTechnicalBaseline({\n site,\n searchSite: selection?.site,\n url:\n directUrl ?? selection?.client?.startUrl ?? startUrlForSite(site),\n projectId: selection?.client?.id,\n googleAnalyticsPropertyId:\n selection?.client?.analytics.google?.propertyId,\n analyticsConnection: analyticsConnection(selection?.client),\n crawl: !negatedBooleanArg(args, 'crawl'),\n refresh: booleanArg(args.refresh),\n maxPages: numberArg(args['crawl-max-pages']),\n maxDepth: numberArg(args['crawl-max-depth']),\n })\n : undefined\n const technicalCrawl = technicalBaseline\n ? technicalSection(technicalBaseline)\n : undefined\n const exportEvidence = exportPath\n ? await loadSearchConsoleExport({ path: exportPath })\n : undefined\n const exportReconciliation =\n exportEvidence && technicalBaseline?.report && directUrl\n ? reconcileExportPagesWithCrawl({\n pages: exportEvidence.pages.rows,\n crawledUrls: technicalBaseline.report.pages.flatMap((page) => [\n page.url,\n page.finalUrl,\n ]),\n crawlOrigin: siteForDirectUrl(directUrl),\n })\n : undefined\n const exportSummaryInput = exportEvidence\n ? { evidence: exportEvidence, reconciliation: exportReconciliation }\n : undefined\n // Exported pages the crawl never reached are still part of the site\n // being audited, so fetch a bounded sample in the same run instead of\n // deferring their page-level evidence to a follow-up command.\n const unreachedAudit = await (async () => {\n if (!exportReconciliation || exportReconciliation.unreachedCount === 0)\n return undefined\n const urls = unreachedUrlsOnCrawlOrigin(\n exportReconciliation,\n UNREACHED_AUDIT_LIMIT,\n )\n if (!urls.length) return undefined\n const auditReport = await crawlSite({\n url: urls[0] ?? '',\n urls,\n mode: 'list',\n maxPages: urls.length,\n useSitemap: false,\n refresh: booleanArg(args.refresh),\n })\n saveCrawlReport(auditReport, undefined, { retention: 'baseline' })\n return {\n reportId: auditReport.id,\n auditedUrls: auditReport.summary.totalPages,\n totalUnreached: exportReconciliation.unreachedCount,\n capped: exportReconciliation.unreachedCount > urls.length,\n issueGroupsComplete: true,\n topFixes: completeTopFixes(auditReport),\n reviewObservations: completeReviewObservations(auditReport),\n // Bounded by the audit's own URL cap. Retained so title-based\n // evidence can include pages the main crawl never reached.\n pages: auditReport.pages.map((page) => ({\n url: page.finalUrl || page.url,\n title: page.title ?? null,\n })),\n }\n })()\n const titlePages = technicalBaseline?.report\n ? titleEvidencePages(\n technicalBaseline.report.pages,\n unreachedAudit?.pages,\n )\n : undefined\n // Title-based topic overlap between exported query phrases and crawled\n // page titles. The export has no query-to-page mapping, so this is a\n // labelled heuristic observation, never a cannibalisation verdict.\n const topicOverlap =\n exportEvidence && titlePages\n ? topicOverlapCandidates({\n queries: exportEvidence.queries.rows,\n pages: titlePages,\n })\n : undefined\n // Per-page suggested disposition tiers so a migration or cleanup can\n // be decided page by page instead of from one blanket recommendation.\n const pageInventory =\n exportEvidence && titlePages\n ? exportPageInventory({\n pages: exportEvidence.pages.rows,\n sourceCapped: exportEvidence.pages.capped,\n page: inventoryPage,\n reconciliation: exportReconciliation,\n crawledPages: titlePages,\n overlap: topicOverlap,\n })\n : undefined\n const technicalActions = technicalBaseline?.report\n ? technicalCrawlActions({\n crawlReportId: technicalBaseline.report.id,\n topFixes: completeTopFixes(technicalBaseline.report),\n reviewObservations: completeReviewObservations(\n technicalBaseline.report,\n ),\n reconciliation: exportReconciliation,\n ...(unreachedAudit\n ? {\n unreachedAudit: {\n reportId: unreachedAudit.reportId,\n topFixes: unreachedAudit.topFixes,\n reviewObservations: unreachedAudit.reviewObservations,\n titlePrefix: 'unreached pages:',\n },\n }\n : {}),\n ...(topicOverlap ? { topicOverlap } : {}),\n ...(pageInventory ? { pageInventory } : {}),\n })\n : undefined\n const followups = input.printFollowups\n ? reportFollowups(outputReport, {\n crawlStartUrl:\n directUrl ?? selection?.client?.startUrl ?? startUrlForSite(site),\n projectId: selection?.client?.id,\n technicalBaselineStatus: technicalBaseline?.status,\n searchDataAvailable: useSearchData,\n })\n : undefined\n if (\n followups &&\n exportReconciliation &&\n (!unreachedAudit || unreachedAudit.capped)\n ) {\n const audit = unreachedAuditFollowup(exportReconciliation)\n if (audit) followups.unshift(audit)\n }\n if (json) {\n const jsonReport =\n input.printFollowups && !full\n ? compactMainReportJson(report, input.workflowName)\n : outputReport\n const completeActions = reportActionsWithTechnicalEvidence(\n jsonReport.actions,\n technicalActions,\n )\n const reportWithTechnicalEvidence =\n !useSearchData && technicalCrawl\n ? {\n ...jsonReport,\n summary: technicalFirstSummary(\n technicalCrawl,\n exportSummaryInput,\n unreachedAudit,\n ),\n steps: [\n technicalWorkflowStep(technicalCrawl),\n ...exportWorkflowSteps(exportSummaryInput),\n ...jsonReport.steps,\n ],\n actions: completeActions,\n // The compact URL-mode report replaces the empty narrative\n // shell (every section unavailable) with an explicit skip\n // marker. --full keeps the whole narrative object.\n ...(full\n ? {}\n : {\n output: {\n searchSections: {\n status: 'skipped',\n reason:\n 'No Search Console property was selected. Pass --site or --project, or run seo start to connect one.',\n },\n },\n }),\n }\n : { ...jsonReport, actions: completeActions }\n const completeReport =\n technicalCrawl || followups\n ? {\n ...reportWithTechnicalEvidence,\n ...(input.printFollowups\n ? { detail: full ? 'full' : 'summary' }\n : {}),\n ...(technicalCrawl\n ? {\n technicalCrawl:\n input.printFollowups && !full\n ? compactTechnicalSection(technicalCrawl)\n : technicalCrawl,\n }\n : {}),\n ...(exportEvidence\n ? {\n searchConsoleExport: {\n ...searchConsoleExportSection({\n evidence: exportEvidence,\n reconciliation: exportReconciliation,\n pageInventory,\n }),\n ...(unreachedAudit\n ? { unreachedPagesAudit: unreachedAudit }\n : {}),\n ...(topicOverlap\n ? { topicOverlapCandidates: topicOverlap }\n : {}),\n },\n }\n : {}),\n ...(followups ? { nextCommands: followups } : {}),\n }\n : jsonReport\n const contractOptions = {\n reportId: 'report',\n preferRootActions: true,\n verify:\n 'Rerun seo report with the same inputs and confirm the finding is absent or its evidence now matches the intended state.',\n ...(!useSearchData &&\n technicalCrawl &&\n 'issueGroupsComplete' in technicalCrawl &&\n technicalCrawl.issueGroupsComplete\n ? { coverage: 'complete' as const }\n : {}),\n }\n printJson(\n compactAgentWorkflowOutput(\n actionsOnly\n ? agentActionsView(completeReport, contractOptions)\n : withAgentReportContract(completeReport, contractOptions),\n ),\n )\n return\n }\n if (html) {\n const path = await writeReportHtml({\n report: outputReport.output.narrative,\n reportName: 'report',\n title: useSearchData ? 'SEO report' : 'Technical SEO report',\n options: html,\n projectId: selection?.client?.id,\n additionalSections: mainReportHtmlSections({\n technicalCrawl,\n followups,\n }),\n })\n printReportHtmlPath(path)\n return\n }\n if (useSearchData) {\n process.stdout.write(`${outputReport.output.narrative.markdown}\\n\\n`)\n printWorkflow(outputReport)\n } else {\n printTechnicalOnlyIntro(site)\n }\n if (technicalCrawl) {\n printTechnicalSection(technicalCrawl, { providerFree: !useSearchData })\n if (exportEvidence) {\n printSearchConsoleExportSection({\n evidence: exportEvidence,\n reconciliation: exportReconciliation,\n unreachedAudit,\n topicOverlap,\n pageInventory,\n })\n }\n if (!useSearchData) printSkippedProviderSections(technicalCrawl)\n }\n if (followups) printReportFollowups(followups)\n },\n })\n}\n\nexport const diagnosePropertyWorkflowCommand = workflowCommandMeta({\n name: 'diagnose-property',\n description: 'Find what changed in Google Search and what to inspect next',\n})\n\nexport const mainReportCommand = workflowCommandMeta({\n name: 'report',\n workflowName: 'report',\n printFollowups: true,\n description:\n 'Run the main SEO report and recommend the next best follow-up commands',\n})\n","import { analyticsConnection, refreshPrioritiesWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport {\n analyticsConnectionArgs,\n analyticsConnectionFromArgs,\n} from '../analytics/connection.js'\nimport { printActionDetails } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\nimport { printWorkflow } from './output.js'\n\nexport const refreshPrioritiesCommand = defineCommand({\n meta: {\n name: 'refresh-priorities',\n description: 'Agent workflow for a ranked SEO action queue',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum queue items to print. Defaults to 25.',\n },\n },\n ),\n ...analyticsConnectionArgs,\n 'verify-content': defaultTrueBooleanArg(\n 'Verify top opportunities against page title, meta, and content. Defaults to true.',\n 'Skip page content verification.',\n ),\n 'verify-limit': {\n type: 'string',\n description: 'Maximum opportunity URLs to verify. Defaults to 5.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await refreshPrioritiesWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n googleAnalyticsPropertyId: stringArg(args['google-analytics-property']),\n analyticsConnection: analyticsConnectionFromArgs(\n args,\n analyticsConnection(selection.client),\n ),\n verifyContent: booleanArg(args['verify-content']),\n verifyLimit: numberArg(args['verify-limit']),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printWorkflow(report)\n printTable(\n [\n 'Source',\n 'Category',\n 'Score',\n 'Findings',\n 'Template',\n 'Analytics',\n 'Target',\n 'Action',\n ],\n report.output.queue.map((item) => [\n item.source,\n item.category,\n item.score,\n item.grouped?.count ?? 1,\n item.template?.label ?? '-',\n item.analytics?.sessions ?? '-',\n item.target,\n item.action,\n ]),\n )\n printActionDetails(\n 'Queue action details',\n report.output.queue.map((item) => ({\n label: item.target,\n context: `${item.category}, score ${item.score}`,\n action: item.action,\n })),\n )\n },\n})\n","import { technicalWatchWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n defaultTrueBooleanArg,\n jsonFlag,\n listArg,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson } from '../../utils.js'\nimport { printMonitoringRun } from '../monitoring/output.js'\nimport { startUrlForSite } from '../shared.js'\n\nexport const technicalWatchCommand = defineCommand({\n meta: {\n name: 'technical-watch',\n description: 'Agent workflow for crawl-diff and index-watch monitoring',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n url: {\n type: 'string',\n description:\n 'Start URL to crawl. Defaults from the GSC property when possible.',\n },\n urls: {\n type: 'string',\n description: 'Comma-separated URLs to inspect with URL Inspection.',\n },\n sitemaps: {\n type: 'string',\n description:\n 'Comma-separated XML sitemap URLs for quota-aware index monitoring.',\n },\n properties: {\n type: 'string',\n description:\n 'Comma-separated GSC properties for sitemap index monitoring.',\n },\n limit: {\n type: 'string',\n description: 'Maximum pages to crawl. Defaults to 50.',\n },\n 'daily-limit': {\n type: 'string',\n description: 'URL Inspection daily limit per property. Defaults to 2000.',\n },\n 'inspect-limit': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to inspect in this run. Defaults to 100.',\n },\n 'max-urls': {\n type: 'string',\n description:\n 'Maximum sitemap URLs to load for monitoring. Defaults to 50000.',\n },\n language: {\n type: 'string',\n description: 'Optional URL Inspection language code.',\n },\n 'recover-links': defaultTrueBooleanArg(\n 'Check search-value GSC pages for broken, blocked, or poorly redirected URLs. Defaults to true.',\n 'Skip link recovery checks.',\n ),\n 'recover-days': {\n type: 'string',\n description: 'GSC lookback window for link recovery. Defaults to 90.',\n },\n 'recover-limit': {\n type: 'string',\n description:\n 'Maximum search-value pages to check for link recovery. Defaults to 10.',\n },\n 'recover-min-clicks': {\n type: 'string',\n description:\n 'Minimum clicks for link recovery candidates. Defaults to 1.',\n },\n 'recover-min-impressions': {\n type: 'string',\n description:\n 'Minimum impressions for link recovery candidates. Defaults to 100.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n refresh: {\n type: 'boolean',\n default: false,\n description: 'Bypass local HTTP/GSC cache where supported.',\n },\n js: {\n type: 'boolean',\n default: false,\n description: 'Force JavaScript rendering when Playwright is installed.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const watchUrls = listArg(args.urls)\n const sitemaps = listArg(args.sitemaps)\n const startUrl =\n stringArg(args.url) ??\n selection.client?.startUrl ??\n startUrlForSite(selection.site)\n const report = await technicalWatchWorkflow({\n site: selection.site,\n startUrl,\n urls: watchUrls.length ? watchUrls : selection.client?.watchUrls,\n sitemaps: sitemaps.length ? sitemaps : undefined,\n properties: listArg(args.properties).length\n ? listArg(args.properties)\n : undefined,\n limit: numberArg(args.limit),\n languageCode: stringArg(args.language),\n dailyLimit: numberArg(args['daily-limit']),\n inspectLimit: numberArg(args['inspect-limit']),\n maxUrls: numberArg(args['max-urls']),\n refresh: booleanArg(args.refresh),\n js: booleanArg(args.js) ? true : 'auto',\n recoverLinks: booleanArg(args['recover-links']),\n recoverDays: numberArg(args['recover-days']),\n recoverLimit: numberArg(args['recover-limit']),\n recoverMinClicks: numberArg(args['recover-min-clicks']),\n recoverMinImpressions: numberArg(args['recover-min-impressions']),\n })\n if (json) {\n printJson(report)\n return\n }\n printMonitoringRun(report)\n },\n})\n","import { updatePostmortemWorkflow } from '@seo/core'\nimport { defineCommand } from 'citty'\nimport {\n booleanArg,\n jsonFlag,\n numberArg,\n projectArg,\n stringArg,\n} from '../../args.js'\nimport { resolveClientSelection } from '../../selection.js'\nimport { printJson, printTable } from '../../utils.js'\nimport { printNextCommand, printNotes, printReportSummary } from '../output.js'\nimport { cliReportArgs } from '../report-options.js'\n\ntype SegmentSplit = Awaited<\n ReturnType<typeof updatePostmortemWorkflow>\n>['output']['segments']['page']\n\nfunction formatNumber(value: number | null): string {\n if (value === null) return '-'\n return value.toLocaleString('en-GB', {\n maximumFractionDigits: value >= 100 ? 0 : 1,\n })\n}\n\nfunction segmentRows(split: SegmentSplit) {\n return [\n ...split.winners.map((item) => ({ direction: 'winner', item })),\n ...split.losers.map((item) => ({ direction: 'loser', item })),\n ]\n}\n\nfunction printSegmentTable(label: string, split: SegmentSplit): void {\n const rows = segmentRows(split)\n if (!rows.length) return\n process.stdout.write(`\\n${label}\\n`)\n printTable(\n ['Direction', 'Key', 'Clicks', 'Impr.', 'Position'],\n rows.map(({ direction, item }) => [\n direction,\n item.key,\n formatNumber(item.clickDelta),\n formatNumber(item.impressionDelta),\n formatNumber(item.positionDelta),\n ]),\n )\n}\n\nfunction printSegmentCoverage(\n segments: Awaited<\n ReturnType<typeof updatePostmortemWorkflow>\n >['output']['segments'],\n): void {\n process.stdout.write('\\nSegment coverage\\n')\n printTable(\n [\n 'Dimension',\n 'Eligible',\n 'Returned',\n 'Limited',\n 'Result cap',\n 'Source cap',\n 'Source capped',\n ],\n (['page', 'query', 'device', 'country'] as const).map((dimension) => {\n const coverage = segments[dimension].coverage\n return [\n dimension,\n coverage.eligibleRows,\n coverage.returnedRows,\n coverage.limitedRows,\n coverage.resultLimit,\n coverage.sourceRowLimit,\n coverage.sourcePossiblyTruncated ? 'yes' : 'no',\n ]\n }),\n )\n}\n\ntype TemplateMovement = Awaited<\n ReturnType<typeof updatePostmortemWorkflow>\n>['output']['templateMovement'][number]\n\nfunction printTemplateMovement(items: TemplateMovement[]): void {\n if (!items.length) return\n process.stdout.write('\\nTemplate movement\\n')\n printTable(\n [\n 'Direction',\n 'Template',\n 'Pattern confidence',\n 'URLs',\n 'Clicks',\n 'Returned share',\n 'Common terms',\n ],\n items.map((item) => [\n item.direction,\n item.signature,\n item.confidence,\n item.urlCount,\n formatNumber(item.clickDelta),\n `${Math.round(item.movementShare * 100)}%`,\n item.commonTerms.join(', ') || '-',\n ]),\n )\n printNotes(\n 'Template actions',\n items.map((item) => item.summary),\n )\n printNotes('Template evidence scope', [\n 'Shares use returned directional page click movement. Pattern confidence applies only to returned matched-retained page segments.',\n ])\n}\n\nexport const updatePostmortemCommand = defineCommand({\n meta: {\n name: 'update-postmortem',\n description: 'Agent workflow for Google update winner/loser analysis',\n },\n args: {\n site: {\n type: 'string',\n description: 'GSC property URL, for example sc-domain:example.com.',\n },\n client: {\n type: 'string',\n description: 'Legacy alias for --project.',\n },\n project: {\n type: 'string',\n description: 'Saved project id or name.',\n },\n ...cliReportArgs(\n ['days', 'recentDays', 'limit', 'includeBrand', 'refresh'],\n {\n days: {\n description: 'Diagnosis window length in days. Defaults to 90.',\n },\n limit: {\n description: 'Maximum winners/losers per segment. Defaults to 20.',\n },\n },\n ),\n 'known-change': {\n type: 'string',\n description:\n 'Manual site-side change to treat as a confounder, for example pruning pages or blocking traffic.',\n },\n 'ignore-change-log': {\n type: 'boolean',\n default: false,\n description: 'Do not use saved change-log entries as confounders.',\n },\n json: {\n type: 'boolean',\n default: false,\n description: 'Print machine-readable JSON.',\n },\n },\n run: async ({ args }) => {\n const json = jsonFlag(args)\n const selection = await resolveClientSelection({\n client: projectArg(args),\n site: stringArg(args.site),\n options: { json, refresh: booleanArg(args.refresh) },\n })\n const report = await updatePostmortemWorkflow({\n site: selection.site,\n days: numberArg(args.days),\n recentDays: numberArg(args.recent),\n limit: numberArg(args.limit),\n brandTerms: selection.client?.brandTerms,\n includeBrand: booleanArg(args['include-brand']),\n knownConfounders: stringArg(args['known-change'])\n ? [stringArg(args['known-change']) ?? '']\n : undefined,\n includeChangeLog: !booleanArg(args['ignore-change-log']),\n refresh: booleanArg(args.refresh),\n })\n if (json) {\n printJson(report)\n return\n }\n printReportSummary({\n title: 'Update postmortem',\n target: report.site,\n status: 'unknown',\n summary: report.summary,\n metrics: [\n {\n label: 'Attribution',\n value: report.output.update.attribution.replaceAll('-', ' '),\n },\n { label: 'Confidence', value: report.output.update.confidence },\n {\n label: 'Known confounders',\n value: report.output.update.confounders.length,\n },\n ],\n })\n printNotes(\n 'Recommended actions',\n report.actions.map(\n (action) => `${action.title} (${action.confidence}): ${action.action}`,\n ),\n )\n printNotes(\n 'Postmortem findings',\n report.output.insights.map((insight) => insight.summary),\n )\n printNotes(\n 'Segment evidence warnings',\n [\n ...report.output.segments.page.warnings,\n ...report.output.segments.query.warnings,\n ...report.output.segments.device.warnings,\n ...report.output.segments.country.warnings,\n ].filter(\n (warning, index, warnings) => warnings.indexOf(warning) === index,\n ),\n )\n printTemplateMovement(report.output.templateMovement)\n printNotes('Update evidence', report.output.update.evidence)\n printSegmentCoverage(report.output.segments)\n printSegmentTable('Page winners and losers', report.output.segments.page)\n printSegmentTable('Query winners and losers', report.output.segments.query)\n printSegmentTable(\n 'Device winners and losers',\n report.output.segments.device,\n )\n printSegmentTable(\n 'Country winners and losers',\n report.output.segments.country,\n )\n const target = selection.client\n ? `--project ${JSON.stringify(selection.client.id)}`\n : `--site ${JSON.stringify(selection.site)}`\n printNextCommand(`seo export update-postmortem ${target}`)\n },\n})\n","import { arch, platform } from 'node:os'\nimport {\n classifyTelemetryFailure,\n isTelemetryOperation,\n isTelemetryReport,\n SEO_VERSION,\n type TelemetryOperation,\n toSeoError,\n} from '@seo/core'\n\nconst BUG_REPORT_URL = 'https://github.com/iannuttall/seo/issues/new'\nconst ACTIONABLE_CATEGORIES = new Set([\n 'database',\n 'filesystem',\n 'internal',\n 'unknown',\n])\n\ntype ErrorFeedbackOptions = {\n args: string[]\n error: unknown\n nodeVersion?: string\n processArch?: string\n processPlatform?: string\n report?: string\n version?: string\n}\n\nfunction nodeMajor(version: string): string {\n return version.replace(/^v/, '').split('.')[0] || 'unknown'\n}\n\nexport function telemetryOperation(\n args: string[],\n): TelemetryOperation | undefined {\n return isTelemetryOperation(args[0]) ? args[0] : undefined\n}\n\nfunction feedbackSubject(\n report: string | undefined,\n operation: TelemetryOperation | undefined,\n): string {\n if (isTelemetryReport(report)) return `seo ${report}`\n if (operation) return `seo ${operation}`\n return 'seo command'\n}\n\nexport function buildErrorFeedbackUrl(\n options: ErrorFeedbackOptions,\n): string | undefined {\n const failure = classifyTelemetryFailure(options.error)\n if (!ACTIONABLE_CATEGORIES.has(failure.errorCategory)) return undefined\n\n const operation = telemetryOperation(options.args)\n const subject = feedbackSubject(options.report, operation)\n const normalized = toSeoError(options.error)\n const diagnostics = [\n normalized.code,\n failure.errorCategory,\n failure.failureReason,\n failure.failureContext,\n ]\n .filter(Boolean)\n .join(' | ')\n const url = new URL(BUG_REPORT_URL)\n url.searchParams.set('template', 'bug.yml')\n url.searchParams.set('title', `bug: ${subject} failed`)\n url.searchParams.set('version', options.version ?? SEO_VERSION)\n url.searchParams.set(\n 'runtime',\n `Node ${nodeMajor(options.nodeVersion ?? process.version)} on ${\n options.processPlatform ?? platform()\n } (${options.processArch ?? arch()})`,\n )\n url.searchParams.set('diagnostics', diagnostics)\n return url.toString()\n}\n","// Version 0.3.0 moved most reports into eight commands. Old names keep\n// working for this one release and say where they went. Removed commands say\n// so and stop. Both lists go in 0.4.0.\n\nexport const RENAMED: Record<string, string> = {\n 'diagnose-property': 'seo report',\n 'refresh-priorities': 'seo report',\n 'query-cluster': 'seo report',\n 'quick-wins': 'seo report --section quick-wins',\n 'ctr-underperformers': 'seo report --section low-ctr',\n 'striking-distance': 'seo report --section striking-distance',\n 'second-page': 'seo report --section second-page',\n decaying: 'seo report --section content-decay',\n cannibal: 'seo report --section cannibalization',\n 'traffic-anomaly': 'seo report --section traffic-drop',\n 'page-opportunities': 'seo page --url <url>',\n 'audit-page': 'seo page --url <url>',\n 'url-inspect': 'seo page --url <url>',\n 'segment-impact': 'seo compare --date <date>',\n 'update-correlate': 'seo compare --date <date>',\n 'update-postmortem': 'seo compare --date <date>',\n 'link-recover': 'seo index',\n 'gsc-query': 'seo data',\n}\n\n// Removed commands, with the command to use instead when there is one. A key\n// with a space is a subcommand, such as `seo export pseo`, and can have up to\n// three words.\nexport const REMOVED: Record<string, string | null> = {\n 'agent-readiness': null,\n 'ai-readiness': null,\n 'community-intent': null,\n 'entity-readiness': null,\n llms: null,\n 'monthly-report': 'seo report',\n okf: null,\n pseo: null,\n 'report-narrative': 'seo report',\n 'seo-to-ai-query': null,\n 'server-logs': null,\n 'client keyword-sets': null,\n links: 'seo research backlinks --target <domain>',\n 'export knowledge': null,\n 'export monthly': 'seo report --json',\n 'export narrative': 'seo report --json',\n 'export pseo': null,\n indexnow: null,\n 'project keyword-sets': null,\n 'projects keyword-sets': null,\n 'providers semrush': 'seo providers',\n 'providers limits': null,\n 'providers spend': null,\n 'providers dataforseo limits': null,\n 'providers dataforseo spend': null,\n 'providers ahrefs limits': null,\n}\n\nconst SPEND_REASON =\n 'Spend is controlled in your provider account. Set limits in DataForSEO, Ahrefs or the other provider.'\n\n// Why a command was removed, when the general reason does not fit.\nconst REMOVED_REASONS: Record<string, string> = {\n 'providers limits': SPEND_REASON,\n 'providers spend': SPEND_REASON,\n 'providers dataforseo limits': SPEND_REASON,\n 'providers dataforseo spend': SPEND_REASON,\n 'providers ahrefs limits': SPEND_REASON,\n}\n\nconst PROJECT_ALIASES = new Set(['client', 'project', 'projects'])\n\n// The removed command an argument list names, if any. Only the leading\n// words before the first flag count, so a flag value never matches.\nexport function removedCommand(args: string[]): string | null {\n const flag = args.findIndex((arg) => arg.startsWith('-'))\n const words = flag === -1 ? args : args.slice(0, flag)\n const start = words[0] === 'help' ? 1 : 0\n for (let length = 3; length >= 1; length -= 1) {\n const key = words.slice(start, start + length).join(' ')\n if (words.length - start >= length && Object.hasOwn(REMOVED, key)) {\n return key\n }\n }\n return null\n}\n\nexport function renamedNotice(command: string): string | null {\n const next = Object.hasOwn(RENAMED, command) ? RENAMED[command] : undefined\n return next\n ? `\\`seo ${command}\\` is now \\`${next}\\`. The old name stops working in 0.4.0.`\n : null\n}\n\nexport function removedNotice(args: string[]): string | null {\n const command = removedCommand(args)\n if (!command) return null\n const replacement = REMOVED[command]\n const group = command.split(' ')[0] ?? ''\n const next = replacement\n ? `Use \\`${replacement}\\` instead.`\n : PROJECT_ALIASES.has(group)\n ? 'Run `seo projects --help` for the project commands.'\n : group === 'providers'\n ? 'Run `seo providers --help` for the provider commands.'\n : 'Run `seo help` for the commands.'\n const reason = Object.hasOwn(REMOVED_REASONS, command)\n ? REMOVED_REASONS[command]\n : 'SEO Skill now focuses on Search Console, analytics and keyword data.'\n return `\\`seo ${command}\\` was removed in 0.3.0. ${reason} ${next}`\n}\n","import { spawnSync } from 'node:child_process'\nimport { realpathSync } from 'node:fs'\nimport { isCancel, log, select } from '@clack/prompts'\nimport updateNotifier from 'update-notifier'\n\ntype PackageInfo = {\n name: string\n version: string\n}\n\ntype UpdateInfo = {\n current: string\n latest: string\n}\n\ntype UpdateNotifier = {\n update?: UpdateInfo\n}\n\nexport type SelfUpdateCommand = {\n args: string[]\n command: string\n}\n\ntype OfferUpdateOptions = {\n argv?: string[]\n cliPath?: string\n createNotifier?: (pkg: PackageInfo) => UpdateNotifier\n env?: NodeJS.ProcessEnv\n platform?: NodeJS.Platform\n prompt?: (input: {\n command: SelfUpdateCommand\n update: UpdateInfo\n }) => Promise<'later' | 'update'>\n run?: (command: SelfUpdateCommand) => number | null\n stdinIsTty?: boolean\n stdoutIsTty?: boolean\n}\n\nfunction normalizedPath(value: string): string {\n return value.replaceAll('\\\\', '/').toLowerCase()\n}\n\nfunction packageManagerCommand(\n manager: 'bun' | 'npm' | 'pnpm' | 'yarn',\n platform: NodeJS.Platform,\n): string {\n if (platform !== 'win32') return manager\n return `${manager}.cmd`\n}\n\nexport function inferSelfUpdateCommand(\n resolvedCliPath: string,\n platform: NodeJS.Platform = process.platform,\n): SelfUpdateCommand | undefined {\n const path = normalizedPath(resolvedCliPath)\n\n if (\n path.includes('/_npx/') ||\n path.includes('/.npm/_npx/') ||\n path.includes('/.cache/pnpm/dlx/') ||\n path.includes('/.volta/')\n ) {\n return undefined\n }\n\n if (path.includes('/.pnpm/') || path.includes('/pnpm/global/')) {\n return {\n command: packageManagerCommand('pnpm', platform),\n args: ['add', '--global', 'seo@latest'],\n }\n }\n\n if (path.includes('/.bun/install/global/')) {\n return {\n command: packageManagerCommand('bun', platform),\n args: ['add', '--global', 'seo@latest'],\n }\n }\n\n if (path.includes('/.config/yarn/global/')) {\n return {\n command: packageManagerCommand('yarn', platform),\n args: ['global', 'add', 'seo@latest'],\n }\n }\n\n if (path.includes('/node_modules/seo/')) {\n return {\n command: packageManagerCommand('npm', platform),\n args: ['install', '--global', 'seo@latest'],\n }\n }\n\n return undefined\n}\n\nfunction isNewerVersion(current: string, latest: string): boolean {\n const parse = (value: string) =>\n value\n .replace(/^v/, '')\n .split('-')[0]\n ?.split('.')\n .map((part) => Number.parseInt(part, 10)) ?? []\n const currentParts = parse(current)\n const latestParts = parse(latest)\n\n for (let index = 0; index < 3; index += 1) {\n const currentPart = currentParts[index] ?? 0\n const latestPart = latestParts[index] ?? 0\n if (!Number.isFinite(currentPart) || !Number.isFinite(latestPart)) {\n return false\n }\n if (latestPart > currentPart) return true\n if (latestPart < currentPart) return false\n }\n\n return false\n}\n\nexport function canOfferInteractiveUpdate(input: {\n argv: string[]\n env: NodeJS.ProcessEnv\n stdinIsTty: boolean\n stdoutIsTty: boolean\n}): boolean {\n if (!input.stdinIsTty || !input.stdoutIsTty) return false\n if (\n input.env.CI ||\n input.env.NO_UPDATE_NOTIFIER ||\n input.env.NODE_ENV === 'test' ||\n input.env.npm_lifecycle_event ||\n input.env.npm_execpath ||\n input.env.TERM === 'dumb'\n ) {\n return false\n }\n if (input.argv.includes('--json')) return false\n if (\n input.argv.some((arg) => ['--help', '-h', '--version', '-v'].includes(arg))\n ) {\n return false\n }\n if (['help', 'mcp'].includes(input.argv[0] ?? '')) return false\n return true\n}\n\nfunction resolvedCliPath(cliPath: string | undefined): string | undefined {\n if (!cliPath) return undefined\n try {\n return realpathSync(cliPath)\n } catch {\n return cliPath\n }\n}\n\nasync function promptForUpdate(input: {\n command: SelfUpdateCommand\n update: UpdateInfo\n}): Promise<'later' | 'update'> {\n const choice = await select<'later' | 'update'>({\n message: `seo ${input.update.latest} is available. You have ${input.update.current}.`,\n options: [\n {\n value: 'update',\n label: 'Update now',\n hint: [input.command.command, ...input.command.args].join(' '),\n },\n { value: 'later', label: 'Later' },\n ],\n initialValue: 'later',\n })\n return isCancel(choice) ? 'later' : choice\n}\n\nfunction runUpdate(command: SelfUpdateCommand): number | null {\n return spawnSync(command.command, command.args, { stdio: 'inherit' }).status\n}\n\nexport async function maybeOfferSelfUpdate(\n pkg: PackageInfo,\n options: OfferUpdateOptions = {},\n): Promise<number | undefined> {\n const argv = options.argv ?? process.argv.slice(2)\n const env = options.env ?? process.env\n if (\n !canOfferInteractiveUpdate({\n argv,\n env,\n stdinIsTty: options.stdinIsTty ?? Boolean(process.stdin.isTTY),\n stdoutIsTty: options.stdoutIsTty ?? Boolean(process.stdout.isTTY),\n })\n ) {\n return undefined\n }\n\n const path = resolvedCliPath(options.cliPath ?? process.argv[1])\n const command = path\n ? inferSelfUpdateCommand(path, options.platform ?? process.platform)\n : undefined\n if (!command) return undefined\n\n const notifier = (\n options.createNotifier ??\n ((value) =>\n updateNotifier({\n pkg: value,\n shouldNotifyInNpmScript: false,\n }))\n )(pkg)\n const update = notifier.update\n if (!update || !isNewerVersion(update.current, update.latest)) {\n return undefined\n }\n\n const choice = await (options.prompt ?? promptForUpdate)({ command, update })\n if (choice === 'later') return undefined\n\n const status = (options.run ?? runUpdate)(command)\n if (status === 0) {\n log.success(`Updated seo to ${update.latest}. Run your command again.`)\n return 0\n }\n\n log.error('The update failed. Your current version is unchanged.')\n return 1\n}\n","import { existsSync, readFileSync, writeFileSync } from 'node:fs'\nimport { join } from 'node:path'\nimport { getSeoCliPaths } from '@seo/core'\n\n// A one-time notice for people who used 0.2 and now run 0.3, in a terminal\n// only. It is shown once, then a marker file in the config folder stops it.\n\nconst NOTICE = '0.3'\n\nconst TEXT = `SEO Skill 0.3: eight commands replace the 70+ old reports, and old report names print the command to use instead.\nFree hosted MCP server, nothing to install: https://seoskill.dev/docs/mcp\nTo stay on the old version: npm i -g seo@0.2.41\nWhat changed: https://github.com/iannuttall/seo/blob/main/CHANGELOG.md\n`\n\nexport function showUpgradeNotice(argv: string[]): void {\n if (!process.stderr.isTTY || process.env.CI) return\n if (argv.includes('--json') || argv[0] === 'mcp') return\n try {\n const { configDir, configFile } = getSeoCliPaths()\n // Only people who used an older version have a config file already.\n if (!existsSync(configFile)) return\n const marker = join(configDir, 'notices.json')\n const seen = existsSync(marker)\n ? (JSON.parse(readFileSync(marker, 'utf8')) as string[])\n : []\n if (seen.includes(NOTICE)) return\n process.stderr.write(`\\n${TEXT}\\n`)\n writeFileSync(marker, JSON.stringify([...seen, NOTICE]), { mode: 0o600 })\n } catch {\n // A notice is never worth failing a command.\n }\n}\n","import {\n detectTelemetryAgent,\n initializeTelemetry,\n SEO_VERSION,\n seoErrorEnvelope,\n toSeoError,\n trackTelemetryCommandFailed,\n trackTelemetryReportComplete,\n trackTelemetryReportFailed,\n trackTelemetryReportStart,\n trackTelemetrySetupComplete,\n} from '@seo/core'\nimport {\n COMMANDS,\n type CommandId,\n telemetryReportFor,\n} from '@seo/core/commands'\nimport { listReports } from '@seo/mcp'\nimport { defineCommand, runCommand, runMain } from 'citty'\nimport { analyticsCommand } from './commands/analytics/index.js'\nimport { authCommand } from './commands/auth.js'\nimport { cacheCommand } from './commands/cache.js'\nimport { clientCommand, projectCommand } from './commands/clients/index.js'\nimport { contentCommand } from './commands/content.js'\nimport {\n compareCommand,\n dataCommand,\n indexCommand,\n pageCommand,\n reportCommand,\n researchCommand,\n} from './commands/core-commands.js'\nimport { crawlCommand } from './commands/crawl.js'\nimport { crawlReportsCommand } from './commands/crawl-reports.js'\nimport { gscQueryCommand, urlInspectCommand } from './commands/data.js'\nimport {\n trafficAnomalyCommand,\n updateCorrelateCommand,\n} from './commands/diagnosis-reports.js'\nimport {\n changeLogCommand,\n contentGroupsCommand,\n testsCommand,\n} from './commands/experiments/index.js'\nimport { exportCommand } from './commands/export/index.js'\nimport { initCommand } from './commands/init.js'\nimport { logsCommand } from './commands/logs.js'\nimport { mcpCommand } from './commands/mcp.js'\nimport {\n crawlDiffCommand,\n indexCoverageCommand,\n indexWatchCommand,\n linkRecoverCommand,\n monitoringCommand,\n redirectTraceCommand,\n} from './commands/monitoring.js'\nimport {\n aiReferralsCommand,\n cannibalCommand,\n ctrUnderperformersCommand,\n decayingCommand,\n internalLinksCommand,\n pageOpportunitiesCommand,\n queryClusterCommand,\n quickWinsCommand,\n secondPageCommand,\n} from './commands/opportunities/index.js'\nimport { auditPageCommand } from './commands/page-audit.js'\nimport { performanceCommand } from './commands/performance.js'\nimport {\n diagnoseCommand,\n doctorCommand,\n segmentImpactCommand,\n strikingDistanceCommand,\n} from './commands/product/index.js'\nimport { providersCommand } from './commands/providers/index.js'\nimport { reportCatalogCommand } from './commands/report-catalog.js'\nimport { explainCommand, rulesCommand } from './commands/rules.js'\nimport { scheduleCommand } from './commands/schedule.js'\nimport { setupCommand, startCommand } from './commands/setup/index.js'\nimport { skillsCommand } from './commands/skills.js'\nimport {\n privacyCommand,\n resetCommand,\n sitesCommand,\n updatesCommand,\n} from './commands/system.js'\nimport { telemetryCommand } from './commands/telemetry.js'\nimport {\n crawlQueueCommand,\n mainReportCommand,\n refreshPrioritiesCommand,\n technicalWatchCommand,\n updatePostmortemCommand,\n} from './commands/workflows/index.js'\nimport { buildErrorFeedbackUrl, telemetryOperation } from './error-feedback.js'\nimport { removedNotice, renamedNotice } from './renames.js'\nimport { maybeOfferSelfUpdate } from './self-update.js'\nimport { showUpgradeNotice } from './upgrade-notice.js'\nimport { printCatalog, printHeading, printSection } from './utils.js'\n\nconst pkg = {\n name: 'seo',\n version: SEO_VERSION,\n}\n\ntype HelpSection = {\n title: string\n commands: Array<[command: string, description: string]>\n}\n\nconst helpSections: HelpSection[] = [\n {\n title: 'Start here',\n commands: [\n ['seo start', 'Connect Search Console and save a project profile'],\n ['seo report', 'The main report: overview and every section'],\n [\n 'seo report --section quick-wins',\n 'One section of the report, with live page checks',\n ],\n ],\n },\n {\n title: 'Commands',\n commands: [\n ['seo page --url <url>', 'One page: live facts, index status, queries'],\n ['seo compare --date <date>', 'Before and after a date'],\n ['seo index', 'Pages that lost most of their clicks'],\n [\n 'seo research <action>',\n 'Keyword, SERP, competitor and backlink data from your key',\n ],\n ['seo data', 'Raw Search Console rows'],\n ['seo crawl', 'Crawl a site and list technical issues'],\n ['seo internal-links', 'Pages that could link to a target page'],\n ],\n },\n {\n title: 'Setup',\n commands: [\n ['seo projects list', 'List saved project profiles'],\n ['seo sites', 'List Search Console properties'],\n ['seo mcp install', 'Add the local MCP server to your agents'],\n ['seo providers', 'Connect DataForSEO or Ahrefs'],\n ['seo doctor', 'Check local auth and config'],\n ],\n },\n]\n\nconst allHelpSections: HelpSection[] = [\n ...helpSections,\n {\n title: 'More commands',\n commands: [\n ['seo crawl-reports', 'List saved crawl reports'],\n ['seo crawl-diff', 'Compare crawl changes'],\n ['seo crawl-queue', 'Run a crawl and rank the fix queue'],\n ['seo rules', 'List crawler rule ids'],\n ['seo explain --rule missing_title', 'Explain a crawler rule'],\n ['seo redirect-trace', 'Trace redirects'],\n ['seo perf audit', 'Run a page performance audit'],\n ['seo index-coverage', 'Choose pages for URL Inspection'],\n ['seo index-watch', 'Check saved URL Inspection snapshots'],\n ['seo ai-referrals', 'AI referral traffic in Google Analytics'],\n ['seo analytics google report', 'Run a Google Analytics report'],\n ['seo updates', 'List official Google ranking updates'],\n ['seo change-log', 'Track SEO changes'],\n ['seo tests', 'Create and report local SEO tests'],\n ['seo content-groups', 'Manage reusable page and query groups'],\n ['seo monitoring', 'Run and review monitoring'],\n ['seo schedule cron', 'Print cron entries'],\n ['seo export', 'Export report data to CSV'],\n ['seo reports list', 'List every structured report'],\n ['seo skill list', 'Show the packaged SEO skill'],\n ['seo auth', 'Manage Google auth'],\n ['seo cache', 'Manage local cache'],\n ['seo privacy', 'Show local storage paths'],\n ['seo telemetry status', 'Check anonymous usage telemetry'],\n ['seo reset', 'Delete saved credentials and all local data'],\n ],\n },\n]\n\nfunction printHelpSections(sections: HelpSection[]): void {\n printHeading(\n `seo v${pkg.version}`,\n 'Run SEO audits, find what needs fixing, and ship the changes with your agent.',\n )\n process.stdout.write('\\n')\n printCatalog(\n sections.flatMap((section) =>\n section.commands.map(([command, description]) => ({\n category: section.title,\n id: command,\n name: description,\n })),\n ),\n {\n noun: 'command',\n categoryLabels: Object.fromEntries(\n sections.map((section) => [section.title, section.title]),\n ),\n },\n )\n process.stdout.write('\\n')\n printSection(\n 'More help',\n 'Use `seo help <command>` or `seo <command> --help` for command help.',\n 'Use `seo help all` for the longer command list.',\n )\n}\n\nconst main = defineCommand({\n meta: {\n name: 'seo',\n version: pkg.version,\n description: 'Local-first SEO CLI and MCP server',\n },\n subCommands: {\n init: initCommand,\n analytics: analyticsCommand,\n auth: authCommand,\n mcp: mcpCommand,\n doctor: doctorCommand,\n privacy: privacyCommand,\n telemetry: telemetryCommand,\n reset: resetCommand,\n cache: cacheCommand,\n logs: logsCommand,\n crawl: crawlCommand,\n 'crawl-queue': crawlQueueCommand,\n 'crawl-reports': crawlReportsCommand,\n client: clientCommand,\n content: contentCommand,\n project: projectCommand,\n projects: projectCommand,\n providers: providersCommand,\n 'change-log': changeLogCommand,\n tests: testsCommand,\n 'content-groups': contentGroupsCommand,\n 'crawl-diff': crawlDiffCommand,\n diagnose: diagnoseCommand,\n // The 0.2 main report, kept under its old name for one release.\n 'diagnose-property': mainReportCommand,\n export: exportCommand,\n 'index-coverage': indexCoverageCommand,\n 'index-watch': indexWatchCommand,\n 'link-recover': linkRecoverCommand,\n monitoring: monitoringCommand,\n rules: rulesCommand,\n explain: explainCommand,\n 'refresh-priorities': refreshPrioritiesCommand,\n 'redirect-trace': redirectTraceCommand,\n schedule: scheduleCommand,\n skill: skillsCommand,\n start: startCommand,\n setup: setupCommand,\n report: reportCommand,\n page: pageCommand,\n compare: compareCommand,\n index: indexCommand,\n data: dataCommand,\n research: researchCommand,\n reports: reportCatalogCommand,\n 'segment-impact': segmentImpactCommand,\n 'striking-distance': strikingDistanceCommand,\n 'technical-watch': technicalWatchCommand,\n 'update-postmortem': updatePostmortemCommand,\n sites: sitesCommand,\n 'gsc-query': gscQueryCommand,\n 'url-inspect': urlInspectCommand,\n updates: updatesCommand,\n 'traffic-anomaly': trafficAnomalyCommand,\n 'update-correlate': updateCorrelateCommand,\n 'ai-referrals': aiReferralsCommand,\n 'audit-page': auditPageCommand,\n 'second-page': secondPageCommand,\n cannibal: cannibalCommand,\n decaying: decayingCommand,\n 'quick-wins': quickWinsCommand,\n 'page-opportunities': pageOpportunitiesCommand,\n perf: performanceCommand,\n 'internal-links': internalLinksCommand,\n 'ctr-underperformers': ctrUnderperformersCommand,\n 'query-cluster': queryClusterCommand,\n },\n run: async () => {\n if (process.argv.slice(2).length === 0) {\n process.stdout.write(\n 'Use `seo start` to set up, then `seo report` for the main report.\\n',\n )\n }\n },\n})\n\nconst reportAliases: Record<string, string> = {\n cannibal: 'cannibalisation',\n crawl: 'site-crawl',\n 'crawl-queue': 'top-fixes',\n decaying: 'decaying-pages',\n 'diagnose-property': 'search-performance-overview',\n doctor: 'setup-check',\n explain: 'explain-crawl-issue',\n 'link-recover': 'link-recovery',\n 'query-cluster': 'query-clusters',\n report: 'search-performance-overview',\n rules: 'crawler-rules',\n 'update-correlate': 'update-correlation',\n}\n\nconst directReportIds = new Set([\n 'ai-referrals',\n 'audit-page',\n 'crawl-diff',\n 'ctr-underperformers',\n 'index-coverage',\n 'index-watch',\n 'internal-links',\n 'page-opportunities',\n 'quick-wins',\n 'redirect-trace',\n 'refresh-priorities',\n 'second-page',\n 'segment-impact',\n 'striking-distance',\n 'technical-watch',\n 'traffic-anomaly',\n 'update-postmortem',\n])\nconst knownReportIds = new Set(listReports().map((report) => report.id))\n\nfunction flagValue(args: string[], flag: string): string | undefined {\n const at = args.indexOf(flag)\n if (at >= 0) return args[at + 1]\n return args.find((arg) => arg.startsWith(`${flag}=`))?.slice(flag.length + 1)\n}\n\nfunction telemetryReportId(args: string[]): string | undefined {\n const [command, subcommand, id] = args\n if (!command) return undefined\n if (command in COMMANDS) {\n return (\n telemetryReportFor(command as CommandId, {\n section: flagValue(args, '--section'),\n action: subcommand,\n }) ?? undefined\n )\n }\n if (command === 'reports' && subcommand === 'run') {\n return id && knownReportIds.has(id) ? id : undefined\n }\n if (command === 'content' && subcommand === 'optimize') {\n return 'content-optimization'\n }\n if (command === 'change-log' && subcommand === 'measure') {\n return 'measure-change'\n }\n if (command === 'monitoring' && subcommand === 'run') {\n return 'technical-watch'\n }\n if (command === 'perf' && subcommand === 'audit') return 'performance-audit'\n if (command === 'tests' && subcommand === 'report') return 'measure-change'\n return (\n reportAliases[command] ??\n (directReportIds.has(command) ? command : undefined)\n )\n}\n\nconst argv = process.argv.slice(2)\nshowUpgradeNotice(argv)\nconst removed = removedNotice(argv)\nif (removed) {\n process.stderr.write(`${removed}\\n`)\n process.exit(2)\n}\nconst renamed = renamedNotice(argv[0] ?? '')\nif (renamed && !argv.some((arg) => ['--help', '-h'].includes(arg))) {\n process.stderr.write(`${renamed}\\n`)\n}\nconst telemetryOptions = { agent: detectTelemetryAgent() }\nconst isTelemetryControl = argv[0] === 'telemetry'\nconst isMcpServer = argv[0] === 'mcp' && argv[1] === 'serve'\nif (!isTelemetryControl && !isMcpServer) {\n initializeTelemetry(telemetryOptions)\n}\nconst updateExitCode = await maybeOfferSelfUpdate(pkg, { argv })\nif (updateExitCode !== undefined) {\n process.exit(updateExitCode)\n}\nif (\n argv.length === 0 ||\n (argv.length === 1 && ['help', '--help', '-h'].includes(argv[0] ?? ''))\n) {\n printHelpSections(helpSections)\n process.exit(0)\n}\nif (argv[0] === 'help' && argv[1] === 'all') {\n printHelpSections(allHelpSections)\n process.exit(0)\n}\nconst commandArgs =\n argv[0] === 'help' && argv.length > 1 ? [...argv.slice(1), '--help'] : argv\nif (commandArgs !== argv) {\n process.argv = [\n process.argv[0] ?? 'node',\n process.argv[1] ?? 'seo',\n ...commandArgs,\n ]\n}\nconst helpRequested = commandArgs.some((arg) => ['--help', '-h'].includes(arg))\nconst versionRequested =\n argv.length === 1 && ['--version', '-v'].includes(argv[0] ?? '')\nconst trackedReport =\n helpRequested || versionRequested ? undefined : telemetryReportId(commandArgs)\n\nif (helpRequested || versionRequested) {\n await runMain(main)\n} else {\n if (trackedReport) {\n trackTelemetryReportStart(trackedReport, telemetryOptions)\n }\n try {\n await runCommand(main, { rawArgs: commandArgs })\n if (trackedReport) {\n trackTelemetryReportComplete(trackedReport, telemetryOptions)\n }\n if (\n ['init', 'setup', 'start'].includes(commandArgs[0] ?? '') &&\n !commandArgs.includes('--dry-run')\n ) {\n trackTelemetrySetupComplete(telemetryOptions)\n }\n } catch (error) {\n if (trackedReport) {\n trackTelemetryReportFailed(trackedReport, error, telemetryOptions)\n } else if (!isTelemetryControl) {\n const operation = telemetryOperation(commandArgs)\n if (operation) {\n trackTelemetryCommandFailed(operation, error, telemetryOptions)\n }\n }\n const normalized = toSeoError(error)\n if (argv.includes('--json')) {\n process.stdout.write(\n `${JSON.stringify(seoErrorEnvelope(normalized), null, 2)}\\n`,\n )\n } else {\n process.stderr.write(`Error: ${normalized.message}\\n`)\n const feedbackUrl = buildErrorFeedbackUrl({\n args: commandArgs,\n error,\n report: trackedReport,\n })\n if (feedbackUrl) {\n process.stderr.write(`Report this bug: ${feedbackUrl}\\n`)\n }\n }\n process.exitCode = normalized.exitCode\n }\n}\n"],"mappings":"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AU,OAAQ,EAAsB,CAAY,CAAE,EAEpE,CACT,CCCA,MAAM,GAAyC,CAC7C,KAAM,EACN,OAAQ,EACR,IAAK,CACP,EAEa,GAAe,EAAc,CACxC,KAAM,CACJ,KAAM,QACN,YAAa,0DACf,EACA,KAAM,CACJ,SAAU,CACR,KAAM,aACN,SAAU,GACV,YAAa,8CACf,EACA,IAAK,CACH,KAAM,SACN,YACE,oEACJ,EACA,KAAM,CACJ,KAAM,SACN,YAAa,4CACf,EACA,OAAQ,CACN,KAAM,SACN,YAAa,6BACf,EACA,QAAS,CACP,KAAM,SACN,YAAa,2BACf,EACA,GAAG,GACH,KAAM,CACJ,KAAM,SACN,YACE,wFACJ,EACA,OAAQ,CACN,KAAM,UACN,QAAS,GACT,YACE,+FACJ,EACA,cAAe,CACb,KAAM,SACN,YACE,oEACJ,EACA,KAAM,CACJ,KAAM,SACN,YAAa,qCACf,EACA,YAAa,CACX,KAAM,SACN,YAAa,2CACf,EACA,YAAa,CACX,KAAM,SACN,YAAa,wDACf,EACA,YAAa,CACX,KAAM,SACN,YAAa,gDACf,EACA,YAAa,CACX,KAAM,SACN,YACE,yFACJ,EACA,qBAAsB,CACpB,KAAM,SACN,YAAa,6CACf,EACA,oBAAqB,CACnB,KAAM,SACN,YAAa,sCACf,EACA,QAAS,CACP,KAAM,UACN,QAAS,GACT,YAAa,gDACf,EACA,QAAS,CACP,KAAM,SACN,YAAa,0CACf,EACA,QAAS,CACP,KAAM,SACN,YAAa,0CACf,EACA,aAAc,CACZ,KAAM,UACN,QAAS,GACT,YAAa,oCACf,EACA,YAAa,CACX,KAAM,UACN,QAAS,GACT,YAAa,4CACf,EACA,cAAe,CACb,KAAM,UACN,QAAS,GACT,YACE,6DACJ,EACA,GAAI,CACF,KAAM,UACN,QAAS,GACT,YAAa,kCACf,EACA,UAAW,CACT,KAAM,SACN,YACE,gEACJ,EACA,KAAM,CACJ,KAAM,UACN,QAAS,GACT,YAAa,uDACf,EACA,OAAQ,CACN,KAAM,SACN,YACE,sFACJ,EACA,OAAQ,CACN,KAAM,SACN,YAAa,8CACf,EACA,IAAK,CACH,KAAM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"}