feat(site): bb-sites adapters — turn any site into a structured-data CLI
Release binaries / Build macOS ARM64 (push) Has been cancelled
Release binaries / Build macOS x64 (push) Has been cancelled
Release binaries / Build Linux ARM64 (push) Has been cancelled
Release binaries / Build Linux musl ARM64 (push) Has been cancelled
Release binaries / Build Linux musl x64 (push) Has been cancelled
Release binaries / Build Linux x64 (push) Has been cancelled
Release binaries / Build Windows x64 (push) Has been cancelled
Release binaries / Attach binaries to GitHub Release (push) Has been cancelled

Add `chrome-use site` — run community bb-sites adapters over chrome-use's
stealth transport. An adapter is a per-command JS function that calls a
site's own JSON API from inside your logged-in tab (your cookies, same-origin
fetch, the site's modules) and returns clean JSON — no clicking/scraping.

- site update   fetch the upstream bb-sites pack into ~/.chrome-use/sites
- site list     list installed adapters (name/cmd)
- site info     show an adapter's @meta (args, domain, capabilities)
- site <name>/<cmd> [args]  navigate to its domain (reuse tab if already there) + eval, return JSON

chrome-use ships zero adapter code; `site update` fetches epiral/bb-sites at
runtime (like a package manager). Adapters remain their authors' property.

cli/src/site.rs (load/parse/build_eval/list/update/map_args + tests), wired
via commands.rs (parse), actions.rs (handle_site), main.rs (CLI dispatch).
Docs in README, README.zh, skill-data/core. Verified live: github/issues
returned 30 real issues as JSON over the relay.
This commit is contained in:
leeguooooo
2026-06-17 16:02:40 +09:00
parent c667e0e704
commit d81bc01645
11 changed files with 516 additions and 3 deletions
+42
View File
@@ -78,6 +78,7 @@ const KNOWN_COMMANDS: &[&str] = &[
"drag",
"dialog",
"upload",
"site",
];
/// Levenshtein distance, capped — small inputs only (command names).
@@ -1193,6 +1194,47 @@ fn parse_command_inner(args: &[String], flags: &Flags) -> Result<Value, ParseErr
Ok(json!({ "id": id, "action": "evaluate", "script": script }))
}
"site" => {
// `site <name>/<command> [positional...] [--key value]`. The
// `update`/`list`/`info` subcommands are handled CLI-side (main.rs)
// and never reach here — by this point `rest[0]` is a `name/cmd`
// adapter spec. Load it, map the args onto the adapter's declared
// `args`, and emit a `site` action: the daemon navigates to the
// adapter's @meta.domain (reusing the tab if already there) and evals
// the adapter function in the site's own logged-in page.
let spec = rest.first().ok_or(ParseError::InvalidValue {
message: "site requires <name>/<command> (run `chrome-use site list`)".to_string(),
usage: "site <name>/<command> [args]",
})?;
let adapter =
crate::site::load_adapter(spec).map_err(|e| ParseError::InvalidValue {
message: e,
usage: "site <name>/<command> [args]",
})?;
let domain = adapter
.domain()
.ok_or(ParseError::InvalidValue {
message: format!("site: adapter `{spec}` @meta is missing a \"domain\""),
usage: "site <name>/<command>",
})?
.to_string();
// Split remaining args: `--key value` → named, everything else → positional.
let mut positional: Vec<String> = Vec::new();
let mut named: Vec<(String, String)> = Vec::new();
let mut it = rest[1..].iter();
while let Some(a) = it.next() {
if let Some(key) = a.strip_prefix("--") {
let val = it.next().map(|s| s.to_string()).unwrap_or_default();
named.push((key.to_string(), val));
} else {
positional.push(a.to_string());
}
}
let mapped = crate::site::map_args(&adapter, &positional, &named);
let script = crate::site::build_eval(&adapter, &mapped);
Ok(json!({ "id": id, "action": "site", "domain": domain, "script": script }))
}
// === Stealth self-check ===
"stealth" => {
// `stealth [status]` — local stealth self-check: mode, live probes