Files
Kigi-CLI/crates/codegen/kigi-workspace/src/lib.rs
T
ZacharyZhang-NY 6f31415ed6 §9 acceptance: grep-zero sweep — every internal x.ai/grok identifier renamed
The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok'
crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party
license archives, README provenance, and the required 'Based on Grok
Build Open Source' attribution, now sourced from version_attribution.txt).

Wire-visible renames (both sides in this repo, changed in lockstep):
- Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode).
- Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* /
  _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps
  a read-side alias for the legacy '_x.ai/session/update' method so
  existing updates.jsonl histories load; writes emit only the new name
  (both directions test-pinned).
- Agent types grok-build* → kigi* with a documented legacy-prefix alias
  at resolution time so persisted sessions keep resolving.
- ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case
  kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build
  implementation dirs renamed to kigi*.
- x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes
  grokday/groknight → kigiday/kiginight (old persisted values fall back
  to the default theme), web_fetch allowlist xAI hosts → kimi.com +
  moonshot platforms, changelog CDN → this repo, grok-build changelog
  archives deleted.
- BYOK default endpoint removed: [endpoints] api_base_url is now truly
  optional with NO default — consumers fail fast with the flag name when
  unset (no silent x.ai egress). Mock harnesses inject it explicitly.
- System-prompt identity fixed: 'released by xAI' → 'an unofficial
  community CLI for Kimi' (template + regenerated encrypted form).

Also repaired pre-existing grok-era test debt found by the sweep: the
stale trace_classify default-model pin, the grok-pager UA label test,
pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY
test could previously reach the real api.moonshot.cn), and the outdated
oauth fixture scope key.

Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings);
FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed;
deny advisories ok.
2026-07-18 02:48:46 -04:00

167 lines
6.1 KiB
Rust

#![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 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 permission;
pub mod project_config;
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::WorkspaceHandle;
pub use kigi_hunk_tracker::HunkTrackerHandle;
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 startup.
pub fn init_metrics() {
handle::init_metrics();
session::swap_policy::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(
"kigi_workspace_toolset_swap_rejected_total",
&[("reason", "turn_active"), ("trigger", "update_tool_config")]
));
assert!(has(
"kigi_workspace_rewind_checkpoint_capture_total",
&[("domain", "fs"), ("outcome", "completed")]
));
assert!(
families
.iter()
.any(|mf| mf.name() == "kigi_workspace_terminal_backend_orphaned_total")
);
}
}