Skip to content

Commit c70e070

Browse files
committed
feat: implement SessionEnd hook, add multi-agent support, and update Antigravity MCP configuration logic
1 parent 76a1e1c commit c70e070

14 files changed

Lines changed: 1547 additions & 89 deletions

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ By default, `omni init --claude` automatically hooks into **Claude Code**. Howev
154154

155155
1. **VS Code & Continue.dev**: Use our MCP context provider (`integrations/continue-dev/`).
156156
2. **OpenCode & Codex CLI**: Built-in wrappers automatically pipe command output to OMNI.
157-
3. **Antigravity IDE**: OMNI natively supports IDEs like Antigravity via MCP over stdio. Just import the plugin manifest (`integrations/antigravity/antigravity.plugin.json`).
157+
3. **Antigravity IDE**: OMNI registers as a native MCP server in Antigravity's config (`~/.gemini/antigravity/mcp_config.json`). Run `omni init --antigravity` to set up automatically.
158158

159159
**Multi-Agent Tuning (`~/.omni/config.toml`)**
160160
Different agents have different pain points. Keep VS Code chat clean, whilst letting OpenCode read more data. Tune them individually:

docs/HOW_TO_USE.md

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1190,6 +1190,53 @@ You can use OMNI natively with OpenClaw by installing the official skill from Cl
11901190
- **Install Command**: `clawhub install omni-signal-engine`
11911191
- **Automatic Setup**: OpenClaw integration is completely automatic. Run `omni doctor --fix` to fetch and install the latest plugin directly from the OMNI public repository.
11921192

1193+
### Antigravity IDE
1194+
1195+
OMNI integrates with Antigravity IDE as a native MCP server, registered directly in Antigravity's MCP configuration file.
1196+
1197+
**Automatic Setup:**
1198+
```bash
1199+
omni init --antigravity
1200+
```
1201+
1202+
This registers OMNI as an MCP server at:
1203+
- **macOS/Linux**: `~/.gemini/antigravity/mcp_config.json`
1204+
- **Windows**: `%USERPROFILE%\.gemini\antigravity\mcp_config.json`
1205+
1206+
**Manual Setup:**
1207+
1208+
If you prefer to configure manually, add the `omni` entry to your `mcp_config.json`:
1209+
1210+
```json
1211+
{
1212+
"mcpServers": {
1213+
"omni": {
1214+
"command": "/opt/homebrew/bin/omni",
1215+
"args": ["serve"]
1216+
}
1217+
}
1218+
}
1219+
```
1220+
1221+
> [!NOTE]
1222+
> Replace `/opt/homebrew/bin/omni` with the actual path to your OMNI binary. You can find it by running `which omni`.
1223+
1224+
**Verification:**
1225+
```bash
1226+
omni doctor # Check Antigravity integration status
1227+
```
1228+
1229+
The doctor output will show:
1230+
```
1231+
Antigravity IDE:
1232+
Config: ~/.gemini/antigravity/mcp_config.json [OK]
1233+
```
1234+
1235+
**Uninstall:**
1236+
```bash
1237+
omni reset --antigravity # Remove OMNI from Antigravity MCP config
1238+
```
1239+
11931240
---
11941241

11951242
*This is a living document. OMNI is under active development — check the [CHANGELOG](https://github.com/fajarhide/omni/blob/main/CHANGELOG.md) for updates after each release.*

src/agents/antigravity.rs

Lines changed: 72 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ use std::path::PathBuf;
66

77
pub struct AntigravityIntegration;
88

9+
impl AntigravityIntegration {
10+
/// Returns the path to the Antigravity MCP config file.
11+
/// macOS/Linux: ~/.gemini/antigravity/mcp_config.json
12+
/// Windows: %USERPROFILE%\.gemini\antigravity\mcp_config.json
13+
fn config_path() -> PathBuf {
14+
dirs::home_dir()
15+
.unwrap_or_else(|| PathBuf::from("."))
16+
.join(".gemini/antigravity/mcp_config.json")
17+
}
18+
}
19+
920
impl AgentIntegration for AntigravityIntegration {
1021
fn id(&self) -> &'static str {
1122
"antigravity"
@@ -16,86 +27,89 @@ impl AgentIntegration for AntigravityIntegration {
1627
}
1728

1829
fn install(&self, exe_path: &str) -> anyhow::Result<()> {
19-
let extensions_dir = dirs::home_dir()
20-
.unwrap_or_else(|| PathBuf::from("."))
21-
.join(".antigravity/extensions");
22-
let plugin_dir = extensions_dir.join("omni-signal-engine");
23-
24-
fs::create_dir_all(&plugin_dir)?;
25-
26-
let manifest = json!({
27-
"name": "omni-signal-engine",
28-
"version": "0.1.0",
29-
"description": "OMNI intelligent output distillation for Antigravity IDE",
30-
"type": "mcp",
31-
"mcp": {
32-
"transport": "stdio",
33-
"command": exe_path,
34-
"args": ["--mcp"]
35-
}
36-
});
30+
let config_path = Self::config_path();
31+
32+
if let Some(parent) = config_path.parent() {
33+
fs::create_dir_all(parent)?;
34+
}
35+
36+
let mut val = if config_path.exists() {
37+
let content = fs::read_to_string(&config_path)?;
38+
serde_json::from_str(&content).unwrap_or_else(|_| json!({}))
39+
} else {
40+
json!({})
41+
};
3742

38-
fs::write(
39-
plugin_dir.join("package.json"),
40-
serde_json::to_string_pretty(&manifest)?,
41-
)?;
43+
if let Some(obj) = val.as_object_mut() {
44+
let mcp_servers = obj.entry("mcpServers").or_insert_with(|| json!({}));
45+
if let Some(servers) = mcp_servers.as_object_mut() {
46+
servers.insert(
47+
"omni".to_string(),
48+
json!({
49+
"command": exe_path,
50+
"args": ["serve"]
51+
}),
52+
);
53+
}
54+
}
4255

56+
fs::write(&config_path, serde_json::to_string_pretty(&val)?)?;
4357
println!(
44-
" {} Installed MCP Plugin to ~/.antigravity/extensions/omni-signal-engine",
58+
" {} Configured MCP Server in ~/.gemini/antigravity/mcp_config.json",
4559
"✓".green()
4660
);
4761
Ok(())
4862
}
4963

5064
fn uninstall(&self) -> anyhow::Result<()> {
51-
let plugin_dir = dirs::home_dir()
52-
.unwrap_or_else(|| PathBuf::from("."))
53-
.join(".antigravity/extensions/omni-signal-engine");
65+
let config_path = Self::config_path();
5466

55-
if plugin_dir.exists() {
56-
fs::remove_dir_all(&plugin_dir).ok();
57-
println!(
58-
" {} Removed MCP Plugin from ~/.antigravity/extensions/",
59-
"✓".yellow()
60-
);
67+
if !config_path.exists() {
68+
return Ok(());
6169
}
70+
71+
let content = fs::read_to_string(&config_path)?;
72+
let Ok(mut val) = serde_json::from_str::<serde_json::Value>(&content) else {
73+
return Ok(());
74+
};
75+
76+
if let Some(obj) = val.as_object_mut()
77+
&& let Some(servers) = obj.get_mut("mcpServers").and_then(|v| v.as_object_mut())
78+
{
79+
servers.remove("omni");
80+
}
81+
82+
fs::write(&config_path, serde_json::to_string_pretty(&val)?)?;
83+
println!(
84+
" {} Removed MCP Server from ~/.gemini/antigravity/mcp_config.json",
85+
"✓".yellow()
86+
);
6287
Ok(())
6388
}
6489

6590
fn doctor_check(&self, _fix_mode: bool, _warnings: &mut Vec<String>) -> bool {
66-
let antigravity_dir = dirs::home_dir()
67-
.unwrap_or_else(|| PathBuf::from("."))
68-
.join(".antigravity/extensions");
91+
let config_path = Self::config_path();
6992

7093
println!("\n {}", "Antigravity IDE:".cyan());
71-
let mut ag_found = false;
72-
if antigravity_dir.exists()
73-
&& let Ok(entries) = fs::read_dir(&antigravity_dir)
94+
if config_path.exists()
95+
&& fs::read_to_string(&config_path)
96+
.unwrap_or_default()
97+
.contains("\"omni\":")
7498
{
75-
for entry in entries.flatten() {
76-
if entry
77-
.file_name()
78-
.to_string_lossy()
79-
.contains("omni-signal-engine")
80-
{
81-
println!(
82-
" {:<15} {} {}",
83-
"Config:".bright_black(),
84-
"plugin installed".bright_black(),
85-
"[OK]".green().bold()
86-
);
87-
ag_found = true;
88-
break;
89-
}
90-
}
91-
}
92-
if !ag_found {
99+
println!(
100+
" {:<15} {} {}",
101+
"Config:".bright_black(),
102+
"~/.gemini/antigravity/mcp_config.json".bright_black(),
103+
"[OK]".green().bold()
104+
);
105+
true
106+
} else {
93107
println!(
94108
" {:<15} {}",
95109
"Config:".bright_black(),
96-
"not configured (check GUI)".bright_black()
110+
"not configured".bright_black()
97111
);
112+
false
98113
}
99-
ag_found
100114
}
101115
}

src/agents/claude.rs

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,15 +338,37 @@ pub fn install_omni_hooks(val: &mut Value, exe_path: &str) {
338338
}));
339339
};
340340

341-
let script_path = format!("{} --pre-hook", exe_path);
341+
let ensure_async_hook = |arr_val: &mut serde_json::Value, hook_cmd: &str| {
342+
let arr = arr_val.as_array_mut().unwrap();
343+
for v in arr.iter() {
344+
if let Some(inner) = v.get("hooks").and_then(|h| h.as_array()) {
345+
for h in inner {
346+
if h.get("command").and_then(|c| c.as_str()) == Some(hook_cmd) {
347+
return;
348+
}
349+
}
350+
}
351+
}
352+
arr.push(json!({
353+
"hooks": [{
354+
"type": "command",
355+
"command": hook_cmd,
356+
"async": true
357+
}]
358+
}));
359+
};
360+
361+
let pre_cmd = format!("{} --pre-hook", exe_path);
342362
let post_cmd = format!("{} --post-hook", exe_path);
343363
let session_cmd = format!("{} --session-start", exe_path);
344364
let compact_cmd = format!("{} --pre-compact", exe_path);
365+
let hook_cmd = format!("{} --hook", exe_path);
345366

367+
// Core hooks (blocking)
346368
ensure_hook(
347369
hooks.entry("PreToolUse").or_insert_with(|| json!([])),
348370
"Bash",
349-
&script_path,
371+
&pre_cmd,
350372
);
351373
ensure_hook(
352374
hooks.entry("PostToolUse").or_insert_with(|| json!([])),
@@ -363,6 +385,27 @@ pub fn install_omni_hooks(val: &mut Value, exe_path: &str) {
363385
"",
364386
&compact_cmd,
365387
);
388+
389+
// v0.5.7: New hooks (async — non-blocking, no output needed)
390+
ensure_async_hook(
391+
hooks.entry("SessionEnd").or_insert_with(|| json!([])),
392+
&hook_cmd,
393+
);
394+
ensure_async_hook(
395+
hooks
396+
.entry("PostToolUseFailure")
397+
.or_insert_with(|| json!([])),
398+
&hook_cmd,
399+
);
400+
ensure_hook(
401+
hooks.entry("SubagentStart").or_insert_with(|| json!([])),
402+
"",
403+
&session_cmd,
404+
);
405+
ensure_async_hook(
406+
hooks.entry("FileChanged").or_insert_with(|| json!([])),
407+
&hook_cmd,
408+
);
366409
}
367410

368411
pub fn install_mcp_server(exe_path: &str) -> anyhow::Result<()> {

src/agents/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod codex;
55
pub mod copilot;
66
pub mod cursor;
77
pub mod gemini;
8+
pub mod multiagent;
89
pub mod openclaw;
910
pub mod opencode;
1011
pub mod roo_code;

0 commit comments

Comments
 (0)