# Portable Toolkit

`portable-toolkit` is a collection of portable command-line tools for daily development, DevOps, and AI client configuration workflows.

It currently includes:

| Tool | Description |
| --- | --- |
| `git_commit_generator` | Generates Conventional Commits-style commit messages from staged Git diffs by calling an AI API |
| `mcp_sync` | Syncs one shared `mcpServers.json` file to global MCP configuration files for multiple AI clients |
| `file_cipher` | Encrypts and decrypts files with AES-128-GCM |
| `get_ip_info` | Fetches and prints public IP information from `https://ipinfo.io/json` |

## Requirements

- Rust 2021 toolchain
- Git, required by `git_commit_generator` to read staged changes
- AI API configuration, required only by `git_commit_generator`
- `cargo-zigbuild`, MinGW, and Rust targets, required only for cross-platform builds

## Quick Start

```bash
# Build all binaries
cargo build

# Build release binaries
cargo build --release

# Run the default tool, git_commit_generator
cargo run

# Run a specific tool
cargo run --bin mcp_sync -- --help
cargo run --bin file_cipher -- --help
cargo run --bin get_ip_info
```

Release binaries are generated under `target/release/`.

## git_commit_generator

`git_commit_generator` reads staged changes in the current Git repository:

```bash
git diff --cached
```

It then calls the configured AI API and generates a commit message. By default, it only prints a ready-to-run `git commit -m "..."` command. With `--auto`, it executes the commit directly.

### Configuration

Create a `.env` file in the project root:

```dotenv
AI_API_KEY="your_api_key"
AI_API_URL="https://api.example.com/v1/chat/completions"
AI_MODEL="model-name"
```

| Variable | Description |
| --- | --- |
| `AI_API_KEY` | API key for the AI service |
| `AI_API_URL` | AI API endpoint URL |
| `AI_MODEL` | Model name sent in the request body |

### Usage

```bash
# 1. Stage changes
git add .

# 2. Generate a commit command
cargo run --bin git_commit_generator

# 3. Generate and execute git commit automatically
cargo run --bin git_commit_generator -- --auto

# 4. Set the AI API timeout in milliseconds
cargo run --bin git_commit_generator -- --timeout 60000
```

You can also run the release binary directly:

```bash
./target/release/git_commit_generator
./target/release/git_commit_generator --auto
```

## mcp_sync

`mcp_sync` syncs one source `mcpServers.json` file to global configuration files for multiple AI clients. The default source path is:

```text
~/data/config/ai_conf/mcpServers.json
```

### Supported Clients

| Client | Config File | Format |
| --- | --- | --- |
| `claude` | `~/.claude.json` | JSON |
| `codex` | `~/.codex/config.toml` | TOML |
| `copilot` | `~/.copilot/mcp-config.json` | JSON |
| `gemini` | `~/.gemini/settings.json` | JSON |
| `cursor` | `~/.cursor/mcp.json` | JSON |

The sync preserves unrelated fields in each target configuration file and only replaces the MCP configuration section:

- JSON clients use `mcpServers`
- Codex TOML configuration uses `mcp_servers`

### Usage

```bash
# Sync to all supported clients
cargo run --bin mcp_sync

# Sync to selected clients only
cargo run --bin mcp_sync -- --clients cursor
cargo run --bin mcp_sync -- --clients claude,codex,cursor

# Use a custom source configuration
cargo run --bin mcp_sync -- --config /path/to/mcpServers.json
```

After building, run:

```bash
mcp_sync
mcp_sync --clients cursor
mcp_sync --config /path/to/mcpServers.json
```

## file_cipher

`file_cipher` encrypts and decrypts files with AES-128-GCM. The key must be exactly 16 bytes.

```bash
# Encrypt a file
cargo run --bin file_cipher -- encrypt \
  --input plain.txt \
  --output cipher.bin \
  --key 1234567890123456

# Decrypt a file
cargo run --bin file_cipher -- decrypt \
  --input cipher.bin \
  --output restored.txt \
  --key 1234567890123456
```

Encrypted output format:

```text
12-byte nonce + ciphertext + GCM tag
```

## get_ip_info

`get_ip_info` requests `https://ipinfo.io/json` and prints the response body.

```bash
cargo run --bin get_ip_info

# Release binary
./target/release/get_ip_info
```

## Quality Checks

```bash
# Format code
cargo fmt

# Check formatting
cargo fmt --all -- --check

# Run Clippy
cargo clippy --all-targets --all-features -- -D warnings

# Run tests
cargo test --all --all-features

# Build documentation
RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --all-features
```

## Cross-Platform Builds

The project provides `scripts/install.sh` for local and cross-platform builds. By default, it builds only the current platform and installs binaries to:

```text
~/data/bin
```

```bash
# Build the current platform
cd scripts
./install.sh

# Build all supported platforms
BUILD_MODE=all ./install.sh

# Force cargo-zigbuild
BUILD_CMD=zigbuild ./install.sh

# Debug mode
DEBUG=true ./install.sh
```

Supported platforms:

- `x86_64-apple-darwin`
- `aarch64-apple-darwin`
- `x86_64-unknown-linux-gnu`
- `aarch64-unknown-linux-gnu`
- `x86_64-pc-windows-gnu`

Cross-platform build artifacts are copied to:

```text
target/releases/{platform}/
```

For more details, see [scripts/BUILD.md](scripts/BUILD.md).

## Project Structure

```text
src/
├── bin/
│   ├── file_cipher.rs
│   ├── get_ip_info.rs
│   ├── git_commit_generator.rs
│   └── mcp_sync.rs
├── cipher.rs
├── lib.rs
├── mcp_sync/
└── model/
```

## Notes

- `.env` contains sensitive values, is ignored by `.gitignore`, and must not be committed.
- `git_commit_generator` must run inside a Git repository and requires staged changes.
- `file_cipher` requires a key that is exactly 16 bytes long.
- Podman does not support short image names. Use fully qualified image names if container-related commands are added later.
