dx-forge 0.1.3

Production-ready VCS and orchestration engine for DX tools with Git-like versioning, dual-watcher architecture, traffic branch system, and component injection
Documentation
# Using dx-forge as a library in your DX tools


This document explains how to use the `dx-forge` crate from other DX tools. It covers adding the crate as a dependency, the most useful APIs (orchestrator, watchers, storage), examples for common integration patterns, and build tips for development.

Target audience: authors of DX tools (plugins, CLIs, and integrations) who want to reuse Forge's orchestration, detection, and storage pieces without running the CLI binary.

---

## Quick summary


- Crate name: `dx-forge` (see `Cargo.toml` at the repository root).  
- Rust Edition: 2021, minimum toolchain: 1.70.
- No special cargo features are required to use the core APIs.

You can depend on `dx-forge` from crates.io (if published), a Git repository, or locally during development.

## Add as a dependency


Choose one option depending on whether you depend on a released crate or a local copy:

- crates.io (if published):

```toml
[dependencies]
dx-forge = "0.0.2"
```

- Git dependency (useful for tracking `main` or a branch/tag):

```toml
[dependencies]
dx-forge = { git = "https://github.com/najmus-sakib-hossain/forge", branch = "main" }
```

- Local path dependency (recommended while hacking locally):

```toml
[dependencies]
dx-forge = { path = "../forge" }
```

If you include `dx-forge` in a workspace, prefer the `path` or workspace member approach so versions stay in sync.

---

## What you get (high-level API)


`dx-forge` exposes a number of modules and high-level types designed to be reused by DX tools. The main entry points you will likely need:

- Orchestration
  - `Orchestrator`, `DxTool`, `ExecutionContext`, `ToolOutput`, `OrchestratorConfig`

- Change detection
  - `DualWatcher`, `FileWatcher`, `LspWatcher`, `FileChange`, `ChangeKind`, `ChangeSource`

- Storage and persistence
  - `Database`, `OperationLog`, blob helpers, `time_travel` utilities

- CRDT primitives
  - `Operation`, `OperationType`, `Position`

- Patterns, injection and tooling helpers
  - `PatternDetector`, `InjectionManager`, `ToolRegistry`, `ToolInfo`

These types are re-exported from the crate root so you can import them like `use dx_forge::Orchestrator;`.

---

## Example 1 — Implement a small DX tool and register with the Orchestrator


This is the canonical way to build a small dx-tool that cooperates with Forge's orchestrator.

```rust
use anyhow::Result;
use dx_forge::{Orchestrator, DxTool, ExecutionContext, ToolOutput};

struct MyDxTool;

impl DxTool for MyDxTool {
    fn name(&self) -> &str { "dx-mytool" }
    fn version(&self) -> &str { "0.1.0" }
    fn priority(&self) -> u32 { 50 }

    fn execute(&mut self, ctx: &ExecutionContext) -> Result<ToolOutput> {
        // Inspect changed files from the execution context
        for f in &ctx.changed_files {
            println!("Tool sees changed file: {}", f.display());
        }

        // Do work (formatting, injection, codegen, etc.)
        Ok(ToolOutput::success())
    }
}

fn main() -> Result<()> {
    // Create orchestrator for the repository root
    let mut orch = Orchestrator::new(".")?;

    // Register your tool
    orch.register_tool(Box::new(MyDxTool))?;

    // Execute all registered tools
    let outputs = orch.execute_all()?;
    println!("Executed {} tools", outputs.len());
    Ok(())
}
```

Notes:
- `Orchestrator::new` takes a repository root (path where `.dx/forge` will live).
- Tools are executed synchronously by default in priority order; `OrchestratorConfig` can be used to tune parallelism.

---

## Example 2 — Subscribe to file changes with `DualWatcher` (recommended)


Use the `DualWatcher` when you want your tool to react to live edits (LSP preferred) and fallback to file system events.

```rust
use anyhow::Result;
use dx_forge::{DualWatcher, ChangeKind};

#[tokio::main]

async fn main() -> Result<()> {
    // Create a watcher
    let mut watcher = DualWatcher::new()?;

    // Start watching the repository root (async)
    watcher.start(".").await?;

    // Subscribe to change events
    let mut rx = watcher.receiver();

    // Loop and handle changes
    loop {
        match rx.recv().await {
            Ok(change) => {
                match change.kind {
                    ChangeKind::Created => println!("Created: {}", change.path.display()),
                    ChangeKind::Modified => println!("Modified: {}", change.path.display()),
                    ChangeKind::Deleted => println!("Deleted: {}", change.path.display()),
                    _ => {}
                }
            }
            Err(_) => break,
        }
    }

    Ok(())
}
```

Use `DualWatcher::analyze_patterns(change)` to run the built-in `PatternDetector` against a change (it reads content when needed).

---

## Caveats & implementation notes


- LSP integration: The `LspWatcher` in this repository contains a lightweight scaffold and example flow (it logs that it is running in "mock mode"). A production integration requires wiring the LSP JSON-RPC stream (or editor integration) into the `LspWatcher::process_lsp_event` hook so that real `textDocument/didChange` events are delivered.

- Async vs sync: `DualWatcher` and many watcher-related APIs are asynchronous and expect a Tokio runtime (`#[tokio::main]` or equivalent). The `Orchestrator` and `DxTool` trait are synchronous in the current implementation — if your tool needs async work, run a Tokio runtime inside your tool or adapt the orchestrator to execute async tasks.

- Optional pieces: If you only need pattern detection or injection (for example, in a small in-editor helper), you can depend only on `PatternDetector` and `InjectionManager` (they are exported by the crate) to keep your dependency footprint smaller.


## Example 3 — Persist operations with `OperationLog`


Forge provides an `OperationLog` backed by a `Database` (SQLite). Use it to persist operation-level edits.

```rust
use anyhow::Result;
use std::sync::Arc;
use dx_forge::storage::Database;
use dx_forge::storage::OperationLog;
use dx_forge::crdt::{Operation, OperationType};

fn main() -> Result<()> {
    // Create/open the database under the forge path
    let forge_path = std::path::Path::new(".dx/forge");
    let db = Database::new(forge_path)?;
    db.initialize()?;

    // Create an OperationLog writer
    let oplog = OperationLog::new(Arc::new(db));

    // Build an operation (example: file create)
    let op = Operation::new(
        "src/example.rs".to_string(),
        OperationType::FileCreate { content: "fn main() {}".to_string() },
        "actor-1".to_string(),
    );

    // Append (async persistence happens in a background thread)
    let appended = oplog.append(op)?;
    println!("operation appended: {}", appended);

    Ok(())
}
```

Notes:
- `Database::new` expects the `forge_path` (e.g. `.dx/forge`). Call `initialize()` once to create tables.
- `OperationLog::append` enqueues operations for background persistence and returns whether the op was new.

---

## Logging and debug


Forge uses `tracing`/`tracing-subscriber`. To see debug output from forge components, set the `RUST_LOG` environment variable and initialize a subscriber in your binary (or rely on the crate's own initialization when using the CLI).

Example (run-time):

```bash
RUST_LOG=dx_forge=debug cargo run --bin your-tool
```

If you embed `dx-forge` in a larger application, initialize a `tracing-subscriber` early in `main`:

```rust
use tracing_subscriber::fmt::layer;
use tracing_subscriber::EnvFilter;

tracing_subscriber::registry()
    .with(EnvFilter::from_default_env())
    .with(layer())
    .init();
```

---

## API Quick Reference


- `Orchestrator::new(repo_root)` — create an orchestrator for the repo
- `orchestrator.register_tool(Box::new(your_tool))` — register a `DxTool`
- `orchestrator.execute_all()` — run registered tools
- `DualWatcher::new()` / `start(path)` / `receiver()` — watch and subscribe to file changes
- `Database::new(&forge_path)` / `db.initialize()` — initialize storage
- `OperationLog::new(Arc::new(db))` / `oplog.append(op)` — persist operations

Refer to the in-code docs and the `src/` module re-exports for a full list of types.

---

## Build tips & platform notes


- Windows: building the project may require `pkg-config` and Visual C++ Build Tools for native dependencies (libgit2). If you run into `libgit2-sys` or `pkg-config` errors, install `pkg-config` (choco/scoop/MSYS2) and the MSVC toolchain.
- Use local `path` dependencies while developing tools together with `dx-forge` for faster iteration.
- If you only need detection (pattern matching and injection) but not persistence, consider using `PatternDetector` and `InjectionManager` directly to avoid pulling large native dependencies.

---

## Contributing & support


If you need extra library-level helper functions (for example, utilities to run the orchestrator as a long-running service, or more ergonomic watcher adapters) please open an issue or a PR in the repository.

License: MIT OR Apache-2.0