§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
@@ -1496,7 +1496,7 @@ mod searchable_text_tests {
b.subagent_type = "explore".into();
b.persona = Some("scout".into());
b.role = Some("researcher".into());
b.model = Some("grok-test".into());
b.model = Some("kigi-test".into());
b.activity_label = Some("Running: cargo build".into());
}
let text = block.searchable_text().expect("subagent text");
@@ -1504,7 +1504,7 @@ mod searchable_text_tests {
assert!(text.contains("explore"), "got: {text:?}");
assert!(text.contains("scout"), "got: {text:?}");
assert!(text.contains("researcher"), "got: {text:?}");
assert!(text.contains("grok-test"), "got: {text:?}");
assert!(text.contains("kigi-test"), "got: {text:?}");
assert!(text.contains("Running: cargo build"), "got: {text:?}");
assert!(text.contains("panicked at assert"), "got: {text:?}");
}
@@ -1539,9 +1539,9 @@ mod searchable_text_tests {
auto_compact_threshold_percent: 85,
usage_categories: vec![],
};
let block = RenderBlock::context_info(snapshot, "grok-4.5");
let block = RenderBlock::context_info(snapshot, "kigi-4.5");
// Only the model name is source text; the rest is a numeric breakdown.
assert_eq!(block.searchable_text().as_deref(), Some("grok-4.5"));
assert_eq!(block.searchable_text().as_deref(), Some("kigi-4.5"));
}
#[test]
@@ -466,7 +466,7 @@ mod tests {
#[test]
fn preamble_uses_primary_text_color_for_description() {
// Pin theme to avoid races with parallel tests that call `cache::set`.
crate::theme::cache::set(crate::theme::ThemeKind::GrokNight);
crate::theme::cache::set(crate::theme::ThemeKind::KigiNight);
let block =
BgTaskBlock::started("ls", "t1").with_description(Some("List the files".into()));
let text = block.preamble(&test_ctx()).expect("preamble");
@@ -24,7 +24,7 @@ use kigi_shell::session::{ContextInfo, count_detail};
/// Context
///
/// 36.7k / 1.0m tokens (3.67%)
/// grok-4
/// kigi-4
///
/// ◆ ◆ ◆ ◆ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇
/// ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇ ◇
@@ -467,7 +467,7 @@ impl ContextInfoBlock {
// (routed from kigi-shell's model config resolution). This makes
// the “Auto-compact at X%” line and the tip band match exactly what
// remote settings / user TOML / env have configured for the
// current model (e.g. 65 for grok-build).
// current model (e.g. 65 for kigi).
//
// `threshold_tokens` uses `div_ceil` rather than truncating integer
// division so it matches the rounded `usage_pct` from `ContextInfo`
@@ -705,7 +705,7 @@ mod tests {
#[test]
fn build_lines_contains_header_tokens_and_model() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
// Layout: Context / <blank> / tokens / model.
@@ -715,12 +715,12 @@ mod tests {
assert!(l2.contains("tokens"));
// Percent now shows 2 decimal places (36.7k / 1m = 3.67%).
assert!(l2.contains("(3.67%)"), "got: {l2:?}");
assert_eq!(line_text(&lines, 3), "grok-4");
assert_eq!(line_text(&lines, 3), "kigi-4");
}
#[test]
fn build_lines_contains_tokens_summary() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let l2 = line_text(&lines, 2);
@@ -747,7 +747,7 @@ mod tests {
// line is also showing.
let mut snap = snapshot();
snap.usage_pct = 80;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let last = line_text(&lines, lines.len() - 1);
@@ -756,7 +756,7 @@ mod tests {
#[test]
fn build_lines_omits_tip_below_threshold() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
assert!(!all_text(&lines).contains("/compact"));
@@ -770,7 +770,7 @@ mod tests {
// other (manual /compact vs. auto-compact about to fire).
let mut snap = snapshot();
snap.usage_pct = 85; // the historical default (and value in snapshot() helper)
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
assert!(!all_text(&lines).contains("/compact"));
@@ -778,7 +778,7 @@ mod tests {
#[test]
fn build_lines_shows_auto_compact_estimate_below_threshold() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let all = all_text(&lines);
@@ -796,7 +796,7 @@ mod tests {
snap.total = 4_000_000;
snap.used = 0;
snap.usage_pct = 0;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let all = all_text(&lines);
@@ -809,7 +809,7 @@ mod tests {
#[test]
fn build_lines_auto_compact_eta_arithmetic_at_known_snapshot() {
// 1M window, 36_700 used: ceil(850_000) - 36_700 = 813_300 → "813k".
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let all = all_text(&lines);
@@ -849,7 +849,7 @@ mod tests {
let mut snap = snapshot();
snap.total = 2_000_000;
snap.used = 36_700;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let l2 = line_text(&lines, 2);
@@ -863,7 +863,7 @@ mod tests {
fn build_lines_shows_imminent_auto_compact_at_threshold() {
let mut snap = snapshot();
snap.usage_pct = 85;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let all = all_text(&lines);
@@ -926,7 +926,7 @@ mod tests {
snap.tool_definitions_tokens = 0;
snap.free_tokens = 90_000;
snap.usage_pct = 10;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let (diamonds, tools, free, total) = count_bar_glyphs(&lines, BarLayout::WIDE);
@@ -941,7 +941,7 @@ mod tests {
#[test]
fn bar_total_cells_always_sum_to_one_hundred() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let (_, _, _, total) = count_bar_glyphs(&lines, BarLayout::WIDE);
@@ -957,7 +957,7 @@ mod tests {
snap.tool_definitions_tokens = 0;
snap.message_tokens = 0;
snap.free_tokens = 0;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let (diamonds, tools, free, total) = count_bar_glyphs(&lines, BarLayout::WIDE);
@@ -979,7 +979,7 @@ mod tests {
snap.message_tokens = 1_000;
snap.free_tokens = 0;
snap.usage_pct = 100;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let (diamonds, tools, free, total) = count_bar_glyphs(&lines, BarLayout::WIDE);
@@ -999,7 +999,7 @@ mod tests {
snap.tool_definitions_tokens = 800;
snap.free_tokens = 0;
snap.usage_pct = 100;
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let (diamonds, tools, free, total) = count_bar_glyphs(&lines, BarLayout::WIDE);
@@ -1027,7 +1027,7 @@ mod tests {
auto_compact_threshold_percent: 65,
usage_categories: vec![],
};
let block = ContextInfoBlock::new(snap, "grok-build");
let block = ContextInfoBlock::new(snap, "kigi");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
@@ -1055,7 +1055,7 @@ mod tests {
TokenUsageCategory::skills_listing(&"x".repeat(9_600), 21),
TokenUsageCategory::mcp_servers(&"y".repeat(1_200), 4),
];
let block = ContextInfoBlock::new(snap, "grok-4");
let block = ContextInfoBlock::new(snap, "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let all = all_text(&lines);
@@ -1161,7 +1161,7 @@ mod tests {
#[test]
fn narrow_bar_renders_10_rows() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::NARROW);
// The bar starts at index 5 (header / blank / tokens / model /
@@ -1179,7 +1179,7 @@ mod tests {
#[test]
fn narrow_bar_total_cells_still_100() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::NARROW);
let (_, _, _, total) = count_bar_glyphs(&lines, BarLayout::NARROW);
@@ -1190,7 +1190,7 @@ mod tests {
fn narrow_bar_each_row_has_at_most_10_cells() {
// Sanity: no single bar row should exceed the narrow row_len.
// We count cell glyphs (not separator spaces) per row.
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::NARROW);
for (offset, line) in lines[5..15].iter().enumerate() {
@@ -1215,7 +1215,7 @@ mod tests {
#[test]
fn wide_bar_each_row_has_at_most_20_cells() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
for (offset, line) in lines[5..10].iter().enumerate() {
@@ -1258,7 +1258,7 @@ mod tests {
#[test]
fn legend_label_uses_secondary_color_wide() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let row = find_legend_line(&lines, "System prompt").expect("legend row");
@@ -1279,7 +1279,7 @@ mod tests {
#[test]
fn legend_label_uses_secondary_color_narrow() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::NARROW);
let row = find_legend_line(&lines, "System prompt").expect("legend row 1");
@@ -1299,7 +1299,7 @@ mod tests {
#[test]
fn narrow_legend_wraps_to_two_lines_per_category() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::NARROW);
let categories = [
@@ -1335,7 +1335,7 @@ mod tests {
#[test]
fn narrow_legend_data_row_starts_with_one_space_indent() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::NARROW);
// The data row for the first legend entry sits at index 17
@@ -1355,7 +1355,7 @@ mod tests {
#[test]
fn wide_legend_remains_single_line_per_category() {
let block = ContextInfoBlock::new(snapshot(), "grok-4");
let block = ContextInfoBlock::new(snapshot(), "kigi-4");
let theme = test_theme();
let lines = block.build_lines(&theme, BarLayout::WIDE);
let row_text =
@@ -143,14 +143,14 @@ pub fn mermaid_block_ranges(view: &MarkdownRenderView) -> Vec<Range<usize>> {
/// Whether a theme renders diagrams on a dark surface.
///
/// `GrokDay` is the only light theme; every other concrete theme (and the
/// `GrokNight` default that `Auto` resolves to before it reaches the cache) is
/// `KigiDay` is the only light theme; every other concrete theme (and the
/// `KigiNight` default that `Auto` resolves to before it reaches the cache) is
/// dark. The render worker maps this to `kigi_mermaid::MermaidTheme`; it
/// lives here (rather than referencing the engine crate) so the
/// always-compiled detection module stays independent of the optional
/// `mermaid` feature.
pub fn theme_is_dark(theme: ThemeKind) -> bool {
!matches!(theme, ThemeKind::GrokDay)
!matches!(theme, ThemeKind::KigiDay)
}
/// Cache key for a rendered diagram: content hash + theme + quality tier +
@@ -580,7 +580,7 @@ mod tests {
fn cache_key_sensitivity() {
let dark = MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
);
@@ -589,7 +589,7 @@ mod tests {
dark,
MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
)
@@ -599,7 +599,7 @@ mod tests {
dark,
MermaidCacheKey::derive(
"flowchart TD\nA-->C",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
)
@@ -609,7 +609,7 @@ mod tests {
dark,
MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokDay,
ThemeKind::KigiDay,
80,
MermaidRenderQuality::Terminal,
)
@@ -619,7 +619,7 @@ mod tests {
dark,
MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
160,
MermaidRenderQuality::Terminal,
)
@@ -627,7 +627,7 @@ mod tests {
// Quality tier change ⇒ different key (and filename).
let open = MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Open,
);
@@ -638,7 +638,7 @@ mod tests {
open,
MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
999,
MermaidRenderQuality::Open,
)
@@ -650,20 +650,20 @@ mod tests {
// Widths within the same bucket collapse to one key.
let a = MermaidCacheKey::derive(
"x",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
);
let b = MermaidCacheKey::derive(
"x",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80 + MERMAID_WIDTH_BUCKET - 1,
MermaidRenderQuality::Terminal,
);
assert_eq!(a, b);
let c = MermaidCacheKey::derive(
"x",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80 + MERMAID_WIDTH_BUCKET,
MermaidRenderQuality::Terminal,
);
@@ -677,7 +677,7 @@ mod tests {
let mut set = HashSet::new();
let key = MermaidCacheKey::derive(
"A-->B\n",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
);
@@ -685,7 +685,7 @@ mod tests {
assert!(set.contains(&key));
assert!(!set.contains(&MermaidCacheKey::derive(
"A-->B\n",
ThemeKind::GrokDay,
ThemeKind::KigiDay,
80,
MermaidRenderQuality::Terminal,
)));
@@ -825,13 +825,13 @@ mod tests {
// -- theme mapping + cache filename --------------------------------------
#[test]
fn theme_is_dark_maps_grokday_to_light_only() {
fn theme_is_dark_maps_kigiday_to_light_only() {
assert!(
!theme_is_dark(ThemeKind::GrokDay),
"GrokDay is the light theme"
!theme_is_dark(ThemeKind::KigiDay),
"KigiDay is the light theme"
);
for dark in [
ThemeKind::GrokNight,
ThemeKind::KigiNight,
ThemeKind::TokyoNight,
ThemeKind::RosePineMoon,
ThemeKind::OscuraMidnight,
@@ -844,7 +844,7 @@ mod tests {
fn cache_filename_is_stable_and_keyed() {
let a = MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
);
@@ -860,21 +860,21 @@ mod tests {
// Different theme / source / width → different filename.
let b = MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokDay,
ThemeKind::KigiDay,
80,
MermaidRenderQuality::Terminal,
);
assert_ne!(a.cache_filename(), b.cache_filename());
let c = MermaidCacheKey::derive(
"flowchart TD\nA-->C",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Terminal,
);
assert_ne!(a.cache_filename(), c.cache_filename());
let open = MermaidCacheKey::derive(
"flowchart TD\nA-->B",
ThemeKind::GrokNight,
ThemeKind::KigiNight,
80,
MermaidRenderQuality::Open,
);
@@ -794,13 +794,13 @@ mod tests {
#[test]
fn model_unavailable_with_switch() {
let event = SessionEvent::ModelUnavailable {
previous_model_id: "grok-4.5".into(),
new_model_id: "grok-build".into(),
reason: "Model \"grok-4.5\" is no longer available.".into(),
previous_model_id: "kigi-4.5".into(),
new_model_id: "kigi".into(),
reason: "Model \"kigi-4.5\" is no longer available.".into(),
};
assert_eq!(
event.message(),
"Model \"grok-4.5\" is no longer available. Switched to \"grok-build\"."
"Model \"kigi-4.5\" is no longer available. Switched to \"kigi\"."
);
}
@@ -2418,13 +2418,13 @@ mod tests {
type Rgb = (u8, u8, u8);
type SyntectSpans = Vec<(Rgb, String)>;
/// Pins GrokNight via the shared test-lock guard; hold it for the whole
/// Pins KigiNight via the shared test-lock guard; hold it for the whole
/// test so a concurrent theme flip can't skew the compared highlighter walks.
fn pin_groknight_syntect() -> std::sync::MutexGuard<'static, ()> {
fn pin_kiginight_syntect() -> std::sync::MutexGuard<'static, ()> {
let guard = crate::theme::cache::pin_theme();
assert!(
!Theme::groknight().diff_uses_line_fg(),
"GrokNight must be banded for Equal-line syntect path in render"
!Theme::kiginight().diff_uses_line_fg(),
"KigiNight must be banded for Equal-line syntect path in render"
);
guard
}
@@ -2454,7 +2454,7 @@ mod tests {
}
/// Hunk-only: fresh highlighter, only the given lines in order (prod path).
/// Caller pins the theme via `pin_groknight_syntect` (lock is not reentrant).
/// Caller pins the theme via `pin_kiginight_syntect` (lock is not reentrant).
fn hunk_only_raw_styles(path: &Path, lines: &[&str]) -> Vec<SyntectSpans> {
let syntect = get_syntect();
let mut hl = syntect
@@ -2467,7 +2467,7 @@ mod tests {
}
/// Full-file then slice: silent HL from line 1, return styles for all lines.
/// Caller pins the theme via `pin_groknight_syntect` (lock is not reentrant).
/// Caller pins the theme via `pin_kiginight_syntect` (lock is not reentrant).
fn full_file_raw_styles(path: &Path, file_text: &str) -> Vec<SyntectSpans> {
let syntect = get_syntect();
let mut hl = syntect
@@ -2505,7 +2505,7 @@ class ProcessQueueItem(BaseModel):
/// Control: self-contained Rust line → keyword RGB ≠ string RGB (raw syntect).
#[test]
fn syntax_highlight_splits_keyword_and_string_fg() {
let _guard = pin_groknight_syntect();
let _guard = pin_kiginight_syntect();
let path = Path::new("probe.rs");
let lines = hunk_only_raw_styles(path, &["let x = \"hello\";"]);
assert_eq!(lines.len(), 1);
@@ -2552,7 +2552,7 @@ class ProcessQueueItem(BaseModel):
/// (and differ from cold hunk-only spill) after a mid-file closing `"""`.
#[test]
fn file_scoped_matches_full_file_on_field_line() {
let _guard = pin_groknight_syntect();
let _guard = pin_kiginight_syntect();
let path = Path::new("queue_item.py");
let (file, hunk, field_ln) = fixture_python_close_hunk();
let close_ln = hunk[0].ln;
@@ -2629,7 +2629,7 @@ class ProcessQueueItem(BaseModel):
/// baked under another theme it must not paint — hunk-only output.
#[test]
fn file_scoped_stale_theme_falls_back_to_hunk_only() {
let _guard = pin_groknight_syntect();
let _guard = pin_kiginight_syntect();
let path = Path::new("queue_item.py");
let (file, hunk, field_ln) = fixture_python_close_hunk();
// Real computed map: paintable by construction (line keys and texts
@@ -2672,7 +2672,7 @@ class ProcessQueueItem(BaseModel):
);
// Stale: the SAME paintable map baked under another theme is skipped.
let stale = ThemeKind::GrokDay;
let stale = ThemeKind::KigiDay;
assert_ne!(stale, crate::theme::cache::current_kind());
block.highlight = EditHighlightPhase::FileScoped {
by_new_line,
@@ -2739,7 +2739,7 @@ class ProcessQueueItem(BaseModel):
/// after a mid-file closing `"""`.
#[test]
fn triple_quote_hunk_only_differs_from_full_file_today() {
let _guard = pin_groknight_syntect();
let _guard = pin_kiginight_syntect();
let path = Path::new("queue_item.py");
let (file, hunk, field_ln) = fixture_python_close_hunk();
let close_ln = hunk[0].ln;
@@ -447,7 +447,7 @@ session content
#[test]
fn shorten_memory_path() {
// Paths under the configured grok memory root keep one trailing segment group.
// Paths under the configured kigi memory root keep one trailing segment group.
let memory_root = kigi_config::kigi_home().join("memory");
let session = memory_root.join("xai-50aa78f0/sessions/2026-05-01.md");
let top = memory_root.join("MEMORY.md");
@@ -656,7 +656,7 @@ mod tests {
ToolCallBlock::ListDir(ListDirToolCallBlock::new("src")),
ToolCallBlock::Search(SearchToolCallBlock::new("todo")),
ToolCallBlock::WebFetch(WebFetchToolCallBlock::new("https://example.com")),
ToolCallBlock::WebSearch(WebSearchToolCallBlock::new("grok")),
ToolCallBlock::WebSearch(WebSearchToolCallBlock::new("kigi")),
ToolCallBlock::IntegrationSearch(IntegrationSearchToolCallBlock::new("linear")),
ToolCallBlock::UseTool(UseToolCallBlock::new("linear__save_issue")),
ToolCallBlock::MemorySearch(MemorySearchToolCallBlock::new("auth")),
@@ -1114,7 +1114,7 @@ mod tests {
fn prompt_band_color_native_vs_rgb() {
use ratatui::style::Color;
let theme = Theme::groknight();
let theme = Theme::kiginight();
assert_eq!(
UserPromptBlock::prompt_band_color_for(&theme, false, true),
Some(Color::DarkGray)
@@ -950,9 +950,9 @@ impl ScrollbackState {
if let Some(entry) = self.entries.get_mut(&id)
&& let RenderBlock::ToolCall(ToolCallBlock::Execute(ref mut exec)) = entry.block
{
// Replace output entirely — grok-shell sends full accumulated buffer each tick.
// Replace output entirely — kigi-shell sends full accumulated buffer each tick.
// The shell now sends clean output (no ANSI codes) when the client sets
// x.ai/bashOutputNoColor: true, so no stripping is needed.
// kigi/bashOutputNoColor: true, so no stripping is needed.
exec.output = Some(output.to_string());
entry.invalidate_cache();
self.dirty_heights.insert(id);
@@ -542,7 +542,7 @@ mod tests {
};
// Three distinct URLs across two searches, one duplicated.
let entries = vec![
searched("grok", &["https://a.com", "https://b.com"]),
searched("kigi", &["https://a.com", "https://b.com"]),
searched("pager", &["https://b.com", "https://c.com"]),
];
let l = label(&entries);
@@ -2539,7 +2539,7 @@ mod tests {
#[test]
fn persistent_and_active_overlay_agree_on_same_endpoints() {
// Pin theme to avoid races with parallel tests that call `cache::set`.
crate::theme::cache::set(crate::theme::ThemeKind::GrokNight);
crate::theme::cache::set(crate::theme::ThemeKind::KigiNight);
let mut model = ResolvedSelectionModel::default();
for i in 0..4u16 {
model.push_line(ResolvedSelectableLine {
@@ -407,7 +407,7 @@ impl<'a> EntryRenderer<'a> {
///
/// Mirrors `desired_height` but derives the content line count from the block's
/// raw source text (`searchable_text`) instead of laying it out. Lets the layout
/// cache size off-screen entries on a bulk load (`grok -r`) without word-wrapping
/// cache size off-screen entries on a bulk load (`kigi -r`) without word-wrapping
/// and markdown-rendering every entry (O(history)). On-screen entries get their
/// EXACT `desired_height`, so visible content is never estimated.
pub fn estimate_height(&self, width: u16) -> u16 {
@@ -1486,7 +1486,7 @@ mod tests {
// Background blocks own the gutter via the existing full-area fill, so
// the no-bg clear must not run for them. Concrete theme so bg_light !=
// bg_base (Theme::current() quantizes both to Reset in the test env).
let theme = Theme::groknight();
let theme = Theme::kiginight();
assert_ne!(
theme.bg_light, theme.bg_base,
"test premise: block bg must differ from base bg"
@@ -1517,14 +1517,14 @@ mod tests {
// code rectangle gets a notch. Concrete theme so the two bgs differ.
//
// Requires color support: under `NO_COLOR` the global markdown style
// carries no code background while this test's local `groknight()`
// carries no code background while this test's local `kiginight()`
// theme still has RGB — a mismatch impossible in production.
// (Historically this passed under NO_COLOR only because the md_style
// Reset→silver fallback bug painted a concrete bg despite the opt-out.)
if !crate::theme::color_support::detect().has_color() {
return;
}
let theme = Theme::groknight();
let theme = Theme::kiginight();
let mut entry = ScrollbackEntry::new(RenderBlock::agent_message("```\nZZZZ\n```\n"));
// The code block's only content row is the first content row, which is
// also where the timestamp overlay lands. Drop `created_at` so the
@@ -1802,7 +1802,7 @@ mod tests {
// The off-screen estimate accounts for the affordance row (one per
// diagram) and so never under-reserves vs the realized height — the
// invariant a bulk load (`grok -r`) relies on to avoid clipping.
// invariant a bulk load (`kigi -r`) relies on to avoid clipping.
let est_on = r.estimate_height(80);
assert_eq!(
est_on,
@@ -1872,7 +1872,7 @@ mod tests {
// their previews as panel is pinned by block-side tests.)
use crate::scrollback::block::StubBlock;
let theme = Theme::groknight();
let theme = Theme::kiginight();
let entry = ScrollbackEntry::new(RenderBlock::Stub(
StubBlock::new("alpha\nbravo", Color::Blue).with_line_bg(LINE_BG, true),
));
@@ -1900,7 +1900,7 @@ mod tests {
// tool-preview panels.
use crate::scrollback::block::StubBlock;
let theme = Theme::groknight();
let theme = Theme::kiginight();
let entry = ScrollbackEntry::new(RenderBlock::Stub(
StubBlock::new("alpha\nbravo", Color::Blue).with_line_bg(LINE_BG, false),
));