Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
625 changes: 121 additions & 504 deletions README.md

Large diffs are not rendered by default.

62 changes: 62 additions & 0 deletions docs/chat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Chat Mode

`mainwpcontrol chat` lets you manage your Dashboard in plain English, using your own LLM API key:

```bash
export ANTHROPIC_API_KEY='sk-ant-...'

mainwpcontrol chat
mainwpcontrol chat "list all sites with pending updates"
```

Chat is optional. Every operation it can perform is also a plain `abilities run` command, and nothing else in the CLI depends on it. It earns its place for exploration: when you don't know which ability you need, or you want to chain a few lookups without writing the JSON yourself.

## Providers

Set one API key to enable chat. With multiple keys set, the provider is auto-detected; override with `MAINWP_LLM_PROVIDER` or `--provider`.

| Variable | Provider |
|----------|----------|
| `ANTHROPIC_API_KEY` | Anthropic Claude |
| `OPENAI_API_KEY` | OpenAI GPT |
| `GOOGLE_API_KEY` | Google Gemini |
| `OPENROUTER_API_KEY` | OpenRouter |
| `LOCAL_LLM_API_KEY` | Local LLM (with optional `LOCAL_LLM_URL`, defaults to localhost) |

`MAINWP_LLM_API_KEY` works as a generic key for whichever provider is selected. Pick a model with `MAINWP_LLM_MODEL` or `--model`. Persistent defaults (`llmProvider`, `chatContextMessages`) go in `~/.config/mainwpcontrol/settings.json`; see [Configuration](configuration.md#settings-file).

## Flags

| Flag | Description |
|------|-------------|
| `--provider` | Choose the LLM provider explicitly |
| `--model` | Choose the model |
| `--max-turns` | Limit conversation turns |
| `--max-context-messages` | Limit messages kept in context |
| `--no-stream` | Disable streamed responses |
| `--api-key` | API key for the provider; prefer the environment variable, since flags are visible in the process list |
| `--base-url` | Endpoint override for local or proxied providers |

## Safety

The model proposes; it never confirms or executes on its own. Chat runs abilities through the same execution path and policy as the CLI commands, so the classification and confirm rules in [Safety & Destructive Operations](safety.md) apply unchanged:

- Read and write abilities the model calls are executed and the results returned to the conversation.
- A destructive ability stops the conversation: you see a successful preview of what would be affected, and it runs only after your explicit approval at the terminal.
- Approvals are single-use. Approving one deletion does not pre-approve the next one.
- The model cannot set `confirm` or `dry_run` itself; those come from your terminal, never from the conversation.

## What the provider sees

Chat sends more to the LLM provider than the conversation text. Per request, the provider receives:

- your messages and the model's own prior turns
- every discovered ability's name, description, and input JSON schema, sent as tool definitions so the model knows what it can call
- the inputs the model proposes for each call
- ability results and error messages, with credential material redacted before serialization

Your Application Password and your provider API key are never part of the payload. Ability results are your real site data, so treat chat the way you'd treat pasting that data into an AI tool, and pick your provider accordingly (including the local provider, which keeps everything on your machine).

## Scripting note

Chat is interactive by design. In non-TTY environments (pipes, CI), `mainwpcontrol chat` without a message argument exits with guidance instead of hanging. For automation, use `abilities run`; that's what it's for.
176 changes: 176 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# CLI Reference

The `mainwpcontrol` commands, their flags, and the exit-code contract. `mainwpcontrol <command> --help` is always the authoritative listing for the version you have installed. For the credential and settings model behind these commands, see [Configuration](configuration.md).

## Global flags

These work on every command except the built-in `help` and `autocomplete` commands.

| Flag | Description |
|------|-------------|
| `--json` | Structured JSON output: exactly one envelope on stdout |
| `--quiet` / `-q` | Suppress output (exit code only) |
| `--profile <name>` | Use a specific profile for this command |
| `--debug` | Show redacted debug diagnostics on stderr |
| `--help` | Show help |

## `login`

Connects to a Dashboard and creates a profile named after its hostname. Interactive by default; prompts for URL, username, and Application Password, then stores the credentials in your OS keychain.

```bash
# Interactive
mainwpcontrol login

# Non-interactive (CI, headless): password from the environment
export MAINWP_APP_PASSWORD='xxxx xxxx xxxx xxxx xxxx xxxx'
mainwpcontrol login --url https://dashboard.example.com --username admin
```

| Flag | Description |
|------|-------------|
| `--url <url>` | Dashboard URL (HTTPS required unless `MAINWP_ALLOW_HTTP=1` or the `allowInsecureHttp` setting is enabled) |
| `--username <name>` | WordPress username |
| `--name <name>` | Profile name (defaults to the Dashboard hostname) |
| `--password <pw>` | Application Password; prefer `MAINWP_APP_PASSWORD` or the prompt, since flags are visible in the process list |
| `--skip-ssl-verify` | Accept a self-signed certificate for this profile (not for production) |

When no OS keychain is available, credentials are not stored on disk; keep `MAINWP_APP_PASSWORD` set for each run.

## `abilities list`

Shows every operation your Dashboard exposes, grouped by category, with each one's type (read, write, destructive) and the exact `abilities run` command to execute it.

```bash
mainwpcontrol abilities list
mainwpcontrol abilities list --category sites
mainwpcontrol abilities list --json
```

## `abilities info`

Shows one ability's description, input schema, and safety annotations.

```bash
mainwpcontrol abilities info list-sites-v1
mainwpcontrol abilities info delete-site-v1 --json
```

## `abilities run`

Executes an ability by its versioned name.

```bash
mainwpcontrol abilities run list-sites-v1 --json
mainwpcontrol abilities run get-site-v1 --input '{"site_id_or_domain": 1}' --json
mainwpcontrol abilities run get-site-v1 --input-file params.json --json
echo '{"site_id_or_domain": 1}' | mainwpcontrol abilities run get-site-v1 --input - --json
```

| Flag | Description |
|------|-------------|
| `--input` / `-i` | Input parameters as JSON (use `-` for stdin) |
| `--input-file` | Read input from a JSON file |
| `--dry-run` | Preview a destructive ability without executing |
| `--confirm` | Execute a destructive ability |
| `--force` | Skip the interactive confirmation prompt (CI mode) |
| `--wait` | Block until a batch job completes |
| `--wait-timeout` | Max seconds to wait (default: 300) |

`--dry-run` and `--confirm` are mutually exclusive. Destructive abilities refuse to run without one of them; the intended sequence is preview first, then confirm. The full flow, including what `--force` does and doesn't skip, is in [Safety & Destructive Operations](safety.md).

## `jobs watch`

Watches a batch job until it finishes. Operations that affect many items return a `job_id` immediately instead of blocking.

```bash
mainwpcontrol jobs watch <job-id>
mainwpcontrol jobs watch <job-id> --timeout 120
```

| Flag | Description |
|------|-------------|
| `--timeout` | Max seconds to watch before giving up |
| `--initial-delay` | First polling delay in milliseconds |
| `--max-delay` | Polling backoff ceiling in milliseconds |
| `--no-progress` | Suppress the progress display |

A timeout or interruption leaves the job running on the Dashboard; re-run `jobs watch` with the same ID to pick it back up. Using `--wait` on the original `abilities run` command is equivalent to running the command and watching the job in one step.

## `profile`

Each `login` creates a profile, a named connection to one Dashboard, identified by hostname. Manage several Dashboards by logging in once per Dashboard.

```bash
mainwpcontrol profile list
mainwpcontrol profile use production.example.com
mainwpcontrol profile delete staging.example.com # also removes its keychain credentials
```

Any command accepts `--profile <name>` to target a profile without switching the default.

`profile delete` always asks for confirmation and has no skip flag. In non-interactive contexts (pipes, CI) it cancels safely instead of deleting, so treat profile removal as a manual step.

## `config show`

Prints the active settings (from `~/.config/mainwpcontrol/settings.json` and defaults), with secrets redacted.

```bash
mainwpcontrol config show
mainwpcontrol config show --verbose
mainwpcontrol config show --json
```

## `doctor`

Checks configuration, credentials, and Dashboard connectivity. Run it first when something isn't working.

```bash
mainwpcontrol doctor
mainwpcontrol doctor -v # verbose
mainwpcontrol doctor --json
```

## `chat`

Talks to your Dashboard in plain English using your own LLM API key. Optional; nothing else depends on it.

```bash
export ANTHROPIC_API_KEY='sk-ant-...'
mainwpcontrol chat
mainwpcontrol chat "list all sites with pending updates"
```

Chat-specific flags: `--provider`, `--model`, `--max-turns`, `--max-context-messages`, `--no-stream`, `--api-key` (prefer the environment variable; flags are visible in the process list), and `--base-url` for local or proxy endpoints. Providers, models, and the chat safety model are in [Chat Mode](chat.md).

## Shell completion

```bash
# Bash
source "$(npm root -g)/@mainwp/control/scripts/completions/mainwpcontrol.bash"

# Zsh
source "$(npm root -g)/@mainwp/control/scripts/completions/mainwpcontrol.zsh"
```

## Exit codes

| Code | Meaning | CI usage |
|------|---------|----------|
| 0 | Success | Continue pipeline |
| 1 | User/input error | Fix command syntax |
| 2 | Auth/config error | Check credentials |
| 3 | Network error | Retry or check connectivity |
| 4 | API error | Check ability parameters |
| 5 | Internal error | Report bug |
| 130 | Interrupted (SIGINT) | Ctrl-C during a prompt or `jobs watch`; standard Unix 128+signal convention, outside the 0-5 contract |
| 143 | Terminated (SIGTERM) | `jobs watch` killed by a supervisor or timeout wrapper; same 128+signal convention |

```bash
# Pipeline branching on exit codes
if mainwpcontrol abilities run check-sites-v1 --json --quiet; then
echo "All sites healthy"
else
echo "Issues detected"
fi
```
97 changes: 97 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Configuration

How MainWP Control stores credentials, profiles, and settings, and every environment variable it reads.

## Credential storage

`mainwpcontrol login` stores your Application Password in the operating system keychain (macOS Keychain, Windows Credential Manager, libsecret on Linux). Pre-built keychain binaries are included for macOS, Windows, and Linux (x64 and arm64); on other platforms npm may need C++ build tools during installation.

The profile file on disk records the Dashboard URL and username only. It never contains passwords.

Stored credentials are bound to the Dashboard identity they were created for. If you upgraded from a 1.0.x beta and requests now fail with an authentication error, run `mainwpcontrol login` once per profile; see [Troubleshooting](troubleshooting.md#authentication-fails-after-upgrading).

### Environment variable auth

For CI, Docker, and machines without a keychain, put the password in the environment instead:

```bash
export MAINWP_APP_PASSWORD='xxxx xxxx xxxx xxxx xxxx xxxx'
mainwpcontrol login --url https://dashboard.example.com --username admin
```

When no keychain is available, the password is never written to disk; keep `MAINWP_APP_PASSWORD` set for each run. The profile file is still written and records the Dashboard URL and username, as it does in every mode. If keytar is installed but broken, set `MAINWPCONTROL_NO_KEYTAR=1` to skip loading it.

## Profiles

A profile is a named connection to one Dashboard, created automatically by `login` and named after the hostname:

```bash
# Creates profile "staging.example.com"
mainwpcontrol login --url https://staging.example.com --username admin

# Creates profile "production.example.com"
mainwpcontrol login --url https://production.example.com --username admin
```

Profiles live at `~/.config/mainwpcontrol/profiles.json`. Switch the default with `profile use`, target one per command with `--profile`, and remove one (including its keychain entry) with `profile delete`. Command details are in the [CLI Reference](cli-reference.md#profile).

## Settings file

Optional defaults live at `~/.config/mainwpcontrol/settings.json` (or `$XDG_CONFIG_HOME/mainwpcontrol/settings.json` if you set `XDG_CONFIG_HOME`):

```json
{
"defaultJsonOutput": true,
"timeout": 30000,
"debug": false,
"llmProvider": "openai",
"chatContextMessages": 20
}
```

| Setting | Type | Description |
|---------|------|-------------|
| `defaultJsonOutput` | boolean | Default to JSON output |
| `timeout` | number | HTTP request timeout in milliseconds |
| `debug` | boolean | Enable debug output |
| `llmProvider` | string | Default LLM provider for chat |
| `chatContextMessages` | number | Max messages in chat context |
| `skipSSLVerification` | boolean | Disable TLS verification (insecure; prefer the per-profile setting via `login --skip-ssl-verify`) |
| `allowInsecureHttp` | boolean | Allow `http://` Dashboard URLs without `MAINWP_ALLOW_HTTP=1` |

Inspect the active values with `mainwpcontrol config show`.

## Environment variables

### MainWP

| Variable | Description |
|----------|-------------|
| `MAINWP_APP_PASSWORD` | Application Password for non-interactive login, and for commands when no keychain is available |
| `MAINWPCONTROL_NO_KEYTAR` | Set to `1` to skip keytar (keychain) loading entirely |
| `MAINWP_ALLOW_HTTP` | Set to `1` to allow insecure HTTP Dashboard URLs |

### Chat / LLM

| Variable | Description |
|----------|-------------|
| `ANTHROPIC_API_KEY` | Anthropic Claude |
| `OPENAI_API_KEY` | OpenAI GPT |
| `GOOGLE_API_KEY` | Google Gemini |
| `OPENROUTER_API_KEY` | OpenRouter |
| `LOCAL_LLM_API_KEY` | Local LLM provider (required to enable the local provider) |
| `LOCAL_LLM_URL` | Local endpoint URL (optional, defaults to localhost) |
| `MAINWP_LLM_API_KEY` | Generic API key for the selected provider (alternative to the provider-specific variables) |
| `MAINWP_LLM_PROVIDER` | Override the auto-detected provider |
| `MAINWP_LLM_MODEL` | Specify the model to use |

Chat behavior and flags are covered in [Chat Mode](chat.md).

## TLS and HTTP

HTTPS is required by default. Two escape hatches exist for development environments:

- `mainwpcontrol login --skip-ssl-verify` accepts a self-signed certificate for that profile.
- `MAINWP_ALLOW_HTTP=1` (or `allowInsecureHttp` in settings) permits `http://` URLs.

Both send credentials over connections an attacker on the network path can read or alter. Use them for local development against test Dashboards, never in production.
Loading
Loading