M0: compilable skeleton — Kigi 0.1.0 fork surgery

Hard fork of xai-org/grok-build (Apache-2.0) re-targeted as Kigi, an
unofficial Kimi Code CLI community build.

Rename & identity
- 72 xai-*/xai-grok-* crates -> kigi-* (explicit: xai-grok-pager-bin ->
  kigi-bin [binary `kigi`], xai-grok-pager -> kigi-tui; rest mechanical);
  ptyctl, ptyctl-cli, third_party/ unchanged; proto package
  xai.grok.tools.v1 -> kigi.tools.v1
- Config home ~/.kigi (KIGI_SHARE_DIR override), env prefix GROK_* ->
  KIGI_*, `kigi --version` carries the unofficial-community-build notice
- clap identity, help text, startup banner, prompt templates rebranded
  (templates re-encrypted)

Deletions (PRD removal list #5/#6/#7/#9/#10)
- voice input (xai-grok-voice) and all TUI wiring
- telemetry: Mixpanel client, external OTel stream, Sentry, OTLP layers,
  trace/GCS/S3 upload queues (kigi-file-utils halved), workspace upload
  module & dc_log, heap-profile uploader, auth-diagnostics uploader,
  session-analytics halves of feedback; local zero-egress observability
  preserved in new kigi-log crate (unified log, --debug firehose,
  subsystem file logs, opt-in instrumentation)
- announcements (crate, remote-settings fields, TUI surfaces)
- plugin marketplace (crate, sources/browse/CTA/extensions-modal tab);
  direct plugin install/uninstall/update via kigi-agent git_install kept
- relay/gateway/assets endpoints and features (agent relay, headless
  relay transport, gateway bridge, LeaderEnvUrls); leader IPC socket now
  ~/.kigi/leader.sock + KIGI_LEADER_SOCKET, no ws-url derivation
- functional types rehomed instead of deleted: PermissionMode ->
  kigi-config-types, McpInitStrategy -> kigi-mcp, PrCreationSource ->
  session signals, TerminalDiagnostics -> kigi-pager-render, agent_id ->
  shell util

Endpoints
- kigi-env rewritten: single production KigiEndpoints {coding_api_base_url
  https://api.kimi.com/coding/v1 (KIGI_CODE_BASE_URL), oauth_host
  https://auth.kimi.com (KIGI_OAUTH_HOST), update_base_url (GitHub
  Releases API), upgrade_page_url}; GrokBuildEnvironment enum deleted

Toolchain & workspace hygiene
- Rust 1.97.0 pinned; edition 2024; full cargo update; git2 hoisted to
  workspace at 0.21 (Option->Result API migration), quick-xml 0.41
- Root Cargo.toml hand-maintained (PRD §8.1): version 0.1.0 inherited by
  all members, members sorted, unused deps pruned
- cargo-deny advisories gate (deny.toml with documented transitive
  exceptions); CI workflow (check/clippy/fmt/deny/test, macOS+Linux)
- cross-crate test seams re-gated behind `test-support` cargo feature;
  insta snapshot baselines renamed to the kigi_tui prefix
- clippy --workspace --all-targets: zero warnings; fmt clean

Fixes surfaced by the port
- updater probe/installer divergence (bin/kigi vs bin/grok symlink set)
- idle model-metadata refresh dead under KIGI_CODE_BASE_URL override
  (new is_effective_coding_endpoint_url, loopback+override aware)
- macOS symlinked-TMPDIR fixture canonicalization (foreign_sessions,
  fast-worktree); RSS measurement tests serialized via serial_test

Docs & legal (Apache §4)
- NOTICE added (upstream attribution + change statement); THIRD-PARTY
  notices sustained; kigi-tools ported-code notices extended; README,
  CONTRIBUTING, SECURITY, AGENTS.md rewritten

Out of scope for M0 (tracked): Kimi auth/inference (M1), search/fetch,
command parity, config import (M2), Computer Hub excision & final
brand-token sweep (M2), distribution & self-update rewrite (M3).
This commit is contained in:
2026-07-17 05:31:01 -04:00
commit d6c20fc13f
2612 changed files with 1353757 additions and 0 deletions
+188
View File
@@ -0,0 +1,188 @@
#![allow(
unused_imports,
unused_variables,
unused_mut,
unreachable_code,
dead_code
)]
//! Core workspace library: FS, VCS, permissions, tool config, and subsystem wiring.
pub mod activity;
pub mod capability;
pub mod channel;
pub mod config;
pub mod daemonize;
pub mod diag_server;
pub mod discovery;
pub mod envrc;
pub mod error;
pub mod file_system;
pub mod folder_trust;
pub mod foreign_sessions;
pub mod fs_notify;
pub mod handle;
pub mod hub;
pub mod hub_auth;
pub mod hub_channel;
pub mod hub_ids;
pub mod hub_server;
pub mod mcp;
pub mod permission;
pub mod preview_supervisor;
pub mod project_config;
pub mod recovery;
pub mod rpc_envelope;
pub mod session;
pub mod status_config;
pub use status_config::StatusConfig;
pub mod trust;
pub mod util;
pub mod workspace_ops;
pub mod worktree;
pub use capability::CapabilityMode;
pub use channel::{TransportCallResult, TransportContext, TransportError, TransportNotification};
pub use config::{
AgentSessionConfig, DEFAULT_EVENT_BUFFER_CAPACITY, HookSourceConfig, IsolationMode,
MemoryConfig, SessionContextFactory, SessionTerminalBackend, WorkspaceConfig,
};
pub use error::{WorkspaceError, WorkspaceResult};
pub use file_system::*;
pub use handle::{
DrainOutcome, DrainReason, WorkspaceHandle, connect_local_workspace, resolve_workspace_home,
termination_grace_from_env,
};
pub use hub::HubConfig;
pub use kigi_hunk_tracker::HunkTrackerHandle;
pub use kigi_workspace_client::WorkspaceClient;
pub use kigi_workspace_types::WorkspaceEvent;
pub use permission::*;
pub use session::{WorkspaceSession, WorkspaceShared};
pub use session::{file_state, git, jj};
pub use workspace_ops::{WorkspaceOp, WorkspaceOps};
/// Zero-init every workspace metric family so idle panels render a `0` baseline
/// instead of "No data". Idempotent; call once at workspace-server startup.
pub fn init_metrics() {
handle::init_metrics();
session::swap_policy::init_metrics();
permission::init_metrics();
hub_server::init_metrics();
}
/// Crate-wide lock serializing every test that mutates the process-global
/// environment (`KIGI_SHARE_DIR`, `HOME`, …). nextest isolates each test in its own
/// process, but `cargo test --lib` shares ONE process across threads, so
/// per-module locks don't serialize cross-module — a peer test in another module
/// can clobber `KIGI_SHARE_DIR` mid-test. A single shared lock (used by every
/// env-mutating test module) is required for that single-process run to be
/// race-free.
#[cfg(test)]
pub(crate) static ENV_TEST_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
/// Crate-shared RAII guard for a single process env var in tests: sets (or
/// unsets) it on construction and restores the prior value on drop. The ONE
/// generic env-var guard for the whole crate (replaces the per-module copies).
///
/// Hold it together with [`ENV_TEST_LOCK`] for the test's lifetime, acquiring
/// the lock FIRST so it drops LAST — the env restore (this guard) then runs
/// before the lock releases, so no peer test observes the temporary value.
#[cfg(test)]
pub(crate) struct TestEnvGuard {
key: &'static str,
prev: Option<std::ffi::OsString>,
}
#[cfg(test)]
impl TestEnvGuard {
/// Set `key` to `val`, restoring the prior value on drop.
pub(crate) fn set(key: &'static str, val: &std::path::Path) -> Self {
let prev = std::env::var_os(key);
unsafe { std::env::set_var(key, val) };
Self { key, prev }
}
/// Unset `key`, restoring the prior value on drop.
pub(crate) fn unset(key: &'static str) -> Self {
let prev = std::env::var_os(key);
unsafe { std::env::remove_var(key) };
Self { key, prev }
}
}
#[cfg(test)]
impl Drop for TestEnvGuard {
fn drop(&mut self) {
match self.prev.take() {
Some(prev) => unsafe { std::env::set_var(self.key, prev) },
None => unsafe { std::env::remove_var(self.key) },
}
}
}
/// Holds [`ENV_TEST_LOCK`] AND a set of [`TestEnvGuard`]s as ONE value, so a
/// test (or fixture) can return/bind it however it likes and still be correct.
///
/// Struct fields drop in DECLARATION order, so `_env` (declared first) restores
/// every env var BEFORE `_lock` (declared last) releases the lock — making the
/// "restore before unlock" invariant compile-enforced, not convention-dependent
/// (a single `let _ = LockedTestEnv::lock()…;` binding can't reorder it).
///
/// Acquire the lock first via [`lock`](Self::lock), then mutate env under it with
/// the chained [`set`](Self::set) builder.
#[cfg(test)]
pub(crate) struct LockedTestEnv {
_env: Vec<TestEnvGuard>,
_lock: std::sync::MutexGuard<'static, ()>,
}
#[cfg(test)]
impl LockedTestEnv {
/// Acquire [`ENV_TEST_LOCK`] (held until this value drops).
pub(crate) fn lock() -> Self {
Self {
_env: Vec::new(),
_lock: ENV_TEST_LOCK.lock().unwrap_or_else(|e| e.into_inner()),
}
}
/// Set `key` to `val` under the held lock, restoring the prior value on drop.
///
/// Intended for DISTINCT keys; the restore order across repeated `set`s of
/// the SAME key is unspecified (guards restore in insertion order).
pub(crate) fn set(mut self, key: &'static str, val: &std::path::Path) -> Self {
self._env.push(TestEnvGuard::set(key, val));
self
}
}
#[cfg(test)]
mod init_metrics_tests {
/// `init_metrics()` is idempotent (a double call must not panic on
/// re-register) and populates a `0` baseline series for each family so
/// panels render `0` instead of "No data".
#[test]
fn init_metrics_is_idempotent_and_registers_baselines() {
super::init_metrics();
super::init_metrics();
let families = prometheus::gather();
let has = |name: &str, want: &[(&str, &str)]| {
families
.iter()
.filter(|mf| mf.name() == name)
.flat_map(|mf| mf.get_metric())
.any(|m| {
want.iter().all(|(k, v)| {
m.get_label()
.iter()
.any(|l| l.name() == *k && l.value() == *v)
})
})
};
assert!(has(
"grok_workspace_rpc_requests_total",
&[("method", "unknown"), ("result", "error")]
));
assert!(has(
"grok_workspace_drain_started_total",
&[("reason", "sigterm")]
));
assert!(has(
"grok_workspace_toolset_swap_rejected_total",
&[("reason", "turn_active"), ("trigger", "update_tool_config")]
));
assert!(
families
.iter()
.any(|mf| mf.name() == "grok_workspace_permission_timeout_total")
);
}
}