§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
@@ -9,9 +9,9 @@ use crate::permission::{
use agent_client_protocol::{self as acp, Client as _};
use kigi_acp_lib::AcpAgentGatewaySender as GatewaySender;
use kigi_file_utils::events::{Event, EventWriter, PermissionDecision};
use kigi_tools::implementations::grok_build::web_fetch::domain_from_url;
use kigi_tools::implementations::kigi::web_fetch::domain_from_url;
const REJECT_ONCE_LABEL: &str = "No, and tell Grok what to do differently";
const REJECT_ONCE_LABEL: &str = "No, and tell Kigi what to do differently";
/// Stable option id for the edit prompt's "Yes, allow all edits during this
/// session" choice. Distinct from the generic `"always-allow"` id (used by
@@ -40,7 +40,7 @@ pub const ALLOW_EDITS_SESSION_OPTION_ID: &str = "allow-edits-session";
/// 2. Drains any queued permission requests with `AllowOnce` responses
/// 3. Persists `[ui] permission_mode = "always-approve"` to
/// `~/.kigi/config.toml` via the `Effect::PersistPermissionMode` effect
/// 4. Sends the existing `x.ai/yolo_mode_changed` ACP notification so
/// 4. Sends the existing `kigi/yolo_mode_changed` ACP notification so
/// the agent's permission manager flips its `yolo_mode` flag
///
/// This split keeps the wire protocol bog-standard ACP (no new methods or
@@ -96,7 +96,7 @@ fn enable_always_approve_option() -> acp::PermissionOption {
}
/// Returns whether the given option is the special "enable always-approve mode"
/// (global yolo) option that is prepended for GrokTUI / GrokPager / Desktop.
/// (global yolo) option that is prepended for KigiTUI / KigiPager / Desktop.
///
/// This is the canonical way to identify the option instead of matching on
/// its human-facing label or assuming position 0. Callers that need to
@@ -108,12 +108,12 @@ pub fn is_enable_always_approve_option(opt: &acp::PermissionOption) -> bool {
/// Returns `true` if the given client type should see the prepended
/// "enable always-approve mode" option. Limited to the three clients
/// (`GrokTUI`, `GrokPager`, `Desktop`) that wire the option id through
/// (`KigiTUI`, `KigiPager`, `Desktop`) that wire the option id through
/// to their YOLO toggle. Other clients keep their existing option set.
fn client_supports_enable_always_approve(client_type: ClientType) -> bool {
matches!(
client_type,
ClientType::GrokTUI | ClientType::GrokPager | ClientType::Desktop
ClientType::KigiTUI | ClientType::KigiPager | ClientType::Desktop
)
}
@@ -188,8 +188,8 @@ pub fn mcp_tool_action<'a>(tool_name: &'a str, server_prefix: Option<&str>) -> &
/// Pretty-format a single MCP server- or tool-name segment for display:
/// split on `'_'`, title-case each word, join with spaces. Leaves
/// non-underscore characters (camelCase, hyphens) intact, so
/// `"list_issues"` → `"List Issues"`, `"grok_com_notion"` →
/// `"Grok Com Notion"`, and `"getMyTaskList"` → `"GetMyTaskList"`.
/// `"list_issues"` → `"List Issues"`, `"kigi_com_notion"` →
/// `"Kigi Com Notion"`, and `"getMyTaskList"` → `"GetMyTaskList"`.
pub fn mcp_titleize_segment(name: &str) -> String {
name.split('_')
.map(|word| {
@@ -248,10 +248,10 @@ pub struct McpToolPermission {
/// e.g. `"Always allow:"`. Mirrors `BashCommandPermission::prompt_prefix`.
pub prompt_prefix: String,
/// Full tool name as the agent called it
/// (e.g. `"grok_com_notion__notion-fetch"`).
/// (e.g. `"kigi_com_notion__notion-fetch"`).
pub tool_name: String,
/// Server segment (everything before the single `__` separator,
/// e.g. `"grok_com_notion"`). `None` if the tool name has no `__`,
/// e.g. `"kigi_com_notion"`). `None` if the tool name has no `__`,
/// in which case the view hides the scope toggle and only offers
/// tool-scope.
pub server_prefix: Option<String>,
@@ -397,7 +397,7 @@ impl AcpPrompter {
),
);
// Bash options for GrokTUI - interactive selection with expandable/contractable terms
// Bash options for KigiTUI - interactive selection with expandable/contractable terms
let mut bash_options: IndexMap<acp::PermissionOptionId, acp::PermissionOption> =
IndexMap::new();
bash_options.insert(
@@ -543,7 +543,7 @@ impl AcpPrompter {
if self.remember_tool_approvals
&& matches!(
self.client_type,
ClientType::GrokTUI | ClientType::GrokPager | ClientType::Desktop
ClientType::KigiTUI | ClientType::KigiPager | ClientType::Desktop
) =>
{
serde_json::to_value(primary_command_from_script(bash_command))
@@ -565,11 +565,11 @@ impl AcpPrompter {
match access {
AccessKind::Edit(_) => self.edit_options.clone(),
AccessKind::Bash(bash_command) => {
// For GrokTUI clients, use the fancy interactive options with term selection
// For KigiTUI clients, use the fancy interactive options with term selection
// For generic clients (web, etc.), use simpler options that work without
// special UI handling
match self.client_type {
ClientType::GrokTUI | ClientType::GrokPager | ClientType::Desktop => {
ClientType::KigiTUI | ClientType::KigiPager | ClientType::Desktop => {
let mut bash_commands: IndexMap<
acp::PermissionOptionId,
acp::PermissionOption,
@@ -601,7 +601,7 @@ impl AcpPrompter {
bash_commands
}
ClientType::Generic
| ClientType::GrokWeb
| ClientType::KigiWeb
| ClientType::Nebula
| ClientType::Extension => {
// For generic clients, use simpler options that display well
@@ -654,7 +654,7 @@ impl AcpPrompter {
// `fallback_options` (`always-allow`) and the manager's
// plain `AllowAlways` arm persists tool-scope.
match self.client_type {
ClientType::GrokTUI | ClientType::GrokPager | ClientType::Desktop => {
ClientType::KigiTUI | ClientType::KigiPager | ClientType::Desktop => {
let mut options: IndexMap<acp::PermissionOptionId, acp::PermissionOption> =
IndexMap::new();
let server_prefix = tool_name.split_once("__").map(|(s, _)| s.to_owned());
@@ -694,7 +694,7 @@ impl AcpPrompter {
options
}
ClientType::Generic
| ClientType::GrokWeb
| ClientType::KigiWeb
| ClientType::Nebula
| ClientType::Extension => self.fallback_options.clone(),
}
@@ -991,7 +991,7 @@ mod tests {
#[test]
fn gate_off_strips_bash_always_allow_keeps_yes_no() {
let p = prompter_with_gate(ClientType::GrokPager, false);
let p = prompter_with_gate(ClientType::KigiPager, false);
let access = AccessKind::Bash("kubectl get pods".to_owned());
let opts = p.build_options(&access);
assert!(
@@ -1012,7 +1012,7 @@ mod tests {
#[test]
fn gate_on_includes_bash_always_allow() {
let p = prompter_with_gate(ClientType::GrokPager, true);
let p = prompter_with_gate(ClientType::KigiPager, true);
let access = AccessKind::Bash("kubectl get pods".to_owned());
let opts = p.build_options(&access);
assert!(
@@ -1027,7 +1027,7 @@ mod tests {
#[test]
fn gate_off_strips_mcp_always_allow() {
let p = prompter_with_gate(ClientType::GrokPager, false);
let p = prompter_with_gate(ClientType::KigiPager, false);
let access = AccessKind::MCPTool {
name: "linear__list".to_owned(),
input: serde_json::Value::Null,
@@ -1040,7 +1040,7 @@ mod tests {
#[test]
fn gate_off_strips_generic_bash_always_and_reject_always() {
let p = prompter_with_gate(ClientType::GrokWeb, false);
let p = prompter_with_gate(ClientType::KigiWeb, false);
let access = AccessKind::Bash("kubectl get pods".to_owned());
let opts = p.build_options(&access);
assert!(!has_option(&opts, "always-allow"));
@@ -1051,7 +1051,7 @@ mod tests {
#[test]
fn gate_off_strips_web_fetch_always_allow_domain() {
let p = prompter_with_gate(ClientType::GrokPager, false);
let p = prompter_with_gate(ClientType::KigiPager, false);
let access = AccessKind::WebFetch("https://example.com/x".to_owned());
let opts = p.build_options(&access);
assert!(!has_option(&opts, "allow-always-domain"));
@@ -1063,7 +1063,7 @@ mod tests {
fn bash_meta_present_only_when_gate_on_for_fancy_clients() {
let access = AccessKind::Bash("kubectl get pods".to_owned());
// Gate on + fancy client → meta carries the parsed command parts.
let on = prompter_with_gate(ClientType::GrokPager, true);
let on = prompter_with_gate(ClientType::KigiPager, true);
let meta = on.bash_selection_meta(&access).expect("meta present");
assert!(
serde_json::from_value::<
@@ -1073,10 +1073,10 @@ mod tests {
"meta must deserialize back into BashCommandHighlights"
);
// Gate off → no meta (no allow-always-command row to scope).
let off = prompter_with_gate(ClientType::GrokPager, false);
let off = prompter_with_gate(ClientType::KigiPager, false);
assert!(off.bash_selection_meta(&access).is_none());
// Generic client never gets the fancy-UI meta, even with the gate on.
let generic = prompter_with_gate(ClientType::GrokWeb, true);
let generic = prompter_with_gate(ClientType::KigiWeb, true);
assert!(generic.bash_selection_meta(&access).is_none());
// Non-bash access never carries bash meta.
assert!(
@@ -1087,7 +1087,7 @@ mod tests {
#[test]
fn bash_reject_always_command_maps_selected_words() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let access = AccessKind::Bash("cargo test --workspace".to_owned());
let opts = p.build_options(&access);
// Pager path: the ←/→ word-scope selection arrives as
@@ -1121,7 +1121,7 @@ mod tests {
#[test]
fn gate_off_keeps_edit_session_allow() {
// The edit session allow is governed separately, not by this gate.
let p = prompter_with_gate(ClientType::GrokPager, false);
let p = prompter_with_gate(ClientType::KigiPager, false);
let access = AccessKind::Edit("src/main.rs".to_owned());
let opts = p.build_options(&access);
assert!(
@@ -1142,7 +1142,7 @@ mod tests {
#[test]
fn mcp_prompt_includes_allow_always_with_meta() {
let p = prompter(ClientType::GrokTUI);
let p = prompter(ClientType::KigiTUI);
let access = AccessKind::MCPTool {
name: "linear__list".to_owned(),
input: serde_json::Value::Null,
@@ -1161,7 +1161,7 @@ mod tests {
#[test]
fn mcp_prompt_no_separator_hides_server_scope() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let access = AccessKind::MCPTool {
name: "standalone".to_owned(),
input: serde_json::Value::Null,
@@ -1178,7 +1178,7 @@ mod tests {
#[test]
fn mcp_response_tool_scope() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let access = AccessKind::MCPTool {
name: "linear__list".to_owned(),
input: serde_json::Value::Null,
@@ -1197,7 +1197,7 @@ mod tests {
#[test]
fn mcp_response_server_scope() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let access = AccessKind::MCPTool {
name: "linear__list".to_owned(),
input: serde_json::Value::Null,
@@ -1216,7 +1216,7 @@ mod tests {
#[test]
fn mcp_response_empty_server_falls_back_to_tool() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let access = AccessKind::MCPTool {
name: "linear__list".to_owned(),
input: serde_json::Value::Null,
@@ -1238,7 +1238,7 @@ mod tests {
// TUI / Desktop case: option id is `allow-always-mcp` but the renderer
// does not build the toggle meta. The prompter must default to
// tool-scope using the access-kind name.
let p = prompter(ClientType::GrokTUI);
let p = prompter(ClientType::KigiTUI);
let access = AccessKind::MCPTool {
name: "notion__fetch".to_owned(),
input: serde_json::Value::Null,
@@ -1253,7 +1253,7 @@ mod tests {
#[test]
fn mcp_fallback_client_returns_plain_allow_always() {
// non-TUI clients (Generic / GrokWeb / Extension / …) see `fallback_options`. The
// non-TUI clients (Generic / KigiWeb / Extension / …) see `fallback_options`. The
// legacy `"always-allow"` id maps to plain `PromptOutcome::AllowAlways`;
// the manager arm persists tool-scope from there.
let p = prompter(ClientType::Generic);
@@ -1303,7 +1303,7 @@ mod tests {
fn mcp_titleize_segment_handles_snake_camel_kebab() {
// snake_case → words split + each title-cased
assert_eq!(mcp_titleize_segment("list_issues"), "List Issues");
assert_eq!(mcp_titleize_segment("grok_com_notion"), "Grok Com Notion");
assert_eq!(mcp_titleize_segment("kigi_com_notion"), "Kigi Com Notion");
// single word: just capitalize first letter
assert_eq!(mcp_titleize_segment("linear"), "Linear");
// camelCase preserved (no `_` to split on, only first letter touched)
@@ -1330,7 +1330,7 @@ mod tests {
/// pin position 0 with an exhaustive enumeration.
#[test]
fn enable_always_approve_is_first_option_for_pager() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let cases: Vec<(&str, AccessKind)> = vec![
("edit", AccessKind::Edit("write".to_owned())),
("bash", AccessKind::Bash("ls -la".to_owned())),
@@ -1362,13 +1362,13 @@ mod tests {
}
}
/// Same pin as above for `GrokTUI` and `Desktop` — both client types
/// Same pin as above for `KigiTUI` and `Desktop` — both client types
/// route the option id through to the YOLO toggle, so both must
/// see it. A copy-paste regression that limits the prepend to one
/// client only would be caught here.
#[test]
fn enable_always_approve_is_first_for_tui_and_desktop() {
for ct in [ClientType::GrokTUI, ClientType::Desktop] {
for ct in [ClientType::KigiTUI, ClientType::Desktop] {
let p = prompter(ct);
let opts = p.build_options(&AccessKind::Edit("write".to_owned()));
assert_eq!(
@@ -1387,7 +1387,7 @@ mod tests {
fn enable_always_approve_omitted_for_non_tui_clients() {
for ct in [
ClientType::Generic,
ClientType::GrokWeb,
ClientType::KigiWeb,
ClientType::Nebula,
ClientType::Extension,
] {
@@ -1406,7 +1406,7 @@ mod tests {
/// state for this id. Pin the override for every access kind.
#[test]
fn enable_always_approve_maps_to_allow_once_for_every_access_kind() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let cases: Vec<(&str, AccessKind)> = vec![
("edit", AccessKind::Edit("write".to_owned())),
("bash", AccessKind::Bash("ls".to_owned())),
@@ -1440,7 +1440,7 @@ mod tests {
/// target kind is in play. Pin the kind regardless.
#[test]
fn enable_always_approve_uses_allow_once_kind() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
let opts = p.build_options(&AccessKind::Edit("write".to_owned()));
let opt = opts
.get(&enable_always_approve_id())
@@ -1461,7 +1461,7 @@ mod tests {
/// allow-once, reject-once, reject-always-command].
#[test]
fn bash_option_order_toggle_first_reject_always_last() {
let p = prompter(ClientType::GrokPager);
let p = prompter(ClientType::KigiPager);
// "ls" has a parseable primary command, so `allow-always-command`
// will be inserted into the option list.
let access = AccessKind::Bash("ls -la".to_owned());