§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
+1 -1
View File
@@ -15,7 +15,7 @@ use crate::matcher::HookMatcher;
#[derive(Debug)]
pub struct HooksMap {
pub events: HashMap<HookEventName, Vec<MatcherGroup>>,
/// Event names present in the JSON but not recognized by Grok.
/// Event names present in the JSON but not recognized by Kigi.
pub skipped_events: Vec<String>,
}
+1 -1
View File
@@ -650,7 +650,7 @@ mod tests {
fn load_from_settings_file_no_hooks_key() {
let dir = tempfile::tempdir().unwrap();
let settings = dir.path().join("settings.json");
std::fs::write(&settings, r#"{"theme": "dark", "model": "grok-3"}"#).unwrap();
std::fs::write(&settings, r#"{"theme": "dark", "model": "kigi-3"}"#).unwrap();
let (registry, errors) =
load_hooks_from_sources(&[HookSource::SettingsFile(&settings)], &[]);
+1 -1
View File
@@ -20,7 +20,7 @@ pub struct PreToolUseResult {
/// Hook failures (timeouts, crashes, command-not-found, env-var
/// pre-spawn refusals, malformed output) are **fail-open**: the failure
/// is logged and surfaced in the per-hook results for the UI scrollback,
/// but the tool call continues as if the hook had allowed it. Grok
/// but the tool call continues as if the hook had allowed it. Kigi
/// runs in protected environments where induced-failure bypass of
/// security hooks is not part of the threat model; the previous
/// fail-closed posture over-blocked innocent tool calls when
+3 -3
View File
@@ -63,7 +63,7 @@ use std::collections::HashMap;
/// "Apple logo" PUA char) plus a long magic ASCII prefix. The full
/// sentinel string adds 128 bits of per-call entropy as a hex suffix
/// followed by another `U+F8FF` char.
const SENTINEL_PREFIX: &str = "\u{f8ff}__GROK_HOOKS_MASK_";
const SENTINEL_PREFIX: &str = "\u{f8ff}__KIGI_HOOKS_MASK_";
const SENTINEL_SUFFIX: &str = "__\u{f8ff}";
/// Build a per-call sentinel string used to hide modifier-form
@@ -704,7 +704,7 @@ mod tests {
}
/// An earlier sentinel was a fixed string
/// `"\u{f8ff}__GROK_HOOKS_MASK__\u{f8ff}"`. A user-supplied
/// `"\u{f8ff}__KIGI_HOOKS_MASK__\u{f8ff}"`. A user-supplied
/// `extra_env` value containing that exact byte sequence would
/// have been silently rewritten to `${` by the unmask step. The
/// per-call randomized sentinel removes this hazard. This
@@ -713,7 +713,7 @@ mod tests {
/// though the input also references that variable through `${VAL}`.
#[test]
fn expand_preserves_pre_existing_legacy_fixed_sentinel_in_extra() {
let legacy_sentinel = "\u{f8ff}__GROK_HOOKS_MASK__\u{f8ff}";
let legacy_sentinel = "\u{f8ff}__KIGI_HOOKS_MASK__\u{f8ff}";
let mut extra = HashMap::new();
// Value embeds the legacy sentinel followed by what would
// have been parsed as an identifier+brace if the unmask
+1 -1
View File
@@ -529,7 +529,7 @@ mod tests {
prompt_id: None,
payload: HookPayload::SessionStart {
source: "new".into(),
model_id: Some("grok-3".into()),
model_id: Some("kigi-3".into()),
agent_type: None,
},
};
+2 -2
View File
@@ -1,11 +1,11 @@
//! # kigi-hooks
//!
//! Runtime hook system for Grok — file-based discovery, command execution,
//! Runtime hook system for Kigi — file-based discovery, command execution,
//! and policy enforcement.
//!
//! ## Overview
//!
//! This crate provides a minimal hooks system for Grok. Hooks are discovered
//! This crate provides a minimal hooks system for Kigi. Hooks are discovered
//! from dedicated directories (`~/.kigi/hooks/` and `<git-worktree-root>/.kigi/hooks/`),
//! defined in JSON files (compatible settings format), and executed as child processes.
//!
+12 -12
View File
@@ -6,9 +6,9 @@ use regex::Regex;
///
/// - an empty pattern or `"*"` matches every tool;
/// - a "simple" pattern (only `[A-Za-z0-9_|]`, i.e. a plain name or `|`-list) is an
/// **exact** match against each name (after external→Grok alias expansion), NOT a regex;
/// **exact** match against each name (after external→Kigi alias expansion), NOT a regex;
/// - anything else is an **unanchored** regex (also tested against the tool's external
/// alias names, so e.g. `^Bash$` matches the Grok tool `run_terminal_command`).
/// alias names, so e.g. `^Bash$` matches the Kigi tool `run_terminal_command`).
///
/// The simple-vs-regex split is deliberate: it avoids anchoring a `|`-alternation (a
/// naive `^a|b|c$` anchors only the first/last term and silently over-matches). Whitespace
@@ -61,8 +61,8 @@ fn is_simple_form(pattern: &str) -> bool {
}
/// Expand a simple-form pattern into the exact set of names it matches: each `|`-term
/// plus any Grok tool names that term aliases (so `"Bash"` also matches
/// `run_terminal_command`), per the shared external-name to Grok registry in
/// plus any Kigi tool names that term aliases (so `"Bash"` also matches
/// `run_terminal_command`), per the shared external-name to Kigi registry in
/// `kigi-tools`. Empty terms and duplicates are dropped.
fn exact_names(pattern: &str) -> Vec<String> {
let mut names: Vec<String> = Vec::new();
@@ -155,22 +155,22 @@ mod tests {
// ── External tool-name aliases ────────────────────────────────
#[test]
fn claude_bash_matches_grok_tool() {
fn claude_bash_matches_kigi_tool() {
let m = HookMatcher::new("Bash").unwrap();
assert!(m.is_match("Bash")); // external alias name
assert!(m.is_match("run_terminal_command")); // Grok name
assert!(m.is_match("run_terminal_command")); // Kigi name
assert!(!m.is_match("read_file"));
// Bug-fix regression: exact, not prefix.
assert!(!m.is_match("run_terminal_command_v2"));
}
#[test]
fn claude_edit_write_matches_grok_tool_exactly() {
fn claude_edit_write_matches_kigi_tool_exactly() {
let m = HookMatcher::new("Edit|Write").unwrap();
assert!(m.is_match("Edit"));
assert!(m.is_match("Write"));
assert!(m.is_match("search_replace")); // Grok equivalent
assert!(m.is_match("hashline_edit")); // second Grok alias
assert!(m.is_match("search_replace")); // Kigi equivalent
assert!(m.is_match("hashline_edit")); // second Kigi alias
assert!(!m.is_match("read_file"));
// The old anchoring bug matched these; the exact-list mode must not.
assert!(!m.is_match("Editorial"));
@@ -178,7 +178,7 @@ mod tests {
}
#[test]
fn claude_read_matches_grok_tool() {
fn claude_read_matches_kigi_tool() {
let m = HookMatcher::new("Read").unwrap();
assert!(m.is_match("Read"));
assert!(m.is_match("read_file"));
@@ -186,8 +186,8 @@ mod tests {
}
#[test]
fn regex_against_claude_alias_matches_grok_tool() {
// A regex written against an external alias still matches the Grok tool
fn regex_against_claude_alias_matches_kigi_tool() {
// A regex written against an external alias still matches the Kigi tool
// (legacy alias-name expansion).
let m = HookMatcher::new("^Bash$").unwrap();
assert!(m.is_match("run_terminal_command"));
@@ -87,7 +87,7 @@ pub async fn run_command_hook(
let mut cmd = if is_shell_command {
// Refuse to spawn when the command interpolates an env var that
// we can't resolve from any of: the runner's always-set vars, the
// per-hook extra_env (plugin vars), or Grok's own process env. The
// per-hook extra_env (plugin vars), or Kigi's own process env. The
// alternative is letting sh expand the var to empty -- which then
// produces a broken command, exits 127, and (for PreToolUse hooks)
// fails closed with an opaque "exit code 127" reason. Catching it
@@ -287,7 +287,7 @@ pub(crate) const RUNNER_ALWAYS_SET_ENV: &[&str] = &[
/// * the runner's always-set env vars (see [`RUNNER_ALWAYS_SET_ENV`]),
/// * the per-hook `extra_env` map (set by the plugin adapter for plugin
/// hooks),
/// * the Grok process's own environment (which is inherited by the child),
/// * the Kigi process's own environment (which is inherited by the child),
/// * local shell assignments inside the command itself (e.g. an
/// `INPUT=$(cat)` earlier in the string defines `INPUT` for the rest of
/// the command).
+6 -6
View File
@@ -6,7 +6,7 @@ use std::path::{Path, PathBuf};
// exist only to migrate prior grants out of the legacy file.
/// Path to the legacy project-hook trust file
/// (`<user_kigi_home>/trusted-hook-projects`), or `None` when no user grok home
/// (`<user_kigi_home>/trusted-hook-projects`), or `None` when no user kigi home
/// resolves. Retained only for the one-time migration into folder-trust.
pub fn legacy_trust_file_path() -> Option<PathBuf> {
Some(kigi_config::user_kigi_home()?.join("trusted-hook-projects"))
@@ -59,7 +59,7 @@ fn is_hook_disabled_with_file(hook_name: &str, file: &Path) -> bool {
/// Disable a hook by name. Adds to .
pub fn disable_hook(hook_name: &str) -> Result<(), String> {
let file = disabled_hooks_file_path()
.ok_or_else(|| "no user grok home (set $KIGI_SHARE_DIR or $HOME)".to_string())?;
.ok_or_else(|| "no user kigi home (set $KIGI_SHARE_DIR or $HOME)".to_string())?;
disable_hook_with_file(hook_name, &file)
}
@@ -122,7 +122,7 @@ fn enable_hook_with_file(hook_name: &str, file: &Path) -> Result<bool, String> {
Ok(true)
}
/// Returns the path to `$KIGI_SHARE_DIR/disabled-hooks`, or `None` when no user grok
/// Returns the path to `$KIGI_SHARE_DIR/disabled-hooks`, or `None` when no user kigi
/// home resolves.
fn disabled_hooks_file_path() -> Option<PathBuf> {
Some(kigi_config::user_kigi_home()?.join("disabled-hooks"))
@@ -134,9 +134,9 @@ mod tests {
/// Each test creates its own legacy file in its own temp dir -- no shared state.
fn trust_file_in(dir: &Path) -> PathBuf {
let grok_dir = dir.join(".kigi");
std::fs::create_dir_all(&grok_dir).unwrap();
grok_dir.join("trusted-hook-projects")
let kigi_dir = dir.join(".kigi");
std::fs::create_dir_all(&kigi_dir).unwrap();
kigi_dir.join("trusted-hook-projects")
}
#[test]