refactor: rename project surface to mergegate
This commit is contained in:
parent
3f1453b23c
commit
29c72fee83
111 changed files with 1586 additions and 873 deletions
|
|
@ -5,7 +5,7 @@ GITHUB_TOKEN=ghp_your_github_token_here
|
||||||
|
|
||||||
# Repository Information
|
# Repository Information
|
||||||
# Format: owner/repo (e.g., YourUsername/my-project)
|
# Format: owner/repo (e.g., YourUsername/my-project)
|
||||||
REPOSITORY=ShunsukeHayashi/miyabi-cli-standalone
|
REPOSITORY=ShunsukeHayashi/mergegate
|
||||||
|
|
||||||
# Anthropic API Key (optional for local development)
|
# Anthropic API Key (optional for local development)
|
||||||
# Get key at: https://console.anthropic.com/
|
# Get key at: https://console.anthropic.com/
|
||||||
|
|
|
||||||
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -176,3 +176,6 @@ yarn-error.log*
|
||||||
.ai/
|
.ai/
|
||||||
.env
|
.env
|
||||||
.gitnexus
|
.gitnexus
|
||||||
|
project_memory/task-events.jsonl
|
||||||
|
project_memory/tasks.snapshot.json
|
||||||
|
project_memory/.tasks.lock
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
# Repository Guidelines
|
# Repository Guidelines
|
||||||
|
|
||||||
## Project Structure & Module Organization
|
## Project Structure & Module Organization
|
||||||
- Rust workspace lives under `crates/`: `miyabi-cli` (CLI entry), `miyabi-tui` (UI), and `miyabi-core` (shared logic, config, sessions, Polaris/DTP: `gate`, `store`, `lock`, `protocol`). Shared workspace config in `Cargo.toml`.
|
- Rust workspace lives under `crates/`: `mergegate-cli` (CLI entry), `mergegate-tui` (UI), and `mergegate-core` (shared logic, config, sessions, MergeGate/DTP: `gate`, `store`, `lock`, `protocol`). Shared workspace config in `Cargo.toml`.
|
||||||
- ルートに `package.json` はない(過去テンプレート由来の記述は削除済み)。フロント系ツールが別ディレクトリにあれば、その README に従う。
|
- ルートに `package.json` はない(過去テンプレート由来の記述は削除済み)。フロント系ツールが別ディレクトリにあれば、その README に従う。
|
||||||
- Supporting assets: `.claude/` agent configs, `docs/` for design notes, `project_memory/` for Polaris タスク台帳(`tasks.json`)、`.github/` for CI workflows。
|
- Supporting assets: `.claude/` agent configs, `docs/` for design notes, `project_memory/` for Polaris タスク台帳(`tasks.json`)、`.github/` for CI workflows。
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -181,7 +181,7 @@ miyabi gate manual-complete <task-id> --reason "理由" --operator "名前"
|
||||||
<!-- gitnexus:start -->
|
<!-- gitnexus:start -->
|
||||||
# GitNexus — Code Intelligence
|
# GitNexus — Code Intelligence
|
||||||
|
|
||||||
This project is indexed by GitNexus as **miyabi-cli-standalone** (5691 symbols, 12441 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
This project is indexed by GitNexus as **miyabi-cli-standalone** (5866 symbols, 12893 relationships, 300 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
||||||
|
|
||||||
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
||||||
|
|
||||||
|
|
|
||||||
575
Cargo.lock
generated
575
Cargo.lock
generated
|
|
@ -146,6 +146,21 @@ dependencies = [
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-set"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||||
|
dependencies = [
|
||||||
|
"bit-vec",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bit-vec"
|
||||||
|
version = "0.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.10.0"
|
version = "2.10.0"
|
||||||
|
|
@ -209,6 +224,12 @@ version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg_aliases"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
version = "0.4.42"
|
version = "0.4.42"
|
||||||
|
|
@ -301,16 +322,6 @@ dependencies = [
|
||||||
"unicode-segmentation",
|
"unicode-segmentation",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "core-foundation"
|
|
||||||
version = "0.9.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "core-foundation-sys"
|
name = "core-foundation-sys"
|
||||||
version = "0.8.7"
|
version = "0.8.7"
|
||||||
|
|
@ -498,15 +509,6 @@ version = "1.15.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "encoding_rs"
|
|
||||||
version = "0.8.35"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
|
@ -592,21 +594,6 @@ version = "0.1.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types"
|
|
||||||
version = "0.3.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
|
||||||
dependencies = [
|
|
||||||
"foreign-types-shared",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "foreign-types-shared"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "form_urlencoded"
|
name = "form_urlencoded"
|
||||||
version = "1.2.2"
|
version = "1.2.2"
|
||||||
|
|
@ -741,8 +728,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi",
|
"wasi",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -752,9 +741,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"r-efi",
|
"r-efi",
|
||||||
"wasip2",
|
"wasip2",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -778,25 +769,6 @@ version = "0.3.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "h2"
|
|
||||||
version = "0.4.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386"
|
|
||||||
dependencies = [
|
|
||||||
"atomic-waker",
|
|
||||||
"bytes",
|
|
||||||
"fnv",
|
|
||||||
"futures-core",
|
|
||||||
"futures-sink",
|
|
||||||
"http",
|
|
||||||
"indexmap",
|
|
||||||
"slab",
|
|
||||||
"tokio",
|
|
||||||
"tokio-util",
|
|
||||||
"tracing",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "half"
|
name = "half"
|
||||||
version = "2.7.1"
|
version = "2.7.1"
|
||||||
|
|
@ -881,7 +853,6 @@ dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"h2",
|
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
|
|
@ -907,22 +878,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-rustls",
|
"tokio-rustls",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
]
|
"webpki-roots",
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "hyper-tls"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0"
|
|
||||||
dependencies = [
|
|
||||||
"bytes",
|
|
||||||
"http-body-util",
|
|
||||||
"hyper",
|
|
||||||
"hyper-util",
|
|
||||||
"native-tls",
|
|
||||||
"tokio",
|
|
||||||
"tokio-native-tls",
|
|
||||||
"tower-service",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -944,11 +900,9 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2",
|
||||||
"system-configuration",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-registry",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1302,6 +1256,12 @@ dependencies = [
|
||||||
"hashbrown 0.15.5",
|
"hashbrown 0.15.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lru-slab"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "matchers"
|
name = "matchers"
|
||||||
version = "0.2.0"
|
version = "0.2.0"
|
||||||
|
|
@ -1318,10 +1278,72 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "mime"
|
name = "mergegate-cli"
|
||||||
version = "0.3.17"
|
version = "0.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
dependencies = [
|
||||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
"anyhow",
|
||||||
|
"chrono",
|
||||||
|
"clap",
|
||||||
|
"crossterm 0.29.0",
|
||||||
|
"mergegate-core",
|
||||||
|
"mergegate-tui",
|
||||||
|
"ratatui",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mergegate-core"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"async-trait",
|
||||||
|
"chrono",
|
||||||
|
"dirs",
|
||||||
|
"fs2",
|
||||||
|
"futures",
|
||||||
|
"git2",
|
||||||
|
"glob",
|
||||||
|
"proptest",
|
||||||
|
"regex",
|
||||||
|
"reqwest",
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
"serde_yaml",
|
||||||
|
"tempfile",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
"tokio",
|
||||||
|
"toml",
|
||||||
|
"tracing",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"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]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
|
|
@ -1345,72 +1367,6 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miyabi-cli"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"chrono",
|
|
||||||
"clap",
|
|
||||||
"crossterm 0.29.0",
|
|
||||||
"miyabi-core",
|
|
||||||
"miyabi-tui",
|
|
||||||
"ratatui",
|
|
||||||
"serde_json",
|
|
||||||
"tokio",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miyabi-core"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"async-trait",
|
|
||||||
"chrono",
|
|
||||||
"dirs",
|
|
||||||
"fs2",
|
|
||||||
"futures",
|
|
||||||
"git2",
|
|
||||||
"glob",
|
|
||||||
"regex",
|
|
||||||
"reqwest",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"serde_yaml",
|
|
||||||
"tempfile",
|
|
||||||
"thiserror 2.0.17",
|
|
||||||
"tokio",
|
|
||||||
"toml",
|
|
||||||
"tracing",
|
|
||||||
"tracing-subscriber",
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "miyabi-tui"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"anyhow",
|
|
||||||
"arboard",
|
|
||||||
"chrono",
|
|
||||||
"crossterm 0.29.0",
|
|
||||||
"futures",
|
|
||||||
"miyabi-core",
|
|
||||||
"once_cell",
|
|
||||||
"pulldown-cmark",
|
|
||||||
"ratatui",
|
|
||||||
"serde",
|
|
||||||
"serde_json",
|
|
||||||
"syntect",
|
|
||||||
"textwrap",
|
|
||||||
"thiserror 2.0.17",
|
|
||||||
"tokio",
|
|
||||||
"unicode-width 0.2.0",
|
|
||||||
"uuid",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "moxcms"
|
name = "moxcms"
|
||||||
version = "0.7.9"
|
version = "0.7.9"
|
||||||
|
|
@ -1421,23 +1377,6 @@ dependencies = [
|
||||||
"pxfm",
|
"pxfm",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "native-tls"
|
|
||||||
version = "0.2.14"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"log",
|
|
||||||
"openssl",
|
|
||||||
"openssl-probe",
|
|
||||||
"openssl-sys",
|
|
||||||
"schannel",
|
|
||||||
"security-framework",
|
|
||||||
"security-framework-sys",
|
|
||||||
"tempfile",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nu-ansi-term"
|
name = "nu-ansi-term"
|
||||||
version = "0.50.3"
|
version = "0.50.3"
|
||||||
|
|
@ -1569,38 +1508,21 @@ dependencies = [
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl"
|
|
||||||
version = "0.10.75"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"cfg-if",
|
|
||||||
"foreign-types",
|
|
||||||
"libc",
|
|
||||||
"once_cell",
|
|
||||||
"openssl-macros",
|
|
||||||
"openssl-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "openssl-macros"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-probe"
|
name = "openssl-probe"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "openssl-src"
|
||||||
|
version = "300.5.4+3.5.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl-sys"
|
name = "openssl-sys"
|
||||||
version = "0.9.111"
|
version = "0.9.111"
|
||||||
|
|
@ -1609,6 +1531,7 @@ checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cc",
|
"cc",
|
||||||
"libc",
|
"libc",
|
||||||
|
"openssl-src",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
@ -1713,6 +1636,15 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ppv-lite86"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9"
|
||||||
|
dependencies = [
|
||||||
|
"zerocopy",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.103"
|
version = "1.0.103"
|
||||||
|
|
@ -1722,6 +1654,25 @@ dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proptest"
|
||||||
|
version = "1.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744"
|
||||||
|
dependencies = [
|
||||||
|
"bit-set",
|
||||||
|
"bit-vec",
|
||||||
|
"bitflags",
|
||||||
|
"num-traits",
|
||||||
|
"rand",
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_xorshift",
|
||||||
|
"regex-syntax",
|
||||||
|
"rusty-fork",
|
||||||
|
"tempfile",
|
||||||
|
"unarray",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pulldown-cmark"
|
name = "pulldown-cmark"
|
||||||
version = "0.12.2"
|
version = "0.12.2"
|
||||||
|
|
@ -1750,6 +1701,12 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quick-error"
|
||||||
|
version = "1.2.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quick-error"
|
name = "quick-error"
|
||||||
version = "2.0.1"
|
version = "2.0.1"
|
||||||
|
|
@ -1765,6 +1722,61 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quinn"
|
||||||
|
version = "0.11.9"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"cfg_aliases",
|
||||||
|
"pin-project-lite",
|
||||||
|
"quinn-proto",
|
||||||
|
"quinn-udp",
|
||||||
|
"rustc-hash",
|
||||||
|
"rustls",
|
||||||
|
"socket2",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quinn-proto"
|
||||||
|
version = "0.11.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
"lru-slab",
|
||||||
|
"rand",
|
||||||
|
"ring",
|
||||||
|
"rustc-hash",
|
||||||
|
"rustls",
|
||||||
|
"rustls-pki-types",
|
||||||
|
"slab",
|
||||||
|
"thiserror 2.0.17",
|
||||||
|
"tinyvec",
|
||||||
|
"tracing",
|
||||||
|
"web-time",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quinn-udp"
|
||||||
|
version = "0.5.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg_aliases",
|
||||||
|
"libc",
|
||||||
|
"once_cell",
|
||||||
|
"socket2",
|
||||||
|
"tracing",
|
||||||
|
"windows-sys 0.60.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quote"
|
name = "quote"
|
||||||
version = "1.0.42"
|
version = "1.0.42"
|
||||||
|
|
@ -1780,6 +1792,44 @@ version = "5.3.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand"
|
||||||
|
version = "0.9.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1"
|
||||||
|
dependencies = [
|
||||||
|
"rand_chacha",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_chacha"
|
||||||
|
version = "0.9.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb"
|
||||||
|
dependencies = [
|
||||||
|
"ppv-lite86",
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_core"
|
||||||
|
version = "0.9.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c"
|
||||||
|
dependencies = [
|
||||||
|
"getrandom 0.3.4",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_xorshift"
|
||||||
|
version = "0.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ratatui"
|
name = "ratatui"
|
||||||
version = "0.29.0"
|
version = "0.29.0"
|
||||||
|
|
@ -1858,30 +1908,27 @@ checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"base64",
|
"base64",
|
||||||
"bytes",
|
"bytes",
|
||||||
"encoding_rs",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"h2",
|
|
||||||
"http",
|
"http",
|
||||||
"http-body",
|
"http-body",
|
||||||
"http-body-util",
|
"http-body-util",
|
||||||
"hyper",
|
"hyper",
|
||||||
"hyper-rustls",
|
"hyper-rustls",
|
||||||
"hyper-tls",
|
|
||||||
"hyper-util",
|
"hyper-util",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"mime",
|
|
||||||
"native-tls",
|
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
|
"quinn",
|
||||||
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"sync_wrapper",
|
"sync_wrapper",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-native-tls",
|
"tokio-rustls",
|
||||||
"tokio-util",
|
"tokio-util",
|
||||||
"tower",
|
"tower",
|
||||||
"tower-http",
|
"tower-http",
|
||||||
|
|
@ -1891,6 +1938,7 @@ dependencies = [
|
||||||
"wasm-bindgen-futures",
|
"wasm-bindgen-futures",
|
||||||
"wasm-streams",
|
"wasm-streams",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
"webpki-roots",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1907,6 +1955,12 @@ dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.44"
|
version = "0.38.44"
|
||||||
|
|
@ -1940,6 +1994,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
|
checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"once_cell",
|
"once_cell",
|
||||||
|
"ring",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"rustls-webpki",
|
"rustls-webpki",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
|
@ -1952,6 +2007,7 @@ version = "1.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a"
|
checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"web-time",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
@ -1972,6 +2028,18 @@ version = "1.0.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rusty-fork"
|
||||||
|
version = "0.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2"
|
||||||
|
dependencies = [
|
||||||
|
"fnv",
|
||||||
|
"quick-error 1.2.3",
|
||||||
|
"tempfile",
|
||||||
|
"wait-timeout",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.20"
|
version = "1.0.20"
|
||||||
|
|
@ -1987,44 +2055,12 @@ dependencies = [
|
||||||
"winapi-util",
|
"winapi-util",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "schannel"
|
|
||||||
version = "0.1.28"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1"
|
|
||||||
dependencies = [
|
|
||||||
"windows-sys 0.61.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "security-framework"
|
|
||||||
version = "2.11.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"core-foundation",
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
"security-framework-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "security-framework-sys"
|
|
||||||
version = "2.15.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.228"
|
version = "1.0.228"
|
||||||
|
|
@ -2279,27 +2315,6 @@ dependencies = [
|
||||||
"yaml-rust",
|
"yaml-rust",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "system-configuration"
|
|
||||||
version = "0.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
|
|
||||||
dependencies = [
|
|
||||||
"bitflags",
|
|
||||||
"core-foundation",
|
|
||||||
"system-configuration-sys",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "system-configuration-sys"
|
|
||||||
version = "0.6.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
|
|
||||||
dependencies = [
|
|
||||||
"core-foundation-sys",
|
|
||||||
"libc",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.23.0"
|
version = "3.23.0"
|
||||||
|
|
@ -2382,7 +2397,7 @@ dependencies = [
|
||||||
"fax",
|
"fax",
|
||||||
"flate2",
|
"flate2",
|
||||||
"half",
|
"half",
|
||||||
"quick-error",
|
"quick-error 2.0.1",
|
||||||
"weezl",
|
"weezl",
|
||||||
"zune-jpeg",
|
"zune-jpeg",
|
||||||
]
|
]
|
||||||
|
|
@ -2428,6 +2443,21 @@ dependencies = [
|
||||||
"zerovec",
|
"zerovec",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec"
|
||||||
|
version = "1.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa"
|
||||||
|
dependencies = [
|
||||||
|
"tinyvec_macros",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tinyvec_macros"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio"
|
name = "tokio"
|
||||||
version = "1.48.0"
|
version = "1.48.0"
|
||||||
|
|
@ -2455,16 +2485,6 @@ dependencies = [
|
||||||
"syn",
|
"syn",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "tokio-native-tls"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
|
||||||
dependencies = [
|
|
||||||
"native-tls",
|
|
||||||
"tokio",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tokio-rustls"
|
name = "tokio-rustls"
|
||||||
version = "0.26.4"
|
version = "0.26.4"
|
||||||
|
|
@ -2654,6 +2674,12 @@ version = "0.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unarray"
|
||||||
|
version = "0.1.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicase"
|
name = "unicase"
|
||||||
version = "2.8.1"
|
version = "2.8.1"
|
||||||
|
|
@ -2761,6 +2787,15 @@ version = "0.2.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wait-timeout"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.5.0"
|
version = "2.5.0"
|
||||||
|
|
@ -2876,6 +2911,25 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "web-time"
|
||||||
|
version = "1.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||||
|
dependencies = [
|
||||||
|
"js-sys",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "webpki-roots"
|
||||||
|
version = "1.0.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed"
|
||||||
|
dependencies = [
|
||||||
|
"rustls-pki-types",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "weezl"
|
name = "weezl"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
|
|
@ -2954,17 +3008,6 @@ version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-registry"
|
|
||||||
version = "0.6.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720"
|
|
||||||
dependencies = [
|
|
||||||
"windows-link",
|
|
||||||
"windows-result",
|
|
||||||
"windows-strings",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-result"
|
name = "windows-result"
|
||||||
version = "0.4.1"
|
version = "0.4.1"
|
||||||
|
|
|
||||||
12
Cargo.toml
12
Cargo.toml
|
|
@ -1,9 +1,9 @@
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
members = [
|
members = [
|
||||||
"crates/miyabi-cli",
|
"crates/mergegate-cli",
|
||||||
"crates/miyabi-tui",
|
"crates/mergegate-tui",
|
||||||
"crates/miyabi-core",
|
"crates/mergegate-core",
|
||||||
]
|
]
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
|
|
@ -12,9 +12,9 @@ edition = "2021"
|
||||||
rust-version = "1.75"
|
rust-version = "1.75"
|
||||||
authors = ["Miyabi Team"]
|
authors = ["Miyabi Team"]
|
||||||
license = "BUSL-1.1"
|
license = "BUSL-1.1"
|
||||||
repository = "https://github.com/ShunsukeHayashi/miyabi-cli-standalone"
|
repository = "https://github.com/ShunsukeHayashi/mergegate"
|
||||||
homepage = "https://github.com/ShunsukeHayashi/miyabi-cli-standalone"
|
homepage = "https://github.com/ShunsukeHayashi/mergegate"
|
||||||
description = "Miyabi - Autonomous AI Development Framework"
|
description = "MergeGate - Deterministic task execution and merge workflow for AI-assisted development"
|
||||||
keywords = ["ai", "cli", "tui", "autonomous", "development"]
|
keywords = ["ai", "cli", "tui", "autonomous", "development"]
|
||||||
categories = ["command-line-utilities", "development-tools"]
|
categories = ["command-line-utilities", "development-tools"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,7 @@ cargo clippy --all-targets -- -D warnings
|
||||||
cargo fmt --all --check
|
cargo fmt --all --check
|
||||||
|
|
||||||
# 実行
|
# 実行
|
||||||
cargo run -p miyabi-cli
|
cargo run -p mergegate-cli --bin mergegate
|
||||||
```
|
```
|
||||||
|
|
||||||
## ライセンス
|
## ライセンス
|
||||||
|
|
|
||||||
|
|
@ -1,2 +1,13 @@
|
||||||
# miyabi-cli-standalone
|
# MergeGate
|
||||||
Autonomous development powered by Agentic OS
|
Deterministic execution protocol 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`
|
||||||
|
|
||||||
|
- `miyabi tui` / `mergegate tui`: terminal assistant
|
||||||
|
- `miyabi gate` / `mergegate gate`: deterministic task execution, file locks, and PR/merge workflow
|
||||||
|
|
||||||
|
Start with `cargo build --release`, then run `./target/release/mergegate --help` or `./target/release/mergegate gate guide`.
|
||||||
|
|
|
||||||
134
README.md
134
README.md
|
|
@ -1,34 +1,62 @@
|
||||||
# Miyabi CLI
|
# MergeGate
|
||||||
|
|
||||||
A powerful terminal-based AI assistant with TUI (Terminal User Interface) built in Rust.
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
This repository has two common entry points:
|
||||||
|
|
||||||
|
- `miyabi tui` / `mergegate tui`: interactive terminal assistant
|
||||||
|
- `miyabi gate` / `mergegate gate`: deterministic task execution and file-lock workflow for repo work
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
## 60-Second Setup
|
## 60-Second Setup
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. Clone and build
|
# 1. Clone and build
|
||||||
git clone https://github.com/ShunsukeHayashi/miyabi-cli-standalone.git
|
git clone https://github.com/ShunsukeHayashi/mergegate.git
|
||||||
cd miyabi-cli-standalone
|
cd mergegate
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
# 2. Set API key
|
# 2. Set API key
|
||||||
export ANTHROPIC_API_KEY="sk-ant-..."
|
export ANTHROPIC_API_KEY="sk-ant-..."
|
||||||
|
|
||||||
# 3. Run
|
# 3. Run
|
||||||
./target/release/miyabi tui
|
./target/release/mergegate tui
|
||||||
```
|
```
|
||||||
|
|
||||||
That's it! Start chatting with Claude in your terminal.
|
That's it. Start with the TUI, or jump straight into `mergegate gate` for repo workflow control.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Features
|
## Why MergeGate
|
||||||
|
|
||||||
- **Interactive TUI** - Beautiful terminal interface with markdown rendering
|
- **Execution layer for code intelligence** - Pair blast-radius understanding with deterministic execution, not chat-only automation
|
||||||
- **Chat Mode** - Conversational AI assistant
|
- **Deterministic task execution** - Register, analyze, lock, review, and merge in a verifiable order
|
||||||
- **Agent Mode** - Autonomous task execution with tool approval
|
- **Repo-safe agent workflow** - File locks and gate checks reduce accidental overlap and unsafe edits
|
||||||
- **Session Management** - Persist and resume conversations
|
- **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
|
- **Configurable** - TOML-based configuration
|
||||||
- **Extended Thinking** - Support for Claude 4.5+ extended thinking
|
|
||||||
|
## 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.
|
||||||
|
|
||||||
|
That is the role split:
|
||||||
|
|
||||||
|
- `GitNexus`: query, context, impact, detect-changes, rename, wiki, graph exploration
|
||||||
|
- `MergeGate`: register, impact record, assign, file lock, branch, PR, merge, completion discipline
|
||||||
|
|
||||||
|
If GitNexus answers "what is this change connected to?", MergeGate answers "how do we carry it through safely?"
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
|
|
@ -40,16 +68,22 @@ That's it! Start chatting with Claude in your terminal.
|
||||||
### Build from Source
|
### Build from Source
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/ShunsukeHayashi/miyabi-cli-standalone.git
|
git clone https://github.com/ShunsukeHayashi/mergegate.git
|
||||||
cd miyabi-cli-standalone
|
cd mergegate
|
||||||
cargo build --release
|
cargo build --release
|
||||||
```
|
```
|
||||||
|
|
||||||
Binary will be at `target/release/miyabi`.
|
Binary will be at `target/release/miyabi` and `target/release/mergegate`.
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### 1. Generate Config
|
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
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./target/release/miyabi init
|
./target/release/miyabi init
|
||||||
|
|
@ -57,7 +91,7 @@ Binary will be at `target/release/miyabi`.
|
||||||
|
|
||||||
This creates `~/.miyabi/config.toml`.
|
This creates `~/.miyabi/config.toml`.
|
||||||
|
|
||||||
### 2. Set API Key
|
#### 2. Set API Key
|
||||||
|
|
||||||
Edit `~/.miyabi/config.toml`:
|
Edit `~/.miyabi/config.toml`:
|
||||||
|
|
||||||
|
|
@ -72,7 +106,7 @@ Or use environment variable:
|
||||||
export ANTHROPIC_API_KEY="sk-ant-..."
|
export ANTHROPIC_API_KEY="sk-ant-..."
|
||||||
```
|
```
|
||||||
|
|
||||||
### 3. Launch TUI
|
#### 3. Launch TUI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./target/release/miyabi tui
|
./target/release/miyabi tui
|
||||||
|
|
@ -80,8 +114,55 @@ export ANTHROPIC_API_KEY="sk-ant-..."
|
||||||
./target/release/miyabi
|
./target/release/miyabi
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 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
|
||||||
|
|
||||||
|
```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"
|
||||||
|
```
|
||||||
|
|
||||||
|
Typical flow:
|
||||||
|
|
||||||
|
1. `register`
|
||||||
|
2. `impact`
|
||||||
|
3. `assign`
|
||||||
|
4. implement
|
||||||
|
5. `branch`
|
||||||
|
6. `pr`
|
||||||
|
7. `merge` or `manual-complete`
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
`MergeGate` is the product and documentation name.
|
||||||
|
Both `miyabi` and `mergegate` work today.
|
||||||
|
|
||||||
### CLI Commands
|
### CLI Commands
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -94,6 +175,11 @@ miyabi sessions -d <id> # Delete session
|
||||||
miyabi sessions -e <id> # Export session to JSON
|
miyabi sessions -e <id> # Export session to JSON
|
||||||
miyabi version # Show version info
|
miyabi version # Show version info
|
||||||
miyabi agent <prompt> # Run autonomous agent
|
miyabi agent <prompt> # 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
|
||||||
```
|
```
|
||||||
|
|
||||||
### CLI Options
|
### CLI Options
|
||||||
|
|
@ -187,7 +273,7 @@ Agent mode features:
|
||||||
|
|
||||||
## Core Library Features
|
## Core Library Features
|
||||||
|
|
||||||
The `miyabi-core` crate provides powerful utilities for building AI applications.
|
The `mergegate-core` crate provides powerful utilities for building AI applications.
|
||||||
|
|
||||||
### Git Utilities
|
### Git Utilities
|
||||||
|
|
||||||
|
|
@ -373,10 +459,10 @@ flags.load_from_map(config);
|
||||||
## Project Structure
|
## Project Structure
|
||||||
|
|
||||||
```
|
```
|
||||||
miyabi-cli-standalone/
|
mergegate/
|
||||||
├── crates/
|
├── crates/
|
||||||
│ ├── miyabi-cli/ # CLI entry point
|
│ ├── mergegate-cli/ # CLI entry point
|
||||||
│ ├── miyabi-core/ # Core library
|
│ ├── mergegate-core/ # Core library
|
||||||
│ │ ├── agent.rs # Agent system
|
│ │ ├── agent.rs # Agent system
|
||||||
│ │ ├── anthropic.rs # Anthropic API client
|
│ │ ├── anthropic.rs # Anthropic API client
|
||||||
│ │ ├── cache.rs # TTL cache system
|
│ │ ├── cache.rs # TTL cache system
|
||||||
|
|
@ -391,7 +477,7 @@ miyabi-cli-standalone/
|
||||||
│ │ ├── session.rs # Session management
|
│ │ ├── session.rs # Session management
|
||||||
│ │ ├── tools.rs # Built-in tools
|
│ │ ├── tools.rs # Built-in tools
|
||||||
│ │ └── ...
|
│ │ └── ...
|
||||||
│ └── miyabi-tui/ # TUI implementation
|
│ └── mergegate-tui/ # TUI implementation
|
||||||
│ ├── app.rs # Main application
|
│ ├── app.rs # Main application
|
||||||
│ ├── views.rs # UI views
|
│ ├── views.rs # UI views
|
||||||
│ └── ...
|
│ └── ...
|
||||||
|
|
@ -482,7 +568,7 @@ RUST_LOG=debug ./target/release/miyabi tui
|
||||||
|
|
||||||
- Check `miyabi --help` for CLI options
|
- Check `miyabi --help` for CLI options
|
||||||
- Press `F1` in TUI for keybindings
|
- Press `F1` in TUI for keybindings
|
||||||
- Open an issue: https://github.com/ShunsukeHayashi/miyabi-cli-standalone/issues
|
- Open an issue: https://github.com/ShunsukeHayashi/mergegate/issues
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
## 1.1 verify_merge ラッパー (~50行)
|
## 1.1 verify_merge ラッパー (~50行)
|
||||||
|
|
||||||
- [ ] `crates/miyabi-core/src/protocol.rs` に `verify_merge()` を追加
|
- [x] `crates/miyabi-core/src/protocol.rs` に `verify_merge()` を追加
|
||||||
- 既存の `get_pull_request()` (github.rs) を呼ぶ
|
- 既存の `get_pull_request()` (github.rs) を呼ぶ
|
||||||
- `PullRequest.merge_commit_sha` を取得
|
- `PullRequest.merge_commit_sha` を取得
|
||||||
- `pr.state == "merged"` を検証
|
- `pr.state == "merged"` を検証
|
||||||
|
|
@ -12,59 +12,53 @@
|
||||||
- tasks.json 更新: merge_commit + state → done
|
- tasks.json 更新: merge_commit + state → done
|
||||||
- ロック解放
|
- ロック解放
|
||||||
- 後続タスク blocked → pending
|
- 後続タスク blocked → pending
|
||||||
- [ ] CLI に `miyabi gate verify-merge <task-id>` サブコマンド追加
|
- [x] CLI に `miyabi gate verify-merge <task-id>` サブコマンド追加
|
||||||
- [ ] テスト: mock PullRequest で merged → done 遷移
|
- [x] テスト: mock PullRequest で merged → done 遷移
|
||||||
|
|
||||||
## 1.2 escape hatch (~50行)
|
## 1.2 escape hatch (~50行)
|
||||||
|
|
||||||
- [ ] `protocol.rs` に `force_unlock()` 追加
|
- [x] `protocol.rs` に `force_unlock()` 追加
|
||||||
```
|
```
|
||||||
fn force_unlock(&self, task_id: &str, reason: &str, operator: &str) -> Result<()>
|
fn force_unlock(&self, task_id: &str, reason: &str, operator: &str) -> Result<()>
|
||||||
```
|
```
|
||||||
- ロック即解放
|
- ロック即解放
|
||||||
- event log に reason + operator を記録
|
- event log に reason + operator を記録
|
||||||
- state は変更しない(implementing のまま)
|
- state は変更しない(implementing のまま)
|
||||||
- [ ] `protocol.rs` に `manual_complete()` 追加
|
- [x] `protocol.rs` に `manual_complete()` 追加
|
||||||
```
|
```
|
||||||
fn manual_complete(&self, task_id: &str, reason: &str, operator: &str) -> Result<()>
|
fn manual_complete(&self, task_id: &str, reason: &str, operator: &str) -> Result<()>
|
||||||
```
|
```
|
||||||
- PR/merge なしで done に遷移
|
- PR/merge なしで done に遷移
|
||||||
- event log に reason + operator + "manual" を記録
|
- event log に reason + operator + "manual" を記録
|
||||||
- CompletionMode::Manual として区別
|
- `CompletionMode::Manual` として区別(2026-04-10 実装反映)
|
||||||
- [ ] CLI に `miyabi gate force-unlock <task-id> --reason R --operator O` 追加
|
- [x] CLI に `miyabi gate force-unlock <task-id> --reason R --operator O` 追加
|
||||||
- [ ] CLI に `miyabi gate manual-complete <task-id> --reason R --operator O` 追加
|
- [x] CLI に `miyabi gate manual-complete <task-id> --reason R --operator O` 追加
|
||||||
- [ ] テスト: force_unlock → ロック解放確認
|
- [x] テスト: force_unlock → ロック解放確認
|
||||||
- [ ] テスト: manual_complete → done 遷移 + event 記録
|
- [x] テスト: manual_complete → done 遷移 + event 記録
|
||||||
|
|
||||||
## 1.3 E2E テスト (~100行)
|
## 1.3 E2E テスト (~100行)
|
||||||
|
|
||||||
- [ ] `crates/miyabi-core/src/protocol.rs` の tests モジュールに E2E 追加
|
- [x] `crates/miyabi-core/src/protocol.rs` の tests モジュールに E2E 追加(`full_lifecycle_register_to_merged_releases_lock` — マージ完了時は `TaskState::Merged`)
|
||||||
```
|
```
|
||||||
#[test]
|
#[test]
|
||||||
fn full_lifecycle_register_to_done() {
|
fn full_lifecycle_register_to_merged_releases_lock() {
|
||||||
// 1. register(issue=1, title="test")
|
// register → impact → assign → branch → pr → merge(40hex)
|
||||||
// 2. check_dependencies → ready
|
// assert: Merged, lock == None
|
||||||
// 3. record_impact(risk=LOW)
|
|
||||||
// 4. assign_and_lock(agent="test", files=["src/test.rs"])
|
|
||||||
// 5. record_branch("feature/issue-1-test")
|
|
||||||
// 6. record_pr(42)
|
|
||||||
// 7. record_merge("a1b2c3d4...40hex")
|
|
||||||
// 8. assert: state == Done, lock == None
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
- [ ] GATE 拒否テスト: issue=0 → GateError
|
- [x] GATE 拒否テスト: issue=0 → GateError(既存テスト群でカバー)
|
||||||
- [ ] GATE 拒否テスト: impact なしで assign → GateError
|
- [x] GATE 拒否テスト: impact なしで assign → GateError(既存)
|
||||||
- [ ] GATE 拒否テスト: HIGH risk + 承認なし → GateError
|
- [x] GATE 拒否テスト: HIGH risk + 承認なし → GateError(既存)
|
||||||
- [ ] GATE 拒否テスト: ロック競合 → LockError
|
- [x] GATE 拒否テスト: ロック競合 → LockError(既存)
|
||||||
- [ ] GATE 拒否テスト: 不正 SHA → GateError
|
- [x] GATE 拒否テスト: 不正 SHA → GateError(既存)
|
||||||
- [ ] escape hatch テスト: force_unlock + manual_complete
|
- [x] escape hatch テスト: force_unlock + manual_complete
|
||||||
|
|
||||||
## 1.4 最終確認
|
## 1.4 最終確認
|
||||||
|
|
||||||
- [ ] `cargo test --all` → 全 GREEN
|
- [x] `cargo test --all` → 全 GREEN
|
||||||
- [ ] `cargo clippy --all-targets --all-features -- -D warnings` → ゼロエラー
|
- [x] `cargo clippy --all-targets --all-features -- -D warnings` → ゼロエラー
|
||||||
- [ ] `cargo build --release` → リリースビルド成功
|
- [x] `cargo build --release` → リリースビルド成功
|
||||||
- [ ] `npx gitnexus analyze --force` → 再インデックス
|
- [ ] `npx gitnexus analyze --force` → 再インデックス(必要時に手動)
|
||||||
- [ ] `git tag v1.0-dtp-complete`
|
- [ ] `git tag v1.0-dtp-complete`(リリース判断後)
|
||||||
- [ ] `git push origin v1.0-dtp-complete`
|
- [ ] `git push origin v1.0-dtp-complete`
|
||||||
- [ ] `~/bin/announce "Polaris v1.0 完成。全 GATE 実装済み。テスト GREEN。"`
|
- [ ] `~/bin/announce "Polaris v1.0 完成。全 GATE 実装済み。テスト GREEN。"`
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "miyabi-cli"
|
name = "mergegate-cli"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
@ -7,16 +7,20 @@ authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
description = "Miyabi CLI - Main command-line interface"
|
description = "MergeGate CLI - Main command-line interface for deterministic task execution and agent-assisted development"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "miyabi"
|
name = "miyabi"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "mergegate"
|
||||||
|
path = "src/bin/mergegate.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Workspace crates
|
# Workspace crates
|
||||||
miyabi-core = { path = "../miyabi-core" }
|
miyabi-core = { package = "mergegate-core", path = "../mergegate-core" }
|
||||||
miyabi-tui = { path = "../miyabi-tui" }
|
miyabi-tui = { package = "mergegate-tui", path = "../mergegate-tui" }
|
||||||
|
|
||||||
# CLI
|
# CLI
|
||||||
clap = { workspace = true }
|
clap = { workspace = true }
|
||||||
|
|
@ -32,6 +36,7 @@ tokio = { workspace = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
|
||||||
# Serialization
|
# Serialization
|
||||||
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
|
|
||||||
# Utilities
|
# Utilities
|
||||||
1
crates/mergegate-cli/src/bin/mergegate.rs
Normal file
1
crates/mergegate-cli/src/bin/mergegate.rs
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
include!("../main.rs");
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
//! Miyabi CLI - Main entry point
|
/// MergeGate CLI - Main entry point
|
||||||
|
|
||||||
use chrono::Duration as ChronoDuration;
|
use chrono::Duration as ChronoDuration;
|
||||||
use clap::{Parser, Subcommand, ValueEnum};
|
use clap::{CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum};
|
||||||
use miyabi_core::{FeatureFlagManager, RulesLoader};
|
use miyabi_core::{FeatureFlagManager, RulesLoader};
|
||||||
|
use serde::Serialize;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
use std::io::{self, BufRead, BufReader, Write};
|
use std::io::{self, BufRead, BufReader, Write};
|
||||||
|
|
@ -13,6 +14,7 @@ use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
/// Global feature flags manager
|
/// Global feature flags manager
|
||||||
static FEATURE_FLAGS: std::sync::OnceLock<FeatureFlagManager> = std::sync::OnceLock::new();
|
static FEATURE_FLAGS: std::sync::OnceLock<FeatureFlagManager> = std::sync::OnceLock::new();
|
||||||
|
static INVOKED_BINARY_NAME: std::sync::OnceLock<String> = std::sync::OnceLock::new();
|
||||||
|
|
||||||
/// Get the global feature flags manager
|
/// Get the global feature flags manager
|
||||||
pub fn feature_flags() -> &'static FeatureFlagManager {
|
pub fn feature_flags() -> &'static FeatureFlagManager {
|
||||||
|
|
@ -27,9 +29,40 @@ pub fn feature_flags() -> &'static FeatureFlagManager {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn detect_invoked_binary_name() -> String {
|
||||||
|
std::env::args()
|
||||||
|
.next()
|
||||||
|
.and_then(|path| {
|
||||||
|
std::path::Path::new(&path)
|
||||||
|
.file_name()
|
||||||
|
.map(|name| name.to_string_lossy().into_owned())
|
||||||
|
})
|
||||||
|
.filter(|name| !name.is_empty())
|
||||||
|
.unwrap_or_else(|| "miyabi".to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn current_binary_name() -> &'static str {
|
||||||
|
INVOKED_BINARY_NAME
|
||||||
|
.get_or_init(detect_invoked_binary_name)
|
||||||
|
.as_str()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gate_command(command: &str) -> String {
|
||||||
|
if command.is_empty() {
|
||||||
|
format!("{} gate", current_binary_name())
|
||||||
|
} else {
|
||||||
|
format!("{} gate {}", current_binary_name(), command)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn agent_guide() -> String {
|
||||||
|
AGENT_GUIDE_TEMPLATE
|
||||||
|
.replace("{{GATE}}", &gate_command(""))
|
||||||
|
.replace("{{BINARY}}", current_binary_name())
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[command(name = "miyabi")]
|
#[command(author, version, about = "MergeGate - Deterministic task execution and merge workflow for AI-assisted development", long_about = None)]
|
||||||
#[command(author, version, about = "Miyabi - Autonomous AI Development Framework", long_about = None)]
|
|
||||||
struct Cli {
|
struct Cli {
|
||||||
/// Model to use (overrides config)
|
/// Model to use (overrides config)
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
|
|
@ -102,12 +135,15 @@ enum Commands {
|
||||||
},
|
},
|
||||||
#[command(
|
#[command(
|
||||||
about = "Deterministic Task Protocol gate controls",
|
about = "Deterministic Task Protocol gate controls",
|
||||||
long_about = "Run miyabi gate init to set up a new project.\n\nDeterministic Task Protocol gate controls"
|
long_about = "Run the gate init command to set up a new project.\n\nDeterministic Task Protocol gate controls"
|
||||||
)]
|
)]
|
||||||
Gate {
|
Gate {
|
||||||
/// Output format
|
/// Output format
|
||||||
#[arg(long, value_enum, default_value_t = OutputFormat::Text)]
|
#[arg(long, value_enum, default_value_t = OutputFormat::Text)]
|
||||||
format: OutputFormat,
|
format: OutputFormat,
|
||||||
|
/// Emit a hook-friendly JSON event envelope to stdout
|
||||||
|
#[arg(long)]
|
||||||
|
emit_event: bool,
|
||||||
/// Path to the task ledger JSON file
|
/// Path to the task ledger JSON file
|
||||||
#[arg(long, default_value = "project_memory/tasks.json")]
|
#[arg(long, default_value = "project_memory/tasks.json")]
|
||||||
store_path: PathBuf,
|
store_path: PathBuf,
|
||||||
|
|
@ -278,7 +314,7 @@ enum GateCommand {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize)]
|
||||||
struct AssignPlanAttachment {
|
struct AssignPlanAttachment {
|
||||||
attachment_type: String,
|
attachment_type: String,
|
||||||
source: String,
|
source: String,
|
||||||
|
|
@ -286,7 +322,7 @@ struct AssignPlanAttachment {
|
||||||
content: String,
|
content: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize)]
|
||||||
struct AssignExecutionPlan {
|
struct AssignExecutionPlan {
|
||||||
task_title: String,
|
task_title: String,
|
||||||
risk_level: Option<String>,
|
risk_level: Option<String>,
|
||||||
|
|
@ -296,7 +332,7 @@ struct AssignExecutionPlan {
|
||||||
next_steps: Vec<String>,
|
next_steps: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Serialize)]
|
||||||
struct InitStatus {
|
struct InitStatus {
|
||||||
initialized: bool,
|
initialized: bool,
|
||||||
current_dir: String,
|
current_dir: String,
|
||||||
|
|
@ -409,7 +445,11 @@ async fn main() -> anyhow::Result<()> {
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
.init();
|
.init();
|
||||||
|
|
||||||
let cli = Cli::parse();
|
let invoked_binary_name = detect_invoked_binary_name();
|
||||||
|
let _ = INVOKED_BINARY_NAME.set(invoked_binary_name.clone());
|
||||||
|
let clap_binary_name: &'static str = Box::leak(invoked_binary_name.into_boxed_str());
|
||||||
|
let matches = Cli::command().name(clap_binary_name).get_matches();
|
||||||
|
let cli = Cli::from_arg_matches(&matches).unwrap_or_else(|error| error.exit());
|
||||||
|
|
||||||
match cli.command {
|
match cli.command {
|
||||||
Some(Commands::Tui) | None => {
|
Some(Commands::Tui) | None => {
|
||||||
|
|
@ -874,10 +914,11 @@ async fn main() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
Some(Commands::Gate {
|
Some(Commands::Gate {
|
||||||
format,
|
format,
|
||||||
|
emit_event,
|
||||||
store_path,
|
store_path,
|
||||||
command,
|
command,
|
||||||
}) => {
|
}) => {
|
||||||
let code = handle_gate_command(&format, &store_path, command)?;
|
let code = handle_gate_command(&format, emit_event, &store_path, command)?;
|
||||||
std::process::exit(code);
|
std::process::exit(code);
|
||||||
}
|
}
|
||||||
Some(Commands::Openclaw { command }) => {
|
Some(Commands::Openclaw { command }) => {
|
||||||
|
|
@ -1245,6 +1286,7 @@ async fn main() -> anyhow::Result<()> {
|
||||||
|
|
||||||
fn handle_gate_command(
|
fn handle_gate_command(
|
||||||
format: &OutputFormat,
|
format: &OutputFormat,
|
||||||
|
emit_event: bool,
|
||||||
store_path: &std::path::Path,
|
store_path: &std::path::Path,
|
||||||
command: GateCommand,
|
command: GateCommand,
|
||||||
) -> anyhow::Result<i32> {
|
) -> anyhow::Result<i32> {
|
||||||
|
|
@ -1263,7 +1305,10 @@ fn handle_gate_command(
|
||||||
|
|
||||||
let result = match command {
|
let result = match command {
|
||||||
GateCommand::Init => {
|
GateCommand::Init => {
|
||||||
initialize_gate_project(format, store_path)?;
|
let status = initialize_gate_project(format, emit_event, store_path)?;
|
||||||
|
if emit_event {
|
||||||
|
emit_gate_event("gate_initialized", None, &status);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
GateCommand::Register {
|
GateCommand::Register {
|
||||||
|
|
@ -1297,7 +1342,9 @@ fn handle_gate_command(
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("task_registered", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("registered: {} ({})", task.id, task.title);
|
println!("registered: {} ({})", task.id, task.title);
|
||||||
|
|
@ -1312,20 +1359,22 @@ fn handle_gate_command(
|
||||||
.status(task_id.as_deref())
|
.status(task_id.as_deref())
|
||||||
.map(|status| match status {
|
.map(|status| match status {
|
||||||
StatusReport::Task(task) => {
|
StatusReport::Task(task) => {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("task_status", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("{}: {:?} - {}", task.id, task.current_state, task.title);
|
print_gate_task_status(&task);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
StatusReport::Snapshot(snapshot) => {
|
StatusReport::Snapshot(snapshot) => {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("status_snapshot", None, &snapshot);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&snapshot).unwrap());
|
println!("{}", serde_json::to_string_pretty(&snapshot).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("tasks: {}", snapshot.tasks.len());
|
let dispatchable = protocol.dispatchable().ok();
|
||||||
for task in snapshot.tasks {
|
print_gate_snapshot_status(&snapshot, dispatchable.as_ref());
|
||||||
println!(" {} [{:?}] {}", task.id, task.current_state, task.title);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1340,15 +1389,14 @@ fn handle_gate_command(
|
||||||
.and_then(|result| {
|
.and_then(|result| {
|
||||||
let attachments = protocol.attach_context(&task_id, actor, &node)?;
|
let attachments = protocol.attach_context(&task_id, actor, &node)?;
|
||||||
let plan = build_assign_execution_plan(&result.task, attachments);
|
let plan = build_assign_execution_plan(&result.task, attachments);
|
||||||
if matches!(format, OutputFormat::Json) {
|
let output = serde_json::json!({
|
||||||
println!(
|
"assignment": result,
|
||||||
"{}",
|
"plan": assign_plan_to_json(&plan),
|
||||||
serde_json::to_string_pretty(&serde_json::json!({
|
});
|
||||||
"assignment": result,
|
if emit_event {
|
||||||
"plan": assign_plan_to_json(&plan),
|
emit_gate_event("lock_acquired", Some(&task_id), &output);
|
||||||
}))
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
.unwrap()
|
println!("{}", serde_json::to_string_pretty(&output).unwrap());
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
println!("assigned: {} -> {}@{}", result.task.id, agent, agent_node);
|
println!("assigned: {} -> {}@{}", result.task.id, agent, agent_node);
|
||||||
print_assign_execution_plan(&result, &plan);
|
print_assign_execution_plan(&result, &plan);
|
||||||
|
|
@ -1383,7 +1431,9 @@ fn handle_gate_command(
|
||||||
&node,
|
&node,
|
||||||
)
|
)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("impact_recorded", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("impact recorded: {}", task.id);
|
println!("impact recorded: {}", task.id);
|
||||||
|
|
@ -1392,7 +1442,9 @@ fn handle_gate_command(
|
||||||
GateCommand::Branch { task_id, name } => protocol
|
GateCommand::Branch { task_id, name } => protocol
|
||||||
.record_branch(&task_id, &name, actor, &node)
|
.record_branch(&task_id, &name, actor, &node)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("branch_created", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("branch recorded: {} -> {}", task.id, name);
|
println!("branch recorded: {} -> {}", task.id, name);
|
||||||
|
|
@ -1402,7 +1454,9 @@ fn handle_gate_command(
|
||||||
protocol
|
protocol
|
||||||
.attach_context(&task_id, actor, &node)
|
.attach_context(&task_id, actor, &node)
|
||||||
.map(|attachments| {
|
.map(|attachments| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("context_attached", Some(&task_id), &attachments);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&attachments).unwrap());
|
println!("{}", serde_json::to_string_pretty(&attachments).unwrap());
|
||||||
} else if attachments.is_empty() {
|
} else if attachments.is_empty() {
|
||||||
println!("no context attachments: {}", task_id);
|
println!("no context attachments: {}", task_id);
|
||||||
|
|
@ -1427,7 +1481,9 @@ fn handle_gate_command(
|
||||||
protocol
|
protocol
|
||||||
.refresh_context(&task_id, actor, &node)
|
.refresh_context(&task_id, actor, &node)
|
||||||
.map(|attachments| {
|
.map(|attachments| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("context_refreshed", Some(&task_id), &attachments);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&attachments).unwrap());
|
println!("{}", serde_json::to_string_pretty(&attachments).unwrap());
|
||||||
} else if attachments.is_empty() {
|
} else if attachments.is_empty() {
|
||||||
println!("no context attachments: {}", task_id);
|
println!("no context attachments: {}", task_id);
|
||||||
|
|
@ -1448,7 +1504,9 @@ fn handle_gate_command(
|
||||||
GateCommand::Pr { task_id, number } => protocol
|
GateCommand::Pr { task_id, number } => protocol
|
||||||
.record_pr(&task_id, number, actor, &node)
|
.record_pr(&task_id, number, actor, &node)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("pr_created", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("pr recorded: {} -> #{}", task.id, number);
|
println!("pr recorded: {} -> #{}", task.id, number);
|
||||||
|
|
@ -1457,7 +1515,9 @@ fn handle_gate_command(
|
||||||
GateCommand::Merge { task_id, sha } => protocol
|
GateCommand::Merge { task_id, sha } => protocol
|
||||||
.record_merge(&task_id, &sha, actor, &node)
|
.record_merge(&task_id, &sha, actor, &node)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("task_completed", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("merge recorded: {} -> {}", task.id, sha);
|
println!("merge recorded: {} -> {}", task.id, sha);
|
||||||
|
|
@ -1466,7 +1526,9 @@ fn handle_gate_command(
|
||||||
GateCommand::VerifyMerge { task_id, repo } => protocol
|
GateCommand::VerifyMerge { task_id, repo } => protocol
|
||||||
.verify_merge(&task_id, &repo, actor, &node)
|
.verify_merge(&task_id, &repo, actor, &node)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("task_completed", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
let sha = task
|
let sha = task
|
||||||
|
|
@ -1484,7 +1546,9 @@ fn handle_gate_command(
|
||||||
} => protocol
|
} => protocol
|
||||||
.force_unlock(&task_id, &reason, &operator)
|
.force_unlock(&task_id, &reason, &operator)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("lock_released", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("lock released: {} by {}", task.id, operator);
|
println!("lock released: {} by {}", task.id, operator);
|
||||||
|
|
@ -1497,14 +1561,18 @@ fn handle_gate_command(
|
||||||
} => protocol
|
} => protocol
|
||||||
.manual_complete(&task_id, &reason, &operator)
|
.manual_complete(&task_id, &reason, &operator)
|
||||||
.map(|task| {
|
.map(|task| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("task_completed", Some(&task.id), &task);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
println!("{}", serde_json::to_string_pretty(&task).unwrap());
|
||||||
} else {
|
} else {
|
||||||
println!("task completed manually: {} by {}", task.id, operator);
|
println!("task completed manually: {} by {}", task.id, operator);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
GateCommand::Locks => protocol.locks().map(|locks| {
|
GateCommand::Locks => protocol.locks().map(|locks| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("locks_reported", None, &locks);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&locks).unwrap());
|
println!("{}", serde_json::to_string_pretty(&locks).unwrap());
|
||||||
} else if locks.is_empty() {
|
} else if locks.is_empty() {
|
||||||
println!("no active locks");
|
println!("no active locks");
|
||||||
|
|
@ -1515,7 +1583,9 @@ fn handle_gate_command(
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
GateCommand::Dag => protocol.dag().map(|report| {
|
GateCommand::Dag => protocol.dag().map(|report| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("dag_reported", None, &report);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
||||||
} else {
|
} else {
|
||||||
for (index, level) in report.levels.iter().enumerate() {
|
for (index, level) in report.levels.iter().enumerate() {
|
||||||
|
|
@ -1524,10 +1594,16 @@ fn handle_gate_command(
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
GateCommand::Dispatchable => protocol.dispatchable().map(|report| {
|
GateCommand::Dispatchable => protocol.dispatchable().map(|report| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("dispatchable_reported", None, &report);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
||||||
} else if report.tasks.is_empty() {
|
} else if report.tasks.is_empty() {
|
||||||
println!("no dispatchable tasks");
|
println!("no dispatchable tasks");
|
||||||
|
println!("next:");
|
||||||
|
println!(" {}", gate_command("status"));
|
||||||
|
println!(" {}", gate_command("dag"));
|
||||||
|
println!(" {}", gate_command("guide"));
|
||||||
} else {
|
} else {
|
||||||
for task in report.tasks {
|
for task in report.tasks {
|
||||||
println!("{} [{}] {}", task.id, task.priority, task.title);
|
println!("{} [{}] {}", task.id, task.priority, task.title);
|
||||||
|
|
@ -1536,6 +1612,13 @@ fn handle_gate_command(
|
||||||
}),
|
}),
|
||||||
GateCommand::Serve { port } => {
|
GateCommand::Serve { port } => {
|
||||||
serve_dashboard(store_path, port)?;
|
serve_dashboard(store_path, port)?;
|
||||||
|
if emit_event {
|
||||||
|
emit_gate_event(
|
||||||
|
"dashboard_started",
|
||||||
|
None,
|
||||||
|
serde_json::json!({ "port": port }),
|
||||||
|
);
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
GateCommand::Dream {
|
GateCommand::Dream {
|
||||||
|
|
@ -1553,7 +1636,9 @@ fn handle_gate_command(
|
||||||
protocol
|
protocol
|
||||||
.dream(since, auto, &repo_root, actor, &node)
|
.dream(since, auto, &repo_root, actor, &node)
|
||||||
.and_then(|report| {
|
.and_then(|report| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
if emit_event {
|
||||||
|
emit_gate_event("dream_recorded", None, &report);
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
println!("{}", serde_json::to_string_pretty(&report).unwrap());
|
||||||
} else {
|
} else {
|
||||||
print_dream_report(&report);
|
print_dream_report(&report);
|
||||||
|
|
@ -1586,15 +1671,14 @@ fn handle_gate_command(
|
||||||
Err(ProtocolError::input("heartbeat currently requires --all"))
|
Err(ProtocolError::input("heartbeat currently requires --all"))
|
||||||
} else {
|
} else {
|
||||||
protocol.heartbeat_all().map(|renewed| {
|
protocol.heartbeat_all().map(|renewed| {
|
||||||
if matches!(format, OutputFormat::Json) {
|
let output = serde_json::json!({
|
||||||
println!(
|
"renewed": renewed,
|
||||||
"{}",
|
"count": renewed.len(),
|
||||||
serde_json::to_string_pretty(&serde_json::json!({
|
});
|
||||||
"renewed": renewed,
|
if emit_event {
|
||||||
"count": renewed.len(),
|
emit_gate_event("heartbeat_renewed", None, &output);
|
||||||
}))
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
.unwrap()
|
println!("{}", serde_json::to_string_pretty(&output).unwrap());
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
println!("renewed leases: {}", renewed.len());
|
println!("renewed leases: {}", renewed.len());
|
||||||
for task_id in renewed {
|
for task_id in renewed {
|
||||||
|
|
@ -1605,7 +1689,7 @@ fn handle_gate_command(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GateCommand::Guide => {
|
GateCommand::Guide => {
|
||||||
print!("{AGENT_GUIDE}");
|
print!("{}", agent_guide());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1613,19 +1697,19 @@ fn handle_gate_command(
|
||||||
Ok(match result {
|
Ok(match result {
|
||||||
Ok(()) => 0,
|
Ok(()) => 0,
|
||||||
Err(ProtocolError::GateRejected(message)) => {
|
Err(ProtocolError::GateRejected(message)) => {
|
||||||
emit_gate_error(format, "gate_rejected", &message);
|
emit_gate_error(format, emit_event, "gate_rejected", &message);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
Err(ProtocolError::DependencyBlocked(message)) => {
|
Err(ProtocolError::DependencyBlocked(message)) => {
|
||||||
emit_gate_error(format, "gate_rejected", &message);
|
emit_gate_error(format, emit_event, "gate_rejected", &message);
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
Err(ProtocolError::Input(message)) => {
|
Err(ProtocolError::Input(message)) => {
|
||||||
emit_gate_error(format, "input_error", &message);
|
emit_gate_error(format, emit_event, "input_error", &message);
|
||||||
2
|
2
|
||||||
}
|
}
|
||||||
Err(ProtocolError::Internal(error)) => {
|
Err(ProtocolError::Internal(error)) => {
|
||||||
emit_gate_error(format, "internal_error", &error.to_string());
|
emit_gate_error(format, emit_event, "internal_error", &error.to_string());
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
@ -1678,17 +1762,23 @@ fn assign_next_steps(
|
||||||
miyabi_core::store::CompletionMode::GithubPr => vec![
|
miyabi_core::store::CompletionMode::GithubPr => vec![
|
||||||
"1. Create branch".to_string(),
|
"1. Create branch".to_string(),
|
||||||
"2. Make changes".to_string(),
|
"2. Make changes".to_string(),
|
||||||
format!("3. miyabi gate branch {task_id} ..."),
|
format!("3. {} {task_id} ...", gate_command("branch")),
|
||||||
format!("4. miyabi gate pr {task_id} ..."),
|
format!("4. {} {task_id} ...", gate_command("pr")),
|
||||||
format!("5. miyabi gate merge {task_id} ..."),
|
format!("5. {} {task_id} ...", gate_command("merge")),
|
||||||
],
|
],
|
||||||
miyabi_core::store::CompletionMode::Manual => vec![
|
miyabi_core::store::CompletionMode::Manual => vec![
|
||||||
"1. Complete the work".to_string(),
|
"1. Complete the work".to_string(),
|
||||||
format!("2. miyabi gate manual-complete {task_id} --reason ... --operator ..."),
|
format!(
|
||||||
|
"2. {} {task_id} --reason ... --operator ...",
|
||||||
|
gate_command("manual-complete")
|
||||||
|
),
|
||||||
],
|
],
|
||||||
miyabi_core::store::CompletionMode::ExternalOp => vec![
|
miyabi_core::store::CompletionMode::ExternalOp => vec![
|
||||||
"1. Complete external operation".to_string(),
|
"1. Complete external operation".to_string(),
|
||||||
format!("2. miyabi gate manual-complete {task_id} --reason ... --operator ..."),
|
format!(
|
||||||
|
"2. {} {task_id} --reason ... --operator ...",
|
||||||
|
gate_command("manual-complete")
|
||||||
|
),
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1737,10 +1827,145 @@ fn print_assign_execution_plan(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_gate_task_status(task: &miyabi_core::store::ExecutionTask) {
|
||||||
|
println!("task: {}", task.id);
|
||||||
|
println!("title: {}", task.title);
|
||||||
|
println!("state: {:?}", task.current_state);
|
||||||
|
|
||||||
|
if task.issue_number > 0 {
|
||||||
|
println!("issue: #{}", task.issue_number);
|
||||||
|
}
|
||||||
|
println!("completion mode: {:?}", task.completion_mode);
|
||||||
|
|
||||||
|
if let Some(impact) = &task.impact {
|
||||||
|
println!(
|
||||||
|
"impact: {:?} (symbols: {})",
|
||||||
|
impact.risk_level, impact.affected_symbols
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("impact: not recorded");
|
||||||
|
}
|
||||||
|
|
||||||
|
match task.current_state {
|
||||||
|
miyabi_core::store::TaskState::Pending | miyabi_core::store::TaskState::Draft => {
|
||||||
|
if task.impact.is_none() {
|
||||||
|
println!("next:");
|
||||||
|
println!(" {} {} --risk low --symbols 0", gate_command("impact"), task.id);
|
||||||
|
println!(
|
||||||
|
" {} {} --agent <name> --node <machine> --files \"path/to/file\"",
|
||||||
|
gate_command("assign"),
|
||||||
|
task.id
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("next:");
|
||||||
|
println!(
|
||||||
|
" {} {} --agent <name> --node <machine> --files \"path/to/file\"",
|
||||||
|
gate_command("assign"),
|
||||||
|
task.id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
miyabi_core::store::TaskState::Implementing => {
|
||||||
|
println!("next:");
|
||||||
|
println!(" {} {} <branch-name>", gate_command("branch"), task.id);
|
||||||
|
println!(" {} {}", gate_command("attach"), task.id);
|
||||||
|
}
|
||||||
|
miyabi_core::store::TaskState::Reviewing => {
|
||||||
|
println!("next:");
|
||||||
|
println!(" {} {} <number>", gate_command("pr"), task.id);
|
||||||
|
println!(" {} {} <40-char-sha>", gate_command("merge"), task.id);
|
||||||
|
}
|
||||||
|
miyabi_core::store::TaskState::Merged | miyabi_core::store::TaskState::Done => {
|
||||||
|
println!("next:");
|
||||||
|
println!(" {}", gate_command("dispatchable"));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_gate_snapshot_status(
|
||||||
|
snapshot: &miyabi_core::store::TasksSnapshot,
|
||||||
|
dispatchable: Option<&miyabi_core::protocol::DispatchableReport>,
|
||||||
|
) {
|
||||||
|
if snapshot.tasks.is_empty() {
|
||||||
|
println!("tasks: 0");
|
||||||
|
println!("status: ready to initialize or register your first task");
|
||||||
|
println!("this is not an error. it means the ledger is empty.");
|
||||||
|
println!("next:");
|
||||||
|
println!(" {}", gate_command("init"));
|
||||||
|
println!(" {} --issue <N> --title \"Your task\"", gate_command("register"));
|
||||||
|
println!(" {}", gate_command("guide"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let total = snapshot.tasks.len();
|
||||||
|
let completed = snapshot
|
||||||
|
.tasks
|
||||||
|
.iter()
|
||||||
|
.filter(|task| {
|
||||||
|
matches!(
|
||||||
|
task.current_state,
|
||||||
|
miyabi_core::store::TaskState::Done | miyabi_core::store::TaskState::Merged
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
let active = snapshot
|
||||||
|
.tasks
|
||||||
|
.iter()
|
||||||
|
.filter(|task| {
|
||||||
|
matches!(
|
||||||
|
task.current_state,
|
||||||
|
miyabi_core::store::TaskState::Implementing
|
||||||
|
| miyabi_core::store::TaskState::Reviewing
|
||||||
|
| miyabi_core::store::TaskState::Analyzing
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
let waiting = total.saturating_sub(completed + active);
|
||||||
|
let dispatchable_count = dispatchable.map(|report| report.count).unwrap_or(0);
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"tasks: {} (dispatchable: {}, locks: {})",
|
||||||
|
total,
|
||||||
|
dispatchable_count,
|
||||||
|
snapshot.file_locks.len()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"summary: {} completed, {} active, {} waiting",
|
||||||
|
completed, active, waiting
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(report) = dispatchable {
|
||||||
|
if !report.tasks.is_empty() {
|
||||||
|
println!("next tasks:");
|
||||||
|
for task in report.tasks.iter().take(3) {
|
||||||
|
println!(" {} [{}] {}", task.id, task.priority, task.title);
|
||||||
|
}
|
||||||
|
println!("next:");
|
||||||
|
println!(" {} <task-id>", gate_command("status"));
|
||||||
|
println!(
|
||||||
|
" {} <task-id> --agent <name> --node <machine> --files \"path/to/file\"",
|
||||||
|
gate_command("assign")
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
println!("next:");
|
||||||
|
println!(" {}", gate_command("dag"));
|
||||||
|
println!(" {}", gate_command("locks"));
|
||||||
|
println!(" {}", gate_command("guide"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("all tasks:");
|
||||||
|
for task in &snapshot.tasks {
|
||||||
|
println!(" {} [{:?}] {}", task.id, task.current_state, task.title);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn initialize_gate_project(
|
fn initialize_gate_project(
|
||||||
format: &OutputFormat,
|
format: &OutputFormat,
|
||||||
|
emit_event: bool,
|
||||||
store_path: &std::path::Path,
|
store_path: &std::path::Path,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<InitStatus> {
|
||||||
let current_dir = std::env::current_dir()?;
|
let current_dir = std::env::current_dir()?;
|
||||||
let created_path = store_path.display().to_string();
|
let created_path = store_path.display().to_string();
|
||||||
let initialized = if store_path.exists() {
|
let initialized = if store_path.exists() {
|
||||||
|
|
@ -1773,6 +1998,10 @@ fn initialize_gate_project(
|
||||||
github_project_detected,
|
github_project_detected,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if emit_event {
|
||||||
|
return Ok(status);
|
||||||
|
}
|
||||||
|
|
||||||
if matches!(format, OutputFormat::Json) {
|
if matches!(format, OutputFormat::Json) {
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
|
|
@ -1785,15 +2014,15 @@ fn initialize_gate_project(
|
||||||
"gitignore_updated": status.gitignore_updated,
|
"gitignore_updated": status.gitignore_updated,
|
||||||
"github_project_detected": status.github_project_detected,
|
"github_project_detected": status.github_project_detected,
|
||||||
"next_steps": [
|
"next_steps": [
|
||||||
"miyabi gate register --issue <N> --title ...",
|
gate_command("status"),
|
||||||
"miyabi gate status",
|
gate_command("guide"),
|
||||||
"miyabi gate --help"
|
format!("{} --issue <N> --title ...", gate_command("register"))
|
||||||
],
|
],
|
||||||
}))?
|
}))?
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if status.initialized {
|
if status.initialized {
|
||||||
println!("Polaris initialized in {}", status.current_dir);
|
println!("MergeGate initialized in {}", status.current_dir);
|
||||||
println!("Created: {}", status.created_path);
|
println!("Created: {}", status.created_path);
|
||||||
} else {
|
} else {
|
||||||
println!("Already initialized");
|
println!("Already initialized");
|
||||||
|
|
@ -1805,13 +2034,13 @@ fn initialize_gate_project(
|
||||||
println!("⚠️ No GitHub remote. Run: gh repo create <name> --private");
|
println!("⚠️ No GitHub remote. Run: gh repo create <name> --private");
|
||||||
}
|
}
|
||||||
println!("Next steps:");
|
println!("Next steps:");
|
||||||
println!(" miyabi gate register --issue <N> --title ...");
|
println!(" {}", gate_command("status"));
|
||||||
println!(" miyabi gate status");
|
println!(" {}", gate_command("guide"));
|
||||||
println!(" miyabi gate --help");
|
println!(" {} --issue <N> --title ...", gate_command("register"));
|
||||||
print_init_checklist(&status);
|
print_init_checklist(&status);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_init_checklist(status: &InitStatus) {
|
fn print_init_checklist(status: &InitStatus) {
|
||||||
|
|
@ -2011,8 +2240,24 @@ fn print_dream_report(report: &miyabi_core::DreamReport) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_gate_error(format: &OutputFormat, kind: &str, message: &str) {
|
fn emit_gate_event(event: &str, task_id: Option<&str>, payload: impl serde::Serialize) {
|
||||||
if matches!(format, OutputFormat::Json) {
|
println!(
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string_pretty(&serde_json::json!({
|
||||||
|
"event": event,
|
||||||
|
"task_id": task_id,
|
||||||
|
"source": "miyabi-gate",
|
||||||
|
"ts": chrono::Utc::now(),
|
||||||
|
"payload": payload,
|
||||||
|
}))
|
||||||
|
.unwrap()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn emit_gate_error(format: &OutputFormat, emit_event: bool, kind: &str, message: &str) {
|
||||||
|
if emit_event {
|
||||||
|
emit_gate_event(kind, None, serde_json::json!({ "message": message }));
|
||||||
|
} else if matches!(format, OutputFormat::Json) {
|
||||||
println!(
|
println!(
|
||||||
"{}",
|
"{}",
|
||||||
serde_json::to_string_pretty(&serde_json::json!({
|
serde_json::to_string_pretty(&serde_json::json!({
|
||||||
|
|
@ -2026,12 +2271,12 @@ fn emit_gate_error(format: &OutputFormat, kind: &str, message: &str) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const AGENT_GUIDE: &str = r#"
|
const AGENT_GUIDE_TEMPLATE: &str = r#"
|
||||||
# Polaris (miyabi-gate) — Agent Guide
|
# MergeGate ({{GATE}}) — Agent Guide
|
||||||
|
|
||||||
## What is this?
|
## What is this?
|
||||||
|
|
||||||
Polaris is a deterministic task execution protocol. It enforces a strict
|
MergeGate is a deterministic task execution protocol. It enforces a strict
|
||||||
workflow so that any agent on any machine produces the same verifiable result.
|
workflow so that any agent on any machine produces the same verifiable result.
|
||||||
Tasks are tracked in project_memory/tasks.json, not in conversation memory.
|
Tasks are tracked in project_memory/tasks.json, not in conversation memory.
|
||||||
|
|
||||||
|
|
@ -2047,53 +2292,53 @@ Tasks are tracked in project_memory/tasks.json, not in conversation memory.
|
||||||
|
|
||||||
```
|
```
|
||||||
Step 1: Register
|
Step 1: Register
|
||||||
miyabi-gate gate register --issue <N> --title "Task description"
|
{{GATE}} register --issue <N> --title "Task description"
|
||||||
|
|
||||||
Step 2: Impact analysis
|
Step 2: Impact analysis
|
||||||
miyabi-gate gate impact <task-id> --risk <low|medium|high|critical> --symbols <N>
|
{{GATE}} impact <task-id> --risk <low|medium|high|critical> --symbols <N>
|
||||||
# Add --approve if risk is high or critical
|
# Add --approve if risk is high or critical
|
||||||
|
|
||||||
Step 3: Assign (acquires file locks)
|
Step 3: Assign (acquires file locks)
|
||||||
miyabi-gate gate assign <task-id> --agent <your-name> --node <machine> --files "file1.rs,file2.rs"
|
{{GATE}} assign <task-id> --agent <your-name> --node <machine> --files "file1.rs,file2.rs"
|
||||||
# This prints an execution plan and context attachments. Read them.
|
# This prints an execution plan and context attachments. Read them.
|
||||||
|
|
||||||
Step 4: Work
|
Step 4: Work
|
||||||
# Edit ONLY the locked files. Pre-commit hook blocks unlocked files.
|
# Edit ONLY the locked files. Pre-commit hook blocks unlocked files.
|
||||||
|
|
||||||
Step 5: Branch
|
Step 5: Branch
|
||||||
miyabi-gate gate branch <task-id> feature/issue-<N>-<slug>
|
{{GATE}} branch <task-id> feature/issue-<N>-<slug>
|
||||||
|
|
||||||
Step 6: PR
|
Step 6: PR
|
||||||
miyabi-gate gate pr <task-id> <PR-number>
|
{{GATE}} pr <task-id> <PR-number>
|
||||||
|
|
||||||
Step 7: Merge
|
Step 7: Merge
|
||||||
miyabi-gate gate merge <task-id> <merge-commit-sha>
|
{{GATE}} merge <task-id> <merge-commit-sha>
|
||||||
```
|
```
|
||||||
|
|
||||||
## For document-only tasks (no PR needed)
|
## For document-only tasks (no PR needed)
|
||||||
|
|
||||||
```
|
```
|
||||||
miyabi-gate gate register --issue <N> --title "Doc task" --completion-mode manual
|
{{GATE}} register --issue <N> --title "Doc task" --completion-mode manual
|
||||||
miyabi-gate gate impact <task-id> --risk low --symbols 0
|
{{GATE}} impact <task-id> --risk low --symbols 0
|
||||||
miyabi-gate gate assign <task-id> --agent <name> --node <machine> --files "docs/file.md"
|
{{GATE}} assign <task-id> --agent <name> --node <machine> --files "docs/file.md"
|
||||||
# ... do the work ...
|
# ... do the work ...
|
||||||
miyabi-gate gate manual-complete <task-id> --reason "reason" --operator <name>
|
{{GATE}} manual-complete <task-id> --reason "reason" --operator <name>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Checking state
|
## Checking state
|
||||||
|
|
||||||
```
|
```
|
||||||
miyabi-gate gate status # All tasks
|
{{GATE}} status # All tasks
|
||||||
miyabi-gate gate status <task-id> # One task
|
{{GATE}} status <task-id> # One task
|
||||||
miyabi-gate gate locks # Active file locks
|
{{GATE}} locks # Active file locks
|
||||||
miyabi-gate gate dag # Dependency graph
|
{{GATE}} dag # Dependency graph
|
||||||
miyabi-gate gate dispatchable # Tasks ready to work on
|
{{GATE}} dispatchable # Tasks ready to work on
|
||||||
miyabi-gate gate attach <task-id> # View context attachments
|
{{GATE}} attach <task-id> # View context attachments
|
||||||
```
|
```
|
||||||
|
|
||||||
## Context attachments (auto-injected on assign)
|
## Context attachments (auto-injected on assign)
|
||||||
|
|
||||||
When you run `assign`, Polaris automatically attaches:
|
When you run `assign`, MergeGate automatically attaches:
|
||||||
- GitHub Issue body
|
- GitHub Issue body
|
||||||
- Impact analysis result
|
- Impact analysis result
|
||||||
- Obsidian vault notes matching the task title (if OBSIDIAN_VAULT_PATH is set)
|
- Obsidian vault notes matching the task title (if OBSIDIAN_VAULT_PATH is set)
|
||||||
|
|
@ -2101,15 +2346,17 @@ When you run `assign`, Polaris automatically attaches:
|
||||||
- First 30 lines of each locked file
|
- First 30 lines of each locked file
|
||||||
- First 30 lines of depth-1 impact files (direct callers)
|
- First 30 lines of depth-1 impact files (direct callers)
|
||||||
|
|
||||||
Use `miyabi-gate gate attach <task-id> --format json` to get this as JSON
|
Use `{{GATE}} attach <task-id>` to inspect the attachments.
|
||||||
|
Use `{{GATE}} --format json status` or `{{GATE}} --format json locks`
|
||||||
|
when you need machine-readable output from supported commands.
|
||||||
for programmatic injection into prompts.
|
for programmatic injection into prompts.
|
||||||
|
|
||||||
## Emergency commands
|
## Emergency commands
|
||||||
|
|
||||||
```
|
```
|
||||||
miyabi-gate gate force-unlock <task-id> --reason "why" --operator <name>
|
{{GATE}} force-unlock <task-id> --reason "why" --operator <name>
|
||||||
miyabi-gate gate manual-complete <task-id> --reason "why" --operator <name>
|
{{GATE}} manual-complete <task-id> --reason "why" --operator <name>
|
||||||
miyabi-gate gate heartbeat --all # Renew all lease heartbeats
|
{{GATE}} heartbeat --all # Renew all lease heartbeats
|
||||||
```
|
```
|
||||||
|
|
||||||
## Exit codes
|
## Exit codes
|
||||||
|
|
@ -2128,23 +2375,23 @@ cargo clippy --all-targets --all-features -- -D warnings
|
||||||
## Self-improvement
|
## Self-improvement
|
||||||
|
|
||||||
```
|
```
|
||||||
miyabi-gate gate dream # Extract learnings from event log
|
{{GATE}} dream # Extract learnings from event log
|
||||||
miyabi-gate gate dream --auto # Also write High learnings to docs/ and update SKILL.md
|
{{GATE}} dream --auto # Also write High learnings to docs/ and update SKILL.md
|
||||||
miyabi-gate gate serve # Web dashboard at localhost:4848
|
{{GATE}} serve # Web dashboard at localhost:4848
|
||||||
```
|
```
|
||||||
|
|
||||||
## Command Reference
|
## Command Reference
|
||||||
|
|
||||||
### init
|
### init
|
||||||
Initialize project memory in the current repo.
|
Initialize project memory in the current repo.
|
||||||
miyabi-gate gate init
|
{{GATE}} init
|
||||||
|
|
||||||
### register
|
### register
|
||||||
Register a new task. Creates an entry in tasks.json.
|
Register a new task. Creates an entry in tasks.json.
|
||||||
miyabi-gate gate register --issue <N> --title "Title"
|
{{GATE}} register --issue <N> --title "Title"
|
||||||
miyabi-gate gate register --issue <N> --title "Title" --completion-mode manual
|
{{GATE}} register --issue <N> --title "Title" --completion-mode manual
|
||||||
miyabi-gate gate register --issue <N> --title "Title" --dependencies dep-1,dep-2
|
{{GATE}} register --issue <N> --title "Title" --dependencies dep-1,dep-2
|
||||||
miyabi-gate gate register --issue <N> --title "Title" --no-bus
|
{{GATE}} register --issue <N> --title "Title" --no-bus
|
||||||
Options:
|
Options:
|
||||||
--issue <N> GitHub issue number (required, 0 = auto-create)
|
--issue <N> GitHub issue number (required, 0 = auto-create)
|
||||||
--title <TEXT> Task title (required)
|
--title <TEXT> Task title (required)
|
||||||
|
|
@ -2157,9 +2404,9 @@ miyabi-gate gate serve # Web dashboard at localhost:4848
|
||||||
|
|
||||||
### impact
|
### impact
|
||||||
Record impact analysis for a task.
|
Record impact analysis for a task.
|
||||||
miyabi-gate gate impact <task-id> --risk low --symbols 3
|
{{GATE}} impact <task-id> --risk low --symbols 3
|
||||||
miyabi-gate gate impact <task-id> --risk high --symbols 12 --approve
|
{{GATE}} impact <task-id> --risk high --symbols 12 --approve
|
||||||
miyabi-gate gate impact <task-id> --risk medium --symbols 5 --depth1 "src/a.rs,src/b.rs"
|
{{GATE}} impact <task-id> --risk medium --symbols 5 --depth1 "src/a.rs,src/b.rs"
|
||||||
Options:
|
Options:
|
||||||
--risk <LEVEL> low | medium | high | critical
|
--risk <LEVEL> low | medium | high | critical
|
||||||
--symbols <N> Number of affected symbols
|
--symbols <N> Number of affected symbols
|
||||||
|
|
@ -2170,7 +2417,7 @@ miyabi-gate gate serve # Web dashboard at localhost:4848
|
||||||
|
|
||||||
### assign
|
### assign
|
||||||
Acquire file locks and start implementation.
|
Acquire file locks and start implementation.
|
||||||
miyabi-gate gate assign <task-id> --agent codex --node macbook --files "src/main.rs,src/lib.rs"
|
{{GATE}} assign <task-id> --agent codex --node macbook --files "src/main.rs,src/lib.rs"
|
||||||
Options:
|
Options:
|
||||||
--agent <NAME> Agent name (required)
|
--agent <NAME> Agent name (required)
|
||||||
--node <NAME> Machine name (required)
|
--node <NAME> Machine name (required)
|
||||||
|
|
@ -2178,63 +2425,61 @@ miyabi-gate gate serve # Web dashboard at localhost:4848
|
||||||
|
|
||||||
### branch
|
### branch
|
||||||
Record branch creation.
|
Record branch creation.
|
||||||
miyabi-gate gate branch <task-id> feature/issue-45-auth
|
{{GATE}} branch <task-id> feature/issue-45-auth
|
||||||
|
|
||||||
### pr
|
### pr
|
||||||
Record PR creation.
|
Record PR creation.
|
||||||
miyabi-gate gate pr <task-id> 88
|
{{GATE}} pr <task-id> 88
|
||||||
|
|
||||||
### merge
|
### merge
|
||||||
Record merge verification. Releases locks and unblocks dependents.
|
Record merge verification. Releases locks and unblocks dependents.
|
||||||
miyabi-gate gate merge <task-id> <40-char-SHA>
|
{{GATE}} merge <task-id> <40-char-SHA>
|
||||||
|
|
||||||
### status
|
### status
|
||||||
Show task status.
|
Show task status.
|
||||||
miyabi-gate gate status # All tasks
|
{{GATE}} status # All tasks
|
||||||
miyabi-gate gate status <task-id> # One task
|
{{GATE}} status <task-id> # One task
|
||||||
miyabi-gate gate status --format json
|
{{GATE}} --format json status
|
||||||
|
|
||||||
### locks
|
### locks
|
||||||
List active file locks.
|
List active file locks.
|
||||||
miyabi-gate gate locks
|
{{GATE}} locks
|
||||||
miyabi-gate gate locks --format json
|
{{GATE}} --format json locks
|
||||||
|
|
||||||
### dag
|
### dag
|
||||||
Show DAG dependency levels.
|
Show DAG dependency levels.
|
||||||
miyabi-gate gate dag
|
{{GATE}} dag
|
||||||
|
|
||||||
### dispatchable
|
### dispatchable
|
||||||
Show tasks ready to be worked on (dependencies resolved, no lock).
|
Show tasks ready to be worked on (dependencies resolved, no lock).
|
||||||
miyabi-gate gate dispatchable
|
{{GATE}} dispatchable
|
||||||
miyabi-gate gate dispatchable --format json
|
|
||||||
|
|
||||||
### attach
|
### attach
|
||||||
View context attachments for a task.
|
View context attachments for a task.
|
||||||
miyabi-gate gate attach <task-id>
|
{{GATE}} attach <task-id>
|
||||||
miyabi-gate gate attach <task-id> --format json
|
|
||||||
|
|
||||||
### refresh
|
### refresh
|
||||||
Force-refresh context attachments (clears cache).
|
Force-refresh context attachments (clears cache).
|
||||||
miyabi-gate gate refresh <task-id>
|
{{GATE}} refresh <task-id>
|
||||||
|
|
||||||
### verify-merge
|
### verify-merge
|
||||||
Verify merge state via GitHub API.
|
Verify merge state via GitHub API.
|
||||||
miyabi-gate gate verify-merge <task-id> --repo owner/repo
|
{{GATE}} verify-merge <task-id> --repo owner/repo
|
||||||
|
|
||||||
### force-unlock
|
### force-unlock
|
||||||
Emergency: release a lock without completing the task.
|
Emergency: release a lock without completing the task.
|
||||||
miyabi-gate gate force-unlock <task-id> --reason "why" --operator "name"
|
{{GATE}} force-unlock <task-id> --reason "why" --operator "name"
|
||||||
|
|
||||||
### manual-complete
|
### manual-complete
|
||||||
Complete a task without merge verification (for doc/ops tasks).
|
Complete a task without merge verification (for doc/ops tasks).
|
||||||
miyabi-gate gate manual-complete <task-id> --reason "why" --operator "name"
|
{{GATE}} manual-complete <task-id> --reason "why" --operator "name"
|
||||||
|
|
||||||
### dream
|
### dream
|
||||||
Analyze event logs and extract learnings.
|
Analyze event logs and extract learnings.
|
||||||
miyabi-gate gate dream
|
{{GATE}} dream
|
||||||
miyabi-gate gate dream --since 24h
|
{{GATE}} dream --since 24h
|
||||||
miyabi-gate gate dream --auto
|
{{GATE}} dream --auto
|
||||||
miyabi-gate gate dream --auto --vault-path /path/to/obsidian
|
{{GATE}} dream --auto --vault-path /path/to/obsidian
|
||||||
Options:
|
Options:
|
||||||
--since <DURATION> Filter events (e.g. 24h, 7d, 30m)
|
--since <DURATION> Filter events (e.g. 24h, 7d, 30m)
|
||||||
--auto Write High learnings to docs/ + update SKILL.md
|
--auto Write High learnings to docs/ + update SKILL.md
|
||||||
|
|
@ -2242,18 +2487,18 @@ miyabi-gate gate serve # Web dashboard at localhost:4848
|
||||||
|
|
||||||
### heartbeat
|
### heartbeat
|
||||||
Renew lock lease heartbeats.
|
Renew lock lease heartbeats.
|
||||||
miyabi-gate gate heartbeat --all
|
{{GATE}} heartbeat --all
|
||||||
|
|
||||||
### serve
|
### serve
|
||||||
Start web dashboard.
|
Start web dashboard.
|
||||||
miyabi-gate gate serve
|
{{GATE}} serve
|
||||||
miyabi-gate gate serve --port 8080
|
{{GATE}} serve --port 8080
|
||||||
Options:
|
Options:
|
||||||
--port <N> Port number (default: 4848)
|
--port <N> Port number (default: 4848)
|
||||||
|
|
||||||
### guide
|
### guide
|
||||||
Print this guide.
|
Print this guide.
|
||||||
miyabi-gate gate guide
|
{{GATE}} guide
|
||||||
|
|
||||||
### Global options (apply to all gate commands)
|
### Global options (apply to all gate commands)
|
||||||
--format <text|json> Output format (default: text)
|
--format <text|json> Output format (default: text)
|
||||||
|
|
@ -2265,7 +2510,7 @@ const POLARIS_DASHBOARD_HTML: &str = r##"<!DOCTYPE html>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<title>Polaris Dashboard</title>
|
<title>MergeGate Dashboard</title>
|
||||||
<style>
|
<style>
|
||||||
:root {
|
:root {
|
||||||
color-scheme: light;
|
color-scheme: light;
|
||||||
|
|
@ -2371,7 +2616,7 @@ const POLARIS_DASHBOARD_HTML: &str = r##"<!DOCTYPE html>
|
||||||
<body>
|
<body>
|
||||||
<div class="shell">
|
<div class="shell">
|
||||||
<header>
|
<header>
|
||||||
<h1>Polaris Dashboard</h1>
|
<h1>MergeGate Dashboard</h1>
|
||||||
<p class="subtitle">Deterministic Task Protocol live view</p>
|
<p class="subtitle">Deterministic Task Protocol live view</p>
|
||||||
<p class="meta" id="meta">Loading...</p>
|
<p class="meta" id="meta">Loading...</p>
|
||||||
</header>
|
</header>
|
||||||
|
|
@ -2574,7 +2819,7 @@ fn serve_dashboard(store_path: &std::path::Path, port: u16) -> anyhow::Result<()
|
||||||
store_path.to_path_buf(),
|
store_path.to_path_buf(),
|
||||||
);
|
);
|
||||||
let listener = TcpListener::bind(("127.0.0.1", port))?;
|
let listener = TcpListener::bind(("127.0.0.1", port))?;
|
||||||
println!("Polaris Dashboard listening on http://127.0.0.1:{port}");
|
println!("MergeGate Dashboard listening on http://127.0.0.1:{port}");
|
||||||
|
|
||||||
for stream in listener.incoming() {
|
for stream in listener.incoming() {
|
||||||
match stream {
|
match stream {
|
||||||
|
|
@ -2706,7 +2951,7 @@ fn bus_enqueue(task_id: &str, title: &str, store_path: &std::path::Path) {
|
||||||
let entry = serde_json::json!({
|
let entry = serde_json::json!({
|
||||||
"ts": chrono::Utc::now().to_rfc3339(),
|
"ts": chrono::Utc::now().to_rfc3339(),
|
||||||
"agent": std::env::var("POLARIS_AGENT_ID").unwrap_or_else(|_| "system".into()),
|
"agent": std::env::var("POLARIS_AGENT_ID").unwrap_or_else(|_| "system".into()),
|
||||||
"skill": "polaris-ops",
|
"skill": "mergegate-ops",
|
||||||
"task": format!("register: {title} ({task_id})"),
|
"task": format!("register: {title} ({task_id})"),
|
||||||
"result": "queued",
|
"result": "queued",
|
||||||
"score": 0.0,
|
"score": 0.0,
|
||||||
|
|
@ -2718,7 +2963,11 @@ fn bus_enqueue(task_id: &str, title: &str, store_path: &std::path::Path) {
|
||||||
.open(&path)
|
.open(&path)
|
||||||
{
|
{
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
let _ = writeln!(file, "{}", serde_json::to_string(&entry).unwrap_or_default());
|
let _ = writeln!(
|
||||||
|
file,
|
||||||
|
"{}",
|
||||||
|
serde_json::to_string(&entry).unwrap_or_default()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "miyabi-core"
|
name = "mergegate-core"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
@ -7,7 +7,7 @@ authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
description = "Miyabi Core - Shared types and utilities"
|
description = "MergeGate Core - Shared types and utilities"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
|
|
@ -154,7 +154,7 @@ where
|
||||||
|
|
||||||
/// Append a "Common Rejection Patterns" section to SKILL.md if gate rejections are detected.
|
/// Append a "Common Rejection Patterns" section to SKILL.md if gate rejections are detected.
|
||||||
fn update_skill_md_from_patterns(report: &DreamReport, repo_root: &Path) -> Result<()> {
|
fn update_skill_md_from_patterns(report: &DreamReport, repo_root: &Path) -> Result<()> {
|
||||||
let skill_path = repo_root.join("skills/polaris-ops/SKILL.md");
|
let skill_path = repo_root.join("skills/mergegate-ops/SKILL.md");
|
||||||
if !skill_path.exists() {
|
if !skill_path.exists() {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
@ -672,10 +672,10 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn update_skill_md_appends_when_no_marker() {
|
fn update_skill_md_appends_when_no_marker() {
|
||||||
let tmp = TempDir::new().unwrap();
|
let tmp = TempDir::new().unwrap();
|
||||||
let skills_dir = tmp.path().join("skills/polaris-ops");
|
let skills_dir = tmp.path().join("skills/mergegate-ops");
|
||||||
fs::create_dir_all(&skills_dir).unwrap();
|
fs::create_dir_all(&skills_dir).unwrap();
|
||||||
let skill_path = skills_dir.join("SKILL.md");
|
let skill_path = skills_dir.join("SKILL.md");
|
||||||
fs::write(&skill_path, "# Polaris Ops\n\nExisting content.\n").unwrap();
|
fs::write(&skill_path, "# MergeGate Ops\n\nExisting content.\n").unwrap();
|
||||||
|
|
||||||
let mut rejections = HashMap::new();
|
let mut rejections = HashMap::new();
|
||||||
rejections.insert("GATE 3".to_string(), 2);
|
rejections.insert("GATE 3".to_string(), 2);
|
||||||
|
|
@ -690,7 +690,7 @@ mod tests {
|
||||||
|
|
||||||
update_skill_md_from_patterns(&report, tmp.path()).unwrap();
|
update_skill_md_from_patterns(&report, tmp.path()).unwrap();
|
||||||
let content = fs::read_to_string(&skill_path).unwrap();
|
let content = fs::read_to_string(&skill_path).unwrap();
|
||||||
assert!(content.contains("# Polaris Ops"));
|
assert!(content.contains("# MergeGate Ops"));
|
||||||
assert!(content.contains("Existing content."));
|
assert!(content.contains("Existing content."));
|
||||||
assert!(content.contains("## よくある拒否パターン(自動生成)"));
|
assert!(content.contains("## よくある拒否パターン(自動生成)"));
|
||||||
assert!(content.contains("GATE 3"));
|
assert!(content.contains("GATE 3"));
|
||||||
|
|
@ -699,12 +699,12 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn update_skill_md_replaces_marker_preserves_following_sections() {
|
fn update_skill_md_replaces_marker_preserves_following_sections() {
|
||||||
let tmp = TempDir::new().unwrap();
|
let tmp = TempDir::new().unwrap();
|
||||||
let skills_dir = tmp.path().join("skills/polaris-ops");
|
let skills_dir = tmp.path().join("skills/mergegate-ops");
|
||||||
fs::create_dir_all(&skills_dir).unwrap();
|
fs::create_dir_all(&skills_dir).unwrap();
|
||||||
let skill_path = skills_dir.join("SKILL.md");
|
let skill_path = skills_dir.join("SKILL.md");
|
||||||
fs::write(
|
fs::write(
|
||||||
&skill_path,
|
&skill_path,
|
||||||
"# Polaris Ops\n\n\
|
"# MergeGate Ops\n\n\
|
||||||
## よくある拒否パターン(自動生成)\n\n\
|
## よくある拒否パターン(自動生成)\n\n\
|
||||||
| GATE | 回数 | 対処法 |\n|------|------|--------|\n| old | 1 | old |\n\n\
|
| GATE | 回数 | 対処法 |\n|------|------|--------|\n| old | 1 | old |\n\n\
|
||||||
## 関連スキル\n\n- important link\n",
|
## 関連スキル\n\n- important link\n",
|
||||||
|
|
@ -475,13 +475,13 @@ mod tests {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
for file in &files {
|
for file in &files {
|
||||||
let conflict = manager.has_conflict(&[file.clone()]).unwrap();
|
let conflict = manager.has_conflict(std::slice::from_ref(file)).unwrap();
|
||||||
assert!(conflict.conflicting);
|
assert!(conflict.conflicting);
|
||||||
}
|
}
|
||||||
|
|
||||||
manager.release_lock("task-a").unwrap();
|
manager.release_lock("task-a").unwrap();
|
||||||
for file in &files {
|
for file in &files {
|
||||||
let conflict = manager.has_conflict(&[file.clone()]).unwrap();
|
let conflict = manager.has_conflict(std::slice::from_ref(file)).unwrap();
|
||||||
assert!(!conflict.conflicting);
|
assert!(!conflict.conflicting);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -550,11 +550,11 @@ mod proptest_tests {
|
||||||
) {
|
) {
|
||||||
let (_tmp, ss, mgr) = setup();
|
let (_tmp, ss, mgr) = setup();
|
||||||
seed(&ss, "task-a");
|
seed(&ss, "task-a");
|
||||||
mgr.acquire_lock("task-a", "agent", "node", &[file.clone()]).unwrap();
|
mgr.acquire_lock("task-a", "agent", "node", std::slice::from_ref(&file)).unwrap();
|
||||||
let c = mgr.has_conflict(&[file.clone()]).unwrap();
|
let c = mgr.has_conflict(std::slice::from_ref(&file)).unwrap();
|
||||||
prop_assert!(c.conflicting);
|
prop_assert!(c.conflicting);
|
||||||
mgr.release_lock("task-a").unwrap();
|
mgr.release_lock("task-a").unwrap();
|
||||||
let c = mgr.has_conflict(&[file]).unwrap();
|
let c = mgr.has_conflict(std::slice::from_ref(&file)).unwrap();
|
||||||
prop_assert!(!c.conflicting);
|
prop_assert!(!c.conflicting);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -565,8 +565,8 @@ mod proptest_tests {
|
||||||
let (_tmp, ss, mgr) = setup();
|
let (_tmp, ss, mgr) = setup();
|
||||||
seed(&ss, "task-a");
|
seed(&ss, "task-a");
|
||||||
seed(&ss, "task-b");
|
seed(&ss, "task-b");
|
||||||
mgr.acquire_lock("task-a", "agent", "node", &[file.clone()]).unwrap();
|
mgr.acquire_lock("task-a", "agent", "node", std::slice::from_ref(&file)).unwrap();
|
||||||
let result = mgr.acquire_lock("task-b", "agent", "node", &[file]);
|
let result = mgr.acquire_lock("task-b", "agent", "node", std::slice::from_ref(&file));
|
||||||
prop_assert!(result.is_err());
|
prop_assert!(result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -626,7 +626,7 @@ impl DeterministicExecutionProtocol {
|
||||||
|
|
||||||
pub fn dispatchable(&self) -> ProtocolResult<DispatchableReport> {
|
pub fn dispatchable(&self) -> ProtocolResult<DispatchableReport> {
|
||||||
let snapshot = self.snapshot_store.load().map_err(ProtocolError::from)?;
|
let snapshot = self.snapshot_store.load().map_err(ProtocolError::from)?;
|
||||||
let tasks = snapshot
|
let tasks: Vec<ExecutionTask> = snapshot
|
||||||
.tasks
|
.tasks
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|task| matches!(task.current_state, TaskState::Pending | TaskState::Blocked))
|
.filter(|task| matches!(task.current_state, TaskState::Pending | TaskState::Blocked))
|
||||||
|
|
@ -645,7 +645,12 @@ impl DeterministicExecutionProtocol {
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
Ok(DispatchableReport { tasks })
|
let task_ids = tasks.iter().map(|task| task.id.clone()).collect();
|
||||||
|
Ok(DispatchableReport {
|
||||||
|
count: tasks.len(),
|
||||||
|
task_ids,
|
||||||
|
tasks,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn attach_context_with_limit(
|
fn attach_context_with_limit(
|
||||||
|
|
@ -1087,6 +1092,8 @@ pub struct DagReport {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub struct DispatchableReport {
|
pub struct DispatchableReport {
|
||||||
|
pub count: usize,
|
||||||
|
pub task_ids: Vec<String>,
|
||||||
pub tasks: Vec<ExecutionTask>,
|
pub tasks: Vec<ExecutionTask>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1789,6 +1796,8 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatchable = protocol.dispatchable().unwrap();
|
let dispatchable = protocol.dispatchable().unwrap();
|
||||||
|
assert_eq!(dispatchable.count, 1);
|
||||||
|
assert_eq!(dispatchable.task_ids, vec!["phase-a".to_string()]);
|
||||||
assert_eq!(dispatchable.tasks.len(), 1);
|
assert_eq!(dispatchable.tasks.len(), 1);
|
||||||
assert_eq!(dispatchable.tasks[0].id, "phase-a");
|
assert_eq!(dispatchable.tasks[0].id, "phase-a");
|
||||||
}
|
}
|
||||||
|
|
@ -2777,7 +2786,7 @@ mod tests {
|
||||||
assert!(extract_wikilinks("no links here").is_empty());
|
assert!(extract_wikilinks("no links here").is_empty());
|
||||||
assert!(extract_wikilinks("[[]]").is_empty()); // empty name
|
assert!(extract_wikilinks("[[]]").is_empty()); // empty name
|
||||||
assert!(extract_wikilinks("[[ ]]").is_empty()); // whitespace only
|
assert!(extract_wikilinks("[[ ]]").is_empty()); // whitespace only
|
||||||
// Unclosed link: should still extract the name
|
// Unclosed link: should still extract the name
|
||||||
assert_eq!(extract_wikilinks("[[unclosed"), vec!["unclosed"]);
|
assert_eq!(extract_wikilinks("[[unclosed"), vec!["unclosed"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1002,10 +1002,16 @@ mod tests {
|
||||||
assert_eq!(task.current_state, TaskState::Implementing);
|
assert_eq!(task.current_state, TaskState::Implementing);
|
||||||
assert!(task.lock.is_some());
|
assert!(task.lock.is_some());
|
||||||
assert!(task.impact.is_some());
|
assert!(task.impact.is_some());
|
||||||
assert_eq!(task.impact.as_ref().unwrap().risk_level, ImpactRiskLevel::High);
|
assert_eq!(
|
||||||
|
task.impact.as_ref().unwrap().risk_level,
|
||||||
|
ImpactRiskLevel::High
|
||||||
|
);
|
||||||
assert!(task.github_evidence.is_some());
|
assert!(task.github_evidence.is_some());
|
||||||
assert_eq!(task.github_evidence.as_ref().unwrap().pr_number, 42);
|
assert_eq!(task.github_evidence.as_ref().unwrap().pr_number, 42);
|
||||||
assert_eq!(task.github_evidence.as_ref().unwrap().pr_state, GitHubPrState::Open);
|
assert_eq!(
|
||||||
|
task.github_evidence.as_ref().unwrap().pr_state,
|
||||||
|
GitHubPrState::Open
|
||||||
|
);
|
||||||
// file_locks should be populated from legacy lock
|
// file_locks should be populated from legacy lock
|
||||||
assert!(snapshot.file_locks.contains_key("src/main.rs"));
|
assert!(snapshot.file_locks.contains_key("src/main.rs"));
|
||||||
}
|
}
|
||||||
|
|
@ -1083,7 +1089,7 @@ mod proptest_tests {
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
#[test]
|
#[test]
|
||||||
fn cas_rejects_stale_version(version in 1u64..100) {
|
fn cas_rejects_stale_version(_version in 1u64..100) {
|
||||||
let tmp = TempDir::new().unwrap();
|
let tmp = TempDir::new().unwrap();
|
||||||
let store = SnapshotStore::new(
|
let store = SnapshotStore::new(
|
||||||
tmp.path().join("snap.json"),
|
tmp.path().join("snap.json"),
|
||||||
|
|
@ -1101,7 +1107,7 @@ mod proptest_tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn upsert_is_idempotent(n in 1usize..10) {
|
fn upsert_is_idempotent(n in 1usize..10) {
|
||||||
let tmp = TempDir::new().unwrap();
|
let tmp = TempDir::new().unwrap();
|
||||||
let store = SnapshotStore::new(
|
let _store = SnapshotStore::new(
|
||||||
tmp.path().join("snap.json"),
|
tmp.path().join("snap.json"),
|
||||||
tmp.path().join(".lock"),
|
tmp.path().join(".lock"),
|
||||||
);
|
);
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "miyabi-tui"
|
name = "mergegate-tui"
|
||||||
version.workspace = true
|
version.workspace = true
|
||||||
edition.workspace = true
|
edition.workspace = true
|
||||||
rust-version.workspace = true
|
rust-version.workspace = true
|
||||||
|
|
@ -7,7 +7,7 @@ authors.workspace = true
|
||||||
license.workspace = true
|
license.workspace = true
|
||||||
repository.workspace = true
|
repository.workspace = true
|
||||||
homepage.workspace = true
|
homepage.workspace = true
|
||||||
description = "Miyabi TUI - Terminal User Interface following Codex patterns"
|
description = "MergeGate TUI - Terminal interface for MergeGate and agent-assisted development"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "miyabi-tui"
|
name = "miyabi-tui"
|
||||||
|
|
@ -19,7 +19,7 @@ path = "src/lib.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
# Workspace dependencies
|
# Workspace dependencies
|
||||||
miyabi-core = { path = "../miyabi-core" }
|
miyabi-core = { package = "mergegate-core", path = "../mergegate-core" }
|
||||||
arboard = { version = "3", optional = true }
|
arboard = { version = "3", optional = true }
|
||||||
|
|
||||||
# TUI Framework
|
# TUI Framework
|
||||||
|
|
@ -101,7 +101,7 @@ impl App {
|
||||||
});
|
});
|
||||||
|
|
||||||
let welcome_message = if client.is_some() {
|
let welcome_message = if client.is_some() {
|
||||||
"Welcome to Miyabi CLI! Type your message and press Enter. Press Ctrl+P for commands, F1 for help."
|
"Welcome to MergeGate. Type your message and press Enter. Press Ctrl+P for commands, F1 for help."
|
||||||
} else {
|
} else {
|
||||||
"⚠ ANTHROPIC_API_KEY not set. Please set it in config or environment to use Claude API."
|
"⚠ ANTHROPIC_API_KEY not set. Please set it in config or environment to use Claude API."
|
||||||
};
|
};
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Getting Started with miyabi-cli-standalone
|
# Getting Started with MergeGate
|
||||||
|
|
||||||
Miyabiプロジェクトへようこそ!このガイドでは、ゼロからMiyabiを使い始めるまでの手順を詳しく解説します。
|
Miyabiプロジェクトへようこそ!このガイドでは、ゼロからMiyabiを使い始めるまでの手順を詳しく解説します。
|
||||||
|
|
||||||
|
|
@ -66,18 +66,18 @@ echo $ANTHROPIC_API_KEY
|
||||||
|
|
||||||
#### 2.1 GitHub CLI使用(推奨)
|
#### 2.1 GitHub CLI使用(推奨)
|
||||||
```bash
|
```bash
|
||||||
cd miyabi-cli-standalone
|
cd mergegate
|
||||||
gh repo create miyabi-cli-standalone --private --source=. --remote=origin
|
gh repo create mergegate --private --source=. --remote=origin
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 2.2 手動作成
|
#### 2.2 手動作成
|
||||||
1. https://github.com/new にアクセス
|
1. https://github.com/new にアクセス
|
||||||
2. Repository nameに `miyabi-cli-standalone` を入力
|
2. Repository nameに `mergegate` を入力
|
||||||
3. "Private"を選択
|
3. "Private"を選択
|
||||||
4. "Create repository"をクリック
|
4. "Create repository"をクリック
|
||||||
5. ローカルリポジトリと接続:
|
5. ローカルリポジトリと接続:
|
||||||
```bash
|
```bash
|
||||||
git remote add origin https://github.com/YOUR_USERNAME/miyabi-cli-standalone.git
|
git remote add origin https://github.com/YOUR_USERNAME/mergegate.git
|
||||||
git branch -M main
|
git branch -M main
|
||||||
git add .
|
git add .
|
||||||
git commit -m "feat: initial commit 🚀"
|
git commit -m "feat: initial commit 🚀"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Operation Plan - miyabi-cli-standalone
|
# Operation Plan - MergeGate
|
||||||
|
|
||||||
**Project**: miyabi-cli-standalone
|
**Project**: mergegate
|
||||||
**Created**: 2025-11-22
|
**Created**: 2025-11-22
|
||||||
**Execution Method**: Miyabi Autonomous Agents
|
**Execution Method**: Miyabi Autonomous Agents
|
||||||
|
|
||||||
|
|
@ -49,11 +49,11 @@ miyabi agent run coordinator --issue 24 # Tool Trait
|
||||||
miyabi status
|
miyabi status
|
||||||
|
|
||||||
# Issue一覧
|
# Issue一覧
|
||||||
gh issue list --repo ShunsukeHayashi/miyabi-cli-standalone \
|
gh issue list --repo ShunsukeHayashi/mergegate \
|
||||||
--label "🏗️ state:implementing"
|
--label "🏗️ state:implementing"
|
||||||
|
|
||||||
# PR確認
|
# PR確認
|
||||||
gh pr list --repo ShunsukeHayashi/miyabi-cli-standalone
|
gh pr list --repo ShunsukeHayashi/mergegate
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -64,7 +64,7 @@ gh pr list --repo ShunsukeHayashi/miyabi-cli-standalone
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 前日のPRをレビュー
|
# 1. 前日のPRをレビュー
|
||||||
gh pr list --repo ShunsukeHayashi/miyabi-cli-standalone --state open
|
gh pr list --repo ShunsukeHayashi/mergegate --state open
|
||||||
|
|
||||||
# 2. ブロッカー確認
|
# 2. ブロッカー確認
|
||||||
gh issue list --label "🚫 state:blocked"
|
gh issue list --label "🚫 state:blocked"
|
||||||
|
|
@ -124,7 +124,7 @@ gh issue list --label "📥 state:pending" --milestone "v0.2.0 - Advanced Text R
|
||||||
miyabi status
|
miyabi status
|
||||||
|
|
||||||
# GitHub Issues
|
# GitHub Issues
|
||||||
gh issue list --repo ShunsukeHayashi/miyabi-cli-standalone
|
gh issue list --repo ShunsukeHayashi/mergegate
|
||||||
|
|
||||||
# ラベル別
|
# ラベル別
|
||||||
gh issue list --label "📊 priority:P0-Critical"
|
gh issue list --label "📊 priority:P0-Critical"
|
||||||
|
|
@ -233,7 +233,7 @@ cargo clippy --all-targets
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# マイルストーン一覧
|
# マイルストーン一覧
|
||||||
gh api repos/ShunsukeHayashi/miyabi-cli-standalone/milestones
|
gh api repos/ShunsukeHayashi/mergegate/milestones
|
||||||
|
|
||||||
# 特定マイルストーンの進捗
|
# 特定マイルストーンの進捗
|
||||||
gh issue list --milestone "v0.2.0 - Advanced Text Rendering"
|
gh issue list --milestone "v0.2.0 - Advanced Text Rendering"
|
||||||
|
|
@ -328,7 +328,7 @@ gh issue list --label "🚫 state:blocked"
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 今すぐ開始
|
# 今すぐ開始
|
||||||
cd /Users/shunsuke/Dev/miyabi-cli-standalone
|
cd /Users/shunsuke/Dev/mergegate
|
||||||
|
|
||||||
# Critical Path開始
|
# Critical Path開始
|
||||||
miyabi agent run coordinator --issue 19 # API Client (最重要)
|
miyabi agent run coordinator --issue 19 # API Client (最重要)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Preparation Operations - miyabi-cli-standalone
|
# Preparation Operations - MergeGate
|
||||||
|
|
||||||
**Purpose**: Sprint 1開始前の準備作業チェックリスト
|
**Purpose**: Sprint 1開始前の準備作業チェックリスト
|
||||||
**Target Date**: 2025-11-25 (Sprint 1 Start)
|
**Target Date**: 2025-11-25 (Sprint 1 Start)
|
||||||
|
|
@ -71,7 +71,7 @@
|
||||||
|
|
||||||
- [ ] **必要なラベル確認**
|
- [ ] **必要なラベル確認**
|
||||||
```bash
|
```bash
|
||||||
gh label list --repo ShunsukeHayashi/miyabi-cli-standalone | wc -l
|
gh label list --repo ShunsukeHayashi/mergegate | wc -l
|
||||||
# Expected: 45+ labels
|
# Expected: 45+ labels
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -85,7 +85,7 @@
|
||||||
|
|
||||||
- [ ] **マイルストーン確認**
|
- [ ] **マイルストーン確認**
|
||||||
```bash
|
```bash
|
||||||
gh api repos/ShunsukeHayashi/miyabi-cli-standalone/milestones | jq '.[].title'
|
gh api repos/ShunsukeHayashi/mergegate/milestones | jq '.[].title'
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected:
|
Expected:
|
||||||
|
|
@ -98,7 +98,7 @@
|
||||||
|
|
||||||
- [ ] **Issue一覧確認**
|
- [ ] **Issue一覧確認**
|
||||||
```bash
|
```bash
|
||||||
gh issue list --repo ShunsukeHayashi/miyabi-cli-standalone --state all | wc -l
|
gh issue list --repo ShunsukeHayashi/mergegate --state all | wc -l
|
||||||
# Expected: 28 issues
|
# Expected: 28 issues
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -266,7 +266,7 @@
|
||||||
|
|
||||||
- [ ] **Pulse確認**
|
- [ ] **Pulse確認**
|
||||||
```
|
```
|
||||||
https://github.com/ShunsukeHayashi/miyabi-cli-standalone/pulse
|
https://github.com/ShunsukeHayashi/mergegate/pulse
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -277,7 +277,7 @@
|
||||||
|
|
||||||
- [ ] **Issue #10 (MarkdownStream core)**
|
- [ ] **Issue #10 (MarkdownStream core)**
|
||||||
```bash
|
```bash
|
||||||
gh issue view 10 --repo ShunsukeHayashi/miyabi-cli-standalone
|
gh issue view 10 --repo ShunsukeHayashi/mergegate
|
||||||
```
|
```
|
||||||
|
|
||||||
- [ ] **Issue #15 (DiffRender core)**
|
- [ ] **Issue #15 (DiffRender core)**
|
||||||
|
|
@ -316,7 +316,7 @@
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. 環境確認
|
# 1. 環境確認
|
||||||
cd /Users/shunsuke/Dev/miyabi-cli-standalone
|
cd /Users/shunsuke/Dev/mergegate
|
||||||
miyabi status
|
miyabi status
|
||||||
|
|
||||||
# 2. Critical Path 開始
|
# 2. Critical Path 開始
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Product Specification - miyabi-cli-standalone
|
# Product Specification - MergeGate
|
||||||
|
|
||||||
**Version**: 1.0.0
|
**Version**: 1.0.0
|
||||||
**Status**: Draft
|
**Status**: Draft
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Sprint Planning - miyabi-cli-standalone
|
# Sprint Planning - MergeGate
|
||||||
|
|
||||||
**Project**: miyabi-cli-standalone
|
**Project**: mergegate
|
||||||
**Total Sprints**: 4
|
**Total Sprints**: 4
|
||||||
**Sprint Duration**: 5 days (1 week)
|
**Sprint Duration**: 5 days (1 week)
|
||||||
**Start Date**: 2025-11-25
|
**Start Date**: 2025-11-25
|
||||||
|
|
@ -389,7 +389,7 @@ gh issue list --label "🏗️ state:implementing"
|
||||||
### Sprint 1 Quick Start
|
### Sprint 1 Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/shunsuke/Dev/miyabi-cli-standalone
|
cd /Users/shunsuke/Dev/mergegate
|
||||||
|
|
||||||
# Critical Path開始
|
# Critical Path開始
|
||||||
miyabi agent run coordinator --issue 19 # API Client
|
miyabi agent run coordinator --issue 19 # API Client
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# Miyabi CLI ユーザーマニュアル
|
# MergeGate ユーザーマニュアル
|
||||||
|
|
||||||
**Version**: 0.1.0
|
**Version**: 0.1.0
|
||||||
**Last Updated**: 2025-11-23
|
**Last Updated**: 2025-11-23
|
||||||
|
|
@ -22,7 +22,14 @@
|
||||||
|
|
||||||
## はじめに
|
## はじめに
|
||||||
|
|
||||||
Miyabi CLIは、ターミナルで動作するAIアシスタントです。Claude APIを使用して、対話型のチャットや自律的なタスク実行が可能です。
|
MergeGate は、AI-assisted development 向けの deterministic task execution and merge workflow です。CLI では `miyabi` と `mergegate` の両方を使え、対話型の TUI と `gate` ベースの repo workflow を提供します。
|
||||||
|
|
||||||
|
設計思想はシンプルです。
|
||||||
|
|
||||||
|
- `GitNexus`: コードベースを理解する
|
||||||
|
- `MergeGate`: 変更を安全に実行する
|
||||||
|
|
||||||
|
影響範囲が分かるだけでは、AI エージェントは安全に開発できません。どの task を登録し、どのファイルを lock し、どの順序で branch / PR / merge まで進めるかを protocol として固定するのが MergeGate の役割です。
|
||||||
|
|
||||||
### 主な機能
|
### 主な機能
|
||||||
|
|
||||||
|
|
@ -44,21 +51,21 @@ Miyabi CLIは、ターミナルで動作するAIアシスタントです。Claud
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# 1. リポジトリをクローン
|
# 1. リポジトリをクローン
|
||||||
git clone https://github.com/ShunsukeHayashi/miyabi-cli-standalone.git
|
git clone https://github.com/ShunsukeHayashi/mergegate.git
|
||||||
cd miyabi-cli-standalone
|
cd mergegate
|
||||||
|
|
||||||
# 2. リリースビルド
|
# 2. リリースビルド
|
||||||
cargo build --release
|
cargo build --release
|
||||||
|
|
||||||
# 3. バイナリの確認
|
# 3. バイナリの確認
|
||||||
ls -la target/release/miyabi
|
ls -la target/release/miyabi target/release/mergegate
|
||||||
```
|
```
|
||||||
|
|
||||||
### パスを通す(オプション)
|
### パスを通す(オプション)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ~/.bashrc または ~/.zshrc に追加
|
# ~/.bashrc または ~/.zshrc に追加
|
||||||
export PATH="$PATH:/path/to/miyabi-cli-standalone/target/release"
|
export PATH="$PATH:/path/to/mergegate/target/release"
|
||||||
|
|
||||||
# 設定を反映
|
# 設定を反映
|
||||||
source ~/.bashrc # または source ~/.zshrc
|
source ~/.bashrc # または source ~/.zshrc
|
||||||
|
|
@ -528,7 +535,7 @@ max_retries = 5
|
||||||
|
|
||||||
### 問題報告
|
### 問題報告
|
||||||
|
|
||||||
GitHub Issues: https://github.com/ShunsukeHayashi/miyabi-cli-standalone/issues
|
GitHub Issues: https://github.com/ShunsukeHayashi/mergegate/issues
|
||||||
|
|
||||||
### TUIでのヘルプ
|
### TUIでのヘルプ
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Work Breakdown Structure (WBS)
|
# Work Breakdown Structure (WBS)
|
||||||
|
|
||||||
**Project**: miyabi-cli-standalone
|
**Project**: mergegate
|
||||||
**Version**: v1.0.0
|
**Version**: v1.0.0
|
||||||
**Created**: 2025-11-22
|
**Created**: 2025-11-22
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# 改善サイクル — シータサイクル分析に基づく詳細プラン
|
# 改善サイクル — シータサイクル分析に基づく詳細プラン
|
||||||
|
|
||||||
_Polaris タスク: issue-86 | 2026-04-10_
|
_MergeGate タスク: issue-86 | 2026-04-10_
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@
|
||||||
|
|
||||||
## リポジトリ
|
## リポジトリ
|
||||||
|
|
||||||
- **Miyabi-G-K/miyabi-cli-standalone**: Private
|
- **ShunsukeHayashi/mergegate**: Private
|
||||||
- **Miyabi-G-K/deterministic-task-protocol**: Private
|
- **Miyabi-G-K/deterministic-task-protocol**: Private
|
||||||
- 公開しない。npm にも公開しない。
|
- 公開しない。npm にも公開しない。
|
||||||
|
|
||||||
## 保護対象
|
## 保護対象
|
||||||
|
|
||||||
1. **Polaris (DTP) アーキテクチャ**
|
1. **MergeGate (DTP) アーキテクチャ**
|
||||||
- GATE チェーンによる確定的状態遷移
|
- GATE チェーンによる確定的状態遷移
|
||||||
- ファイルロック + DAG + ステートマシンの三位一体
|
- ファイルロック + DAG + ステートマシンの三位一体
|
||||||
- ワークツリー不要の論理的並列分離
|
- ワークツリー不要の論理的並列分離
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
- ドリーミング(event log → 学び昇格)
|
- ドリーミング(event log → 学び昇格)
|
||||||
- シータサイクル統合
|
- シータサイクル統合
|
||||||
|
|
||||||
3. **miyabi gate CLI**
|
3. **MergeGate CLI**
|
||||||
- 11+ サブコマンドの実装
|
- 11+ サブコマンドの実装
|
||||||
- pre-commit / post-commit hook 統合
|
- pre-commit / post-commit hook 統合
|
||||||
- Bus ドッキングブリッジ
|
- Bus ドッキングブリッジ
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue