§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
+2 -2
View File
@@ -2,7 +2,7 @@
//!
//! Parses the `_meta` JSON from `SessionNotification` into a struct with
//! typed fields. All fields are `Option` — gracefully degrades when
//! grok-shell hasn't been updated or meta is absent.
//! kigi-shell hasn't been updated or meta is absent.
use serde::{Deserialize, Serialize};
@@ -154,7 +154,7 @@ mod tests {
#[test]
fn parse_missing_new_fields() {
// Simulate old grok-shell that doesn't send streamStartMs/turnStartMs
// Simulate old kigi-shell that doesn't send streamStartMs/turnStartMs
let meta_json = json!({
"totalTokens": 1000u64,
"agentTimestampMs": 1700000000000i64,
+40 -40
View File
@@ -54,8 +54,8 @@ pub struct AcpConnection {
pub rx: AcpClientRx,
/// Available models and current selection.
pub models: ModelState,
/// Whether the agent is a grok-shell instance.
pub is_grok_shell: bool,
/// Whether the agent is a kigi-shell instance.
pub is_kigi_shell: bool,
/// Auth methods advertised by the agent.
pub auth_methods: Vec<acp::AuthMethod>,
/// Cancellation token to stop the agent.
@@ -64,9 +64,9 @@ pub struct AcpConnection {
/// Seeded into every new `AgentSession` so autocomplete has shell builtins
/// and skills immediately, before any `AvailableCommandsUpdate` arrives.
pub available_commands: Vec<acp::AvailableCommand>,
/// Whether interactive login is required (deferred auth for `grok.com`).
/// Whether interactive login is required (deferred auth for `kimi-code`).
pub needs_login: bool,
/// Login button label from `AuthMethod.name` (e.g., "grok.com", "Acme Corp").
/// Login button label from `AuthMethod.name` (e.g., "kimi-code", "Acme Corp").
pub login_label: Option<String>,
/// The auth method ID to use for login (copied from the first advertised method).
pub login_method_id: Option<acp::AuthMethodId>,
@@ -83,7 +83,7 @@ pub struct AcpConnection {
/// resolved by the shell (remote settings / config / env; default OFF) and
/// advertised in `InitializeResponse.meta.sessionRecap`. The client gates
/// its automatic away-recap poll and the manual `/recap` on this so a
/// disabled feature produces zero `x.ai/recap` traffic. Defaults to `false`
/// disabled feature produces zero `kigi/recap` traffic. Defaults to `false`
/// when absent (e.g. an older shell that predates the feature).
pub session_recap_available: bool,
/// `AuthManager` for pager-side authenticated channels.
@@ -183,14 +183,14 @@ pub async fn connect(cancel: &CancellationToken, flags: ConnectFlags) -> Result<
// Spawn the agent
let memory_config = agent_config.memory_config.clone();
let spawned = spawn::spawn_grok_shell(agent_config, cancel, memory_config).await?;
let spawned = spawn::spawn_kigi_shell(agent_config, cancel, memory_config).await?;
let auth_manager = spawned.auth_manager.clone();
let (tx, rx) = (spawned.channel.tx, spawned.channel.rx);
// Initialize
let (
models,
is_grok_shell,
is_kigi_shell,
auth_methods,
default_auth_method_id,
available_commands,
@@ -218,7 +218,7 @@ pub async fn connect(cancel: &CancellationToken, flags: ConnectFlags) -> Result<
tx,
rx,
models,
is_grok_shell,
is_kigi_shell,
auth_methods,
cancel: spawned.cancel,
available_commands,
@@ -291,7 +291,7 @@ pub async fn connect_via_leader(
let (
models,
is_grok_shell,
is_kigi_shell,
auth_methods,
default_auth_method_id,
available_commands,
@@ -329,7 +329,7 @@ pub async fn connect_via_leader(
tx,
rx,
models,
is_grok_shell,
is_kigi_shell,
auth_methods,
cancel: bridge.cancel,
available_commands,
@@ -439,10 +439,10 @@ fn client_capabilities_meta(flags: &ConnectFlags) -> serde_json::Value {
let hunk_mode =
crate::settings::canonical_hunk_tracker_mode(flags.hunk_tracker_mode.as_deref());
serde_json::json!({
"x.ai/incrementalBashOutput": true,
"x.ai/hunkTracker": { "mode": hunk_mode },
"x.ai/bashOutputNoColor": true,
"x.ai/gitHeadChanged": true,
"kigi/incrementalBashOutput": true,
"kigi/hunkTracker": { "mode": hunk_mode },
"kigi/bashOutputNoColor": true,
"kigi/gitHeadChanged": true,
})
}
@@ -482,11 +482,11 @@ async fn initialize(
let resp: acp::InitializeResponse = acp_send(req, tx).await?;
// Check if this is a grok-shell agent
let is_grok_shell = resp
// Check if this is a kigi-shell agent
let is_kigi_shell = resp
.meta
.as_ref()
.and_then(|m| m.get("grokShell"))
.and_then(|m| m.get("kigiShell"))
.and_then(|v| v.as_bool())
.unwrap_or(false);
@@ -514,7 +514,7 @@ async fn initialize(
Ok((
models,
is_grok_shell,
is_kigi_shell,
resp.auth_methods,
default_auth_method_id,
available_commands,
@@ -545,7 +545,7 @@ pub fn parse_session_recap_available(meta: Option<&acp::Meta>) -> bool {
/// Determine whether interactive login is needed based on the advertised auth methods.
///
/// Matches TUI startup behavior: if the first method is `grok.com`, defer auth
/// Matches TUI startup behavior: if the first method is `kimi-code`, defer auth
/// and show the login-aware welcome flow. Otherwise, authenticate eagerly.
///
/// Returns `(needs_login, login_label, login_method_id, auth_start_mode)`.
@@ -589,7 +589,7 @@ pub fn startup_auth_metadata(
///
/// Used when eager auth (cached_token / API key) fails and we need to fall
/// back to the welcome screen with a working login button. Scans the list
/// for a `grok.com` or `oidc` method — these are the ones that can trigger
/// for a `kimi-code` or `oidc` method — these are the ones that can trigger
/// a browser-based re-auth flow.
pub fn find_interactive_login_method(
auth_methods: &[acp::AuthMethod],
@@ -767,7 +767,7 @@ mod tests {
#[test]
fn parse_available_commands_missing_key_returns_empty() {
let meta = serde_json::json!({ "grokShell": true });
let meta = serde_json::json!({ "kigiShell": true });
let cmds = parse_available_commands(meta.as_object());
assert!(cmds.is_empty());
}
@@ -801,7 +801,7 @@ mod tests {
#[test]
fn parse_session_recap_available_defaults_off_when_missing() {
let meta = serde_json::json!({ "grokShell": true, "cancelRewind": true });
let meta = serde_json::json!({ "kigiShell": true, "cancelRewind": true });
assert!(!parse_session_recap_available(meta.as_object()));
assert!(!parse_session_recap_available(None));
}
@@ -832,28 +832,28 @@ mod tests {
}
#[test]
fn startup_auth_grok_com_no_provider_needs_login_pending() {
let methods = vec![make_auth_method("grok.com", "grok.com", None)];
fn startup_auth_kigi_com_no_provider_needs_login_pending() {
let methods = vec![make_auth_method("kimi-code", "kimi-code", None)];
let (needs, label, method_id, mode) = startup_auth_metadata(&methods);
assert!(needs);
assert_eq!(label.as_deref(), Some("grok.com"));
assert_eq!(method_id.as_ref().unwrap().0.as_ref(), "grok.com");
assert_eq!(label.as_deref(), Some("kimi-code"));
assert_eq!(method_id.as_ref().unwrap().0.as_ref(), "kimi-code");
assert_eq!(mode, AuthStartMode::Pending);
}
#[test]
fn startup_auth_grok_com_with_external_provider_command() {
fn startup_auth_kigi_com_with_external_provider_command() {
let meta = serde_json::json!({ "external_provider": true });
let methods = vec![make_auth_method("grok.com", "Acme Corp", Some(meta))];
let methods = vec![make_auth_method("kimi-code", "Acme Corp", Some(meta))];
let (needs, label, method_id, mode) = startup_auth_metadata(&methods);
assert!(needs);
assert_eq!(label.as_deref(), Some("Acme Corp"));
assert_eq!(method_id.as_ref().unwrap().0.as_ref(), "grok.com");
assert_eq!(method_id.as_ref().unwrap().0.as_ref(), "kimi-code");
assert_eq!(mode, AuthStartMode::Command);
}
#[test]
fn startup_auth_non_grok_com_no_login() {
fn startup_auth_non_kigi_com_no_login() {
let methods = vec![make_auth_method("api-key", "API Key", None)];
let (needs, label, method_id, mode) = startup_auth_metadata(&methods);
assert!(!needs);
@@ -890,7 +890,7 @@ mod tests {
// enterprise-style: model has `env_key` set and the env var resolves,
// so the shell-side predicate returns true.
has_external_api_key: true,
// Realistic enterprise user: no cached session token, default `grok.com`
// Realistic enterprise user: no cached session token, default `kimi-code`
// login (no enterprise OIDC).
has_cached_token: false,
login_label: None,
@@ -916,27 +916,27 @@ mod tests {
/// `auth_methods.first()`. This locks the failure mode of the regression:
/// if a future refactor makes the pager scan past `.first()`, this test
/// stops being equivalent to
/// `startup_auth_grok_com_no_provider_needs_login_pending` above and
/// `startup_auth_kigi_com_no_provider_needs_login_pending` above and
/// either passes or fails on a meaningful new code path.
#[test]
fn startup_auth_xai_api_key_not_first_still_requires_login() {
use kigi_shell::agent::auth_method::{KIGI_COM_METHOD_ID, XAI_API_KEY_METHOD_ID};
use kigi_shell::agent::auth_method::{KIMI_CODE_METHOD_ID, XAI_API_KEY_METHOD_ID};
let methods = vec![
make_auth_method(KIGI_COM_METHOD_ID, "Grok", None),
make_auth_method(KIMI_CODE_METHOD_ID, "Kigi", None),
make_auth_method(XAI_API_KEY_METHOD_ID, "xai.api_key", None),
];
let (needs, _, _, _) = startup_auth_metadata(&methods);
assert!(
needs,
"with grok.com first, the pager must require login -- pinning \
"with kimi.com first, the pager must require login -- pinning \
the BAD-ordering failure mode (xai.api_key not first)",
);
}
#[test]
fn startup_auth_method_id_is_copied_not_synthesized() {
let methods = vec![make_auth_method("grok.com", "My Login", None)];
let methods = vec![make_auth_method("kimi-code", "My Login", None)];
let (_, _, method_id, _) = startup_auth_metadata(&methods);
// Verify it's the exact same ID from the method, not hardcoded
assert_eq!(&method_id.unwrap(), methods[0].id());
@@ -945,7 +945,7 @@ mod tests {
#[test]
fn startup_auth_external_provider_false_is_pending() {
let meta = serde_json::json!({ "external_provider": false });
let methods = vec![make_auth_method("grok.com", "grok.com", Some(meta))];
let methods = vec![make_auth_method("kimi-code", "kimi-code", Some(meta))];
let (_, _, _, mode) = startup_auth_metadata(&methods);
assert_eq!(mode, AuthStartMode::Pending);
}
@@ -1033,12 +1033,12 @@ mod tests {
// Rows 1 & 2 of the truth table: nothing set, and a set-but-blank value,
// both advertise the `agent_only` default (never `""` → AllDirty).
let absent = client_capabilities_meta(&ConnectFlags::default());
assert_eq!(absent["x.ai/hunkTracker"]["mode"], "agent_only");
assert_eq!(absent["kigi/hunkTracker"]["mode"], "agent_only");
let blank = client_capabilities_meta(&ConnectFlags {
hunk_tracker_mode: Some(" ".into()),
..Default::default()
});
assert_eq!(blank["x.ai/hunkTracker"]["mode"], "agent_only");
assert_eq!(blank["kigi/hunkTracker"]["mode"], "agent_only");
}
#[test]
@@ -1050,7 +1050,7 @@ mod tests {
hunk_tracker_mode: Some(raw.into()),
..Default::default()
});
assert_eq!(meta["x.ai/hunkTracker"]["mode"], "off", "raw={raw}");
assert_eq!(meta["kigi/hunkTracker"]["mode"], "off", "raw={raw}");
}
}
}
+9 -13
View File
@@ -74,7 +74,7 @@ impl ModelState {
}
}
/// Machine-readable model ID string for the current model (e.g. "grok-4.5").
/// Machine-readable model ID string for the current model (e.g. "kigi-4.5").
pub fn current_model_id_str(&self) -> Option<&str> {
Some(self.current.as_ref()?.0.as_ref())
}
@@ -94,7 +94,7 @@ impl ModelState {
///
/// Honors an explicit `acceptsImages` bool, else an `inputModalities` array
/// containing `"image"`. DEFAULTS TO `true` when neither key is present:
/// correct today (all current Grok models accept images, so nothing is
/// correct today (all current Kigi models accept images, so nothing is
/// suppressed) and forward-compatible (suppresses non-vision models once the
/// ACP server populates the key). Populating that key server-side is a
/// separate change.
@@ -223,7 +223,7 @@ impl ModelState {
/// Map a typed/selected effort token to its canonical value for the current
/// model. Accepts a menu option id (case-insensitive) or a canonical level
/// that appears as a **value** in that model's menu. Levels the model does
/// not offer (e.g. `none` on grok-4.5) are rejected so we fail in the TUI
/// not offer (e.g. `none` on kigi-4.5) are rejected so we fail in the TUI
/// instead of sending a blocked effort to the API.
pub fn resolve_effort_token(&self, token: &str) -> Option<ReasoningEffort> {
match self.current.as_ref() {
@@ -249,7 +249,7 @@ impl ModelState {
}
// Canonical level (e.g. "high", "max"→xhigh) only if the model menu
// actually offers that value — not free-form power-user aliases that
// would 400 on the server (e.g. `none` on grok-4.5).
// would 400 on the server (e.g. `none` on kigi-4.5).
let parsed = token.parse::<ReasoningEffort>().ok()?;
options
.iter()
@@ -410,21 +410,17 @@ mod tests {
#[test]
fn update_catalog_preserves_user_effort_when_model_unchanged() {
let id = acp::ModelId::new(Arc::from("grok-build"));
let id = acp::ModelId::new(Arc::from("kigi"));
let mut state = ModelState::default();
state.available.insert(
id.clone(),
model_with_effort("grok-build", "Grok Build", "high"),
);
state
.available
.insert(id.clone(), model_with_effort("kigi", "Kigi", "high"));
state.set_current(id.clone(), Some(ReasoningEffort::Xhigh));
assert_eq!(state.reasoning_effort, Some(ReasoningEffort::Xhigh));
// The broadcast carries the model's static default (high) for the same model.
let mut refreshed = IndexMap::new();
refreshed.insert(
id.clone(),
model_with_effort("grok-build", "Grok Build", "high"),
);
refreshed.insert(id.clone(), model_with_effort("kigi", "Kigi", "high"));
state.update_catalog(refreshed, Some(id.clone()));
assert_eq!(
+3 -3
View File
@@ -1,6 +1,6 @@
//! Agent spawning — creates the agent process and ACP channels.
//!
//! Simplified to only support GrokShell (in-process) mode.
//! Simplified to only support KigiShell (in-process) mode.
//! Subprocess and remote modes can be added later if needed.
use std::rc::Rc;
@@ -30,10 +30,10 @@ pub struct SpawnedAgent {
pub auth_manager: std::sync::Arc<AuthManager>,
}
/// Spawn a GrokShell agent in a background thread.
/// Spawn a KigiShell agent in a background thread.
///
/// Returns the ACP client channel for communication and a cancellation token.
pub async fn spawn_grok_shell(
pub async fn spawn_kigi_shell(
agent_config: AgentConfig,
cancel: &CancellationToken,
memory_config: Option<kigi_shell::config::MemoryConfig>,
+5 -5
View File
@@ -255,7 +255,7 @@ pub struct AcpUpdateTracker {
/// Tool call IDs marked as background (`is_background=true`).
///
/// First-detection (no scrollback entry yet): defers entry creation until
/// `x.ai/task_backgrounded` creates a `BgTask` block.
/// `kigi/task_backgrounded` creates a `BgTask` block.
/// Late-detection (Execute block already exists): suppresses further output
/// streaming; the existing block is demoted by `handle_task_backgrounded`.
///
@@ -2129,7 +2129,7 @@ fn task_ids_from_raw_input(raw: &serde_json::Value) -> Vec<String> {
}
/// Check if a tool call is a background execute (`is_background=true`).
///
/// These are deferred from scrollback — the `x.ai/task_backgrounded`
/// These are deferred from scrollback — the `kigi/task_backgrounded`
/// notification creates a `BgTask` block instead of an `Execute` block.
///
/// Eager ACP messages often use `kind=Other` with `title=run_terminal_command`
@@ -2602,7 +2602,7 @@ fn make_relative_path(path: &str) -> String {
mod tests {
use super::*;
use std::sync::Arc;
/// Default meta with no timestamps (simulates old grok-shell or tests that
/// Default meta with no timestamps (simulates old kigi-shell or tests that
/// don't care about timing).
fn meta() -> NotificationMeta {
NotificationMeta::default()
@@ -4602,7 +4602,7 @@ mod tests {
"stream A message should be finished"
);
}
/// No stream_start_ms (old grok-shell) should not break anything.
/// No stream_start_ms (old kigi-shell) should not break anything.
#[test]
fn no_stream_start_ms_preserves_existing_behavior() {
let mut sb = ScrollbackState::new();
@@ -5554,7 +5554,7 @@ mod tests {
.status(acp::ToolCallStatus::Pending)
}
#[test]
fn is_task_tool_recognizes_grok_build_variant() {
fn is_task_tool_recognizes_kigi_variant() {
assert!(is_task_tool(&initial_tool_call("tc1", "task")));
let mut with_variant = initial_tool_call("tc2", "anything");
with_variant.raw_input = Some(serde_json::json!({ "variant" : "Task" }));