# @gately/cli

Push MDX/Markdown docs from your codebase to your [Gately](https://usegately.com) Help Center.

## Install

```bash
npm install -g @gately/cli
```

Or use without installing (always runs the latest version):

```bash
npx @gately/cli@latest push
```

**Updating:**
```bash
# Global install
npm update -g @gately/cli

# Or just use npx — always latest, no update needed
npx @gately/cli@latest push
```

## Quick start

```bash
# 1. Create config
gately init

# 2. Authenticate
gately login

# 3. Preview
gately push --dry-run

# 4. Push
gately push
```

## Commands

| Command | Description |
|---------|-------------|
| `gately login` | Authenticate via browser — picks your project |
| `gately logout` | Remove stored credentials |
| `gately whoami` | Show the currently authenticated project |
| `gately init` | Create a `gately.config.json` in the current directory |
| `gately push` | Push docs to your help center |
| `gately push --dry-run` | Preview what would be pushed without making changes |
| `gately push --no-fix` | Push without auto-fixing invalid icon names |
| `gately pull` | Pull articles from database to local markdown files |
| `gately pull --folder blog` | Pull only articles from specific folder |
| `gately pull --overwrite` | Overwrite existing local files |
| `gately pull --no-update-config` | Skip updating gately.config.json |
| `gately sync` | Pull navigation structure from help center to local repo |
| `gately sync --generate-config` | Generate suggested config from database structure |
| `gately sync -o nav.json` | Save navigation to custom file |
| `gately format` | Format and clean markdown/MDX files (normalize whitespace, line endings) |
| `gately format --check` | Check if files need formatting without modifying them |
| `gately validate` | Check docs for issues without pushing |

## Authentication

```bash
gately login
```

Opens your browser to pick a project. Credentials are stored in `~/.gately/credentials.json`.

You can also use an environment variable or config file instead:

```bash
export GATELY_API_KEY=gately_sk_live_xxxxxxxx
```

Priority: `config.apiKey` → `GATELY_API_KEY` env var → stored credentials.

## Config file

`gately.config.json` at your repo root:

```json
{
  "openapi": "openapi.json",
  "docs": [
    {
      "path": "docs/**/*.{md,mdx}",
      "folder": {
        "name": "Documentation",
        "icon": "hugeicons:book-open-01",
        "description": "Product documentation"
      },
      "category": {
        "name": "Getting Started",
        "icon": "hugeicons:rocket-01"
      },
      "publish": true
    }
  ],
  "delete": ["old-article-slug", "deprecated-guide"],
  "uncategorized": ["draft-article"]
}
```

### Top-level fields

| Field | Type | Description |
|-------|------|-------------|
| `apiKey` | string | API key (or use `GATELY_API_KEY` env var) |
| `apiUrl` | string | Override API URL (defaults to production) |
| `docs` | array | Doc sources — see below |
| `openapi` | string | Path to OpenAPI spec file for interactive API docs |

### Doc source fields

| Field | Type | Description |
|-------|------|-------------|
| `path` | string \| string[] | Glob pattern(s) relative to config file |
| `folder` | string \| NavItem | Folder (max 3 per project) |
| `category` | string \| NavItem | Category inside the folder |
| `subcategory` | string \| NavItem | Subcategory nested under category |
| `publish` | boolean | Publish immediately (default: `false` = draft) |

### NavItem

Each level accepts a plain string (name only) or a full object:

```json
{
  "name": "API Reference",
  "icon": "hugeicons:api",
  "description": "Full REST API docs",
  "display_order": 1,
  "slug": "api-reference"
}
```

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Display name (required) |
| `icon` | string | Hugeicons icon (e.g. `hugeicons:api`) |
| `description` | string | Short description |
| `display_order` | number | Sort order (lower numbers appear first) |
| `slug` | string | Custom URL-friendly slug (auto-generated from name if omitted) |
| `sidebar_title` | string | Shorter label shown in sidebar instead of full name |

Missing items are created automatically. Icons, display_order, and slugs are updated if they change.

### Hierarchy

```
Folder  (max 3 per project)
└── Category
    └── Subcategory
        └── Article
```

Example with subcategories:

```json
{
  "path": "sdk/javascript.mdx",
  "folder": "Documentation",
  "category": { "name": "SDK & Integrations", "icon": "hugeicons:code-circle" },
  "subcategory": { "name": "JavaScript SDK", "icon": "hugeicons:java-script" },
  "publish": true
}
```

## Frontmatter

Per-article control via frontmatter:

```md
---
title: Getting Started
slug: getting-started
sidebar_title: Quick Start
icon: hugeicons:rocket-01
excerpt: Get up and running in 5 minutes.
publish: true
category: Getting Started
subcategory: Quick Start
display_order: 1
keywords: [guide, tutorial, quickstart]
meta_title: Getting Started with Gately
meta_description: Learn how to get up and running with Gately in 5 minutes
og_image_url: https://example.com/og-image.png
show_toc: true
---
```

| Field | Description |
|-------|-------------|
| `title` | Falls back to first H1, then filename |
| `slug` | Auto-generated from title if omitted |
| `sidebar_title` | Shorter label shown in the sidebar |
| `icon` | Hugeicons name shown next to article |
| `excerpt` | Short summary, auto-generated if omitted |
| `publish` | Overrides source-level publish setting |
| `folder` | Overrides source-level folder |
| `category` | Overrides source-level category |
| `subcategory` | Overrides source-level subcategory |
| `display_order` | Sort order within category (lower numbers appear first) |
| `keywords` / `tags` | Array of SEO keywords |
| `meta_title` | SEO title (defaults to `title`) |
| `meta_description` | SEO description (defaults to `excerpt`) |
| `og_image_url` | Open Graph image URL for social sharing |
| `show_toc` | Show table of contents (default: `true`) |

### API Documentation

Create interactive API reference documentation with the `api` field:

```md
---
title: "Login"
api: "POST https://api.usegately.com/api/v1/auth/login"
description: "Authenticate a user with email and password"
---

## Request Body

<ParamField body="email" type="string" required>
  The user's email address
</ParamField>

<ParamField body="password" type="string" required>
  The user's password
</ParamField>
```

The CLI automatically:
- Extracts the HTTP method (`POST`)
- Extracts the endpoint path (`/api/v1/auth/login`)
- Extracts the base URL (`https://api.usegately.com`)
- Marks the article as `api_reference` type
- Enables the interactive "Try It" button in your help center

You can also set `article_type` in the config for entire directories:

```json
{
  "path": "api-reference/**/*.mdx",
  "folder": "API Reference",
  "category": "Authentication",
  "article_type": "api_reference",
  "publish": true
}
```

## Icons

All icons use [Hugeicons](https://hugeicons.com) via [Iconify](https://iconify.design) format:

```
hugeicons:icon-name
```

### Auto-fix

When you run `gately push`, invalid icon names are **automatically fixed** in your source files using the best match from the local icon dataset:

```
✓ fixed icon  hugeicons:rocket-1 → hugeicons:rocket-01  docs/quickstart.md
```

Use `--no-fix` to disable this and just report instead.

### Validate before pushing

```bash
gately validate
```

Checks all files and reports issues without making any changes:

```
  docs/quickstart.md ✗ [icon] "hugeicons:flash-1" is not a valid hugeicons icon
    → change to hugeicons:flash

  docs/sdk/javascript.mdx ⚠ [slug] Missing slug — will be auto-generated from title

✓ OpenAPI spec looks good  (42 endpoints)

2 errors  1 warning
```

`gately validate` exits with code 1 if there are errors — works in CI.

## OpenAPI spec

Add an OpenAPI spec to your config to enable the interactive API reference page in your help center:

```json
{
  "openapi": "openapi.json"
}
```

The spec (JSON or YAML) is uploaded to Gately on every `gately push` and served dynamically per project. Users can enter their API key directly in the playground and fire live requests.

`gately validate` also checks your spec for common issues:
- Missing `info.title` / `info.version`
- No servers defined
- No paths defined
- No security schemes

## CI/CD

```yaml
# .github/workflows/docs.yml
name: Sync docs
on:
  push:
    branches: [main]
    paths: ['docs/**']

jobs:
  sync:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npx @gately/cli format --check
      - run: npx @gately/cli validate
      - run: npx @gately/cli push
        env:
          GATELY_API_KEY: ${{ secrets.GATELY_API_KEY }}
```

The `format --check` command ensures all files are properly formatted before pushing.

## Formatting

The CLI includes a formatter to clean and normalize your markdown/MDX files:

```bash
# Format all files
gately format

# Check if files need formatting (useful in CI)
gately format --check
```

The formatter:
- Normalizes line endings to `\n`
- Removes trailing whitespace
- Removes excessive blank lines (max 2 consecutive)
- Ensures proper spacing around headings, code blocks, and lists
- Ensures single newline at end of file
- Normalizes frontmatter formatting

Run `gately format` before pushing to ensure clean, consistent content.

## How it works

1. Reads `gately.config.json` to find doc sources
2. Parses frontmatter from each `.md` / `.mdx` file
3. Validates icons against local Hugeicons data — auto-fixes invalid names in source files
4. Resolves the Folder → Category → Subcategory hierarchy (creates missing items, updates icons)
5. Upserts articles by slug — creates new ones, updates existing ones
6. Uploads OpenAPI spec if configured

## Supported file types

Both `.md` and `.mdx` are fully supported. Use glob patterns to match both:

```json
{ "path": "docs/**/*.{md,mdx}" }
```

MDX components and custom block syntax (callouts, tabs, steps, cards, accordions) are parsed and converted to Gately's rich content format automatically.
