§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.
This commit is contained in:
2026-07-18 02:48:46 -04:00
parent 86e3724310
commit 6f31415ed6
1056 changed files with 8410 additions and 18307 deletions
@@ -85,7 +85,7 @@ use tokio_util::sync::CancellationToken;
use kigi_paths::AbsPathBuf;
use kigi_workspace::session::git::GitDiscoveryResult;
use kigi_hunk_tracker::HunkTrackerActor;
/// Hard-error message for legacy Direct hub-bind sessions (`x.ai/cloud_server_id`).
/// Hard-error message for legacy Direct hub-bind sessions (`kigi/cloud_server_id`).
pub(crate) const DIRECT_HUB_CLOUD_REMOVED_MSG: &str = "Direct hub cloud removed; use Gateway (envId or existing-workspace attach)";
/// Reject session `_meta` that still requests Direct hub bind (D8).
///
@@ -93,7 +93,7 @@ pub(crate) const DIRECT_HUB_CLOUD_REMOVED_MSG: &str = "Direct hub cloud removed;
pub(crate) fn reject_direct_hub_cloud_meta(
session_meta: Option<&acp::Meta>,
) -> Result<(), acp::Error> {
if session_meta.and_then(|m| m.get("x.ai/cloud_server_id")).is_some() {
if session_meta.and_then(|m| m.get("kigi/cloud_server_id")).is_some() {
return Err(acp::Error::invalid_params().data(DIRECT_HUB_CLOUD_REMOVED_MSG));
}
Ok(())
@@ -147,13 +147,13 @@ impl BridgeAttach {
!matches!(self, Self::NotAttached)
}
}
/// `_meta["x.ai/session"].kind` → [`SessionKind`]; absent/unknown/malformed → `Build`.
/// `_meta["kigi/session"].kind` → [`SessionKind`]; absent/unknown/malformed → `Build`.
fn parse_session_kind(
meta: Option<&acp::Meta>,
) -> crate::session::unified_list::SessionKind {
use crate::session::unified_list::SessionKind;
use serde::Deserialize;
meta.and_then(|m| m.get("x.ai/session"))
meta.and_then(|m| m.get("kigi/session"))
.and_then(|s| s.get("kind"))
.and_then(|k| SessionKind::deserialize(k).ok())
.unwrap_or(SessionKind::Build)
@@ -191,7 +191,7 @@ fn chat_new_session_model_state(
/// `session/new` / `session/load` `_meta` key carrying per-session plugin roots.
pub(crate) const SESSION_PLUGIN_DIRS_META_KEY: &str = "pluginDirs";
/// `initialize` response `_meta` key advertising [`SESSION_PLUGIN_DIRS_META_KEY`] support.
pub(crate) const SESSION_PLUGIN_DIRS_CAPABILITY_KEY: &str = "x.ai/pluginDirs";
pub(crate) const SESSION_PLUGIN_DIRS_CAPABILITY_KEY: &str = "kigi/pluginDirs";
/// Per-session plugin roots from `session/new` / `session/load` `_meta.pluginDirs`,
/// loaded at CliOverride scope (always trusted) into this session's registry only.
/// Paths must be absolute (the SDKs resolve before sending); anything else is
@@ -271,7 +271,7 @@ fn parse_no_replay(meta: Option<&acp::Meta>) -> bool {
meta.and_then(|m| m.get("noReplay")).and_then(|v| v.as_bool()).unwrap_or(false)
}
/// Insert `key`/`value` into a notification's `_meta`, creating the map if absent.
/// Used to stamp `x.ai/leaderClientId` onto replay notifications so the leader can
/// Used to stamp `kigi/leaderClientId` onto replay notifications so the leader can
/// unicast them to the loading client only (see `forward_raw_replay_line`).
fn stamp_meta_value(meta: &mut Option<acp::Meta>, key: &str, value: &serde_json::Value) {
meta.get_or_insert_with(acp::Meta::new).insert(key.to_string(), value.clone());
@@ -284,7 +284,7 @@ fn mark_as_replay(
let obj = meta.get_or_insert_with(acp::Meta::new);
obj.insert("isReplay".to_string(), is_replay);
if let Some(persist) = persist_data {
obj.insert("x.ai/persist".to_string(), persist.clone());
obj.insert("kigi/persist".to_string(), persist.clone());
}
}
/// Resolve a session's REQUESTED auto flag from `_meta`: an explicit `autoMode`
@@ -393,7 +393,7 @@ pub(crate) fn build_prompt_response_meta(
};
serde_json::to_value(meta).expect("PromptResponseMeta is always serializable")
}
/// Typed payload for the `x.ai/settings/update` notification sent to pager
/// Typed payload for the `kigi/settings/update` notification sent to pager
/// clients after remote settings settings are refreshed on `/new`.
///
/// Keeping this as a `#[derive(Serialize)]` struct gives compile-time
@@ -413,13 +413,13 @@ struct SettingsUpdateNotification {
/// Reason why a client is not eligible to use codebase indexing.
///
/// Returned by [`MvpAgent::code_nav_eligibility`] when one of the policy
/// gates fails. Used in `x.ai/code/status` responses and to generate
/// gates fails. Used in `kigi/code/status` responses and to generate
/// clear error messages on code-nav requests from ineligible clients.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CodeNavEligibility {
/// Client type is not web (web-only for initial rollout).
ClientNotWeb,
/// Client did not advertise `x.ai/codeNavigation.enabled`.
/// Client did not advertise `kigi/codeNavigation.enabled`.
CapabilityNotAdvertised,
/// `codebase_indexing` feature is disabled in config (or excluded by glob).
DisabledByConfig,
@@ -519,12 +519,12 @@ pub struct MvpAgent {
/// attribution would require threading `clientIdentifier` from `_meta` through
/// every session handler, which is deferred to future work.
client_type: RefCell<ClientType>,
/// Whether the current client advertised `x.ai/codeNavigation.enabled`.
/// Whether the current client advertised `kigi/codeNavigation.enabled`.
/// Updated on every `initialize()` call — same last-client-wins semantics
/// as `client_type`. Using `Cell<bool>` (not `RefCell`) so `.get()` is a
/// plain copy with no borrow that could be held across an await point.
code_nav_enabled: std::cell::Cell<bool>,
/// Whether the current client advertised `x.ai/folderTrust.interactive` (it
/// Whether the current client advertised `kigi/folderTrust.interactive` (it
/// can render the interactive folder-trust prompt). Set on every
/// `initialize()` (last-client-wins, like `code_nav_enabled`); gates the
/// DORMANT agent→client trust round-trip in `new_session`/`load_session`.
@@ -606,14 +606,14 @@ pub struct MvpAgent {
/// Unified sender for all subagent coordinator events.
/// LEADER-SAFE(shared): channel is multi-producer, coordinator drains.
subagent_event_tx: tokio::sync::mpsc::UnboundedSender<
kigi_tools::implementations::grok_build::task::types::SubagentEvent,
kigi_tools::implementations::kigi::task::types::SubagentEvent,
>,
/// Receiver for subagent events. Taken once by `start_subagent_coordinator()`.
/// `None` after the coordinator drain task has been spawned.
subagent_event_rx: RefCell<
Option<
tokio::sync::mpsc::UnboundedReceiver<
kigi_tools::implementations::grok_build::task::types::SubagentEvent,
kigi_tools::implementations::kigi::task::types::SubagentEvent,
>,
>,
>,
@@ -624,7 +624,7 @@ pub struct MvpAgent {
/// Pushed by the `InjectNotification` handler when a turn is active and the
/// notification has `Next` priority. Drained by the session turn loop
/// (`inject_pending_monitor_events`) into a hidden synthetic user message.
monitor_event_buffer: kigi_tools::implementations::grok_build::task::types::MonitorEventBuffer,
monitor_event_buffer: kigi_tools::implementations::kigi::task::types::MonitorEventBuffer,
/// Per-subagent model ID overrides from config.toml `[subagents.models]`.
/// Populated from `SubagentsConfig.models` during `with_models()`.
subagent_model_overrides: std::collections::HashMap<String, String>,
@@ -653,7 +653,7 @@ pub struct MvpAgent {
/// `plugin_registry_handle`.
///
/// Boot-time plugin discovery is deferred past ACP `initialize` (it walks
/// cwd→git root plus user/marketplace dirs and stalled grok-desktop's first
/// cwd→git root plus user/marketplace dirs and stalled kigi-desktop's first
/// `initialize`), so the shared snapshot starts empty. It is built once on
/// the first session-creating call via [`Self::ensure_plugin_registry`];
/// this flag keeps that to a single discovery walk.
@@ -753,8 +753,8 @@ pub(crate) fn inherited_harness_template(
///
/// When a zero-turn switch rebuilds the harness (`did_rebuild`), the handle
/// must adopt the rebuilt harness's agent type. Otherwise the name is left
/// unchanged — compatible stock switches (e.g. `grok-build` →
/// `grok-build-plan`) intentionally preserve the session's original ACP
/// unchanged — compatible stock switches (e.g. `kigi` →
/// `kigi-plan`) intentionally preserve the session's original ACP
/// `agentProfile`.
pub(crate) fn agent_name_after_model_switch(
did_rebuild: bool,
@@ -770,8 +770,8 @@ pub(crate) fn agent_name_after_model_switch(
/// Harness compatibility for zero-turn / mid-turn model switching.
///
/// Two stock (non-strict) agents are interchangeable — they share the
/// default wire format and toolset, so switching e.g. `grok-build` →
/// `grok-build-plan` doesn't require rebuilding the harness and would
/// default wire format and toolset, so switching e.g. `kigi` →
/// `kigi-plan` doesn't require rebuilding the harness and would
/// destroy a client-supplied `_meta.agentProfile` if it did.
///
/// Strict harnesses (`codex`, …) are only compatible with
@@ -927,7 +927,7 @@ fn resolve_inference_idle_timeout_secs(
let remote = remote_settings.and_then(|s| s.inference_idle_timeout_secs);
per_model.or(remote).unwrap_or(600).max(10)
}
/// Parse the client-advertised `x.ai/hunkTracker.mode` string. Case-insensitive
/// Parse the client-advertised `kigi/hunkTracker.mode` string. Case-insensitive
/// and trimmed. Absent/blank/`off`/`disabled` => `None`; unknown => `AllDirty`.
fn resolve_hunk_tracking_mode(
mode_str: Option<&str>,
@@ -1025,7 +1025,7 @@ impl MvpAgent {
/// Dispatches by on-disk method name:
/// - ACP updates (`"session/update"`) → typed `SessionNotification` for correct
/// TUI dispatch (direct dispatch preserves Rust types, not method strings).
/// - xAI updates (`"_x.ai/session/update"`) → `ExtNotification`.
/// - xAI updates (`"_kigi/session/update"`) → `ExtNotification`.
///
/// When `mark_replay` is true, the notification is tagged with
/// `_meta.isReplay: true` so the client knows it's historical data.
@@ -1058,7 +1058,7 @@ impl MvpAgent {
tracing::debug!("replay: skipping JSONL line with no params");
return;
};
let is_xai = method == "_x.ai/session/update";
let is_xai = method == "_kigi/session/update";
if is_xai {
if target_client_id.is_none() && !mark_replay {
if let Ok(owned) = serde_json::value::RawValue::from_string(
@@ -1070,7 +1070,7 @@ impl MvpAgent {
.gateway
.forward_with_completion(
acp::ExtNotification::new(
"x.ai/session/update",
"kigi/session/update",
std::sync::Arc::from(owned),
),
),
@@ -1094,10 +1094,10 @@ impl MvpAgent {
m.insert("isReplay".to_string(), serde_json::json!(true));
}
if let Some(pd) = persist_data {
m.insert("x.ai/persist".to_string(), pd.clone());
m.insert("kigi/persist".to_string(), pd.clone());
}
if let Some(tid) = target_client_id {
m.insert("x.ai/leaderClientId".to_string(), tid.clone());
m.insert("kigi/leaderClientId".to_string(), tid.clone());
}
}
}
@@ -1108,7 +1108,7 @@ impl MvpAgent {
.gateway
.forward_with_completion(
acp::ExtNotification::new(
"x.ai/session/update",
"kigi/session/update",
std::sync::Arc::from(raw_val),
),
),
@@ -1161,7 +1161,7 @@ impl MvpAgent {
mark_as_replay(&mut notification.meta, persist_data);
}
if let Some(tid) = target_client_id {
stamp_meta_value(&mut notification.meta, "x.ai/leaderClientId", tid);
stamp_meta_value(&mut notification.meta, "kigi/leaderClientId", tid);
}
completions.push(self.gateway.forward_with_completion(notification));
}
@@ -1425,7 +1425,7 @@ impl MvpAgent {
.gateway
.forward_with_completion(
acp::ExtNotification::new(
"x.ai/task_completed",
"kigi/task_completed",
params.into(),
),
),
@@ -1507,7 +1507,7 @@ impl MvpAgent {
});
AuthenticateResponse::new().meta(meta)
}
/// Fire-and-forget `x.ai/settings/update` from the current remote snapshot.
/// Fire-and-forget `kigi/settings/update` from the current remote snapshot.
pub(super) fn emit_settings_update_notification(&self) {
let payload = {
let cfg = self.cfg.borrow();
@@ -1528,7 +1528,7 @@ impl MvpAgent {
if let Ok(params) = serde_json::value::to_raw_value(&payload) {
self.gateway
.forward_fire_and_forget(
acp::ExtNotification::new("x.ai/settings/update", params.into()),
acp::ExtNotification::new("kigi/settings/update", params.into()),
);
}
}