# Commands

The whole surface, what each one prints, and what it exits with.

```
page-scanner pair     [--port <n>] [--rotate] [--wait <s>=120] [--no-wait] [--json]
page-scanner status   [--json]
page-scanner browsers [--json]
page-scanner tabs     [--browser <id|label>] [--wait <s>=30] [--json]
page-scanner scan     (--url <u> | --tab <id>) [--window <id>] [--browser <id|label>]
                      [--format pdf|png|jpeg=pdf] [--page-size auto|a4|letter=a4]
                      [--quality <0-1>] [--video frame|blank] [--open-editor]
                      [--out <file|dir>] [--wait <s>=30] [--timeout <s>=120] [--json]
page-scanner serve    [--daemon] [--idle <min>]
page-scanner stop     [--json]
page-scanner --version | --help
```

## scan

Exactly one of `--url` and `--tab`. `--url` opens a background tab, captures it and closes it
again; `--tab` takes an id from `tabs` and never closes what you already had open.

`--out` is a **file** when it ends in a 2 to 5 character extension and is not an existing
directory, and a **directory*&#x2A; otherwise, in which case the browser's suggested filename is used
inside it. Parent directories are created. A relative path is relative to &#x5F;your_ working
directory, not the daemon's, which is why the daemon hands the bytes back and the command writes
them.

`--page-size` decides what a PDF is laid onto. `a4` and `letter` slice the capture across
printable sheets with a half-inch margin; `auto` is one page the exact size of the capture, which
is not printable and which Acrobat clamps past 200 inches.

## Waiting

Chrome retires the extension's service worker after about thirty seconds of silence, and it dials
back in when something wakes it. `--wait` covers that reconnect, and defaults to 30 seconds for
`tabs` and `scan`. `--wait 0` means do not wait at all, and fails immediately instead.

## What a command prints

- **stdout** carries the answer and nothing else. For `scan` that is one line, the absolute path.
  For `tabs` and `browsers` it is a column-aligned table with no separator row, so `awk` can read
  it.
- **stderr** carries anything addressed to a person: progress, warnings, the reason something
  failed.
- **`--json`** puts exactly one JSON document on stdout, for success and for failure alike, and
  leaves stderr empty.

```json
{
  "ok": true,
  "path": "/Users/you/pdf.pdf",
  "width": 1280,
  "height": 4200,
  "mode": "vector",
  "selectableText": true,
  "truncated": null,
  "browserId": "b-9f2c41",
  "fileName": "PDF - Wikipedia.pdf"
}
```

```json
{ "ok": false, "code": 3, "error": "NO_BROWSER", "message": "No browser is connected." }
```

`truncated` is `null` rather than absent when the capture was whole, so a reader can see the
question was asked. When it is not null it carries what the page measured, what was captured, and
a sentence naming the gap.

## Exit codes

| Code | Meaning                                                                       |
| ---- | ----------------------------------------------------------------------------- |
| 0    | success                                                                       |
| 1    | the browser was reached and the work failed                                   |
| 2    | the arguments were wrong                                                      |
| 3    | no usable browser: none connected, several connected, or the one named is not |
| 4    | not paired                                                                    |
| 5    | the daemon would not start                                                    |

## The daemon

Started on demand by the first command that needs one, and reused by every command after it,
including the MCP server's.

`page-scanner serve` runs it in the foreground, which is how to see why it will not start.
`page-scanner stop` stops it. It exits on its own after 15 idle minutes
(`PAGE_SCANNER_IDLE_MINUTES`, `0` for never) and **never** while a browser is attached: the open
socket is what keeps Chrome's service worker alive.

## Files

Everything lives in `~/.page-scanner`, or in `$PAGE_SCANNER_HOME` if that is set: `config.json`
(the pairing), `daemon.json` (the running daemon) and `daemon.log`. The first two are mode 0600,
which **Windows does not enforce**: NTFS has no such mode, so both are readable by anything
running as you. On a shared machine, restrict the directory yourself.

```
icacls %USERPROFILE%\.page-scanner /inheritance:r /grant:r %USERNAME%:F
```

## From Node

```js
import { scan, listTabs } from '@page-scanner/cli';

const { tabs } = await listTabs();
const result = await scan({ tabId: tabs[0].tabId, out: './out/', format: 'pdf' });
console.log(result.path, result.selectableText);
```
