From 427b99f4003cf93c6591c61fa509f1148912212d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9E=97=20=E9=A7=BF=E7=94=AB=20=28Shunsuke=20Hayashi=29?= Date: Fri, 10 Apr 2026 15:03:49 +0900 Subject: [PATCH] refactor: make mergegate gate-first --- Cargo.lock | 1000 +----------------------------- Cargo.toml | 14 +- README.github.md | 19 +- README.md | 575 +++-------------- crates/mergegate-cli/Cargo.toml | 7 +- crates/mergegate-cli/src/main.rs | 270 +------- docs/USER_MANUAL.md | 598 +++--------------- 7 files changed, 239 insertions(+), 2244 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 60a6895..70e3e5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - [[package]] name = "aho-corasick" version = "1.1.4" @@ -17,12 +11,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "allocator-api2" -version = "0.2.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" - [[package]] name = "android_system_properties" version = "0.1.5" @@ -88,26 +76,6 @@ version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -[[package]] -name = "arboard" -version = "3.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" -dependencies = [ - "clipboard-win", - "image", - "log", - "objc2", - "objc2-app-kit", - "objc2-core-foundation", - "objc2-core-graphics", - "objc2-foundation", - "parking_lot", - "percent-encoding", - "windows-sys 0.60.2", - "x11rb", -] - [[package]] name = "async-trait" version = "0.1.89" @@ -137,15 +105,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bit-set" version = "0.8.0" @@ -173,39 +132,12 @@ version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" -[[package]] -name = "bytemuck" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" - -[[package]] -name = "byteorder-lite" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" - [[package]] name = "bytes" version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - -[[package]] -name = "castaway" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a" -dependencies = [ - "rustversion", -] - [[package]] name = "cc" version = "1.2.47" @@ -284,174 +216,18 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" -[[package]] -name = "clipboard-win" -version = "5.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" -dependencies = [ - "error-code", -] - [[package]] name = "colorchoice" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" -[[package]] -name = "compact_str" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" -dependencies = [ - "castaway", - "cfg-if", - "itoa", - "rustversion", - "ryu", - "static_assertions", -] - -[[package]] -name = "convert_case" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb402b8d4c85569410425650ce3eddc7d698ed96d39a73f941b08fb63082f1e7" -dependencies = [ - "unicode-segmentation", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "crc32fast" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossterm" -version = "0.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" -dependencies = [ - "bitflags", - "crossterm_winapi", - "mio", - "parking_lot", - "rustix 0.38.44", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" -dependencies = [ - "bitflags", - "crossterm_winapi", - "derive_more", - "document-features", - "futures-core", - "mio", - "parking_lot", - "rustix 1.1.2", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" -dependencies = [ - "winapi", -] - -[[package]] -name = "crunchy" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" - -[[package]] -name = "darling" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.20.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "deranged" -version = "0.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" -dependencies = [ - "powerfmt", -] - -[[package]] -name = "derive_more" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" -dependencies = [ - "derive_more-impl", -] - -[[package]] -name = "derive_more-impl" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "dirs" version = "5.0.1" @@ -473,16 +249,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "dispatch2" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" -dependencies = [ - "bitflags", - "objc2", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -494,21 +260,6 @@ dependencies = [ "syn", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - -[[package]] -name = "either" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" - [[package]] name = "equivalent" version = "1.0.2" @@ -525,75 +276,24 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "error-code" -version = "3.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" - [[package]] name = "fastrand" version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" -[[package]] -name = "fax" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" -dependencies = [ - "fax_derive", -] - -[[package]] -name = "fax_derive" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "fdeflate" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" -dependencies = [ - "simd-adler32", -] - [[package]] name = "find-msvc-tools" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" -[[package]] -name = "flate2" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" -dependencies = [ - "crc32fast", - "miniz_oxide", -] - [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -702,25 +402,6 @@ dependencies = [ "slab", ] -[[package]] -name = "gethostname" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" -dependencies = [ - "rustix 1.1.2", - "windows-link", -] - -[[package]] -name = "getopts" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfe4fbac503b8d1f88e6676011885f34b7174f46e59956bba534ba83abded4df" -dependencies = [ - "unicode-width 0.2.0", -] - [[package]] name = "getrandom" version = "0.2.16" @@ -769,28 +450,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "half" -version = "2.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" -dependencies = [ - "cfg-if", - "crunchy", - "zerocopy", -] - -[[package]] -name = "hashbrown" -version = "0.15.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" -dependencies = [ - "allocator-api2", - "equivalent", - "foldhash", -] - [[package]] name = "hashbrown" version = "0.16.1" @@ -1010,12 +669,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "1.1.0" @@ -1037,20 +690,6 @@ dependencies = [ "icu_properties", ] -[[package]] -name = "image" -version = "0.25.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" -dependencies = [ - "bytemuck", - "byteorder-lite", - "moxcms", - "num-traits", - "png", - "tiff", -] - [[package]] name = "indexmap" version = "2.12.1" @@ -1058,29 +697,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.16.1", -] - -[[package]] -name = "indoc" -version = "2.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706" -dependencies = [ - "rustversion", -] - -[[package]] -name = "instability" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435d80800b936787d62688c927b6490e887c7ef5ff9ce922c6c6050fca75eb9a" -dependencies = [ - "darling", - "indoc", - "proc-macro2", - "quote", - "syn", + "hashbrown", ] [[package]] @@ -1105,15 +722,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" -[[package]] -name = "itertools" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" -dependencies = [ - "either", -] - [[package]] name = "itoa" version = "1.0.15" @@ -1202,18 +810,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -1226,36 +822,12 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - -[[package]] -name = "lock_api" -version = "0.4.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" -dependencies = [ - "scopeguard", -] - [[package]] name = "log" version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" -[[package]] -name = "lru" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" -dependencies = [ - "hashbrown 0.15.5", -] - [[package]] name = "lru-slab" version = "0.1.2" @@ -1284,10 +856,7 @@ dependencies = [ "anyhow", "chrono", "clap", - "crossterm 0.29.0", "mergegate-core", - "mergegate-tui", - "ratatui", "serde", "serde_json", "tokio", @@ -1322,39 +891,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "mergegate-tui" -version = "0.1.0" -dependencies = [ - "anyhow", - "arboard", - "chrono", - "crossterm 0.29.0", - "futures", - "mergegate-core", - "once_cell", - "pulldown-cmark", - "ratatui", - "serde", - "serde_json", - "syntect", - "textwrap", - "thiserror 2.0.17", - "tokio", - "unicode-width 0.2.0", - "uuid", -] - -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - [[package]] name = "mio" version = "1.1.0" @@ -1362,21 +898,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "log", "wasi", "windows-sys 0.61.2", ] -[[package]] -name = "moxcms" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fbdd3d7436f8b5e892b8b7ea114271ff0fa00bc5acae845d53b07d498616ef6" -dependencies = [ - "num-traits", - "pxfm", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -1386,12 +911,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "num-conv" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" - [[package]] name = "num-traits" version = "0.2.19" @@ -1401,79 +920,6 @@ dependencies = [ "autocfg", ] -[[package]] -name = "objc2" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" -dependencies = [ - "objc2-encode", -] - -[[package]] -name = "objc2-app-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" -dependencies = [ - "bitflags", - "objc2", - "objc2-core-graphics", - "objc2-foundation", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" -dependencies = [ - "bitflags", - "dispatch2", - "objc2", -] - -[[package]] -name = "objc2-core-graphics" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" -dependencies = [ - "bitflags", - "dispatch2", - "objc2", - "objc2-core-foundation", - "objc2-io-surface", -] - -[[package]] -name = "objc2-encode" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" - -[[package]] -name = "objc2-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" -dependencies = [ - "bitflags", - "objc2", - "objc2-core-foundation", -] - -[[package]] -name = "objc2-io-surface" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" -dependencies = [ - "bitflags", - "objc2", - "objc2-core-foundation", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -1486,28 +932,6 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "onig" -version = "6.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336b9c63443aceef14bea841b899035ae3abe89b7c486aaf4c5bd8aafedac3f0" -dependencies = [ - "bitflags", - "libc", - "once_cell", - "onig_sys", -] - -[[package]] -name = "onig_sys" -version = "69.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7f86c6eef3d6df15f23bcfb6af487cbd2fed4e5581d58d5bf1f5f8b7f6727dc" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "openssl-probe" version = "0.1.6" @@ -1542,35 +966,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" -[[package]] -name = "parking_lot" -version = "0.12.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-link", -] - -[[package]] -name = "paste" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" - [[package]] name = "percent-encoding" version = "2.3.2" @@ -1595,32 +990,6 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "plist" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "740ebea15c5d1428f910cd1a5f52cebf8d25006245ed8ade92702f4943d91e07" -dependencies = [ - "base64", - "indexmap", - "quick-xml", - "serde", - "time", -] - -[[package]] -name = "png" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97baced388464909d42d89643fe4361939af9b7ce7a31ee32a168f832a70f2a0" -dependencies = [ - "bitflags", - "crc32fast", - "fdeflate", - "flate2", - "miniz_oxide", -] - [[package]] name = "potential_utf" version = "0.1.4" @@ -1630,12 +999,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "powerfmt" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" - [[package]] name = "ppv-lite86" version = "0.2.21" @@ -1673,55 +1036,12 @@ dependencies = [ "unarray", ] -[[package]] -name = "pulldown-cmark" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14" -dependencies = [ - "bitflags", - "getopts", - "memchr", - "pulldown-cmark-escape", - "unicase", -] - -[[package]] -name = "pulldown-cmark-escape" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "007d8adb5ddab6f8e3f491ac63566a7d5002cc7ed73901f72057943fa71ae1ae" - -[[package]] -name = "pxfm" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3cbdf373972bf78df4d3b518d07003938e2c7d1fb5891e55f9cb6df57009d84" -dependencies = [ - "num-traits", -] - [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -[[package]] -name = "quick-error" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" - -[[package]] -name = "quick-xml" -version = "0.38.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" -dependencies = [ - "memchr", -] - [[package]] name = "quinn" version = "0.11.9" @@ -1830,36 +1150,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "ratatui" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" -dependencies = [ - "bitflags", - "cassowary", - "compact_str", - "crossterm 0.28.1", - "indoc", - "instability", - "itertools", - "lru", - "paste", - "strum", - "unicode-segmentation", - "unicode-truncate", - "unicode-width 0.2.0", -] - -[[package]] -name = "redox_syscall" -version = "0.5.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" -dependencies = [ - "bitflags", -] - [[package]] name = "redox_users" version = "0.4.6" @@ -1961,19 +1251,6 @@ version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.2" @@ -1983,7 +1260,7 @@ dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys", "windows-sys 0.61.2", ] @@ -2035,7 +1312,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", - "quick-error 1.2.3", + "quick-error", "tempfile", "wait-timeout", ] @@ -2046,21 +1323,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - [[package]] name = "serde" version = "1.0.228" @@ -2153,27 +1415,6 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" -[[package]] -name = "signal-hook" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75a19a7a740b25bc7944bdee6172368f988763b744e3d4dfe753f6b4ece40cc" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - [[package]] name = "signal-hook-registry" version = "1.4.6" @@ -2183,12 +1424,6 @@ dependencies = [ "libc", ] -[[package]] -name = "simd-adler32" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" - [[package]] name = "slab" version = "0.4.11" @@ -2201,12 +1436,6 @@ version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" -[[package]] -name = "smawk" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c388c1b5e93756d0c740965c41e8822f866621d41acbdf6336a6a168f8840c" - [[package]] name = "socket2" version = "0.6.1" @@ -2223,40 +1452,12 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "strsim" version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" -[[package]] -name = "strum" -version = "0.26.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.26.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn", -] - [[package]] name = "subtle" version = "2.6.1" @@ -2294,27 +1495,6 @@ dependencies = [ "syn", ] -[[package]] -name = "syntect" -version = "5.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "656b45c05d95a5704399aeef6bd0ddec7b2b3531b7c9e900abbf7c4d2190c925" -dependencies = [ - "bincode", - "flate2", - "fnv", - "once_cell", - "onig", - "plist", - "regex-syntax", - "serde", - "serde_derive", - "serde_json", - "thiserror 2.0.17", - "walkdir", - "yaml-rust", -] - [[package]] name = "tempfile" version = "3.23.0" @@ -2324,21 +1504,10 @@ dependencies = [ "fastrand", "getrandom 0.3.4", "once_cell", - "rustix 1.1.2", + "rustix", "windows-sys 0.61.2", ] -[[package]] -name = "textwrap" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c13547615a44dc9c452a8a534638acdf07120d4b6847c8178705da06306a3057" -dependencies = [ - "smawk", - "unicode-linebreak", - "unicode-width 0.2.0", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -2388,51 +1557,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "tiff" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" -dependencies = [ - "fax", - "flate2", - "half", - "quick-error 2.0.1", - "weezl", - "zune-jpeg", -] - -[[package]] -name = "time" -version = "0.3.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" -dependencies = [ - "deranged", - "itoa", - "num-conv", - "powerfmt", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" - -[[package]] -name = "time-macros" -version = "0.2.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tinystr" version = "0.8.2" @@ -2680,53 +1804,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" -[[package]] -name = "unicase" -version = "2.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" - [[package]] name = "unicode-ident" version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" -[[package]] -name = "unicode-linebreak" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b09c83c3c29d37506a3e260c08c03743a6bb66a9cd432c6934ab501a190571f" - -[[package]] -name = "unicode-segmentation" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" - -[[package]] -name = "unicode-truncate" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" -dependencies = [ - "itertools", - "unicode-segmentation", - "unicode-width 0.1.14", -] - -[[package]] -name = "unicode-width" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" - -[[package]] -name = "unicode-width" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -2796,16 +1879,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -2930,12 +2003,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "weezl" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" - [[package]] name = "winapi" version = "0.3.9" @@ -2952,15 +2019,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -3044,15 +2102,6 @@ dependencies = [ "windows-targets 0.52.6", ] -[[package]] -name = "windows-sys" -version = "0.59.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.60.2" @@ -3278,32 +2327,6 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" -[[package]] -name = "x11rb" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" -dependencies = [ - "gethostname", - "rustix 1.1.2", - "x11rb-protocol", -] - -[[package]] -name = "x11rb-protocol" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" - -[[package]] -name = "yaml-rust" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "yoke" version = "0.8.1" @@ -3406,18 +2429,3 @@ dependencies = [ "quote", "syn", ] - -[[package]] -name = "zune-core" -version = "0.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" - -[[package]] -name = "zune-jpeg" -version = "0.4.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" -dependencies = [ - "zune-core", -] diff --git a/Cargo.toml b/Cargo.toml index e597be3..017f7f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ resolver = "2" members = [ "crates/mergegate-cli", - "crates/mergegate-tui", "crates/mergegate-core", ] @@ -14,8 +13,8 @@ authors = ["Miyabi Team"] license = "BUSL-1.1" repository = "https://github.com/ShunsukeHayashi/mergegate" homepage = "https://github.com/ShunsukeHayashi/mergegate" -description = "MergeGate - Deterministic task execution and merge workflow for AI-assisted development" -keywords = ["ai", "cli", "tui", "autonomous", "development"] +description = "MergeGate - Engine-agnostic gate CLI for deterministic task execution in AI-assisted development" +keywords = ["ai", "cli", "workflow", "merge", "development"] categories = ["command-line-utilities", "development-tools"] [workspace.dependencies] @@ -24,15 +23,6 @@ tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-std", "syn futures = "0.3" async-trait = "0.1" -# TUI Framework -ratatui = { version = "0.29.0", features = [ - "scrolling-regions", - "unstable-backend-writer", - "unstable-rendered-line-info", - "unstable-widget-ref", -] } -crossterm = { version = "0.29.0", features = ["bracketed-paste", "event-stream"] } - # Text Processing textwrap = "0.16" unicode-width = "0.2" diff --git a/README.github.md b/README.github.md index ba85080..c1bba54 100644 --- a/README.github.md +++ b/README.github.md @@ -1,13 +1,22 @@ # MergeGate -Deterministic execution protocol for AI-assisted development. +Engine-agnostic gate CLI for AI-assisted development. Execution layer for GitNexus-style code intelligence: - `GitNexus`: understand the codebase - `MergeGate`: execute changes safely -Current CLI entrypoints: `miyabi` and `mergegate` +Core product: +- `mergegate gate ...` +- `miyabi gate ...` (compatibility alias) -- `miyabi tui` / `mergegate tui`: terminal assistant -- `miyabi gate` / `mergegate gate`: deterministic task execution, file locks, and PR/merge workflow +MergeGate is designed to sit in front of Claude Code, Codex, Gemini CLI, and other coding agents. The engine can change. The gate protocol should not. + +Start with: + +```bash +cargo build --release +./target/release/mergegate gate status +./target/release/mergegate gate init +./target/release/mergegate gate guide +``` -Start with `cargo build --release`, then run `./target/release/mergegate --help` or `./target/release/mergegate gate guide`. diff --git a/README.md b/README.md index 1b256a6..0067cfa 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,68 @@ # MergeGate -MergeGate is a deterministic execution protocol for AI-assisted development. -It is the execution layer for GitNexus-style code intelligence: GitNexus helps agents understand what will break, and MergeGate makes them execute that work in a safe, verifiable order. +MergeGate is an engine-agnostic gate CLI for AI-assisted development. + +It does not need to be your coding agent, your chat runtime, or your terminal UI. Its job is simpler and more durable: + +- register work +- record impact +- lock files +- assign execution +- track branch and PR state +- verify completion In short: - `GitNexus`: understand the codebase - `MergeGate`: execute changes safely -The project currently supports both `miyabi` and `mergegate` as CLI entrypoints. `miyabi` remains the legacy/default command, and `mergegate` is the product-aligned alias. +MergeGate is designed to sit in front of coding agents such as Claude Code, Codex, and Gemini CLI. The execution engine can change. The gate protocol should not. -This repository has two common entry points: +## What This Project Is -- `miyabi tui` / `mergegate tui`: interactive terminal assistant -- `miyabi gate` / `mergegate gate`: deterministic task execution and file-lock workflow for repo work +MergeGate is a repo workflow tool for deterministic execution. -If you arrived here because of deterministic execution, task locks, PR gates, or agent-safe repo work, start with `mergegate gate` or `miyabi gate`, not the TUI. +The core product is: + +- `miyabi gate ...` +- `mergegate gate ...` + +The binary still supports both `miyabi` and `mergegate` entrypoints today. `mergegate` is the product-aligned command. `miyabi` remains as a compatibility alias. ## 60-Second Setup ```bash -# 1. Clone and build git clone https://github.com/ShunsukeHayashi/mergegate.git cd mergegate cargo build --release -# 2. Set API key -export ANTHROPIC_API_KEY="sk-ant-..." - -# 3. Run -./target/release/mergegate tui +./target/release/mergegate gate status +./target/release/mergegate gate init +./target/release/mergegate gate guide ``` -That's it. Start with the TUI, or jump straight into `mergegate gate` for repo workflow control. - ---- +No API key is required for gate workflow. ## Why MergeGate -- **Execution layer for code intelligence** - Pair blast-radius understanding with deterministic execution, not chat-only automation -- **Deterministic task execution** - Register, analyze, lock, review, and merge in a verifiable order -- **Repo-safe agent workflow** - File locks and gate checks reduce accidental overlap and unsafe edits -- **Interactive TUI** - Terminal assistant for chat, prompts, and agent execution -- **Agent mode** - Autonomous execution with tool approval -- **Session management** - Persist and resume conversations -- **Configurable** - TOML-based configuration +- **Engine agnostic**: Use Claude Code, Codex, Gemini CLI, or another agent runtime +- **Deterministic execution**: Register, analyze, lock, implement, review, and merge in a verifiable order +- **Repo-safe coordination**: Reduce accidental overlap with file locks and explicit task ownership +- **Execution ledger**: Keep branch, PR, merge, and completion state tied to actual work +- **Protocol over chat**: The product is the workflow gate, not a built-in assistant ## Positioning -MergeGate was designed for teams that already believe code understanding is not enough. -Knowing the blast radius of a change is only half of the problem. Agents also need a protocol for when work starts, which files are locked, what must be recorded before editing, and what counts as done. +MergeGate exists because understanding code is not enough. + +Agents also need a protocol for: + +- when a task starts +- which files are locked +- what impact was recorded +- who is implementing +- how branch and PR state are attached +- what counts as done That is the role split: @@ -63,7 +76,6 @@ If GitNexus answers "what is this change connected to?", MergeGate answers "how ### Prerequisites - Rust 1.70+ -- Anthropic API key ### Build from Source @@ -77,75 +89,34 @@ Binary will be at `target/release/miyabi` and `target/release/mergegate`. ## Quick Start -Choose the path that matches what you want to do. - -### A. Use MergeGate as a terminal assistant - -Run the TUI after configuring your API key. - -#### 1. Generate Config +### 1. Check repo status ```bash -./target/release/miyabi init +./target/release/mergegate gate status ``` -This creates `~/.miyabi/config.toml`. +If you see `tasks: 0`, the ledger exists and is simply empty. -#### 2. Set API Key - -Edit `~/.miyabi/config.toml`: - -```toml -[api] -api_key = "sk-ant-..." -``` - -Or use environment variable: +### 2. Initialize gate ledger if needed ```bash -export ANTHROPIC_API_KEY="sk-ant-..." +./target/release/mergegate gate init ``` -#### 3. Launch TUI +This creates `project_memory/tasks.json`. + +### 3. Read the built-in workflow guide ```bash -./target/release/miyabi tui -# or simply -./target/release/miyabi +./target/release/mergegate gate guide ``` -### B. Use MergeGate as a task execution gate - -If you are working inside a repository and want task registration, impact tracking, file locks, and PR/merge recording, use `mergegate gate` or `miyabi gate`. - -#### 1. Check whether the repo is already initialized +### 4. Start a task ```bash -./target/release/miyabi gate status -``` - -If you see `tasks: 0`, that means the ledger exists but is currently empty. - -#### 2. Initialize MergeGate for this repo if needed - -```bash -./target/release/miyabi gate init -``` - -This creates `project_memory/tasks.json` and prepares the repo for gate-managed work. - -#### 3. Read the built-in workflow guide - -```bash -./target/release/miyabi gate guide -``` - -#### 4. Start a task - -```bash -./target/release/miyabi gate register --issue 123 --title "Fix login redirect" -./target/release/miyabi gate impact issue-123 --risk medium --symbols 3 -./target/release/miyabi gate assign issue-123 --agent codex --node macbook --files "src/auth.rs" +./target/release/mergegate gate register --issue 123 --title "Fix login redirect" +./target/release/mergegate gate impact issue-123 --risk medium --symbols 3 +./target/release/mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs" ``` Typical flow: @@ -153,427 +124,83 @@ Typical flow: 1. `register` 2. `impact` 3. `assign` -4. implement +4. implement with your coding agent of choice 5. `branch` 6. `pr` 7. `merge` or `manual-complete` ## Usage -`MergeGate` is the product and documentation name. -Both `miyabi` and `mergegate` work today. +```bash +mergegate gate status +mergegate gate init +mergegate gate guide +mergegate gate register --issue 123 --title "Fix login redirect" +mergegate gate impact issue-123 --risk medium --symbols 3 +mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs" +mergegate gate branch issue-123 codex/fix-login-redirect +mergegate gate pr issue-123 456 +mergegate gate merge issue-123 +``` -### CLI Commands +Compatibility alias: ```bash -miyabi # Start TUI (default) -miyabi tui # Start TUI explicitly -miyabi status # Show status -miyabi init # Generate default config -miyabi sessions # List sessions -miyabi sessions -d # Delete session -miyabi sessions -e # Export session to JSON -miyabi version # Show version info -miyabi agent # Run autonomous agent -miyabi gate status # Show task ledger status -miyabi gate init # Initialize MergeGate in the current repo -miyabi gate guide # Show the full gate workflow guide -mergegate gate status # Same gate workflow with product-aligned command -mergegate tui # Same TUI with product-aligned command +miyabi gate status ``` -### CLI Options +## Core Commands ```bash -miyabi --model claude-sonnet-4-5-20250929 # Override model -miyabi --max-tokens 16384 # Override max tokens -miyabi --thinking # Enable extended thinking -miyabi --config /path/to/config.toml # Custom config -miyabi --session # Resume session +mergegate gate status +mergegate gate init +mergegate gate guide +mergegate gate register --issue 123 --title "Fix login redirect" +mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs" +mergegate gate impact issue-123 --risk medium --symbols 3 +mergegate gate branch issue-123 codex/fix-login-redirect +mergegate gate pr issue-123 456 +mergegate gate merge issue-123 +mergegate gate manual-complete issue-123 --reason "docs-only change" --operator shunsuke +mergegate gate locks +mergegate gate dispatchable +mergegate gate dag ``` -### TUI Keybindings +## Product Direction -| Key | Action | -|-----|--------| -| `Enter` | Send message | -| `Ctrl+P` | Command palette | -| `F1` | Help | -| `Esc` | Close overlay / Cancel | -| `Ctrl+C` | Quit | -| `j/k` | Scroll down/up | -| `Page Up/Down` | Page scroll | +MergeGate is intentionally moving away from: -## Configuration +- built-in TUI as the product center +- built-in agent runtime as the product center +- vendor-specific backend identity -Config file: `~/.miyabi/config.toml` +The durable surface is the gate CLI. -```toml -[api] -api_key = "sk-ant-..." # Anthropic API key -model = "claude-sonnet-4-5-20250929" # Model to use -max_tokens = 8192 # Max response tokens -thinking = false # Extended thinking -system_prompt = "You are a helpful assistant" # System prompt -timeout_secs = 120 # Request timeout -max_retries = 3 # Retry attempts +## Workspace Layout -[ui] -show_sidebar = false # Show sidebar -show_status_bar = true # Show status bar -show_breadcrumb = true # Show breadcrumb -theme = "tokyo-night" # Color theme -vim_mode = false # Vim keybindings -show_line_numbers = true # Line numbers in code - -[session] -auto_save = true # Auto-save sessions -auto_save_interval = 30 # Save interval (seconds) -max_sessions = 100 # Max stored sessions - -[tools] -enable_bash = true # Enable bash tool -enable_file_tools = true # Enable file read/write -enable_search_tools = true # Enable glob/grep -auto_approve_low_risk = false # Auto-approve safe tools -bash_timeout = 120 # Bash command timeout +```text +crates/ + mergegate-cli/ # CLI entrypoint + mergegate-core/ # Gate protocol, store, locks, workflow logic +project_memory/ + tasks.json # Execution ledger +skills/ + mergegate-cli/ + mergegate-ops/ ``` -### Environment Variables - -Override config with environment variables: - -```bash -ANTHROPIC_API_KEY=... # API key -MIYABI_MODEL=... # Model name -MIYABI_MAX_TOKENS=... # Max tokens -MIYABI_THINKING=true # Enable thinking -``` - -## Agent Mode - -Run autonomous tasks with tool execution: - -```bash -# Basic usage -miyabi agent "Create a hello world Python script" - -# With options -miyabi agent "Refactor the utils module" \ - --max-iterations 20 \ - --auto-approve \ - --system "You are an expert Rust developer" -``` - -Agent mode features: -- Autonomous tool execution (bash, file operations, search) -- Approval workflow for risky operations -- Iteration limits for safety -- JSON output format option - -## Core Library Features - -The `mergegate-core` crate provides powerful utilities for building AI applications. - -### Git Utilities - -```rust -use miyabi_core::{find_git_root, get_current_branch, is_in_git_repo}; - -// Find repository root -let root = find_git_root()?; - -// Get current branch -let branch = get_current_branch(&root)?; - -// Check if in git repo -if is_in_git_repo(&path) { - println!("In a git repository"); -} -``` - -### Logger System - -```rust -use miyabi_core::{init_logger, LogLevel, LogFormat}; - -// Initialize with defaults -init_logger(); - -// Or with custom config -use miyabi_core::LoggerConfig; -let config = LoggerConfig { - level: LogLevel::Debug, - format: LogFormat::Json, - ..Default::default() -}; -init_logger_with_config(config); -``` - -### Retry with Backoff - -```rust -use miyabi_core::{retry_with_backoff, BackoffRetryConfig}; - -let config = BackoffRetryConfig::default(); -let result = retry_with_backoff(config, || async { - // Your operation that might fail - make_api_call().await -}).await?; -``` - -### Circuit Breaker - -```rust -use miyabi_core::{CircuitBreaker, CircuitState}; - -let breaker = CircuitBreaker::default(); - -let result = breaker.call(|| { - Box::pin(async { - // Your operation - Ok::<_, std::io::Error>(()) - }) -}).await; - -// Check state -match breaker.state().await { - CircuitState::Closed => println!("Normal operation"), - CircuitState::Open => println!("Circuit open - blocking calls"), - CircuitState::HalfOpen => println!("Testing recovery"), -} -``` - -### Rules System (.miyabirules) - -Support for project-specific rules via `.miyabirules` files: - -```yaml -# .miyabirules -version: 1 -rules: - - name: "no-unwrap" - pattern: ".unwrap()" - suggestion: "Use ? operator or proper error handling" - file_extensions: ["rs"] - severity: "warning" - -agent_preferences: - codegen: - style: "functional" - error_handling: "result" -``` - -```rust -use miyabi_core::{RulesLoader, MiyabiRules}; - -let loader = RulesLoader::new(project_root); -let rules = loader.load_or_default()?; - -// Get rules for a file -let applicable = rules.rules_for_file(Path::new("src/main.rs")); -``` - -### Cache System - -```rust -use miyabi_core::{create_llm_cache, create_api_cache, LLMCacheKey}; - -// LLM response cache (1 hour TTL) -let cache = create_llm_cache(); -let key = LLMCacheKey::new("prompt", "model", Some(0.7)); - -cache.insert(key.clone(), "response".to_string()).await; -let cached = cache.get(&key).await; - -// API cache (30 min TTL) -let api_cache = create_api_cache(); -``` - -### Plugin System - -```rust -use miyabi_core::{Plugin, PluginManager, PluginMetadata, PluginContext, PluginResult}; -use anyhow::Result; - -struct MyPlugin; - -impl Plugin for MyPlugin { - fn metadata(&self) -> PluginMetadata { - PluginMetadata { - name: "my-plugin".to_string(), - version: "1.0.0".to_string(), - description: Some("My custom plugin".to_string()), - author: None, - } - } - - fn init(&mut self) -> Result<()> { - Ok(()) - } - - fn execute(&self, ctx: &PluginContext) -> Result { - Ok(PluginResult { - success: true, - message: Some("Done".to_string()), - data: None, - }) - } -} - -// Register and execute -let manager = PluginManager::new(); -manager.register(Box::new(MyPlugin))?; -let result = manager.execute("my-plugin", &PluginContext::default())?; -``` - -### Feature Flags - -```rust -use miyabi_core::{FeatureFlagManager, FeatureFlag}; - -let flags = FeatureFlagManager::new(); - -// Simple flag -flags.set_flag("new_feature", true); - -if flags.is_enabled("new_feature") { - // Use new feature -} - -// With rollout percentage -flags.set_flag_with_options( - "beta_feature", - true, - Some("Beta testing".to_string()), - Some(0.5), // 50% rollout -); - -// Load from config -use std::collections::HashMap; -let mut config = HashMap::new(); -config.insert("flag1".to_string(), true); -flags.load_from_map(config); -``` - -## Project Structure - -``` -mergegate/ -├── crates/ -│ ├── mergegate-cli/ # CLI entry point -│ ├── mergegate-core/ # Core library -│ │ ├── agent.rs # Agent system -│ │ ├── anthropic.rs # Anthropic API client -│ │ ├── cache.rs # TTL cache system -│ │ ├── config.rs # Configuration -│ │ ├── error_policy.rs # Circuit breaker -│ │ ├── feature_flags.rs # Feature flag management -│ │ ├── git.rs # Git utilities -│ │ ├── logger.rs # Logging system -│ │ ├── plugin.rs # Plugin system -│ │ ├── retry.rs # Retry with backoff -│ │ ├── rules.rs # .miyabirules support -│ │ ├── session.rs # Session management -│ │ ├── tools.rs # Built-in tools -│ │ └── ... -│ └── mergegate-tui/ # TUI implementation -│ ├── app.rs # Main application -│ ├── views.rs # UI views -│ └── ... -├── .miyabi/ # Local config -├── Cargo.toml # Workspace config -└── README.md -``` - -## Development - -### Build - -```bash -cargo build # Debug build -cargo build --release # Release build -``` - -### Test - -```bash -cargo test --all # Run all tests -``` - -### Lint - -```bash -cargo clippy --all-targets -- -D warnings -cargo fmt --all --check -``` - -## Models - -Supported models: -- `claude-sonnet-4-5-20250929` (default) -- `claude-haiku-4-5-20251001` -- `claude-sonnet-4-20250514` - ## Troubleshooting -### Common Issues +### `gate status` says `tasks: 0` -#### "API key not found" -```bash -# Check if environment variable is set -echo $ANTHROPIC_API_KEY +That is not an error. It means the ledger exists but no tasks have been registered yet. -# Or add to config file -vim ~/.miyabi/config.toml -# [api] -# api_key = "sk-ant-..." -``` +### `gate init` says the project is already initialized -#### "Device not configured" error on TUI start -This usually means the terminal doesn't support the required features. Try: -```bash -# Use a different terminal emulator (iTerm2, Alacritty, etc.) -# Or run with explicit terminal type -TERM=xterm-256color ./target/release/miyabi tui -``` +That is usually safe. It means `project_memory/tasks.json` already exists. -#### Build errors -```bash -# Make sure Rust is up to date -rustup update +### I want to use another coding agent -# Clean and rebuild -cargo clean -cargo build --release -``` +That is the intended model. MergeGate is the gate, not the engine. -#### Session not saving -```bash -# Check permissions on sessions directory -ls -la ~/.miyabi/sessions/ - -# Create if missing -mkdir -p ~/.miyabi/sessions -``` - -### Debug Mode - -For verbose logging: -```bash -RUST_LOG=debug ./target/release/miyabi tui -``` - -### Getting Help - -- Check `miyabi --help` for CLI options -- Press `F1` in TUI for keybindings -- Open an issue: https://github.com/ShunsukeHayashi/mergegate/issues - -## License - -MIT - ---- - -Built with Rust, Ratatui, and Claude API. diff --git a/crates/mergegate-cli/Cargo.toml b/crates/mergegate-cli/Cargo.toml index 8a37459..acd0887 100644 --- a/crates/mergegate-cli/Cargo.toml +++ b/crates/mergegate-cli/Cargo.toml @@ -7,7 +7,7 @@ authors.workspace = true license.workspace = true repository.workspace = true homepage.workspace = true -description = "MergeGate CLI - Main command-line interface for deterministic task execution and agent-assisted development" +description = "MergeGate CLI - Engine-agnostic gate workflow for deterministic task execution" [[bin]] name = "miyabi" @@ -20,15 +20,10 @@ path = "src/bin/mergegate.rs" [dependencies] # Workspace crates miyabi-core = { package = "mergegate-core", path = "../mergegate-core" } -miyabi-tui = { package = "mergegate-tui", path = "../mergegate-tui" } # CLI clap = { workspace = true } -# TUI Framework -ratatui = { workspace = true } -crossterm = { workspace = true } - # Async Runtime tokio = { workspace = true } diff --git a/crates/mergegate-cli/src/main.rs b/crates/mergegate-cli/src/main.rs index f177262..0224873 100644 --- a/crates/mergegate-cli/src/main.rs +++ b/crates/mergegate-cli/src/main.rs @@ -62,36 +62,14 @@ fn agent_guide() -> String { } #[derive(Parser)] -#[command(author, version, about = "MergeGate - Deterministic task execution and merge workflow for AI-assisted development", long_about = None)] +#[command(author, version, about = "MergeGate - Engine-agnostic gate CLI for AI-assisted development", long_about = None)] struct Cli { - /// Model to use (overrides config) - #[arg(short, long)] - model: Option, - - /// Maximum tokens for responses (overrides config) - #[arg(long)] - max_tokens: Option, - - /// Enable Extended Thinking (Claude 4.5+) - #[arg(long)] - thinking: bool, - - /// Path to config file - #[arg(short, long)] - config: Option, - - /// Session ID to load on startup - #[arg(short, long)] - session: Option, - #[command(subcommand)] command: Option, } #[derive(Subcommand)] enum Commands { - /// Start the TUI interface - Tui, /// Show status Status, /// Generate default config file @@ -116,23 +94,6 @@ enum Commands { #[arg(short, long)] verbose: bool, }, - /// Run agent with a prompt (autonomous execution) - Agent { - /// The prompt to execute - prompt: String, - /// Maximum iterations (default: 10) - #[arg(long, default_value = "10")] - max_iterations: usize, - /// Auto-approve all tool executions - #[arg(long)] - auto_approve: bool, - /// Output format: text or json - #[arg(long, default_value = "text")] - format: String, - /// System prompt for the agent - #[arg(long)] - system: Option, - }, #[command( about = "Deterministic Task Protocol gate controls", long_about = "Run the gate init command to set up a new project.\n\nDeterministic Task Protocol gate controls" @@ -452,78 +413,35 @@ async fn main() -> anyhow::Result<()> { let cli = Cli::from_arg_matches(&matches).unwrap_or_else(|error| error.exit()); match cli.command { - Some(Commands::Tui) | None => { - // Run TUI - use crossterm::{ - event::{DisableMouseCapture, EnableMouseCapture}, - execute, - terminal::{ - disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen, - }, - }; - use miyabi_core::config::Config; - use miyabi_tui::App; - use ratatui::prelude::*; - use std::io; - - // Load config (from custom path or default) - let mut config = if let Some(config_path) = &cli.config { - Config::load_from(config_path)? - } else { - Config::load().unwrap_or_default() - }; - - // Apply CLI overrides - if let Some(model) = &cli.model { - config.api.model = model.clone(); - } - if let Some(max_tokens) = cli.max_tokens { - config.api.max_tokens = max_tokens; - } - if cli.thinking { - config.api.thinking = true; - } - - enable_raw_mode()?; - let mut stdout = io::stdout(); - execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?; - let backend = CrosstermBackend::new(stdout); - let mut terminal = Terminal::new(backend)?; - - let mut app = App::with_config(config); - - // Load session if specified - if let Some(session_id) = &cli.session { - if let Err(e) = app.load_session(session_id) { - eprintln!("Warning: Failed to load session {}: {}", session_id, e); - } - } - - let res = app.run(&mut terminal).await; - - disable_raw_mode()?; - execute!( - terminal.backend_mut(), - LeaveAlternateScreen, - DisableMouseCapture - )?; - terminal.show_cursor()?; - - if let Err(err) = res { - eprintln!("Error: {}", err); - } + None => { + let mut command = Cli::command(); + command = command.name(current_binary_name()); + command.print_help()?; + println!(); + println!(); + println!("Start here:"); + println!(" {}", gate_command("status")); + println!(" {}", gate_command("init")); + println!(" {}", gate_command("guide")); } Some(Commands::Status) => { use miyabi_core::config::Config; let config = Config::load().unwrap_or_default(); - println!("Miyabi Status: Ready"); + println!("MergeGate Status: Ready"); println!(); + println!("Binary: {}", current_binary_name()); println!("Config: {}", Config::default_path().display()); - println!("Sessions: {}", config.sessions_dir().display()); - println!("Model: {}", config.api.model); println!(); + println!("Core workflow:"); + println!(" {}", gate_command("status")); + println!(" {}", gate_command("init")); + println!(" {}", gate_command("guide")); + println!(); + println!("Direct runtime config remains on disk for compatibility."); + println!("Model: {}", config.api.model); + println!("Sessions: {}", config.sessions_dir().display()); // Load and show rules info let cwd = std::env::current_dir().unwrap_or_default(); @@ -766,152 +684,6 @@ async fn main() -> anyhow::Result<()> { } } } - Some(Commands::Agent { - prompt, - max_iterations, - auto_approve, - format, - system, - }) => { - use miyabi_core::{ - config::Config, Agent, AgentConfig, AgentEvent, AnthropicClient, ExecutorRegistry, - }; - use tokio::sync::mpsc; - - // Load config - let mut config = if let Some(config_path) = &cli.config { - Config::load_from(config_path)? - } else { - Config::load().unwrap_or_default() - }; - - // Apply CLI overrides - if let Some(model) = &cli.model { - config.api.model = model.clone(); - } - if let Some(max_tokens) = cli.max_tokens { - config.api.max_tokens = max_tokens; - } - if cli.thinking { - config.api.thinking = true; - } - - // Get API key - let api_key = config - .api - .api_key - .clone() - .or_else(|| std::env::var("ANTHROPIC_API_KEY").ok()) - .ok_or_else(|| { - anyhow::anyhow!("No API key found. Set ANTHROPIC_API_KEY or add to config.") - })?; - - // Create client - let client = AnthropicClient::new(api_key)? - .with_model(&config.api.model) - .with_max_tokens(config.api.max_tokens) - .with_thinking(config.api.thinking); - - // Create executor registry with standard tools - let registry = ExecutorRegistry::with_standard_tools(); - - // Configure agent - let agent_config = AgentConfig { - max_iterations, - max_tokens_per_turn: config.api.max_tokens, - require_approval: !auto_approve, - auto_approve_patterns: if auto_approve { - vec![ - "read".to_string(), - "glob".to_string(), - "grep".to_string(), - "write".to_string(), - "edit".to_string(), - "bash".to_string(), - ] - } else { - vec!["read".to_string(), "glob".to_string(), "grep".to_string()] - }, - ..Default::default() - }; - - // Create agent - let mut agent = Agent::new(client, registry).with_config(agent_config); - - // Set system prompt - if let Some(sys) = system { - agent = agent.with_system_prompt(sys); - } else if let Some(sys) = config.api.system_prompt { - agent = agent.with_system_prompt(sys); - } - - // Create event channel for progress - let (tx, mut rx) = mpsc::channel(100); - let agent = agent.with_event_channel(tx); - - // Spawn agent execution - let agent_handle = tokio::spawn(async move { agent.run(&prompt).await }); - - // Process events - while let Some(event) = rx.recv().await { - match &event { - AgentEvent::Started { prompt } => { - if format != "json" { - eprintln!("🚀 Agent started with prompt: {}", truncate_str(prompt, 50)); - } - } - AgentEvent::Thinking { iteration } => { - if format != "json" { - eprintln!("💭 Iteration {}", iteration + 1); - } - } - AgentEvent::ToolDetected { name, .. } => { - if format != "json" { - eprintln!("🔧 Tool detected: {}", name); - } - } - AgentEvent::ToolExecuting { name, .. } => { - if format != "json" { - eprintln!("⚡ Executing: {}", name); - } - } - AgentEvent::ToolCompleted { name, .. } => { - if format != "json" { - eprintln!("✅ Completed: {}", name); - } - } - AgentEvent::ToolFailed { name, error } => { - if format != "json" { - eprintln!("❌ Failed {}: {}", name, error); - } - } - AgentEvent::Completed { result } => { - if format == "json" { - println!("{}", serde_json::to_string_pretty(&result)?); - } else { - println!("\n{}", result.output); - eprintln!( - "\n📊 Stats: {} iterations, {} tool calls, {} tokens", - result.iterations, result.tool_calls, result.total_tokens - ); - } - } - AgentEvent::Failed { error } => { - eprintln!("❌ Agent failed: {}", error); - } - _ => {} - } - } - - // Wait for agent to complete - match agent_handle.await? { - Ok(_) => {} - Err(e) => { - eprintln!("Agent error: {}", e); - std::process::exit(1); - } - } - } Some(Commands::Gate { format, emit_event, diff --git a/docs/USER_MANUAL.md b/docs/USER_MANUAL.md index 357b428..d3acc06 100644 --- a/docs/USER_MANUAL.md +++ b/docs/USER_MANUAL.md @@ -1,578 +1,172 @@ # MergeGate ユーザーマニュアル **Version**: 0.1.0 -**Last Updated**: 2025-11-23 - ---- - -## 目次 - -1. [はじめに](#はじめに) -2. [インストール](#インストール) -3. [初期設定](#初期設定) -4. [基本的な使い方](#基本的な使い方) -5. [TUIモード](#tuiモード) -6. [Agentモード](#agentモード) -7. [セッション管理](#セッション管理) -8. [設定ファイル](#設定ファイル) -9. [プロジェクトルール](#プロジェクトルール) -10. [トラブルシューティング](#トラブルシューティング) - ---- +**Last Updated**: 2026-04-10 ## はじめに -MergeGate は、AI-assisted development 向けの deterministic task execution and merge workflow です。CLI では `miyabi` と `mergegate` の両方を使え、対話型の TUI と `gate` ベースの repo workflow を提供します。 +MergeGate は、AI-assisted development 向けの engine-agnostic gate CLI です。 -設計思想はシンプルです。 +このツールはエージェント本体ではありません。TUI や direct backend を前提にせず、repo 作業を安全に進めるための protocol を提供します。 + +役割は次の通りです。 + +- task を登録する +- impact を記録する +- file lock を取る +- branch / PR / merge 状態を結び付ける +- completion を記録する + +設計思想: - `GitNexus`: コードベースを理解する - `MergeGate`: 変更を安全に実行する -影響範囲が分かるだけでは、AI エージェントは安全に開発できません。どの task を登録し、どのファイルを lock し、どの順序で branch / PR / merge まで進めるかを protocol として固定するのが MergeGate の役割です。 +## 何をするツールか -### 主な機能 +MergeGate の中心機能は `gate` です。 -- **TUIモード**: 美しいターミナルUIでの対話 -- **Agentモード**: ファイル操作やコマンド実行を含む自律実行 -- **セッション管理**: 会話履歴の保存・再開 -- **プロジェクトルール**: .miyabirulesによるカスタムルール +```bash +mergegate gate ... +``` ---- +または互換 alias として: + +```bash +miyabi gate ... +``` + +実行エンジンは Claude Code、Codex、Gemini CLI など、どれでも構いません。MergeGate はその前後で repo workflow を制御します。 ## インストール ### 必要要件 - Rust 1.70以上 -- Anthropic APIキー -### ビルド手順 +### ビルド ```bash -# 1. リポジトリをクローン git clone https://github.com/ShunsukeHayashi/mergegate.git cd mergegate - -# 2. リリースビルド cargo build --release - -# 3. バイナリの確認 -ls -la target/release/miyabi target/release/mergegate ``` -### パスを通す(オプション) +## 最初にやること + +### 1. repo の状態確認 ```bash -# ~/.bashrc または ~/.zshrc に追加 -export PATH="$PATH:/path/to/mergegate/target/release" - -# 設定を反映 -source ~/.bashrc # または source ~/.zshrc +./target/release/mergegate gate status ``` ---- +`tasks: 0` は正常です。ledger はあるが task がまだ無い状態です。 -## 初期設定 - -### 1. 設定ファイルの生成 +### 2. 初期化 ```bash -./target/release/miyabi init +./target/release/mergegate gate init ``` -これにより `~/.miyabi/config.toml` が作成されます。 +これで `project_memory/tasks.json` が作成されます。 -### 2. APIキーの設定 - -**方法1: 環境変数(推奨)** -```bash -export ANTHROPIC_API_KEY="sk-ant-api03-..." -``` - -永続化する場合は `~/.bashrc` や `~/.zshrc` に追加: -```bash -echo 'export ANTHROPIC_API_KEY="sk-ant-api03-..."' >> ~/.zshrc -``` - -**方法2: 設定ファイル** -```bash -vim ~/.miyabi/config.toml -``` - -```toml -[api] -api_key = "sk-ant-api03-..." -``` - -### 3. 設定の確認 +### 3. ガイド確認 ```bash -./target/release/miyabi status +./target/release/mergegate gate guide ``` -出力例: -``` -Miyabi Status: Ready +## 基本フロー -Config: /Users/you/.miyabi/config.toml -Sessions: /Users/you/.miyabi/sessions -Model: claude-sonnet-4-5-20250929 - -Rules: 0 rules loaded +```bash +./target/release/mergegate gate register --issue 123 --title "Fix login redirect" +./target/release/mergegate gate impact issue-123 --risk medium --symbols 3 +./target/release/mergegate gate assign issue-123 --agent codex --node macbook --files "src/auth.rs" +./target/release/mergegate gate branch issue-123 codex/fix-login-redirect +./target/release/mergegate gate pr issue-123 456 +./target/release/mergegate gate merge issue-123 ``` ---- +典型的な順番: -## 基本的な使い方 +1. `register` +2. `impact` +3. `assign` +4. 実装 +5. `branch` +6. `pr` +7. `merge` または `manual-complete` -### コマンド一覧 +## コマンド一覧 | コマンド | 説明 | |---------|------| -| `miyabi tui` | TUIモードを起動 | -| `miyabi agent ` | Agentモードで実行 | -| `miyabi status` | ステータス表示 | -| `miyabi version` | バージョン情報 | -| `miyabi init` | 設定ファイル生成 | -| `miyabi sessions` | セッション一覧 | -| `miyabi rules` | プロジェクトルール表示 | +| `mergegate gate status` | ledger 全体または task 状態を表示 | +| `mergegate gate init` | ledger を初期化 | +| `mergegate gate guide` | workflow ガイドを表示 | +| `mergegate gate register` | task を登録 | +| `mergegate gate impact` | impact を記録 | +| `mergegate gate assign` | task を割り当てて lock を取得 | +| `mergegate gate branch` | branch を記録 | +| `mergegate gate pr` | PR 番号を記録 | +| `mergegate gate merge` | merge を記録 | +| `mergegate gate manual-complete` | 手動完了を記録 | +| `mergegate gate locks` | active lock を表示 | +| `mergegate gate dispatchable` | 今着手できる task を表示 | +| `mergegate gate dag` | 依存順序を表示 | -### グローバルオプション +## 実行エンジンとの関係 -| オプション | 説明 | -|-----------|------| -| `-m, --model ` | 使用するモデルを指定 | -| `--max-tokens ` | 最大トークン数 | -| `--thinking` | Extended Thinking有効化 | -| `-c, --config ` | 設定ファイルパス | -| `-s, --session ` | セッションID指定 | +MergeGate は coding agent を置き換えるものではありません。 -### 使用例 +想定している使い方: -```bash -# バージョン確認 -./target/release/miyabi version +- Claude Code が実装する +- Codex が実装する +- Gemini CLI が実装する +- MergeGate が task / lock / merge discipline を管理する -# ステータス確認 -./target/release/miyabi status +つまり: -# モデル指定でTUI起動 -./target/release/miyabi tui --model claude-sonnet-4-5-20250929 +- エージェントは交換可能 +- gate protocol は固定 -# Extended Thinking有効でTUI起動 -./target/release/miyabi tui --thinking -``` +## よくある質問 ---- +### API キーは必要ですか -## TUIモード +`gate` workflow だけなら不要です。 -### 起動 +### TUI は必要ですか -```bash -./target/release/miyabi tui -``` +不要です。MergeGate の本体ではありません。 -### キーバインド +### built-in backend は必要ですか -#### 基本操作 +不要です。MergeGate の本体ではありません。 -| キー | 動作 | -|------|------| -| `Enter` | メッセージ送信 | -| `Ctrl+C` | 終了 | -| `Esc` | オーバーレイを閉じる / キャンセル | -| `F1` | ヘルプ表示 | +### `miyabi` と `mergegate` のどちらを使えばいいですか -#### ナビゲーション - -| キー | 動作 | -|------|------| -| `j` / `↓` | 下にスクロール | -| `k` / `↑` | 上にスクロール | -| `Page Down` | ページ下へ | -| `Page Up` | ページ上へ | -| `g` | 先頭へ | -| `G` | 末尾へ | - -#### コマンド - -| キー | 動作 | -|------|------| -| `Ctrl+P` | コマンドパレット | -| `Ctrl+N` | 新規セッション | -| `Ctrl+O` | セッションを開く | -| `Ctrl+S` | セッション保存 | - -### Vimモード - -設定で有効化できます: - -```toml -[ui] -vim_mode = true -``` - -有効にすると、テキスト入力でVimキーバインドが使用可能になります。 - ---- - -## Agentモード - -Agentモードは、プロンプトに基づいて自律的にタスクを実行します。 - -### 基本使用 - -```bash -./target/release/miyabi agent "タスクの説明" -``` - -### オプション - -| オプション | 説明 | デフォルト | -|-----------|------|-----------| -| `--max-iterations ` | 最大イテレーション数 | 10 | -| `--auto-approve` | ツール実行を自動承認 | false | -| `--format ` | 出力形式 (text/json) | text | -| `--system ` | システムプロンプト | なし | - -### 使用例 - -```bash -# 基本的な実行 -./target/release/miyabi agent "Create a Python script that prints hello world" - -# 自動承認モード(注意して使用) -./target/release/miyabi agent --auto-approve "List all .rs files in src/" - -# イテレーション数を増やす -./target/release/miyabi agent --max-iterations 20 "Refactor the utils module" - -# JSON出力 -./target/release/miyabi agent --format json "Show current directory" - -# カスタムシステムプロンプト -./target/release/miyabi agent --system "You are an expert Rust developer" "Review main.rs" -``` - -### 利用可能なツール - -Agentモードでは以下のツールが使用可能です: - -- **Bash**: シェルコマンドの実行 -- **Read**: ファイルの読み取り -- **Write**: ファイルの書き込み -- **Edit**: ファイルの編集 -- **Glob**: ファイルパターン検索 -- **Grep**: テキスト検索 - -### セキュリティ - -- デフォルトでは危険な操作は承認を求められます -- `--auto-approve` は信頼できるタスクのみに使用してください -- `--max-iterations` で無限ループを防止 - ---- - -## セッション管理 - -### セッション一覧の表示 - -```bash -./target/release/miyabi sessions -``` - -出力例: -``` -ID Title Messages Tokens Updated ------------------------------------------------------------------------------------------- -133b91bf-99c9-4097-974c-c60c9abd2495 test 6 246 2025-11-22 14:36 -19af5958-183f-4b39-be2e-b14b0809181c test 2 21 2025-11-22 14:03 -``` - -### セッションの操作 - -```bash -# セッションを削除 -./target/release/miyabi sessions -d - -# JSONにエクスポート -./target/release/miyabi sessions -e - -# Markdownにエクスポート -./target/release/miyabi sessions -m -``` - -### セッションの再開 - -```bash -# 特定のセッションからTUIを起動 -./target/release/miyabi tui -s -``` - -### 保存場所 - -セッションは `~/.miyabi/sessions/` に保存されます。 - ---- - -## 設定ファイル - -### 設定ファイルの場所 - -``` -~/.miyabi/config.toml -``` - -### 完全な設定例 - -```toml -[api] -# Anthropic APIキー(環境変数ANTHROPIC_API_KEYでも設定可能) -api_key = "sk-ant-api03-..." - -# 使用するモデル -model = "claude-sonnet-4-5-20250929" - -# 最大トークン数 -max_tokens = 8192 - -# Extended Thinking(Claude 4.5+) -thinking = false - -# システムプロンプト -system_prompt = "You are a helpful AI assistant." - -# リクエストタイムアウト(秒) -timeout_secs = 120 - -# 最大リトライ回数 -max_retries = 3 - -[ui] -# サイドバー表示 -show_sidebar = false - -# ステータスバー表示 -show_status_bar = true - -# パンくずリスト表示 -show_breadcrumb = true - -# カラーテーマ -theme = "tokyo-night" - -# Vimモード -vim_mode = false - -# コードブロックの行番号 -show_line_numbers = true - -[session] -# セッションの自動保存 -auto_save = true - -# 自動保存間隔(秒) -auto_save_interval = 30 - -# 最大セッション数 -max_sessions = 100 - -[tools] -# Bashツールを有効化 -enable_bash = true - -# ファイルツール(read/write/edit)を有効化 -enable_file_tools = true - -# 検索ツール(glob/grep)を有効化 -enable_search_tools = true - -# 低リスクツールの自動承認 -auto_approve_low_risk = false - -# Bashコマンドのタイムアウト(秒) -bash_timeout = 120 -``` - -### 環境変数による上書き - -| 環境変数 | 説明 | -|---------|------| -| `ANTHROPIC_API_KEY` | APIキー | -| `MIYABI_MODEL` | モデル名 | -| `MIYABI_MAX_TOKENS` | 最大トークン数 | -| `MIYABI_THINKING` | Extended Thinking (true/false) | - ---- - -## プロジェクトルール - -### .miyabirulesファイル - -プロジェクトルートに `.miyabirules` ファイルを作成することで、プロジェクト固有のルールを定義できます。 - -### ファイル形式 - -```yaml -version: 1 - -rules: - - name: "no-unwrap" - pattern: ".unwrap()" - suggestion: "Use ? operator or proper error handling" - file_extensions: ["rs"] - severity: "warning" - - - name: "no-println-debug" - pattern: "println!" - suggestion: "Use tracing macros for logging" - file_extensions: ["rs"] - severity: "info" - -agent_preferences: - codegen: - style: "functional" - error_handling: "result" - min_score: 80 - review: - min_score: 70 -``` - -### ルールの確認 - -```bash -./target/release/miyabi rules -``` - -### 重要度レベル - -| レベル | 説明 | -|--------|------| -| `error` | 重大な問題(赤) | -| `warning` | 警告(黄) | -| `info` | 情報(青) | - ---- +新規利用では `mergegate` を推奨します。`miyabi` は互換 alias です。 ## トラブルシューティング -### "API key not found" エラー +### `tasks: 0` + +異常ではありません。task が未登録なだけです。 + +### どの task から始めればよいか分からない ```bash -# 環境変数を確認 -echo $ANTHROPIC_API_KEY - -# 設定されていない場合 -export ANTHROPIC_API_KEY="sk-ant-..." +./target/release/mergegate gate dispatchable +./target/release/mergegate gate dag +./target/release/mergegate gate guide ``` -### "Device not configured" エラー - -ターミナルがTUIをサポートしていない可能性があります: +### 既存 repo に導入済みか分からない ```bash -# 別のターミナルを試す(iTerm2, Alacritty等) - -# または明示的にTERM設定 -TERM=xterm-256color ./target/release/miyabi tui +./target/release/mergegate gate status ``` -### ビルドエラー - -```bash -# Rustを最新版に更新 -rustup update - -# クリーンビルド -cargo clean -cargo build --release -``` - -### セッションが保存されない - -```bash -# ディレクトリの確認 -ls -la ~/.miyabi/sessions/ - -# なければ作成 -mkdir -p ~/.miyabi/sessions -``` - -### デバッグモード - -詳細なログを表示: - -```bash -RUST_LOG=debug ./target/release/miyabi tui -``` - -### ネットワークエラー - -```bash -# タイムアウトを延長 -# ~/.miyabi/config.toml -[api] -timeout_secs = 300 -max_retries = 5 -``` - ---- - -## サポート - -### ヘルプの確認 - -```bash -# 全体のヘルプ -./target/release/miyabi --help - -# サブコマンドのヘルプ -./target/release/miyabi agent --help -./target/release/miyabi sessions --help -``` - -### 問題報告 - -GitHub Issues: https://github.com/ShunsukeHayashi/mergegate/issues - -### TUIでのヘルプ - -TUI起動中に `F1` キーでヘルプを表示できます。 - ---- - -## 付録 - -### 対応モデル - -- `claude-sonnet-4-5-20250929` (デフォルト) -- `claude-haiku-4-5-20251001` -- `claude-sonnet-4-20250514` - -### ファイル構成 - -``` -~/.miyabi/ -├── config.toml # 設定ファイル -└── sessions/ # セッションデータ - ├── xxx.json - └── yyy.json -``` - -### ショートカット早見表 - -| 操作 | キー | -|------|------| -| 送信 | Enter | -| 終了 | Ctrl+C | -| ヘルプ | F1 | -| コマンドパレット | Ctrl+P | -| 新規セッション | Ctrl+N | -| セッションを開く | Ctrl+O | -| 保存 | Ctrl+S | - ---- - -**Built with Rust, Ratatui, and Claude API** +ledger が無ければ `gate init` に進めます。