Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions wezterm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ wezterm-client.workspace = true
wezterm-gui-subcommands.workspace = true
wezterm-term.workspace = true

# HRM AI - Optional premium agent management (enable with --features hrm)
hrm-ai = { git = "https://github.com/mikejmorgan-ai/hrm-ai-standalone.git", optional = true }
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The git dependency lacks version pinning (no tag, branch, or rev). This can lead to non-reproducible builds and unexpected breaking changes. Consider pinning to a specific tag or commit hash, e.g., tag = \"v1.0.0\" or rev = \"abc123\".

Copilot uses AI. Check for mistakes.
sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"], optional = true }
Comment on lines +44 to +46
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the Cargo.toml file to see the current state
cat -n wezterm/Cargo.toml | head -60

Repository: cxlinux-ai/cx-core

Length of output: 2220


🏁 Script executed:

# Also check if there are any branding violations in the file
rg -n "(cortex|cortexlinux)" wezterm/Cargo.toml

Repository: cxlinux-ai/cx-core

Length of output: 44


🏁 Script executed:

# Search for any related configuration or documentation mentioning hrm-ai
rg -n "hrm-ai|hrm_ai" wezterm/ --type toml --type yaml --type md

Repository: cxlinux-ai/cx-core

Length of output: 257


Pin the hrm-ai git dependency to a tag or commit.
Unpinned git deps can change without notice and break reproducibility/supply-chain controls.

🔒 Suggested pinning
-hrm-ai = { git = "https://github.com/mikejmorgan-ai/hrm-ai-standalone.git", optional = true }
+hrm-ai = { git = "https://github.com/mikejmorgan-ai/hrm-ai-standalone.git", rev = "<commit-sha>", optional = true }
🤖 Prompt for AI Agents
In `@wezterm/Cargo.toml` around lines 44 - 46, The hrm-ai git dependency in
Cargo.toml is unpinned and should be fixed to a specific tag or commit to ensure
reproducible builds; update the hrm-ai entry (the hrm-ai dependency line) to
include either a tag (e.g., tag = "vX.Y.Z") or a commit SHA (rev =
"<commit-sha>") alongside the git URL so Cargo will fetch a fixed revision
rather than the moving default branch.

tokio = { version = "1", features = ["full"], optional = true }
uuid = { version = "1.6", features = ["v4"], optional = true }

[features]
default = []
hrm = ["dep:hrm-ai", "dep:sqlx", "dep:tokio", "dep:uuid"]

[target."cfg(unix)".dependencies]
termios.workspace = true

Expand Down
183 changes: 183 additions & 0 deletions wezterm/src/cli/fire.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
/**
* Copyright (c) 2026 CX Linux
* Licensed under the Business Source License 1.1
* You may not use this file except in compliance with the License.
*/
Comment on lines +1 to +5
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix the license header copyright holder.
New files must attribute BSL 1.1 to AI Venture Holdings LLC.

📄 Suggested update
- * Copyright (c) 2026 CX Linux
+ * Copyright (c) 2026 AI Venture Holdings LLC

As per coding guidelines, Include BSL 1.1 license header on all new files with copyright to AI Venture Holdings LLC.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Copyright (c) 2026 CX Linux
* Licensed under the Business Source License 1.1
* You may not use this file except in compliance with the License.
*/
/**
* Copyright (c) 2026 AI Venture Holdings LLC
* Licensed under the Business Source License 1.1
* You may not use this file except in compliance with the License.
*/
🤖 Prompt for AI Agents
In `@wezterm/src/cli/fire.rs` around lines 1 - 5, Replace the current license
header in this new file (fire.rs) so it attributes the Business Source License
1.1 to AI Venture Holdings LLC: update the copyright line and ensure the BSL 1.1
notice remains intact and identical in wording to the project's standard header
used across other new files.


//! HRM AI Agent Termination Command
//!
//! Safely terminates AI agents with confirmation and audit logging.
//! This module is only available when the `hrm` feature is enabled.
//!
//! # Example
//! ```bash
//! # Terminate an agent by ID
//! cx fire abc123-def456
//!
//! # Force termination (skip confirmation)
//! cx fire abc123-def456 --force
//!
//! # Terminate with reason
//! cx fire abc123-def456 --reason "Migrating to new server"
//! ```
Comment on lines +7 to +22
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Replace inner doc comments to restore fmt/build and align comment policy.
//! here triggers rustfmt errors (see pipeline). Convert to regular intent-focused comments and use the CX prefix.

✅ Suggested rewrite
-//! HRM AI Agent Termination Command
-//!
-//! Safely terminates AI agents with confirmation and audit logging.
-//! This module is only available when the `hrm` feature is enabled.
-//!
-//! # Example
-//! ```bash
-//! # Terminate an agent by ID
-//! cx fire abc123-def456
-//! 
-//! # Force termination (skip confirmation)
-//! cx fire abc123-def456 --force
-//! 
-//! # Terminate with reason
-//! cx fire abc123-def456 --reason "Migrating to new server"
-//! ```
+// CX Terminal: WHY — provide a guarded termination flow with audit logging
+// when the premium HRM feature is enabled.

As per coding guidelines, Code comments must explain WHY, never WHAT or HOW, and Rust: Mark CX additions with '// CX Terminal:' comment prefix.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//! HRM AI Agent Termination Command
//!
//! Safely terminates AI agents with confirmation and audit logging.
//! This module is only available when the `hrm` feature is enabled.
//!
//! # Example
//! ```bash
//! # Terminate an agent by ID
//! cx fire abc123-def456
//!
//! # Force termination (skip confirmation)
//! cx fire abc123-def456 --force
//!
//! # Terminate with reason
//! cx fire abc123-def456 --reason "Migrating to new server"
//! ```
// CX Terminal: WHY — provide a guarded termination flow with audit logging
// when the premium HRM feature is enabled.
🤖 Prompt for AI Agents
In `@wezterm/src/cli/fire.rs` around lines 7 - 22, Replace the module-level inner
doc comments (the leading //! lines at the top of wezterm/src/cli/fire.rs) with
regular line comments that explain WHY this module exists (not WHAT or HOW),
using the required prefix "// CX Terminal:"; remove example usage blocks and
triple-backticks, keep the note about the hrm feature but convert it to a CX
Terminal comment, and ensure the comment text follows the project's comment
policy (intent-focused WHY and marked with the CX prefix) so rustfmt/build and
policy checks pass.


use anyhow::Result;
use clap::Parser;

#[cfg(feature = "hrm")]
use hrm_ai::{
fire::{AgentTerminationService, TerminationConfig},
database::AgentRepository,
theme::SovereignTheme,
};

/// Terminate (fire) an AI agent
#[derive(Debug, Parser, Clone)]
pub struct FireCommand {
/// Agent ID to terminate
pub agent_id: String,

/// Skip confirmation prompt (dangerous)
#[arg(long, short = 'f')]
pub force: bool,

/// Reason for termination (for audit log)
#[arg(long, short = 'r')]
pub reason: Option<String>,

/// Graceful shutdown timeout in seconds
#[arg(long, default_value = "30")]
pub timeout: u64,

/// Output format: table, json
#[arg(long, default_value = "table")]
pub format: String,
}

impl FireCommand {
pub fn run(self) -> Result<()> {
#[cfg(feature = "hrm")]
{
run_fire_with_hrm(self)
}

#[cfg(not(feature = "hrm"))]
{
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!(" 🔒 HRM AI Premium Feature");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
println!();
println!(" The 'fire' command requires the HRM AI premium module.");
println!();
println!(" To enable HRM AI capabilities, rebuild with:");
println!(" cargo build --features hrm");
println!();
println!(" HRM AI Features:");
println!(" • cx hire <agent-type> - Deploy AI agents");
println!(" • cx fire <agent-id> - Terminate agents");
println!(" • PostgreSQL integration for fleet management");
println!(" • Enterprise compliance automation");
println!();
println!(" License: BSL 1.1 (Business Source License)");
println!("━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━");
Ok(())
}
}
}

#[cfg(feature = "hrm")]
fn run_fire_with_hrm(cmd: FireCommand) -> Result<()> {
use tokio::runtime::Runtime;
use std::time::Duration;

let rt = Runtime::new()?;
rt.block_on(async {
let theme = SovereignTheme::new();

// Print header
theme.print_header("CX Linux Agent Termination");

// Get database URL from environment
let db_url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://localhost/cx_agents".to_string());
Comment on lines +101 to +102
Copy link

Copilot AI Feb 1, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The default database URL uses an unencrypted postgres:// connection. For enterprise-grade deployments mentioned in the documentation, this should default to a secure connection (e.g., require SSL) or at minimum include a warning about the security implications of the default.

Suggested change
let db_url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://localhost/cx_agents".to_string());
let db_url = match std::env::var("DATABASE_URL") {
Ok(url) => url,
Err(_) => {
eprintln!(
"WARNING: DATABASE_URL is not set. Falling back to a local default \
postgres:// connection with sslmode=require.\n\
For production and enterprise deployments, explicitly configure a secure DATABASE_URL."
);
"postgres://localhost/cx_agents?sslmode=require".to_string()
}
};

Copilot uses AI. Check for mistakes.
Comment on lines +101 to +102
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Using a hardcoded fallback for DATABASE_URL can lead to unexpected behavior. If the environment variable is not set, the command will silently try to connect to postgres://localhost/cx_agents, which might not exist or might be the wrong database. This could cause confusion or data corruption.

It's more robust to fail explicitly if DATABASE_URL is not set, forcing the user to configure the environment correctly. This can be achieved by using .context() from anyhow to provide a clear error message.

Suggested change
let db_url = std::env::var("DATABASE_URL")
.unwrap_or_else(|_| "postgres://localhost/cx_agents".to_string());
let db_url = std::env::var("DATABASE_URL")
.context("DATABASE_URL environment variable must be set to connect to the agent database")?;


// Create repository to fetch agent info
let repo = AgentRepository::new(&db_url).await?;
Comment on lines +97 to +105
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inline comments should state intent (WHY) and use the CX prefix.
Comments like “Print header” and “Get database URL” are “what/how”; rephrase to intent or remove.

As per coding guidelines, Code comments must explain WHY, never WHAT or HOW, and Rust: Mark CX additions with '// CX Terminal:' comment prefix.

🤖 Prompt for AI Agents
In `@wezterm/src/cli/fire.rs` around lines 97 - 105, Replace the existing WHAT/HOW
comments above theme.print_header, the DATABASE_URL getenv, and
AgentRepository::new with CX-prefixed intent comments that explain WHY these
steps are necessary; specifically add comments like "// CX Terminal: explain why
we print the termination header (provide user context)" before
theme.print_header, "// CX Terminal: explain why we fall back to default
DATABASE_URL (ensure local dev connectivity)" near the db_url initialization,
and "// CX Terminal: explain why we construct AgentRepository (to fetch agent
termination metadata)" before AgentRepository::new to satisfy the guideline that
comments state intent and use the CX prefix.


// Fetch agent details
let agent = match repo.get_agent(&cmd.agent_id).await? {
Some(a) => a,
None => {
theme.print_error(&format!("Agent not found: {}", cmd.agent_id));
return Ok(());
}
Comment on lines +108 to +113
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let me check the file and the specific lines mentioned
cat -n wezterm/src/cli/fire.rs | head -150 | tail -50

Repository: cxlinux-ai/cx-core

Length of output: 2259


🏁 Script executed:

# Get the context around lines 108-113
sed -n '90,130p' wezterm/src/cli/fire.rs

Repository: cxlinux-ai/cx-core

Length of output: 1467


🏁 Script executed:

# Check the function signature and return type
sed -n '80,120p' wezterm/src/cli/fire.rs

Repository: cxlinux-ai/cx-core

Length of output: 1416


🏁 Script executed:

# Check if anyhow is imported in this file
head -50 wezterm/src/cli/fire.rs | grep -E "^use|^extern"

Repository: cxlinux-ai/cx-core

Length of output: 113


🏁 Script executed:

# Check how errors are handled elsewhere in the file
rg "Err\(|anyhow::" wezterm/src/cli/fire.rs -A 2

Repository: cxlinux-ai/cx-core

Length of output: 100


Return a non-zero exit when the agent is missing.

Printing an error but returning Ok(()) makes automation treat failures as success. Use anyhow::anyhow!() to propagate the error instead, which is already imported in this file and aligns with the error handling pattern used elsewhere in the function.

🚫 Suggested error propagation
-            None => {
-                theme.print_error(&format!("Agent not found: {}", cmd.agent_id));
-                return Ok(());
-            }
+            None => {
+                theme.print_error(&format!("Agent not found: {}", cmd.agent_id));
+                return Err(anyhow::anyhow!("Agent not found: {}", cmd.agent_id));
+            }
🤖 Prompt for AI Agents
In `@wezterm/src/cli/fire.rs` around lines 108 - 113, The code prints an error
when repo.get_agent(&cmd.agent_id).await? returns None but still returns Ok(());
change this to propagate a non-zero failure by returning
Err(anyhow::anyhow!(...)) instead of Ok(()). Replace the None branch that
currently calls theme.print_error(&format!("Agent not found: {}",
cmd.agent_id)); return Ok(()) with a call to theme.print_error(...) followed by
returning Err(anyhow::anyhow!("Agent not found: {}", cmd.agent_id)) so the
function exits with an error when the agent is missing.

};

println!();
println!(" ⚠️ Termination Request");
println!(" ─────────────────────────────────────");
println!(" Agent ID: {}", agent.id);
println!(" Name: {}", agent.name);
println!(" Type: {}", agent.agent_type);
println!(" Server: {}", agent.server_id);
println!(" Status: {:?}", agent.status);
if let Some(ref reason) = cmd.reason {
println!(" Reason: {}", reason);
}
println!();

// Require confirmation unless --force
if !cmd.force {
println!(" ⚠️ WARNING: This action cannot be undone!");
println!();
print!(" Type the agent name to confirm termination: ");
std::io::Write::flush(&mut std::io::stdout())?;

let mut input = String::new();
std::io::stdin().read_line(&mut input)?;

if input.trim() != agent.name {
println!();
println!(" ❌ Termination cancelled - name mismatch");
return Ok(());
}
}

// Create termination service
let config = TerminationConfig {
database_url: db_url,
graceful_timeout: Duration::from_secs(cmd.timeout),
audit_enabled: true,
};

let service = AgentTerminationService::new(config).await?;

// Terminate agent
println!();
println!(" 🔥 Initiating graceful shutdown...");

let reason = cmd.reason.unwrap_or_else(|| "Manual termination".to_string());
let result = service.terminate_agent(&cmd.agent_id, &reason).await?;

if result.success {
println!();
theme.print_success("Agent terminated successfully");
println!();
println!(" Agent ID: {}", cmd.agent_id);
println!(" Shutdown Time: {}ms", result.shutdown_duration_ms);
println!(" Audit ID: {}", result.audit_id);
println!();

if result.tasks_migrated > 0 {
println!(" 📋 {} pending tasks migrated to other agents", result.tasks_migrated);
}
} else {
theme.print_error("Termination failed");
if let Some(error) = result.error {
println!(" Error: {}", error);
}
}

Ok(())
})
}
Loading
Loading