use clap::{Parser, Subcommand};
use std::path::PathBuf;
pub use crate::commands::schema::SchemaType;
const LONG_ABOUT: &str = "\
Agent-first CLI for SEO, GEO (generative engine optimisation), and AEO
(answer engine optimisation) audits.
The binary is the interface: every command emits structured JSON when piped,
human-readable output when run in a terminal. Run `aiseo agent-info` for the
full machine-readable capability manifest.";
#[derive(Parser)]
#[command(version, about = "Agent-first SEO / GEO / AEO auditor", long_about = LONG_ABOUT)]
pub struct Cli {
#[arg(long, global = true)]
pub json: bool,
#[arg(long, global = true)]
pub quiet: bool,
#[command(subcommand)]
pub command: Commands,
}
#[derive(Subcommand)]
pub enum Commands {
#[command(after_long_help = AUDIT_HELP)]
Audit {
file: PathBuf,
#[arg(long, value_name = "SCORE")]
fail_under: Option<u32>,
#[arg(long, value_name = "PATH")]
out: Option<PathBuf>,
#[arg(long, value_name = "LIST")]
factors: Option<String>,
},
#[command(after_long_help = VERIFY_HELP)]
Verify {
before: PathBuf,
current: PathBuf,
},
#[command(after_long_help = FETCH_HELP)]
Fetch {
url: String,
#[arg(long, value_name = "SCORE")]
fail_under: Option<u32>,
#[arg(long, value_name = "PATH")]
out: Option<PathBuf>,
#[arg(long, value_name = "LIST")]
factors: Option<String>,
},
#[command(after_long_help = SCHEMA_HELP)]
Schema {
#[command(subcommand)]
kind: SchemaType,
},
#[command(visible_alias = "info")]
AgentInfo,
Skill {
#[command(subcommand)]
action: SkillAction,
},
Config {
#[command(subcommand)]
action: ConfigAction,
},
Update {
#[arg(long)]
check: bool,
},
#[command(hide = true)]
Contract {
code: i32,
},
}
const VERIFY_HELP: &str = "\
TIPS:
• Run audit first with --out before.json, apply your fix, then verify
• Exit 1 means: previous suggestions still present, or new ones regressed
• Use in an agent loop to stop the agent from claiming work it didn't finish
EXAMPLES:
aiseo audit page.html --out before.json
# ...agent edits page.html...
aiseo verify before.json page.html
# Verify a deployed page against an earlier snapshot
curl -s https://example.com | aiseo verify before.json -";
const FETCH_HELP: &str = "\
TIPS:
• For local files, use `audit` instead — no network, no rate limit
• Network errors are exit code 1 (transient) — retry
• Use `--fail-under` for CI gates that test live deployments
EXAMPLES:
aiseo fetch https://example.com/about
aiseo fetch https://example.com --fail-under 75
aiseo fetch https://example.com | jq '.score_breakdown.components'";
const SCHEMA_HELP: &str = "\
EXAMPLES:
aiseo schema faq --qa 'What is GEO?::Generative Engine Optimisation.' --qa 'Why?::Citations.'
aiseo schema article --title 'Optimal LDL in 2026' --description '...' --date-published 2026-05-24 --author 'Dr Jane Smith' --credentials MD
aiseo schema howto --name 'Lower LDL' --step 'See your GP' --step 'Start a statin' --step 'Re-test in 6 weeks'
aiseo schema organization --name '199 Biotechnologies' --url https://199.bio --logo https://199.bio/logo.png
aiseo schema person --name 'Boris Djordjevic' --job-title 'Founder' --credentials MSc --url https://x.com/longevityboris";
const AUDIT_HELP: &str = "\
TIPS:
• Pipe to `jq` for filtering: `aiseo audit page.html | jq '.suggestions'`
• Score is rough and weighted toward AI-citation surfaces, not legacy SEO
• Position bias warns when TL;DR sits past the first 10% or first statistic past the first 30% of body
• Use --fail-under in CI: `aiseo audit page.html --fail-under 80` exits 1 if score < 80
• Read `score_breakdown.components[]` to know *which* deduction to fix next
EXAMPLES:
aiseo audit ~/site/about.html
aiseo audit ~/site/post.md | jq '{score, suggestions}'
aiseo audit page.html --fail-under 80 # CI gate
aiseo audit page.html --out audit.sarif # GitHub Code Scanning
aiseo audit page.html --out audit.html # printable report (Iowan serif)
aiseo audit page.html | jq '.score_breakdown' # see deductions
# Compose with anything that emits HTML or Markdown on stdout:
curl -s https://example.com | aiseo audit -
search search -q https://js-heavy.com -m scrape --json \\
| jq -r '.results[0].snippet' | aiseo audit -";
#[derive(Subcommand)]
pub enum SkillAction {
Install,
Status,
}
#[derive(Subcommand)]
pub enum ConfigAction {
Show,
Path,
}