# Operator Install/Update Helper

`scripts/install-or-update.sh` is the repeatable local operator path for
installing, updating, diagnosing, and safely unwinding a BrowserBridge
private-alpha checkout on the browser host. It is intentionally conservative:
remote MCP binding requires an explicit host and `--allow-remote`, and the
helper verifies the built Chrome extension before printing load instructions.

## Modes

```sh
./scripts/install-or-update.sh install
./scripts/install-or-update.sh update
./scripts/install-or-update.sh doctor
./scripts/install-or-update.sh dry-run
./scripts/install-or-update.sh uninstall-helper
```

When no mode is supplied, the helper auto-detects install versus update based
on whether the target directory already has a BrowserBridge Git checkout.

Supported flags:

- `--ref <git-ref>`
- `--host <host>`
- `--port <port>`
- `--allow-remote`
- `--dry-run`
- `--print-only`
- `--skip-start` or `--no-start`
- `--with-launchagent`
- `--without-launchagent`
- `--confirm`
- `--extension-id <chrome-extension-id>` for doctor/native manifest checks

## Dry Run

Preview the exact paths and commands without cloning, building, starting
listeners, or writing LaunchAgents:

```sh
./scripts/install-or-update.sh --dry-run
```

For trusted-tailnet testing, the host must be explicit:

```sh
./scripts/install-or-update.sh --dry-run --allow-remote --host <tailnet-ip>
```

The dry-run output includes:

- Chrome extension load path
- MCP command
- native host install-plan command
- native host doctor command
- Hermes adapter validation command
- public latest download URL
- runtime clear-cache command
- existing macOS LaunchAgent status when running on macOS

## Local Loopback Install

```sh
./scripts/install-or-update.sh install --ref main
```

By default the MCP listener binds to `127.0.0.1:7332`. A non-loopback host is
refused unless `--allow-remote` is present.

## Trusted Tailnet Install

```sh
./scripts/install-or-update.sh update --ref main --allow-remote --host <tailnet-ip>
```

Use this only on a trusted private tailnet or isolated lab network. The remote
MCP listener remains authenticated; `--allow-remote` only permits binding beyond
loopback.

## LaunchAgent Mode

To write or update the macOS MCP LaunchAgent, the confirmation flag is required:

```sh
./scripts/install-or-update.sh update \
  --ref main \
  --allow-remote \
  --host <tailnet-ip> \
  --with-launchagent \
  --confirm
```

The helper writes the LaunchAgent and prints the `launchctl` commands to load or
restart it. It does not silently start duplicate listeners.

Without `--confirm`, LaunchAgent mode prints a reviewable plan and exits before
writing anything.

## Doctor Mode

```sh
./scripts/install-or-update.sh doctor --extension-id <chrome-extension-id>
```

Doctor mode does not install dependencies, rebuild files, start listeners, or
write LaunchAgents. It checks:

- `git`, `node`, and `pnpm` or `npx pnpm@9.15.0`
- Chrome presence
- BrowserBridge checkout identity
- tracked dirty worktree status
- extension dist freshness
- service worker path existence
- bare `@browserbridge/*` imports in extension dist
- permission posture
- broad `tabs` or `scripting` permission drift
- target MCP port listener state
- existing LaunchAgent state
- native manifest wildcard origin and extension id mismatch when an extension id
  is supplied

The same extension bundle check is available directly through the companion:

```sh
npx pnpm@9.15.0 --filter @browserbridge/companion exec browserbridge-companion native:validate-extension-dist --path packages/extension/dist
```

## Print-Only And Uninstall Planning

Use `--print-only` to print exact commands without modifying state:

```sh
./scripts/install-or-update.sh update --print-only --allow-remote --host <tailnet-ip>
```

Use `uninstall-helper` to print the safe reset commands. It does not delete
files by itself:

```sh
./scripts/install-or-update.sh uninstall-helper --extension-id <chrome-extension-id>
```

## Validation Performed

After the extension build, the helper checks:

- extension permissions are exactly `nativeMessaging` and `activeTab`
- `host_permissions` is empty
- `content_scripts` is absent
- the service worker file exists
- built JavaScript has no bare `@browserbridge/*` imports
- built JavaScript has no `chrome.scripting` references

If any check fails, the helper stops before printing install instructions or
starting background processes.

## Stale State Recovery

When a harness sees old tabs or stale result shapes, clear the local runtime
cache and restart the adapter/listener:

```sh
npx pnpm@9.15.0 --filter @browserbridge/mcp-server exec browserbridge-mcp runtime:clear-cache --confirm
```

Production harness calls must return `live_unavailable` when no fresh extension
metadata exists. `mock_success` is reserved for explicit demo mode.
