diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..9119ebe
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,64 @@
+name: CI
+
+on:
+ push:
+ branches: [ main, master ]
+ pull_request:
+ branches: [ main, master ]
+
+jobs:
+ build:
+ name: ${{ matrix.config }} ${{ matrix.os }} ${{ matrix.arch }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: ubuntu-latest
+ arch: x86_64
+ config: cli
+ - os: ubuntu-24.04-arm
+ arch: arm64
+ config: cli
+ - os: windows-latest
+ arch: x86_64
+ config: cli
+ - os: macos-latest
+ arch: arm64
+ config: cli
+ - os: macos-13
+ arch: x86_64
+ config: cli
+ - os: ubuntu-latest
+ arch: x86_64
+ config: library
+ - os: windows-latest
+ arch: x86_64
+ config: library
+ - os: macos-latest
+ arch: arm64
+ config: library
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install D
+ uses: dlang-community/setup-dlang@v1
+ with:
+ compiler: ldc-latest
+ - name: Build
+ run: dub build --config=${{ matrix.config }} --build=release
+
+ gui-linux:
+ name: gui ubuntu-latest x86_64
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install Qt
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y qt6-base-dev
+ - name: Install D
+ uses: dlang-community/setup-dlang@v1
+ with:
+ compiler: ldc-latest
+ - name: Build GUI
+ run: dub build --config=gui --build=release
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
new file mode 100644
index 0000000..55a73a4
--- /dev/null
+++ b/.github/workflows/release.yml
@@ -0,0 +1,104 @@
+name: Release
+
+on:
+ push:
+ tags: ['v*']
+
+permissions:
+ contents: write
+
+jobs:
+ build:
+ name: Build ${{ matrix.asset }}
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: ubuntu-latest
+ asset: ver-linux-x86_64
+ lib: libver-linux-x86_64.a
+ lib_glob: '*.a'
+ - os: ubuntu-24.04-arm
+ asset: ver-linux-arm64
+ lib: libver-linux-arm64.a
+ lib_glob: '*.a'
+ - os: windows-latest
+ asset: ver-windows-x86_64.exe
+ lib: ver-windows-x86_64.lib
+ lib_glob: '*.lib'
+ - os: macos-latest
+ asset: ver-macos-arm64
+ lib: libver-macos-arm64.a
+ lib_glob: '*.a'
+ - os: macos-13
+ asset: ver-macos-x86_64
+ lib: libver-macos-x86_64.a
+ lib_glob: '*.a'
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install D
+ uses: dlang-community/setup-dlang@v1
+ with:
+ compiler: ldc-latest
+ - name: Build CLI
+ run: dub build --config=cli --build=release
+ - name: Build library
+ run: dub build --config=library --build=release
+ - name: Stage artifacts
+ shell: bash
+ run: |
+ set -euo pipefail
+ shopt -s nullglob
+ if [[ "${{ runner.os }}" == "Windows" ]]; then
+ mv ver.exe "${{ matrix.asset }}"
+ else
+ mv ver "${{ matrix.asset }}"
+ fi
+ libs=( ${{ matrix.lib_glob }} )
+ cp "${libs[0]}" "${{ matrix.lib }}"
+ - name: Upload
+ uses: actions/upload-artifact@v4
+ with:
+ name: ${{ matrix.asset }}
+ path: |
+ ${{ matrix.asset }}
+ ${{ matrix.lib }}
+
+ gui-linux:
+ name: Build ver-gui-linux-x86_64
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: Install Qt
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y qt6-base-dev
+ - name: Install D
+ uses: dlang-community/setup-dlang@v1
+ with:
+ compiler: ldc-latest
+ - name: Build GUI
+ run: dub build --config=gui --build=release
+ - name: Stage
+ run: mv ver-gui ver-gui-linux-x86_64
+ - name: Upload
+ uses: actions/upload-artifact@v4
+ with:
+ name: ver-gui-linux-x86_64
+ path: ver-gui-linux-x86_64
+
+ release:
+ needs: [build, gui-linux]
+ runs-on: ubuntu-latest
+ steps:
+ - name: Download artifacts
+ uses: actions/download-artifact@v4
+ with:
+ path: dist
+ merge-multiple: true
+ - name: Publish GitHub Release
+ uses: softprops/action-gh-release@v2
+ with:
+ files: dist/*
+ generate_release_notes: true
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..20e5484
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,14 @@
+.dub/
+*.exe
+*.o
+*.obj
+*.lib
+*.a
+*.so
+*.dylib
+ver
+ver-gui
+bin/
+build/
+*.lst
+dub.selections.json
diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc
new file mode 100644
index 0000000..fc5bb90
--- /dev/null
+++ b/CHANGELOG.adoc
@@ -0,0 +1,14 @@
+= Changelog
+
+All notable changes to this project are documented in this file.
+
+== Unreleased
+
+* Relocate project to `dev-centr/ver`
+* Add D library (`ver`), CLI (`ver`), and Qt GUI (`ver-gui`) builds via DUB
+* Add multi-OS CI and tagged release artifacts (CLI + static library; Linux GUI)
+* Keep legacy C sources under `src/` for reference (Makefile still targets them)
+
+== 0.1.0
+
+* Initial C prototype (git/svn/local handlers)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..36b7cd9
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/README.md b/README.md
index 43bd8fa..293b609 100644
--- a/README.md
+++ b/README.md
@@ -1,243 +1,73 @@
-

-

-

-

-

+

+

+

+

+
Ver
-
Universal Version Control Interface — pluggable system for Git, SVN, and other VCS providers with intuitive syntax.
+
Universal Version Control Interface — library, CLI, and Qt GUI with one command model across Git, SVN, and Mercurial.
- Report Bug
+ Explore the docs
·
- Request Feature
+ Report Bug
+ ·
+ Request Feature
-
- Table of Contents
-
- -
- About The Project
-
-
- - Installation
- - Usage
- - Contributing
- - License
- - Contact
-
-
-
## About The Project
-Ver is a pluggable version control interface that provides a unified, intuitive command-line experience across different version control systems. It aims to eliminate the cognitive overhead of learning multiple VCS commands by providing a consistent mental model and syntax.
-
-### Features
+Ver maps a small, consistent vocabulary (`status`, `save`, `sync`, …) onto the nearest VCS root. Use it as a **CLI**, embed the **D library**, or open the **Qt GUI**.
-- **Provider Agnostic**: Works with Git, SVN, Mercurial, and custom providers
-- **Intuitive Syntax**: Commands like `ver save`, `ver history`, `ver sync`
-- **Handler-Based Architecture**: Pluggable system for adding new VCS providers
-- **Auto-Detection**: Automatically detects the VCS provider for your project
-- **Safety Rails**: Prevents common mistakes with built-in safeguards
-- **Cross-Shell Support**: Works in CMD, PowerShell, and Unix shells
-
-(back to top)
+Legacy C sources under `src/` remain for reference; the supported build is DUB (`source/`).
### Built With
-* **CLI / core** — C (Make-based build), handler plugins under `src/handlers/`
-* **Providers** — Git (gitu-handler preferred), SVN, Mercurial, local snapshots
-* **Shells** — CMD, PowerShell, bash/zsh
-
-(back to top)
+* **D** — library + CLI + GUI
+* **DUB** — package / build
+* **Qt 6 + dqt** — optional GUI (`dlang-supplemental/dqt`)
## Installation
```bash
-# Clone the repository
-git clone https://github.com/AMDphreak/ver.git
-cd ver
-
-# Build the project
-make
-
-# Install system-wide
-make install
-```
-
-(back to top)
-
-## Usage
-
-### Basic commands
-
-```bash
-# Initialize a new project (defaults to gitu provider)
-ver init
-
-# Save changes
-ver save "Fixed login bug"
-
-# View history
-ver history
-
-# Sync with remote
-ver sync
-
-# Check status
-ver status
-```
-
-### Architecture
-
-Ver uses a handler-based architecture where:
-
-1. **CLI Dispatcher** (`ver`) - Parses commands and detects providers
-2. **Abstraction Layer** - Maps intuitive commands to provider-specific actions
-3. **Provider Handlers** - Execute the actual VCS commands
-
-#### Included Handlers
-
-- **gitu-handler** - Uses the improved gitu interface (Git Unfuckified)
-- **git-handler** - Standard Git compatibility
-- **local-handler** - Local file snapshots without remote
-
-### Command Mapping
-
-| Ver Command | Git Equivalent | SVN Equivalent | Description |
-|-------------|----------------|----------------|-------------|
-| `ver init` | `git init` | `svn init` | Initialize repository |
-| `ver save` | `git commit` | `svn commit` | Save changes |
-| `ver stage` | `git add` | `svn add` | Stage files |
-| `ver history` | `git log` | `svn log` | View history |
-| `ver sync` | `git pull && git push` | `svn update && svn commit` | Synchronize |
-| `ver branch` | `git branch` | `svn copy` | Manage branches |
-| `ver merge` | `git merge` | `svn merge` | Merge changes |
-
-### Provider Detection
-
-Ver automatically detects the version control provider by looking for:
-
-- `.git/` directory → gitu-handler (preferred) or git-handler
-- `.svn/` directory → svn-handler
-- `.hg/` directory → hg-handler
-- `.ver/` directory → local-handler
-
-### Development
-
-#### Project Structure
-
-```
-ver/
-├── src/
-│ ├── core/ # CLI dispatcher logic
-│ ├── handlers/ # Provider handlers
-│ └── tui/ # Terminal UI components
-├── plugins/ # External handler plugins
-├── tests/ # Test suites
-└── docs/ # Documentation
-```
-
-#### Adding New Handlers
-
-1. Create a handler in `src/handlers/`
-2. Implement the required interface functions
-3. Register the handler in the core dispatcher
-4. Add tests
-
-See `docs/handler-development.md` for details.
-
-### Shell Integration
-
-#### PowerShell
-
-Add to your `$PROFILE`:
-
-```powershell
-function ver { & ver.exe $args }
-```
-
-#### CMD
-
-Create a doskey macro:
-
-```batch
-doskey ver=ver.exe $*
-```
-
-#### Unix Shells
-
-Add to your `.bashrc` or `.zshrc`:
-
-```bash
-alias ver='ver.exe'
+dub build --config=cli --build=release
+dub build --config=library --build=release
+# optional:
+dub build --config=gui --build=release
```
-### Configuration
-
-Ver stores configuration in:
-
-- **Windows**: `%APPDATA%/ver/config.json`
-- **Unix**: `~/.config/ver/config.json`
-
-Example configuration:
+As a dependency (DUB registry after first publish, or git):
```json
-{
- "default_provider": "gitu",
- "handlers": {
- "gitu": {
- "path": "./plugins/gitu-handler",
- "priority": 1
- },
- "git": {
- "path": "./plugins/git-handler",
- "priority": 2
- }
- },
- "ui": {
- "tui_enabled": true,
- "ai_mode": false
+"dependencies": {
+ "ver": {
+ "repository": "git+https://github.com/dev-centr/ver.git",
+ "version": "~main"
}
}
```
-(back to top)
-
-## Contributing
-
-1. Fork the repository
-2. Create a feature branch
-3. Make your changes
-4. Add tests
-5. Submit a pull request
-
-### Top contributors
+## Usage
-
-
-
+```bash
+ver status
+ver save "message"
+ver sync
+ver-gui
+```
-For per-person profile links, prefer [all-contributors](https://allcontributors.org/).
+## Changelog
-(back to top)
+See [CHANGELOG.adoc](./CHANGELOG.adoc).
## License
-MIT License — see [LICENSE](LICENSE) for details.
-
-(back to top)
+Boost Software License 1.0 — see [LICENSE](./LICENSE).
## Contact
-Ryan Johnson — [@amdphreak](https://twitter.com/amdphreak)
-
-Project Link: [https://github.com/AMDphreak/ver](https://github.com/AMDphreak/ver)
-
-Site: [https://ryanjohnson.dev](https://ryanjohnson.dev)
+Dev-Centr — support@devcentr.org
-(back to top)
+Project Link: https://github.com/dev-centr/ver
diff --git a/docs/antora.yml b/docs/antora.yml
new file mode 100644
index 0000000..3033f34
--- /dev/null
+++ b/docs/antora.yml
@@ -0,0 +1,6 @@
+name: ver
+title: Ver
+version: master
+start_page: ROOT:index.adoc
+nav:
+ - modules/ROOT/nav.adoc
diff --git a/docs/modules/ROOT/nav.adoc b/docs/modules/ROOT/nav.adoc
new file mode 100644
index 0000000..bf4b67f
--- /dev/null
+++ b/docs/modules/ROOT/nav.adoc
@@ -0,0 +1,4 @@
+* xref:index.adoc[Overview]
+* xref:installation.adoc[Installation]
+* xref:usage.adoc[Usage]
+* xref:library.adoc[Library API]
diff --git a/docs/modules/ROOT/pages/index.adoc b/docs/modules/ROOT/pages/index.adoc
new file mode 100644
index 0000000..8d6b4fd
--- /dev/null
+++ b/docs/modules/ROOT/pages/index.adoc
@@ -0,0 +1,19 @@
+= Ver
+:description: Universal version-control interface — one command model across Git, SVN, and Mercurial.
+
+Ver is a developer tool that maps a small, consistent command vocabulary (`status`, `save`, `sync`, …) onto the nearest VCS root.
+
+== Surfaces
+
+* *Library* (`ver`) — embed detection and dispatch in other D tools
+* *CLI* (`ver`) — day-to-day shell use
+* *GUI* (`ver-gui`) — Qt front-end over the same library
+
+Repository::
+https://github.com/dev-centr/ver
+
+Docs hub::
+https://docs.devcentr.org/ver/
+
+Package index::
+https://code.dlang.org/packages/ver (DUB; register after the first tagged release)
diff --git a/docs/modules/ROOT/pages/installation.adoc b/docs/modules/ROOT/pages/installation.adoc
new file mode 100644
index 0000000..c507925
--- /dev/null
+++ b/docs/modules/ROOT/pages/installation.adoc
@@ -0,0 +1,38 @@
+= Installation
+
+== From source (DUB)
+
+[source,bash]
+----
+git clone https://github.com/dev-centr/ver.git
+cd ver
+dub build --config=cli --build=release
+dub build --config=library --build=release
+# Optional Qt GUI (needs Qt 6 + dqt):
+dub build --config=gui --build=release
+----
+
+== As a DUB dependency
+
+[source,json]
+----
+"dependencies": {
+ "ver": "~>0.2.0"
+}
+----
+
+Until the package is on https://code.dlang.org[code.dlang.org], depend on git:
+
+[source,json]
+----
+"dependencies": {
+ "ver": {
+ "repository": "git+https://github.com/dev-centr/ver.git",
+ "version": "~main"
+ }
+}
+----
+
+== Releases
+
+GitHub Releases attach CLI binaries and static libraries for Linux/Windows/macOS (x86_64 and arm64 where runners exist), plus a Linux `ver-gui` build.
diff --git a/docs/modules/ROOT/pages/library.adoc b/docs/modules/ROOT/pages/library.adoc
new file mode 100644
index 0000000..ac56c94
--- /dev/null
+++ b/docs/modules/ROOT/pages/library.adoc
@@ -0,0 +1,16 @@
+= Library API
+
+[source,d]
+----
+import ver;
+
+auto kind = detectVcs(".");
+auto result = dispatch("status", null, ".");
+----
+
+Key entry points:
+
+* `detectVcs` / `findVcsRoot` — discovery
+* `dispatch` — command mapping
+* `CommandResult` — exit code + captured output
+* `verVersion` — library/CLI version string
diff --git a/docs/modules/ROOT/pages/usage.adoc b/docs/modules/ROOT/pages/usage.adoc
new file mode 100644
index 0000000..9ee0652
--- /dev/null
+++ b/docs/modules/ROOT/pages/usage.adoc
@@ -0,0 +1,19 @@
+= Usage
+
+[source,bash]
+----
+ver status
+ver save "explain the change"
+ver sync
+ver history
+ver help
+----
+
+`ver` walks upward from the current directory to find `.git`, `.svn`, or `.hg`, then maps the command onto that tool.
+
+GUI:
+
+[source,bash]
+----
+ver-gui
+----
diff --git a/dub.json b/dub.json
new file mode 100644
index 0000000..11e1382
--- /dev/null
+++ b/dub.json
@@ -0,0 +1,45 @@
+{
+ "name": "ver",
+ "description": "Universal version-control interface — library, CLI, and Qt GUI with a consistent command model.",
+ "authors": ["Dev-Centr"],
+ "license": "BSL-1.0",
+ "copyright": "Copyright © 2024–2026, Dev-Centr",
+ "homepage": "https://github.com/dev-centr/ver",
+ "documentationURL": "https://docs.devcentr.org/ver/",
+ "sourcePaths": ["source"],
+ "importPaths": ["source"],
+ "configurations": [
+ {
+ "name": "library",
+ "targetType": "library",
+ "excludedSourceFiles": [
+ "source/app_cli.d",
+ "source/app_gui.d"
+ ]
+ },
+ {
+ "name": "cli",
+ "targetType": "executable",
+ "targetName": "ver",
+ "mainSourceFile": "source/app_cli.d",
+ "excludedSourceFiles": [
+ "source/app_gui.d"
+ ]
+ },
+ {
+ "name": "gui",
+ "targetType": "executable",
+ "targetName": "ver-gui",
+ "mainSourceFile": "source/app_gui.d",
+ "excludedSourceFiles": [
+ "source/app_cli.d"
+ ],
+ "dependencies": {
+ "dqt:widgets": {
+ "repository": "git+https://github.com/dlang-supplemental/dqt.git",
+ "version": "~master"
+ }
+ }
+ }
+ ]
+}
diff --git a/source/app_cli.d b/source/app_cli.d
new file mode 100644
index 0000000..119b404
--- /dev/null
+++ b/source/app_cli.d
@@ -0,0 +1,22 @@
+module app_cli;
+
+import std.stdio : stderr, write, writeln;
+import ver;
+
+int main(string[] args)
+{
+ if (args.length < 2)
+ {
+ write(helpText());
+ return 0;
+ }
+
+ auto result = dispatch(args[1], args[2 .. $]);
+ if (result.stdout.length)
+ write(result.stdout);
+ if (result.stderr.length)
+ stderr.write(result.stderr);
+ if (result.exitCode != 0 && result.stderr.length == 0 && result.stdout.length == 0)
+ stderr.writeln(result.handlerName, ": command failed with code ", result.exitCode);
+ return result.exitCode;
+}
diff --git a/source/app_gui.d b/source/app_gui.d
new file mode 100644
index 0000000..596274b
--- /dev/null
+++ b/source/app_gui.d
@@ -0,0 +1,94 @@
+/** ver-gui — Qt front-end for the Ver library. */
+module app_gui;
+
+import core.runtime;
+import core.stdcpp.new_;
+
+import qt.config;
+import qt.core.object;
+import qt.core.string;
+import qt.helpers;
+import qt.widgets.application;
+import qt.widgets.boxlayout;
+import qt.widgets.label;
+import qt.widgets.lineedit;
+import qt.widgets.mainwindow;
+import qt.widgets.plaintextedit;
+import qt.widgets.pushbutton;
+import qt.widgets.widget;
+
+import ver;
+
+class VerWindow : QMainWindow
+{
+ mixin(Q_OBJECT_D);
+
+ this(QWidget parent = null)
+ {
+ super(parent);
+ setWindowTitle("Ver");
+ resize(720, 480);
+
+ auto central = cpp_new!QWidget(this);
+ auto layout = cpp_new!QVBoxLayout(central);
+
+ auto title = cpp_new!QLabel(central);
+ title.setText("Ver — universal VCS interface");
+ layout.addWidget(title);
+
+ auto prompt = cpp_new!QLabel(central);
+ prompt.setText("Command (e.g. status, history, save hello)");
+ layout.addWidget(prompt);
+
+ input = cpp_new!QLineEdit(central);
+ layout.addWidget(input);
+
+ auto runBtn = cpp_new!QPushButton(central);
+ runBtn.setText("Run");
+ layout.addWidget(runBtn);
+
+ output = cpp_new!QPlainTextEdit(central);
+ output.setReadOnly(true);
+ layout.addWidget(output);
+
+ setCentralWidget(central);
+
+ connect(runBtn.signal!"clicked", this.slot!"onRun");
+ connect(input.signal!"returnPressed", this.slot!"onRun");
+ }
+
+private /+ slots +/:
+ @QSlot final void onRun()
+ {
+ import std.array : split;
+ import std.conv : to;
+ import std.string : strip;
+
+ auto line = input.text().to!string.strip;
+ if (line.length == 0)
+ return;
+ auto parts = line.split();
+ auto result = dispatch(parts[0], parts.length > 1 ? parts[1 .. $] : null);
+ auto text = result.stdout;
+ if (result.stderr.length)
+ text ~= (text.length ? "\n" : "") ~ result.stderr;
+ if (text.length == 0)
+ text = "(exit " ~ result.exitCode.to!string ~ " via " ~ result.handlerName ~ ")";
+ output.setPlainText(QString(text));
+ }
+
+private:
+ QLineEdit input;
+ QPlainTextEdit output;
+}
+
+int main()
+{
+ int argc = Runtime.cArgs.argc;
+ char** argv = Runtime.cArgs.argv;
+ scope app = new QApplication(argc, argv);
+
+ auto window = cpp_new!VerWindow();
+ window.show();
+ return app.exec();
+}