M2 audit: excise the Computer Hub stack — Kigi's last remote-cloud surface

Removed root-and-branch for the zero-egress guarantee (the hub was xAI's
remote-workspace/cloud-sandbox service):

- Crates deleted: kigi-computer-hub-core, kigi-computer-hub-sdk,
  kigi-computer-hub-mcp-adapter, kigi-workspace-client (hub-proxied
  workspace RPC client), and kigi-tracing (its sole network path was the
  OTLP gRPC exporter; zero consumers remained). kigi-tracing-macros
  (purely local) stays.
- kigi-workspace: every hub surface deleted — hub server/channel/auth,
  HITL-over-hub permissions, donation/metrics pumps, file upload RPCs,
  hub tool-snapshot merge (resolve pipeline is MCP-only now),
  WorkspaceOps::Proxy. Local worktrees, sessions, leader IPC, MCP, and
  the ACP permission prompt path are untouched; LocalRegistry re-homed
  into kigi-tool-runtime on the existing ToolDyn types so in-process
  tool dispatch is unchanged.
- kigi-shell: leader workspace-exposure control surface (incl. the
  wss://computer-hub... URL), [hub] config, ObservabilityBridge, hub
  WebSocket proxy, dead OTLP config knobs. ClientMode::Headless (never
  constructed) removed.
- kigi-tui/bin: hidden `kigi workspace` command removed (`kigi
  worktree` stays).
- Renames: --xai-api-base-url → --api-base-url / KIGI_API_BASE_URL /
  [endpoints] api_base_url (serde alias keeps old configs working; the
  flag feeds BYOK/custom-endpoint routing, not main inference);
  grok_version → kigi_version in inspect/models-cache/trace metadata
  (old caches self-heal via version-mismatch refetch).
- Dependency tree: dropped fastrace*, opentelemetry-otlp/http/proto,
  tokio-tungstenite from the workspace; fixed the 4 real useless_format
  violations the fastrace lint allowance was masking and removed the
  allowance.
- marketplaceAllowlist kept: it gates the LOCAL plugin-marketplace
  feature, not an xAI service.

Known §9 leftover (deliberate, for the M3 sweep): the BYOK default base
URL string. Gates: workspace check/clippy 0/0, fmt, deny ok; suites
green (workspace 1042, shell 4918, tui 6634, tools 2608, tool-runtime
47, mcp 154).
This commit is contained in:
2026-07-17 22:34:10 -04:00
parent 5919526e91
commit fa75eb139a
90 changed files with 452 additions and 9702 deletions
+2 -212
View File
@@ -37,7 +37,6 @@ use kigi_tui::app::{
AgentCmd, Command, LeaderMgmtArgs, LeaderMgmtCommand, LeaderTargetArgs, PagerArgs,
resolve_use_leader,
};
use kigi_tui::app::{WorkspaceMgmtArgs, WorkspaceMgmtCommand, WorkspaceStartArgs};
use kigi_tui::client_identity::PAGER_CLIENT_VERSION;
use kigi_update::{UpdateConfig, auto_update, enforce_minimum_version_or_exit};
use std::env;
@@ -48,8 +47,8 @@ fn apply_agent_endpoint_args(agent_args: &kigi_tui::app::AgentArgs, config: &mut
if let Some(v) = &agent_args.coding_api_base_url {
config.endpoints.coding_api_base_url = Some(v.clone());
}
if let Some(v) = &agent_args.xai_api_base_url {
config.endpoints.xai_api_base_url = v.clone();
if let Some(v) = &agent_args.api_base_url {
config.endpoints.api_base_url = v.clone();
}
}
/// Resolve --agent-profile path: canonicalize and verify the file exists.
@@ -324,194 +323,6 @@ fn ensure_control_caps(reg: &LeaderRegistration) -> Result<&LeaderCapabilities>
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Leader does not advertise capabilities (legacy version)"))
}
/// Env override for the `kigi workspace` gate: any truthy value enables the
/// command locally, a falsy one disables it. This is the only gate now that
/// the server-side feature flag (xAI remote settings) is gone.
const WORKSPACE_COMMAND_ENV: &str = "KIGI_WORKSPACE_COMMAND";
/// The `KIGI_WORKSPACE_COMMAND` override, if set (`Some(true)`/`Some(false)`);
/// `None` means unset (the command stays disabled by default).
fn workspace_command_env_override() -> Option<bool> {
std::env::var(WORKSPACE_COMMAND_ENV)
.ok()
.map(|v| env_flag_enabled(&v))
}
/// Resolve the gate: enabled exactly when the env override says so.
fn workspace_command_gate(env_override: Option<bool>) -> bool {
env_override.unwrap_or(false)
}
/// Truthy parse for grok on/off env vars: everything enables except the common
/// falsy spellings (`0`, `false`, `off`, `no`, empty).
fn env_flag_enabled(value: &str) -> bool {
!matches!(
value.trim().to_ascii_lowercase().as_str(),
"" | "0" | "false" | "off" | "no"
)
}
async fn run_workspace_mgmt(args: WorkspaceMgmtArgs) -> Result<()> {
if !workspace_command_gate(workspace_command_env_override()) {
anyhow::bail!(
"`kigi workspace` is experimental and disabled by default. \
Set {WORKSPACE_COMMAND_ENV}=1 to enable it."
)
}
match args.command {
WorkspaceMgmtCommand::Start(a) => workspace_start(a, false).await,
WorkspaceMgmtCommand::Restart(a) => workspace_start(a, true).await,
WorkspaceMgmtCommand::Pause { target, json } => {
workspace_control(&target, json, ControlCommand::WorkspacePause).await
}
WorkspaceMgmtCommand::Resume { target, json } => {
workspace_control(&target, json, ControlCommand::WorkspaceResume).await
}
WorkspaceMgmtCommand::Stop { target, json } => {
workspace_control(&target, json, ControlCommand::WorkspaceStop).await
}
WorkspaceMgmtCommand::Status { target, json } => {
workspace_control(&target, json, ControlCommand::WorkspaceStatus).await
}
}
}
fn ensure_workspace_caps(reg: &LeaderRegistration) -> Result<()> {
let caps = ensure_control_caps(reg)?;
if !caps.workspace_exposure {
anyhow::bail!(
"the running leader does not support workspace exposure — stop the \
leader process and re-run to pick up the new version"
);
}
Ok(())
}
async fn connect_workspace_control(
_agent_config: &AgentConfig,
target: &LeaderTargetArgs,
) -> Result<LeaderClient> {
if target.pid.is_some() {
let (_descriptor, client) = connect_to_leader(target).await?;
return Ok(client);
}
let socket = default_socket_path();
LeaderClient::connect(
socket,
"grok-workspace-cli",
ClientMode::Stdio,
ClientCapabilities::default(),
)
.await
.map_err(|e| {
anyhow::anyhow!(
"no running leader ({e}). \
Start a grok session, or run `grok workspace start`."
)
})
}
async fn workspace_control(
target: &LeaderTargetArgs,
json: bool,
command: ControlCommand,
) -> Result<()> {
let raw_config = kigi_shell::config::load_effective_config_disk_only()
.map_err(|e| anyhow::anyhow!("Failed to load config: {e}"))?;
let agent_config = AgentConfig::new_from_toml_cfg(&raw_config)
.map_err(|e| anyhow::anyhow!("Failed to create agent config: {e}"))?;
let client = connect_workspace_control(&agent_config, target).await?;
ensure_workspace_caps(client.registration())?;
let payload = client.send_control(command).await??;
render_workspace_payload(&payload, json);
client.cancel();
Ok(())
}
async fn workspace_start(args: WorkspaceStartArgs, restart: bool) -> Result<()> {
use kigi_shell::auth::ensure_authenticated;
let raw_config = kigi_shell::config::load_effective_config()
.map_err(|e| anyhow::anyhow!("Failed to load config: {e}"))?;
let agent_config = AgentConfig::new_from_toml_cfg(&raw_config)
.map_err(|e| anyhow::anyhow!("Failed to create agent config: {e}"))?;
let (use_leader, _) = resolve_use_leader(args.leader, args.no_leader, &raw_config, true);
if !use_leader {
anyhow::bail!(
"`grok workspace` requires leader mode (the workspace is shared via the leader).\n\
Enable it with `[cli] use_leader = true` in ~/.kigi/config.toml, or pass --leader."
);
}
ensure_authenticated(
&agent_config.kimi_code_config,
false,
Some("No cached credentials found. Run `kigi login` first."),
)
.await?;
let capabilities = ClientCapabilities {
client_version: Some(PAGER_CLIENT_VERSION.to_string()),
..Default::default()
};
let conn = connect_or_spawn("grok-workspace-cli", ClientMode::Stdio, capabilities)
.await
.map_err(|e| anyhow::anyhow!("failed to start or connect to leader: {e}"))?;
drop(conn);
let target = LeaderTargetArgs::default();
let client = connect_workspace_control(&agent_config, &target).await?;
ensure_workspace_caps(client.registration())?;
if restart {
let _ = client.send_control(ControlCommand::WorkspaceStop).await;
}
let cwd = match args.cwd {
Some(p) => p,
None => std::env::current_dir()
.map_err(|e| anyhow::anyhow!("cannot determine current directory: {e}"))?,
};
let cwd = std::path::absolute(&cwd).unwrap_or(cwd);
let payload = client
.send_control(ControlCommand::WorkspaceStart {
hub_url: args.hub_url.clone(),
cwd: cwd.display().to_string(),
})
.await??;
render_workspace_payload(&payload, args.json);
client.cancel();
Ok(())
}
fn render_workspace_payload(payload: &ControlPayload, json: bool) {
let ControlPayload::WorkspaceStatus {
state,
hub_url,
cwd,
uptime_ms,
active_tool_calls,
sessions,
pid,
} = payload
else {
eprintln!("unexpected control response: {payload:?}");
return;
};
if json {
let value = serde_json::json!(
{ "state" : state, "hubUrl" : hub_url, "cwd" : cwd, "uptimeMs" : uptime_ms,
"activeToolCalls" : active_tool_calls, "sessions" : sessions, "pid" : pid, }
);
println!("{}", serde_json::to_string(&value).unwrap_or_default());
return;
}
if state == "none" {
println!("Workspace exposure: not running (leader PID {pid})");
return;
}
println!("Workspace exposure: {state}");
if let Some(url) = hub_url {
println!(" hub: {url}");
}
if let Some(dir) = cwd {
println!(" cwd: {dir}");
}
println!(" uptime: {}s", uptime_ms / 1000);
println!(" active: {active_tool_calls} tool call(s)");
let session_list = if sessions.is_empty() {
"-".to_string()
} else {
sessions.join(", ")
};
println!(" sessions: {} ({session_list})", sessions.len());
println!(" leader: PID {pid}");
}
/// How to rebuild one session's `session/load` after a leader reconnect.
#[derive(Default, Clone)]
struct CachedSession {
@@ -1604,10 +1415,6 @@ async fn async_main() -> Result<()> {
.map_err(|e| anyhow::anyhow!("Failed to create agent config: {e}"))?;
return kigi_tui::worktree_cmd::run(worktree_args, &agent_config).await;
}
Command::Workspace(workspace_args) => {
init_tracing_simple("cli");
return run_workspace_mgmt(workspace_args).await;
}
Command::Sessions(sessions_args) => {
init_tracing_simple("cli");
return kigi_tui::sessions_cmd::run(sessions_args).await;
@@ -2094,23 +1901,6 @@ mod tests {
"failure path must not flag the startup hook",
);
}
#[test]
fn workspace_command_gate_resolution() {
assert!(workspace_command_gate(Some(true)));
assert!(!workspace_command_gate(Some(false)));
assert!(!workspace_command_gate(None), "unset env defaults to off");
}
#[serial_test::serial(KIGI_WORKSPACE_COMMAND)]
#[test]
fn workspace_command_env_override_parsing() {
unsafe { std::env::remove_var("KIGI_WORKSPACE_COMMAND") };
assert_eq!(workspace_command_env_override(), None);
unsafe { std::env::set_var("KIGI_WORKSPACE_COMMAND", "1") };
assert_eq!(workspace_command_env_override(), Some(true));
unsafe { std::env::set_var("KIGI_WORKSPACE_COMMAND", "off") };
assert_eq!(workspace_command_env_override(), Some(false));
unsafe { std::env::remove_var("KIGI_WORKSPACE_COMMAND") };
}
fn make_state() -> std::sync::Mutex<StdioReplayState> {
std::sync::Mutex::new(StdioReplayState::default())
}