# tail-fin-cli-core
Shared CLI/daemon helpers for [tail-fin](https://github.com/motosan-dev/tail-fin). Consumed by both the `tail-fin` CLI binary and the `tfd` daemon — the two agree on how to construct `BrowserSession`, resolve cookie paths, and format JSON output.
## What's here
| `Ctx` | Connection-mode context (`connect`, `cookies`, `headed`) shared across subcommands + REPL |
| `browser_session(host, headed)` | Connect to an existing Chrome via CDP at `ws://{host}` |
| `launch_browser(headed)` | Launch a fresh headless (or headed) browser — no existing Chrome required |
| `auto_launch_stealth(url, headed)` | Stealth browser fallback for adapters that don't need `--connect` |
| `launch_stealth_session(url, headed)` | Stealth browser navigated to a URL with anti-detection |
| `require_browser(connect, service, action)` | Enforce `--connect`, return a friendly error otherwise |
| `require_browser_session(ctx, service)` | Browser-only adapter: reject `--cookies`, require `--connect`, return `BrowserSession` |
| `resolve_cookies_path(flag, site)` | `"auto"` → `~/.tail-fin/<site>-cookies.txt`; explicit path pass-through |
| `default_cookies_path(site)` | `~/.tail-fin/<site>-cookies.txt` |
| `print_json(value)` | Pretty JSON to stdout |
| `print_list(key, items, count)` | `{ "<key>": items, "count": N }` JSON wrapper |
| `no_mode_error(service, cmd)` | User-facing error when neither `--connect` nor `--cookies` is set |
Site-specific CLI glue (e.g. the Twitter HTTP client constructor) stays in `tail-fin-cli` — this crate is deliberately site-agnostic.
## Usage
```rust
use tail_fin_cli_core::{browser_session, print_json, Ctx};
async fn example(ctx: &Ctx) -> anyhow::Result<()> {
let host = ctx.connect.as_deref().unwrap_or("127.0.0.1:9222");
let session = browser_session(host, ctx.headed).await?;
// ... use session ...
print_json(&serde_json::json!({ "status": "ok" }))?;
Ok(())
}
```
## License
[MIT](../../LICENSE)