Add local CLI #144
3 changed files with 141 additions and 225 deletions
Improve
commit
450e62dd25
|
|
@ -15,9 +15,7 @@ LABEL org.opencontainers.image.source="https://github.com/schmelczer/vault-link"
|
||||||
LABEL org.opencontainers.image.licenses="MIT"
|
LABEL org.opencontainers.image.licenses="MIT"
|
||||||
LABEL org.opencontainers.image.authors="andras@schmelczer.dev"
|
LABEL org.opencontainers.image.authors="andras@schmelczer.dev"
|
||||||
|
|
||||||
|
COPY --from=builder /build/local-client-cli/dist/cli.js /app/cli.js
|
||||||
|
|
||||||
COPY --from=builder --chown=vaultlink:vaultlink /build/local-client-cli/dist/cli.js /app/cli.js
|
|
||||||
|
|
||||||
WORKDIR /vault
|
WORKDIR /vault
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,57 +1,23 @@
|
||||||
# VaultLink Local CLI
|
# VaultLink Local CLI
|
||||||
|
|
||||||
A standalone command-line interface for syncing VaultLink vaults to your local filesystem. This CLI wraps the VaultLink sync client and provides file watching capabilities for real-time synchronization.
|
Standalone CLI for syncing VaultLink vaults to local filesystem with real-time bidirectional sync and file watching.
|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
- Real-time bidirectional sync between local filesystem and VaultLink server
|
|
||||||
- File watching with automatic change detection
|
|
||||||
- Cross-platform support (Linux, macOS, Windows)
|
|
||||||
- Configuration via command-line arguments or JSON file
|
|
||||||
- Comprehensive error handling and logging
|
|
||||||
- Graceful shutdown on SIGINT/SIGTERM
|
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
### Using Docker (Recommended)
|
### Docker (Recommended)
|
||||||
|
|
||||||
The easiest way to run VaultLink CLI is using Docker:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker pull ghcr.io/schmelczer/vault-link-cli:latest
|
docker pull ghcr.io/schmelczer/vault-link-cli:latest
|
||||||
|
|
||||||
# Run with all options via command line
|
|
||||||
docker run -v /path/to/vault:/vault \
|
docker run -v /path/to/vault:/vault \
|
||||||
ghcr.io/schmelczer/vault-link-cli:latest \
|
ghcr.io/schmelczer/vault-link-cli:latest \
|
||||||
-l /vault \
|
-l /vault \
|
||||||
-r https://sync.example.com \
|
-r wss://sync.example.com \
|
||||||
-t your-auth-token \
|
-t your-auth-token \
|
||||||
-v default
|
-v default
|
||||||
|
|
||||||
# Or use a config file
|
|
||||||
docker run -v /path/to/vault:/vault \
|
|
||||||
-v /path/to/config.json:/config.json \
|
|
||||||
ghcr.io/schmelczer/vault-link-cli:latest \
|
|
||||||
-l /vault \
|
|
||||||
-c /config.json
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using Docker Compose
|
### npm
|
||||||
|
|
||||||
```yaml
|
|
||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
vaultlink-cli:
|
|
||||||
image: ghcr.io/schmelczer/vault-link-cli:latest
|
|
||||||
volumes:
|
|
||||||
- ./vault:/vault
|
|
||||||
- ./config.json:/config.json
|
|
||||||
command: -l /vault -c /config.json
|
|
||||||
restart: unless-stopped
|
|
||||||
```
|
|
||||||
|
|
||||||
### From npm Package
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm install -g @schmelczer/local-client-cli
|
npm install -g @schmelczer/local-client-cli
|
||||||
|
|
@ -69,220 +35,172 @@ node dist/cli.js --help
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
### Basic Usage
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
vaultlink \
|
vaultlink \
|
||||||
--local-path ./my-vault \
|
--local-path ./vault \
|
||||||
--remote-uri https://sync.example.com \
|
--remote-uri wss://sync.example.com \
|
||||||
--token your-auth-token \
|
--token your-auth-token \
|
||||||
--vault-name default
|
--vault-name default
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using a Configuration File
|
## Options
|
||||||
|
|
||||||
Create a `config.json` file:
|
### Required
|
||||||
|
|
||||||
```json
|
| Option | Description |
|
||||||
{
|
|--------|-------------|
|
||||||
"remoteUri": "https://sync.example.com",
|
| `-l, --local-path <path>` | Local directory to sync |
|
||||||
"token": "your-auth-token",
|
| `-r, --remote-uri <uri>` | Remote server WebSocket URI (ws:// or wss://) |
|
||||||
"vaultName": "default",
|
| `-t, --token <token>` | Authentication token |
|
||||||
"syncConcurrency": 1,
|
| `-v, --vault-name <name>` | Vault name on server |
|
||||||
"maxFileSizeMB": 10,
|
|
||||||
"ignorePatterns": [".git/**", "*.tmp"],
|
|
||||||
"webSocketRetryIntervalMs": 3500
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Then run:
|
### Optional
|
||||||
|
|
||||||
```bash
|
| Option | Default | Description |
|
||||||
vaultlink --local-path ./my-vault --config config.json
|
|--------|---------|-------------|
|
||||||
```
|
| `--sync-concurrency <number>` | `1` | Concurrent sync operations |
|
||||||
|
| `--max-file-size-mb <number>` | `10` | Maximum file size in MB |
|
||||||
|
| `--ignore-pattern <pattern>` | - | Glob pattern to ignore (repeatable) |
|
||||||
|
| `--websocket-retry-interval-ms <ms>` | `3500` | WebSocket reconnection interval |
|
||||||
|
| `--log-level <level>` | `INFO` | Log level: DEBUG, INFO, WARNING, ERROR |
|
||||||
|
| `-h, --help` | - | Show help |
|
||||||
|
| `-V, --version` | - | Show version |
|
||||||
|
|
||||||
### Command-Line Options
|
### Auto-Ignored Patterns
|
||||||
|
|
||||||
#### Required Arguments
|
- `.vaultlink/**` - Internal sync metadata
|
||||||
|
|
||||||
- `-l, --local-path <PATH>` - Local directory path to sync
|
|
||||||
- `-r, --remote-uri <URI>` - Remote server URI (unless using --config)
|
|
||||||
- `-t, --token <TOKEN>` - Authentication token (unless using --config)
|
|
||||||
- `-v, --vault-name <NAME>` - Vault name (unless using --config)
|
|
||||||
|
|
||||||
#### Optional Arguments
|
|
||||||
|
|
||||||
- `-c, --config <FILE>` - Load configuration from JSON file
|
|
||||||
- `--sync-concurrency <NUM>` - Number of concurrent sync operations (default: 1)
|
|
||||||
- `--max-file-size-mb <NUM>` - Maximum file size in MB (default: 10)
|
|
||||||
- `--ignore-pattern <PATTERN>` - Pattern to ignore (can be used multiple times)
|
|
||||||
- `--websocket-retry-interval-ms <NUM>` - WebSocket retry interval in ms (default: 3500)
|
|
||||||
- `-h, --help` - Print help message
|
|
||||||
- `-V, --version` - Print version
|
|
||||||
|
|
||||||
### Ignore Patterns
|
|
||||||
|
|
||||||
Ignore patterns support glob syntax. The CLI automatically ignores:
|
|
||||||
|
|
||||||
- `.vaultlink/**` - Internal sync data directory
|
|
||||||
- `.git/**` - Git repository files
|
- `.git/**` - Git repository files
|
||||||
|
|
||||||
You can add additional patterns:
|
### Examples
|
||||||
|
|
||||||
|
Basic usage:
|
||||||
```bash
|
```bash
|
||||||
vaultlink \
|
vaultlink -l ./vault -r wss://sync.example.com -t token123 -v default
|
||||||
--local-path ./my-vault \
|
```
|
||||||
--remote-uri https://sync.example.com \
|
|
||||||
--token mytoken \
|
With ignore patterns:
|
||||||
--vault-name default \
|
```bash
|
||||||
|
vaultlink -l ./vault -r wss://sync.example.com -t token123 -v default \
|
||||||
--ignore-pattern "*.tmp" \
|
--ignore-pattern "*.tmp" \
|
||||||
--ignore-pattern ".DS_Store" \
|
--ignore-pattern ".DS_Store" \
|
||||||
--ignore-pattern "node_modules/**"
|
--ignore-pattern "node_modules/**"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
With debug logging:
|
||||||
|
```bash
|
||||||
|
vaultlink -l ./vault -r wss://sync.example.com -t token123 -v default \
|
||||||
|
--log-level DEBUG
|
||||||
|
```
|
||||||
|
|
||||||
## Docker Deployment
|
## Docker Deployment
|
||||||
|
|
||||||
### Self-Hosting with Docker
|
### Docker Run
|
||||||
|
|
||||||
The CLI is designed to run as a long-lived container:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create a vault directory
|
|
||||||
mkdir -p ./vault
|
|
||||||
|
|
||||||
# Create config.json
|
|
||||||
cat > config.json <<EOF
|
|
||||||
{
|
|
||||||
"remoteUri": "https://your-server.com",
|
|
||||||
"token": "your-token",
|
|
||||||
"vaultName": "default"
|
|
||||||
}
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Run the container
|
|
||||||
docker run -d \
|
docker run -d \
|
||||||
--name vaultlink-sync \
|
--name vaultlink-sync \
|
||||||
--restart unless-stopped \
|
--restart unless-stopped \
|
||||||
-v $(pwd)/vault:/vault \
|
-v $(pwd)/vault:/vault \
|
||||||
-v $(pwd)/config.json:/config.json \
|
|
||||||
ghcr.io/schmelczer/vault-link-cli:latest \
|
ghcr.io/schmelczer/vault-link-cli:latest \
|
||||||
-l /vault -c /config.json
|
-l /vault \
|
||||||
|
-r wss://your-server.com \
|
||||||
|
-t your-token \
|
||||||
|
-v default
|
||||||
```
|
```
|
||||||
|
|
||||||
### Kubernetes Deployment
|
### Docker Compose
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: apps/v1
|
services:
|
||||||
kind: Deployment
|
vaultlink-cli:
|
||||||
metadata:
|
|
||||||
name: vaultlink-cli
|
|
||||||
spec:
|
|
||||||
replicas: 1
|
|
||||||
selector:
|
|
||||||
matchLabels:
|
|
||||||
app: vaultlink-cli
|
|
||||||
template:
|
|
||||||
metadata:
|
|
||||||
labels:
|
|
||||||
app: vaultlink-cli
|
|
||||||
spec:
|
|
||||||
containers:
|
|
||||||
- name: vaultlink-cli
|
|
||||||
image: ghcr.io/schmelczer/vault-link-cli:latest
|
image: ghcr.io/schmelczer/vault-link-cli:latest
|
||||||
args:
|
volumes:
|
||||||
|
- ./vault:/vault
|
||||||
|
command:
|
||||||
- "-l"
|
- "-l"
|
||||||
- "/vault"
|
- "/vault"
|
||||||
- "-c"
|
- "-r"
|
||||||
- "/config/config.json"
|
- "wss://sync.example.com"
|
||||||
volumeMounts:
|
- "-t"
|
||||||
- name: vault
|
- "your-token"
|
||||||
mountPath: /vault
|
- "-v"
|
||||||
- name: config
|
- "default"
|
||||||
mountPath: /config
|
restart: unless-stopped
|
||||||
volumes:
|
|
||||||
- name: vault
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: vaultlink-pvc
|
|
||||||
- name: config
|
|
||||||
configMap:
|
|
||||||
name: vaultlink-config
|
|
||||||
```
|
```
|
||||||
|
|
||||||
## How It Works
|
## Health Monitoring
|
||||||
|
|
||||||
1. **Initialization**: The CLI creates a `.vaultlink` directory in your local path to store sync metadata and state
|
The Docker container includes a built-in healthcheck that monitors the WebSocket connection to the server.
|
||||||
2. **Initial Sync**: On first run, all local files are synced to the server
|
|
||||||
3. **File Watching**: The CLI watches for file system changes using Node's `fs.watch` API
|
### Healthcheck Configuration
|
||||||
4. **Real-time Sync**: Any local changes are automatically synced to the server, and server changes are applied locally
|
|
||||||
5. **Graceful Shutdown**: On Ctrl+C or termination signals, the CLI waits for pending operations to complete
|
- **Interval**: 30 seconds
|
||||||
|
- **Timeout**: 10 seconds
|
||||||
|
- **Start period**: 30 seconds (grace period for initial connection)
|
||||||
|
- **Retries**: 3 failed checks before marking unhealthy
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
The CLI writes connection status to `/tmp/vaultlink-health.json` every 10 seconds and whenever the WebSocket connection status changes. The healthcheck script verifies:
|
||||||
|
|
||||||
|
1. The health file exists
|
||||||
|
2. The status is recent (updated within last 30 seconds)
|
||||||
|
3. The WebSocket connection is active
|
||||||
|
|
||||||
|
### Checking Container Health
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# View health status
|
||||||
|
docker ps
|
||||||
|
|
||||||
|
# View detailed health check logs
|
||||||
|
docker inspect --format='{{json .State.Health}}' vaultlink-sync | jq
|
||||||
|
```
|
||||||
|
|
||||||
|
### Custom Healthcheck
|
||||||
|
|
||||||
|
To override the default healthcheck in docker-compose.yml:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
vaultlink-cli:
|
||||||
|
image: ghcr.io/schmelczer/vault-link-cli:latest
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "node", "/app/healthcheck.js"]
|
||||||
|
interval: 15s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 5
|
||||||
|
start_period: 20s
|
||||||
|
```
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Building
|
Build:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run build
|
npm run build
|
||||||
# or from the parent folder, run
|
# or from the parent folder, run
|
||||||
docker build -f local-client-cli/Dockerfile .
|
docker build -f local-client-cli/Dockerfile .
|
||||||
```
|
```
|
||||||
|
|
||||||
### Development Mode with Watch
|
Test:
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running Tests
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm test
|
npm test
|
||||||
```
|
```
|
||||||
|
|
||||||
Tests cover:
|
Docker build:
|
||||||
- Filesystem operations (read, write, delete, rename, etc.)
|
```bash
|
||||||
- CLI argument parsing and validation
|
cd frontend
|
||||||
- Cross-platform path handling
|
docker build -f local-client-cli/Dockerfile -t vault-link-cli:test .
|
||||||
- Error handling
|
```
|
||||||
|
|
||||||
## Architecture
|
## How It Works
|
||||||
|
|
||||||
The CLI consists of several key components:
|
1. Creates `.vaultlink` directory for sync metadata
|
||||||
|
2. Performs initial sync of local files to server
|
||||||
|
3. Watches filesystem for changes using Node's `fs.watch`
|
||||||
|
4. Syncs changes bidirectionally in real-time
|
||||||
|
5. Handles graceful shutdown on SIGINT/SIGTERM
|
||||||
|
|
||||||
- **`cli.ts`**: Main entry point, orchestrates initialization and lifecycle
|
## License
|
||||||
- **`node-filesystem.ts`**: Node.js filesystem adapter implementing the `FileSystemOperations` interface with cross-platform path normalization
|
|
||||||
- **`file-watcher.ts`**: Watches filesystem changes and triggers sync operations
|
|
||||||
- **`args.ts`**: Command-line argument parser using `commander` library
|
|
||||||
- **`config-loader.ts`**: JSON configuration file loader and merger
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
- **commander**: Industry-standard CLI argument parsing with built-in help generation and validation
|
|
||||||
- **sync-client**: Core VaultLink synchronization library
|
|
||||||
|
|
||||||
### Path Handling
|
|
||||||
|
|
||||||
The filesystem adapter ensures cross-platform compatibility by:
|
|
||||||
- **API Contract**: Always accepts forward slashes (`/`) as input
|
|
||||||
- **API Contract**: Always returns forward slashes (`/`) as output
|
|
||||||
- **Implementation**: Converts between forward slashes and platform-native separators internally
|
|
||||||
- **Windows Support**: Automatically converts `/` to `\` on Windows for filesystem operations
|
|
||||||
|
|
||||||
## Error Handling
|
|
||||||
|
|
||||||
The CLI provides robust error handling:
|
|
||||||
|
|
||||||
- Invalid arguments result in clear error messages and exit code 1
|
|
||||||
- Connection failures are reported before starting sync
|
|
||||||
- File operation errors are logged with context
|
|
||||||
- Graceful shutdown ensures no data loss on termination
|
|
||||||
|
|
||||||
## Cross-Platform Support
|
|
||||||
|
|
||||||
The CLI is built with cross-platform compatibility:
|
|
||||||
|
|
||||||
- Uses Node's `path` module for platform-agnostic path handling
|
|
||||||
- Automatically detects platform line endings (CRLF on Windows, LF on Unix)
|
|
||||||
- File watching works on all platforms through Node's native `fs.watch`
|
|
||||||
- Compiled with Webpack for Node target, ensuring broad compatibility
|
|
||||||
- Path normalization ensures consistent behavior across Windows, macOS, and Linux
|
|
||||||
|
|
||||||
|
MIT
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue