Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
7dfb484
fix(codex): add shared native gateway bootstrap
willkill07 Jul 10, 2026
1371da7
test(codex): add cold bootstrap end-to-end coverage
willkill07 Jul 10, 2026
97cd427
docs(codex): explain shared gateway bootstrap
willkill07 Jul 10, 2026
0363f12
feat(claude): share native MCP gateway lifecycle
willkill07 Jul 11, 2026
02b4169
feat(hermes): share native MCP gateway lifecycle
willkill07 Jul 11, 2026
7dc185b
refactor(cli): unify coding-agent gateway bootstrap
willkill07 Jul 11, 2026
2ccaac3
fix(cli): harden persistent agent bootstrap
willkill07 Jul 11, 2026
1ec287e
refactor(cli): unify coding-agent bootstrap lifecycle
willkill07 Jul 11, 2026
e15b0b6
fix(cli): harden shared gateway lifecycle
willkill07 Jul 11, 2026
82c05fc
fix(cli): complete shared agent gateway bootstrap
willkill07 Jul 11, 2026
debbbe6
test(cli): close shared bootstrap coverage gaps
willkill07 Jul 12, 2026
b1d15f0
test(cli): verify full bootstrap patch coverage
willkill07 Jul 12, 2026
d93025e
refactor(cli): simplify shared gateway bootstrap
willkill07 Jul 12, 2026
29e1216
fix(cli): serialize failed gateway recovery
willkill07 Jul 12, 2026
55f2ccb
fix(cli): preserve user-owned Hermes configuration
willkill07 Jul 12, 2026
0e888e9
fix: constrain plugin cleanup ownership
willkill07 Jul 12, 2026
6c3b25d
refactor(cli): organize commands and agents
willkill07 Jul 12, 2026
dca1818
refactor(cli): add internal application root
willkill07 Jul 13, 2026
5841f32
refactor(cli): establish subsystem boundaries
willkill07 Jul 13, 2026
29f52b6
refactor(cli): isolate shared agent mechanics
willkill07 Jul 13, 2026
c5b1fec
refactor(cli): split gateway bootstrap responsibilities
willkill07 Jul 13, 2026
64f091e
refactor(cli): normalize command and service module roots
willkill07 Jul 13, 2026
5463001
refactor(cli): move setup into configuration
willkill07 Jul 13, 2026
9b9ad46
refactor(cli): isolate command arguments from runtime inputs
willkill07 Jul 13, 2026
13952d7
refactor(cli): move descriptors into agent slices
willkill07 Jul 13, 2026
b3bd6fd
refactor(cli): isolate plugin lifecycle rendering
willkill07 Jul 13, 2026
baea306
refactor(cli): split gateway routing and responses
willkill07 Jul 13, 2026
d6bed7e
refactor(cli): isolate session correlation policy
willkill07 Jul 13, 2026
86b36c3
refactor(cli): isolate diagnostics rendering
willkill07 Jul 13, 2026
62d6440
refactor(cli): isolate filesystem locking
willkill07 Jul 13, 2026
113ef1b
refactor(cli): split hook encoding merging and responses
willkill07 Jul 13, 2026
4d9aa18
refactor(cli): remove horizontal agent host facade
willkill07 Jul 13, 2026
3df3363
refactor(cli): isolate plugin schema secret handling
willkill07 Jul 13, 2026
42bec22
test(cli): enforce command syntax and test boundaries
willkill07 Jul 13, 2026
487abaa
test(cli): serialize configuration cwd mutation
willkill07 Jul 13, 2026
dec98bd
refactor(cli): assign runtime inputs to subsystems
willkill07 Jul 13, 2026
02da2c4
refactor(cli): make configuration scope explicit
willkill07 Jul 13, 2026
5ebb030
refactor(cli): colocate core command arguments
willkill07 Jul 13, 2026
e03493b
refactor(cli): finish command syntax colocation
willkill07 Jul 13, 2026
705753b
refactor(cli): move installation inputs out of configuration
willkill07 Jul 13, 2026
1f9cf38
refactor(cli): make all a command-only install target
willkill07 Jul 13, 2026
8931733
refactor(cli): move install assets into agent slices
willkill07 Jul 13, 2026
5d9c0fc
refactor(cli): move Claude launch preparation into agent slice
willkill07 Jul 13, 2026
d274ba0
refactor(cli): move Codex launch preparation into agent slice
willkill07 Jul 13, 2026
a94380e
refactor(cli): move Hermes launch preparation into agent slice
willkill07 Jul 13, 2026
a65d2ad
refactor(cli): relocate marketplace transactions under installation
willkill07 Jul 13, 2026
e30cf54
refactor(cli): route marketplace setup through agent slices
willkill07 Jul 13, 2026
af8fbfe
refactor(cli): move Hermes installation into agent slice
willkill07 Jul 13, 2026
54729e9
refactor(cli): add agent-owned marketplace entrypoints
willkill07 Jul 13, 2026
3c19b0c
refactor(cli): move bounded reads into filesystem
willkill07 Jul 13, 2026
935198c
refactor(cli): split filesystem atomic operations
willkill07 Jul 13, 2026
139cfc6
refactor(cli): split hook delivery and destination
willkill07 Jul 13, 2026
13fb672
refactor(cli): separate diagnostic report model
willkill07 Jul 13, 2026
ed1cc49
refactor(cli): isolate environment diagnostics
willkill07 Jul 13, 2026
8a5b43c
refactor(cli): keep easy-path setup in command layer
willkill07 Jul 13, 2026
86b5dbe
refactor(cli): normalize configure command module
willkill07 Jul 13, 2026
43f5fb4
refactor(cli): separate configure UI from persistence
willkill07 Jul 13, 2026
c402a69
refactor(cli): separate resolved configuration model
willkill07 Jul 13, 2026
d59ece4
refactor(cli): source agent identity from agents
willkill07 Jul 13, 2026
b60cf2c
refactor(cli): split plugin command syntax from dispatch
willkill07 Jul 13, 2026
20c0c16
refactor(cli): isolate gateway request preparation
willkill07 Jul 13, 2026
c482557
refactor(cli): separate session gateway types
willkill07 Jul 13, 2026
f45bd5c
refactor(cli): isolate session idle shutdown
willkill07 Jul 13, 2026
201d1ab
refactor(cli): isolate session alias routing
willkill07 Jul 13, 2026
20d4548
refactor(cli): isolate diagnostic probes
willkill07 Jul 13, 2026
8adb1de
refactor(cli): move file snapshots into filesystem
willkill07 Jul 13, 2026
534ff31
refactor(cli): make marketplace layout agent-owned
willkill07 Jul 13, 2026
0837e70
refactor(cli): make marketplace assets agent-owned
willkill07 Jul 13, 2026
9d09f14
refactor(cli): use agent layout for manifest paths
willkill07 Jul 13, 2026
3b901e7
refactor(cli): delegate marketplace host identity
willkill07 Jul 13, 2026
1375ba0
refactor(cli): delegate marketplace registration commands
willkill07 Jul 13, 2026
922bc87
refactor(cli): define marketplace host contract
willkill07 Jul 13, 2026
e0962d9
refactor(cli): delegate marketplace registration probes
willkill07 Jul 13, 2026
bd57f8d
refactor(cli): delegate marketplace compatibility policy
willkill07 Jul 13, 2026
17f39e6
refactor(cli): bind marketplace setup to agent hosts
willkill07 Jul 13, 2026
12cb538
refactor(cli): move integration selection to agents
willkill07 Jul 13, 2026
88b5461
refactor(cli): move integration doctor dispatch to agents
willkill07 Jul 13, 2026
b6b040a
refactor(cli): move integration readiness to agents
willkill07 Jul 13, 2026
ea01cc7
refactor(cli): make installation agent neutral
willkill07 Jul 13, 2026
601535c
refactor(cli): move setup model into configure command
willkill07 Jul 13, 2026
3fa1aab
refactor(cli): move hook diagnosis into agents
willkill07 Jul 13, 2026
072d4d5
test(cli): enforce runtime architecture boundaries
willkill07 Jul 13, 2026
5dadcce
refactor(cli): normalize plugin service modules
willkill07 Jul 13, 2026
cf3da2f
fix(cli): canonicalize persisted install paths
willkill07 Jul 13, 2026
335b452
fix(cli): restore cross-platform test builds
willkill07 Jul 13, 2026
37ae605
test(cli): expose platform helpers to coverage modules
willkill07 Jul 13, 2026
0d4a743
test(cli): widen helper visibility within crate
willkill07 Jul 13, 2026
e54c97d
test(cli): restore coverage boundary after refactor
willkill07 Jul 13, 2026
7a23cad
docs(cli): explain hook forwarding flags
willkill07 Jul 13, 2026
88fb790
test(cli): avoid pinning help prose
willkill07 Jul 13, 2026
dba6144
chore: split documentation from functionality PR
willkill07 Jul 13, 2026
203d870
fix(cli): align Codex gateway metadata
willkill07 Jul 13, 2026
727c5ea
fix(cli): address bootstrap review findings
willkill07 Jul 13, 2026
2f640ce
fix(cli): address remaining review findings
willkill07 Jul 14, 2026
4949114
Merge upstream main into wkk_relay-447-codex-bootstrap
willkill07 Jul 14, 2026
4d6b464
fix(cli): address lifecycle review feedback
willkill07 Jul 14, 2026
ab7cf50
test: eliminate bootstrap shutdown fixture race
willkill07 Jul 14, 2026
9a7dd8d
test: wait for cancelled plugin initialization cleanup
willkill07 Jul 14, 2026
82c9e74
Merge upstream main into wkk_relay-447-codex-bootstrap
willkill07 Jul 14, 2026
2b1f170
test(ffi): isolate native plugin fixture builds
willkill07 Jul 14, 2026
8ccd903
fix(cli): redact ATOF stream destinations
willkill07 Jul 14, 2026
548ad3b
Merge branch 'main' into wkk_relay-447-codex-bootstrap
willkill07 Jul 14, 2026
98518f8
test(cli): tolerate Windows refresh scheduling
willkill07 Jul 14, 2026
60349cf
Merge remote PR updates
willkill07 Jul 14, 2026
1a6a933
fix(cli): address gateway review feedback
willkill07 Jul 14, 2026
38511b0
fix(cli): report all plugin setup diagnostics
willkill07 Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"plugins": [
{
"name": "nemo-relay-plugin",
"description": "Forward Claude Code lifecycle hooks to a local NeMo Relay sidecar.",
"description": "Run the shared native Relay gateway and capture Claude Code lifecycle events.",
"source": "./integrations/coding-agents/claude-code",
"category": "development"
}
Expand Down
8 changes: 8 additions & 0 deletions .config/nextest.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,11 @@

[profile.ci]
junit = { path = "rust_junit_report.xml" }

[[profile.ci.overrides]]
filter = 'test(windows_supervision_assigns_before_a_wrapper_can_spawn_a_descendant)'
slow-timeout = { period = "20s", terminate-after = 2 }

[[profile.ci.overrides]]
filter = 'test(cli_hook_recovery_consumes_the_same_restart_as_an_overlapping_mcp)'
slow-timeout = { period = "20s", terminate-after = 2 }
2,536 changes: 1,985 additions & 551 deletions ATTRIBUTIONS-Rust.md

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ component_management:
- "crates/cli/src"
statuses:
- type: project
target: 88%
target: 90%
threshold: 0.5%
base: auto
if_ci_failed: error
Expand Down Expand Up @@ -137,8 +137,9 @@ ignore:
- "crates/cli/tests/"
# CLI TTY shells are exercised by smoke tests, but their prompt loops are
# intentionally split away from testable model modules.
- "crates/cli/src/plugins.rs"
- "crates/cli/src/setup.rs"
- "crates/cli/src/plugins/mod.rs"
- "crates/cli/src/plugins/dynamic_editor.rs"
- "crates/cli/src/commands/configure/wizard.rs"
- "**/tests-js/**"
# The Node binding currently reports JS package coverage separately; exclude the
# native Rust bridge until we have direct Rust-side coverage for this crate.
Expand Down
20 changes: 19 additions & 1 deletion crates/cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,34 +34,52 @@ async-stream = "0.3"
axum = "0.8"
base64 = "0.22"
bytes = "1"
chrono = "0.4"
clap = { version = "4", features = ["derive", "env"] }
clap_complete = "4"
console = "0.16"
futures-util = "0.3"
fs2 = "0.4"
http = "1"
http-body-util = "0.1"
hyper = "1"
hyper-util = { version = "0.1", features = ["tokio"] }
dialoguer = { version = "0.11", default-features = false, features = ["password"] }
jsonschema = { version = "0.46.6", default-features = false }
percent-encoding = "2"
reqwest = { version = "0.12", default-features = false, features = ["charset", "http2", "json", "rustls-tls-native-roots", "stream"] }
regex = "1"
rcgen = "0.13"
ring = "0.17"
rustls = { version = "0.23", default-features = false, features = ["ring", "std", "tls12"] }
semver = "1"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
sha2 = "0.11"
strum = { version = "0.27", features = ["derive"] }
subtle = "2"
thiserror = "2"
tokio = { version = "1", features = ["macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
tokio = { version = "1", features = ["io-std", "io-util", "macros", "net", "process", "rt-multi-thread", "signal", "sync", "time"] }
tokio-rustls = { version = "0.26", default-features = false, features = ["ring", "tls12"] }
tokio-tungstenite = { version = "0.27", default-features = false, features = ["connect", "rustls-tls-native-roots"] }
toml = "0.9"
toml_edit = "0.23"
uuid = { workspace = true, features = ["serde", "v7"] }

[target.'cfg(unix)'.dependencies]
libc = "0.2"

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61", features = ["Win32_Foundation", "Win32_Security", "Win32_Security_Authorization", "Win32_Storage_FileSystem", "Win32_System_Diagnostics_ToolHelp", "Win32_System_JobObjects", "Win32_System_SystemInformation", "Win32_System_Threading"] }

[dev-dependencies]
opentelemetry = { workspace = true, features = ["trace"] }
opentelemetry_sdk = { workspace = true, features = ["trace", "testing"] }
shell-words = "1"
syn = { version = "2", features = ["full", "visit"] }
tempfile = "3"
tokio = { version = "1", features = ["test-util"] }
tower = { version = "0.5", features = ["util"] }

[[test]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
use axum::http::HeaderMap;
use serde_json::{Value, json};

use crate::adapters::{
use crate::agents::shared::adapters::{
AdapterOutcome, CLAUDE_CODE_PAYLOAD_EXTRACTOR, ClassificationRules, classify,
};
use crate::model::{AgentKind, NormalizedEvent};
use crate::events::{AgentKind, NormalizedEvent};

/// Normalizes Claude Code hook payloads and returns the hook response Claude expects.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ use axum::http::HeaderMap;
use nemo_relay::api::llm::LlmRequest;
use serde_json::Value;

use crate::alignment::json_string_at;
use crate::config::header_string;
use crate::model::{AgentKind, ToolEvent};
use crate::agents::shared::alignment::json_string_at;
use crate::configuration::header_string;
use crate::events::{AgentKind, ToolEvent};

// Identifies gateway providers that should be labeled as Claude-owned when an Anthropic request
// arrives before a SessionStart hook. Other providers are left generic so mixed gateway traffic
Expand Down Expand Up @@ -109,5 +109,5 @@ fn has_terminal_agent_tool_evidence(result: &serde_json::Value) -> bool {
}

#[cfg(test)]
#[path = "../../tests/coverage/alignment_claude_code_tests.rs"]
#[path = "../../../tests/coverage/agents/alignment_claude_code_tests.rs"]
mod tests;
42 changes: 42 additions & 0 deletions crates/cli/src/agents/claude/assets.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

use serde_json::{Value, json};

use crate::mcp::SERVER_NAME;

pub(crate) fn marketplace_manifest(marketplace: &str, plugin: &str) -> Value {
json!({
"name": marketplace,
"metadata": { "description": "Local NeMo Relay plugins for Claude Code." },
"owner": { "name": "NVIDIA Corporation and Affiliates", "email": "noreply@nvidia.com" },
"plugins": [{
"name": plugin,
"description": "Run the shared native Relay gateway and capture Claude Code lifecycle events.",
"source": "./plugins/nemo-relay-plugin",
"category": "development"
}]
})
}

pub(crate) fn plugin_manifest(plugin: &str) -> Value {
json!({
"name": plugin,
"version": env!("CARGO_PKG_VERSION"),
"description": "Native Relay gateway lifecycle and Claude Code hooks for complete local observability.",
"author": { "name": "NVIDIA Corporation and Affiliates", "url": "https://github.com/NVIDIA/NeMo-Relay" },
"homepage": "https://github.com/NVIDIA/NeMo-Relay",
"repository": "https://github.com/NVIDIA/NeMo-Relay",
"license": "Apache-2.0",
"keywords": ["nemo-relay", "claude-code", "hooks", "observability"],
"mcpServers": "./.mcp.json"
})
}

pub(crate) fn mcp_config(mut server: Value) -> Value {
server
.as_object_mut()
.expect("persistent MCP server is a JSON object")
.insert("alwaysLoad".into(), json!(true));
json!({ "mcpServers": { (SERVER_NAME): server } })
}
6 changes: 6 additions & 0 deletions crates/cli/src/agents/claude/doctor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

pub(crate) fn hook_status() -> Result<String, String> {
Ok("hooks: injected during run".into())
}
Loading
Loading