npm package: @omni-co/model-local-editor
Description: CLI tool for local development of Omni YAML models with file system synchronization
Latest version: 0.2.0

# omni-yaml-sync

CLI tool for local development of Omni YAML models with real-time file system synchronization.

> **⚠️ BETA SOFTWARE**
> This tool is currently in beta and under active development. While functional, you may encounter bugs or unexpected behavior. Please report any issues you find.

## Features

- 🔄 **Real-time sync**: Automatically sync local YAML file changes to Omni
- 🌿 **Branch support**: Work with Omni branches for isolated development
- 🔒 **Safety checks**: Prevents accidental overwrites with modelId validation
- 🔔 **Desktop notifications**: Get notified of sync status, conflicts, and errors
- 📝 **Conflict detection**: Tracks file hashes to detect and warn about conflicts
- 🎨 **Colored output**: Clear, colorful terminal output for better readability

## Installation

```bash
npm install -g @omni-co/model-local-editor
```

## Prerequisites

- Node.js >= 16.0.0
- An Omni API key (set as `OMNI_API_KEY` environment variable)

## Quick Start

### 1. Set up your environment variables

```bash
export OMNI_API_KEY="your-api-key-here"
export OMNI_BASE_URL="https://my-org.omniapp.co"  # or your Omni instance URL
```

For persistence, add these to your `~/.bashrc`, `~/.zshrc`, or equivalent.

### 2. Initialize a directory

```bash
# Initialize with a specific model and branch
omni-sync init <model-id> --branch my-feature-branch --create-branch
```

This creates a `.omni-sync.json` file that tracks your sync configuration.

### 3. Start syncing

```bash
# Start watching for changes and syncing
omni-sync start <model-id>
```

The tool will:
- Fetch all YAML files from Omni
- Watch for local file changes
- Automatically push changes to Omni
- Re-fetch server-formatted YAML after successful updates

## Usage

### Commands

#### `omni-sync init`

Initialize a directory for syncing (creates `.omni-sync.json`).

```bash
omni-sync init <model-id> [options]
```

**Options:**
- `-b, --branch <name>`: Branch name to sync (REQUIRED unless using `--dangerously-edit-shared-model`)
- `--create-branch`: Create the branch if it doesn't exist
- `-d, --dir <directory>`: Directory to initialize (default: current directory)
- `-m, --mode <mode>`: IDE mode: `combined` or `extension` (default: `combined`)
- `--dangerously-edit-shared-model`: **⚠️ NOT RECOMMENDED** - Allow editing the shared model directly without a branch. This bypasses branch isolation and can affect all users of the model. Always use branches for development.

**Examples:**

```bash
# Initialize with existing branch
omni-sync init abc-123-def --branch my-branch

# Initialize and create new branch
omni-sync init abc-123-def --branch my-feature --create-branch

# Initialize in specific directory
omni-sync init abc-123-def --branch main --dir ./my-omni-model
```

#### `omni-sync start`

Start syncing a model to the local directory.

```bash
omni-sync start <model-id> [options]
```

**Options:**
- `-b, --branch <name>`: Branch name to sync (REQUIRED unless using `--dangerously-edit-shared-model`)
- `--create-branch`: Create the branch if it doesn't exist
- `-d, --dir <directory>`: Directory to sync to (default: current directory)
- `-m, --mode <mode>`: IDE mode: `combined` or `extension` (default: `combined`)
- `--override`: Override existing `.omni-sync.json` configuration
- `--dangerously-edit-shared-model`: **⚠️ NOT RECOMMENDED** - Allow editing the shared model directly without a branch. This bypasses branch isolation and can affect all users of the model. Always use branches for development.

**Examples:**

```bash
# Start syncing (uses existing .omni-sync.json)
omni-sync start abc-123-def

# Start syncing with different branch (requires --override)
omni-sync start abc-123-def --branch other-branch --override

# Start syncing and create branch if needed
omni-sync start abc-123-def --branch new-feature --create-branch --override
```

**Safety Features:**

The `start` command will **fail** if:
- `.omni-sync.json` doesn't exist (run `init` first)
- The modelId in `.omni-sync.json` doesn't match the provided modelId (use `--override` to change)

This prevents accidentally overwriting the wrong model's files.

#### `omni-sync branches`

List all branches for a model.

```bash
omni-sync branches <model-id>
```

**Example:**

```bash
omni-sync branches abc-123-def
```

### Environment Variables

- `OMNI_API_KEY` (required): Your Omni API key
- `OMNI_BASE_URL` (required): Base URL for Omni API (e.g., `https://my-org.omniapp.co`)
- `DEBUG` (optional): Set to any value to enable debug logging

### Configuration File (`.omni-sync.json`)

The `.omni-sync.json` file is automatically created and managed by the tool. It contains:

```json
{
  "modelId": "abc-123-def",
  "branchId": "xyz-789-ghi",
  "branchName": "my-feature-branch",
  "mode": "combined",
  "lastSync": "2025-01-15T10:30:00.000Z",
  "fileHashes": {
    "views/users.view": "a1b2c3d4...",
    "topics/analytics.topic": "e5f6g7h8..."
  }
}
```

**⚠️ Important:** Do not manually edit this file unless you know what you're doing.

## How It Works

1. **Initialization**: Fetches the complete model YAML from Omni and writes it to local files with `.yaml` extension
2. **File Extension**: All files are saved locally with `.yaml` extension for better IDE support (e.g., `views/users.view.yaml` instead of `views/users.view`)
3. **File Watching**: Monitors local `*.yaml` files for changes
4. **Debouncing**: Waits 500ms after the last change before syncing
5. **Upload**: POSTs the changed file to Omni's API (automatically removes `.yaml` extension)
6. **Re-fetch**: If successful, fetches the server-formatted version
7. **Conflict Check**: Only updates local file if no new changes were made during the sync
8. **Hash Tracking**: Updates file hashes to track sync state

### File Extensions

For better IDE support with YAML syntax highlighting, all files are stored locally with a `.yaml` extension appended:

- `views/users.view` → `views/users.view.yaml`
- `topics/analytics.topic` → `topics/analytics.topic.yaml`

The tool automatically handles the conversion when syncing with the API.

## Notifications

The tool sends desktop notifications for:

- ✅ **Successful sync**: When a file is successfully synced
- ⚠️ **Conflicts**: When remote changes conflict with local edits
- ❌ **Errors**: Authentication failures, network errors, API errors (includes the actual error message from the API)
- 🔒 **Permission issues**: File system permission errors

### Enabling Notifications on macOS

If you're not seeing desktop notifications, you need to enable them for your terminal:

1. Open **System Settings** → **Notifications**
2. Find your terminal app (Terminal, iTerm2, etc.) in the list
3. Enable **Allow Notifications**
4. Make sure **Do Not Disturb** is turned off

You can verify notifications are working by running the tool with `DEBUG=1`:
```bash
DEBUG=1 omni-sync start <model-id> --branch <branch>
```

Look for debug messages like:
```
DEBUG: Sending notification: Omni Sync Error - Failed to sync model.yaml
```

## Error Handling

### Authentication Errors

If you see authentication errors:

1. Check that `OMNI_API_KEY` is set correctly
2. Verify the API key is valid and not expired
3. Ensure you have proper permissions for the model/branch

### Network Errors

The tool will notify you of network timeouts and connection issues. It does not automatically retry, so you may need to restart the sync.

### Sync Conflicts

If the server rejects your changes (e.g., due to validation errors), you'll receive a notification with the error message. Fix the issue and save the file again to retry.

### Model ID Mismatch

```
Error: Model ID mismatch: .omni-sync.json has abc-123, but you requested xyz-789
```

**Solution**: Use `--override` if you want to change models in this directory, or use a different directory.

## Development

```bash
# Clone the repository
git clone <repo-url>
cd omni-yaml-sync

# Install dependencies
npm install

# Build
npm run build

# Run locally
node dist/cli.js start <model-id> --branch <branch-name>
```

## License

MIT