§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
@@ -71,7 +71,7 @@ curl -LsSf "http://file-server.example.internal/cicd/example/install.sh?nocache"
! sudo du -shx /.Spotlight-V100 /.DocumentRevisions-V100 /private/var/vm /private/var/folders /cores /Library 2>/dev/null | sort -rh
### END
### CMD 21
cat ~/.grok/config.toml | grep composer
cat ~/.kigi/config.toml | grep composer
### END
### CMD 22
KIGI_DEBUG_CONTEXT_WINDOW=100000 KIGI_AUTO_COMPACT_THRESHOLD_PERCENT=5 /tmp/pager-under-test -r 019e0000-0000-7000-8000-000000000001 -p 'reply with exactly: again' --model example-model --always-approve --no-leader > /tmp/compaction-repro/headless5.log 2>&1; echo EXIT=$? >> /tmp/compaction-repro/headless5.log
@@ -95,7 +95,7 @@ strings target/debug/kigi-tui | grep -c slash-mru-writer # must print >=1\
SSH_CONNECTION='10.0.0.1 51234 10.0.0.2 22' \\
### END
### CMD 29
DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/opt/homebrew/lib/faketime/libfaketime.1.dylib FAKETIME_TIMESTAMP_FILE=/tmp/ft.rc FAKETIME_NO_CACHE=1 FAKETIME_DONT_FAKE_MONOTONIC=1 /tmp/pager-date-test --model grok-build --always-approve --no-leader
DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/opt/homebrew/lib/faketime/libfaketime.1.dylib FAKETIME_TIMESTAMP_FILE=/tmp/ft.rc FAKETIME_NO_CACHE=1 FAKETIME_DONT_FAKE_MONOTONIC=1 /tmp/pager-date-test --model kigi --always-approve --no-leader
### END
### CMD 30
DYLD_FORCE_FLAT_NAMESPACE=1 DYLD_INSERT_LIBRARIES=/opt/homebrew/lib/faketime/libfaketime.1.dylib FAKETIME_TIMESTAMP_FILE=/tmp/ft.rc FAKETIME_NO_CACHE=1 FAKETIME_DONT_FAKE_MONOTONIC=1 /tmp/pager-date-test --always-approve --no-leader
@@ -20,7 +20,7 @@ fn kigi_home_override_path_helpers() {
"$KIGI_SHARE_DIR"
);
assert_eq!(
kigi_tui::util::display_user_grok_path("config.toml"),
kigi_tui::util::display_user_kigi_path("config.toml"),
"$KIGI_SHARE_DIR/config.toml"
);
@@ -49,10 +49,10 @@ fn dirs_next_home() -> Option<PathBuf> {
/// auto-permission-mode feature gate pinned explicitly via `gate_on` so each
/// test is self-contained and deterministic regardless of the runner's shell.
fn prepare_sandbox(home: &Path, gate_on: bool) -> Vec<(String, String)> {
let grok = home.join(".kigi");
let _ = std::fs::create_dir_all(&grok);
let kigi = home.join(".kigi");
let _ = std::fs::create_dir_all(&kigi);
if let Some(src) = auth_json_source() {
let dest = grok.join("auth.json");
let dest = kigi.join("auth.json");
if let Err(e) = std::fs::copy(&src, &dest) {
eprintln!("pty_auto_mode: could not copy auth.json ({e}); login may block mode cycle");
} else {
@@ -69,7 +69,7 @@ fn prepare_sandbox(home: &Path, gate_on: bool) -> Vec<(String, String)> {
let home_s = home.display().to_string();
let mut env = vec![
("HOME".into(), home_s.clone()),
("KIGI_SHARE_DIR".into(), grok.display().to_string()),
("KIGI_SHARE_DIR".into(), kigi.display().to_string()),
("XDG_CONFIG_HOME".into(), format!("{home_s}/.config")),
("XDG_DATA_HOME".into(), format!("{home_s}/.local/share")),
("XDG_CACHE_HOME".into(), format!("{home_s}/.cache")),
@@ -186,7 +186,7 @@ pub(crate) fn spawn_polling_session_with_env(
/// Start the mock server with two models that have different agent types,
/// and return a `ContentController` configured for agent-type-mismatch
/// testing. The default model is `"default-model"` (no agent type → uses
/// `grok-build` harness).
/// `kigi` harness).
pub(crate) async fn start_dual_agent_type_content() -> ContentController {
ContentController::start_with_models(vec![
MockModel::new("default-model"),
@@ -217,7 +217,7 @@ pub(crate) fn git_repo_with_mcp_json() -> tempfile::TempDir {
/// point at the isolated temp home, so the trust store starts empty.
pub(crate) fn trust_env(content: &ContentController, feature_on: bool) -> Vec<(String, String)> {
let mut env = content.env_for_pager();
// A self-built (unstamped) grok auto-trusts and never prompts; simulate a
// A self-built (unstamped) kigi auto-trusts and never prompts; simulate a
// release build so the folder-trust feature is actually evaluated here. The
// feature-off case below then exercises the TRUE feature-off path, not
// auto-trust.
@@ -259,7 +259,7 @@ pub(crate) fn turn_sentinel(n: u8) -> String {
/// Seeded server name; it only renders once the MCP list fetch resolves.
pub(crate) const MCP_TEST_SERVER: &str = "ptytestmcp";
/// Budget for session creation plus the `x.ai/mcp/list` round-trip.
/// Budget for session creation plus the `kigi/mcp/list` round-trip.
pub(crate) const MCP_MENU_LOAD_TIMEOUT: Duration = Duration::from_secs(30);
/// Configured servers list with a status badge even when never connected.
@@ -1096,9 +1096,9 @@ pub(crate) fn quit_minimal(harness: &mut PtyHarness) {
}
}
// ── grok wrap e2e ───────────────────────────────────────────────────────
// ── kigi wrap e2e ───────────────────────────────────────────────────────
/// `grok wrap` run budget. Same contention math as the requirements-version
/// `kigi wrap` run budget. Same contention math as the requirements-version
/// test: the child's cold exec of the huge debug binary can land its first
/// write well past 30s under the parallel pty_e2e suite.
#[cfg(unix)]
@@ -1107,7 +1107,7 @@ pub(crate) const WRAP_TIMEOUT: Duration = Duration::from_secs(120);
#[cfg(unix)]
const WRAP_DRAIN_TIMEOUT: Duration = Duration::from_secs(10);
/// Run `grok wrap <wrap_args...>` to completion inside a PTY with an isolated
/// Run `kigi wrap <wrap_args...>` to completion inside a PTY with an isolated
/// `KIGI_SHARE_DIR`, returning the exit code (`None` if it never exited within
/// [`WRAP_TIMEOUT`]) and everything the wrap PTY emitted. `extra_env` is where
/// tests pin `SHELL`; wrap needs no mock content — it dispatches in `main`
@@ -1124,7 +1124,7 @@ pub(crate) fn run_wrap(wrap_args: &[&str], extra_env: &[(&str, &str)]) -> (Optio
env.extend_from_slice(extra_env);
let mut harness =
PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, &args, &env).expect("spawn grok wrap");
PtyHarness::new(&binary, DEFAULT_ROWS, DEFAULT_COLS, &args, &env).expect("spawn kigi wrap");
let code = harness
.wait_for_exit_and_drain(WRAP_TIMEOUT, WRAP_DRAIN_TIMEOUT)
@@ -1139,7 +1139,7 @@ pub(crate) fn run_wrap(wrap_args: &[&str], extra_env: &[(&str, &str)]) -> (Optio
/// Write an executable fake `$SHELL` that prints each argv element on its own
/// `ARG:`-prefixed line and exits 0, so tests can assert the exact argv
/// `grok wrap` hands to the user's shell without depending on any real
/// `kigi wrap` hands to the user's shell without depending on any real
/// shell's rc files or alias state. Keep the returned tempdir alive for the
/// duration of the run.
#[cfg(unix)]
@@ -1,24 +1,24 @@
//! Doubled lines — regression guard via a simulated
//! out-of-band screen reflow.
//!
//! The stack is `tmux -> nvim :terminal -> grok`: nvim/tmux repaint grok's
//! pane out-of-band (no grok PTY resize), and grok's diff renderer only
//! The stack is `tmux -> nvim :terminal -> kigi`: nvim/tmux repaint kigi's
//! pane out-of-band (no kigi PTY resize), and kigi's diff renderer only
//! re-clears on a real size change — so the rows it doesn't own survive and
//! you get doubled lines at the top/bottom until restart.
//!
//! The harness is a single faithful emulator and can't nest a real tmux/nvim,
//! so we SIMULATE the out-of-band reflow with `feed_screen` (writes straight
//! into the virtual terminal, bypassing grok) and then check whether grok
//! heals it. `NVIM` is set in grok's env so it sees the embedded-editor
//! into the virtual terminal, bypassing kigi) and then check whether kigi
//! heals it. `NVIM` is set in kigi's env so it sees the embedded-editor
//! context the fix keys off (mirroring a real nvim `:terminal`).
//!
//! The fix: grok forces a full clear+repaint on `FocusGained` in
//! The fix: kigi forces a full clear+repaint on `FocusGained` in
//! editor/multiplexer contexts, so the injected row is gone after refocus.
//! The final assertion guards that heal.
use super::common::*;
/// Unique sentinel that grok would never render on its own.
/// Unique sentinel that kigi would never render on its own.
const STALE_MARKER: &str = "STALE_OUT_OF_BAND_ROW_ZZZ";
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
@@ -31,7 +31,7 @@ async fn out_of_band_stale_row_heals_on_focus_gained() {
// Mock-auth env + pretend we're inside a neovim `:terminal` (sets the
// embedded-editor context the doubled-line fix gates on).
let mut env = content.env_for_pager();
env.push(("NVIM".into(), "/tmp/grok-pty-harness-fake-nvim.sock".into()));
env.push(("NVIM".into(), "/tmp/kigi-pty-harness-fake-nvim.sock".into()));
let env_refs: Vec<(&str, &str)> = env.iter().map(|(k, v)| (k.as_str(), v.as_str())).collect();
let binary = pager_binary().expect("resolve pager binary");
@@ -49,7 +49,7 @@ async fn out_of_band_stale_row_heals_on_focus_gained() {
);
// Simulate the out-of-band reflow: write a stale row straight into the
// virtual screen at col 1 — the static left margin grok's diff renderer
// virtual screen at col 1 — the static left margin kigi's diff renderer
// doesn't repaint during the logo shimmer. The heal is a full clear, so
// removal is reliable. `\x1b[<row>;<col>H` is 1-based cursor positioning.
h.feed_screen(format!("\x1b[6;1H{STALE_MARKER}").as_bytes());
@@ -58,16 +58,16 @@ async fn out_of_band_stale_row_heals_on_focus_gained() {
"marker should be on the virtual screen right after injection"
);
// grok must not self-heal out-of-band content via ordinary diff redraws:
// kigi must not self-heal out-of-band content via ordinary diff redraws:
// it only rewrites cells whose own model changed, so this row is stranded.
h.update(Duration::from_millis(300));
assert!(
h.contains_text(STALE_MARKER),
"stale row should survive a normal redraw (grok's diff renderer doesn't own it)\nscreen:\n{}",
"stale row should survive a normal redraw (kigi's diff renderer doesn't own it)\nscreen:\n{}",
h.screen_contents()
);
// A FocusGained (CSI I) forces a full clear+repaint that re-asserts grok's
// A FocusGained (CSI I) forces a full clear+repaint that re-asserts kigi's
// whole screen and removes the out-of-band row.
h.inject_keys(b"\x1b[I").expect("inject FocusGained");
// Poll for the heal instead of a fixed settle so host load can't flake it.
@@ -39,7 +39,7 @@ async fn edit_collapsed_oneliner_pty() {
json!({
"file_path": abs.to_string_lossy(),
"old_string": " return \"hi\"",
"new_string": format!(" name = \"grok\" # {BODY_MARKER}\n return f\"hi {{name}}\""),
"new_string": format!(" name = \"kigi\" # {BODY_MARKER}\n return f\"hi {{name}}\""),
})
.to_string(),
);
@@ -3,7 +3,7 @@
use super::common::*;
/// 11. **Initial prompt positional.**
/// Launching `grok "<prompt>"` (the prompt passed as a positional CLI arg)
/// Launching `kigi "<prompt>"` (the prompt passed as a positional CLI arg)
/// auto-starts a new session and submits the prompt as the first turn —
/// no keystrokes injected. This exercises the full loop end-to-end:
/// CLI positional → TUI launch → NewSession → SendPrompt → shell agent →
@@ -17,7 +17,7 @@ async fn initial_prompt_positional_auto_submits() {
));
let binary = pager_binary().expect("resolve pager binary");
// Pass the prompt as a positional argument, exactly like `grok "go"`.
// Pass the prompt as a positional argument, exactly like `kigi "go"`.
let mut harness =
PtyHarness::spawn_with_content(&binary, DEFAULT_ROWS, DEFAULT_COLS, &content, &[PROMPT])
.expect("spawn pager with initial prompt");
@@ -36,7 +36,7 @@ fn run_fg_on_row(rows: &[StyledLine], row_marker: &str, needle: &str) -> Option<
/// Seed a user-invocable skill under `dir/.kigi/skills`. The workspace must
/// be a git repo: the live session advertises workspace-local skills only for
/// git workspaces (offline `grok inspect` scans plain dirs too) — same shape
/// git workspaces (offline `kigi inspect` scans plain dirs too) — same shape
/// as the mid_text_skill_token_echo.yaml scenario's `git_init: true`.
fn seed_test_skill(dir: &Path) {
let skill_dir = dir.join(".kigi").join("skills").join("test-skill");
@@ -4,7 +4,7 @@ use crate::common::*;
/// CLI `--minimal` / `--fullscreen` must not write `[ui] screen_mode` to
/// config.toml. Mode flags are session-scoped; only a manual config.toml edit
/// should make a mode sticky across plain `grok` launches.
/// should make a mode sticky across plain `kigi` launches.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore]
async fn minimal_cli_screen_mode_does_not_persist() {
@@ -51,7 +51,7 @@ async fn minimal_cli_screen_mode_does_not_persist() {
.wait_for_text(WELCOME_SCREEN_SENTINEL, WELCOME_TIMEOUT)
.unwrap_or_else(|e| {
panic!(
"plain grok should open fullscreen after --minimal (no sticky write): {e}\nscreen:\n{}",
"plain kigi should open fullscreen after --minimal (no sticky write): {e}\nscreen:\n{}",
second.screen_contents()
)
});
@@ -10,13 +10,13 @@ use crate::common::*;
/// The first turn is genuinely taller than the screen (a fenced code block, not
/// reflowable prose) so the first welcome card and the turn's head scroll into
/// *native scrollback* before `/new`. The robust "new session" signal is then
/// that a *second* welcome card appears (two `Grok Build` banners in
/// that a *second* welcome card appears (two `Kigi` banners in
/// scrollback+screen), independent of exactly how content scrolled.
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore]
async fn minimal_new_session_keeps_history_and_resets() {
/// Substring printed once per minimal welcome card (see `minimal::welcome`).
const WELCOME_BANNER: &str = "Grok Build";
const WELCOME_BANNER: &str = "Kigi";
let content = ContentController::start().await.expect("start content");
// Code-block rows (not prose, which markdown-reflows to fit on screen) so
@@ -88,7 +88,7 @@ async fn minimal_slash_switches_from_fullscreen() {
"main screen should be cleared on /minimal relaunch; leftover reopen text:\n{screen}"
);
assert!(
screen.contains("Grok Build") || harness.full_text().contains("Grok Build"),
screen.contains("Kigi") || harness.full_text().contains("Kigi"),
"welcome card should re-anchor at top after /minimal relaunch\nscreen:\n{screen}"
);
@@ -83,7 +83,7 @@ async fn minimal_transcript_pager_restore_no_artifacts() {
// transcript temp-file path — the conversation sentinel can't be used as
// the signal, it is already visible on the live screen. Then quit it.
harness
.wait_for_text("grok-transcript-", Duration::from_secs(20))
.wait_for_text("kigi-transcript-", Duration::from_secs(20))
.expect("less shows the transcript");
harness.update(Duration::from_millis(300));
harness.inject_keys(b"q").expect("quit less");
@@ -3,7 +3,7 @@
use super::common::*;
/// The suggestion the mock streams for every request. Serves BOTH the prompt
/// turn and the turn-end `x.ai/suggestPrompt` call (the mock's fixed mode
/// turn and the turn-end `kigi/suggestPrompt` call (the mock's fixed mode
/// answers every request), so after the turn the ghost text mirrors it.
/// Multi-word so the shell-side sanitizer (`sanitize_suggestion`) accepts it.
const SUGGESTION: &str = "review the staged changes";
@@ -22,7 +22,7 @@ const ACCEPT_HINT: &str = "accept suggestion";
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore]
async fn prompt_suggestion_ghost_tab_accepts() {
// The suggestion model (`grok-build-0.1`, the shell's built-in default)
// The suggestion model (`kigi-0.1`, the shell's built-in default)
// must be in the mock catalog: the shell catalog-guards the effective
// suggestion model and *skips the request entirely* when it is not
// sampleable (`prompt_suggest::effective_suggest_model`), exactly as it
@@ -32,7 +32,7 @@ async fn prompt_suggestion_ghost_tab_accepts() {
// `test-model` stays first so it remains the session's default model.
let content = ContentController::start_with_models(vec![
MockModel::new("test-model"),
MockModel::new("grok-build-0.1"),
MockModel::new("kigi-0.1"),
])
.await
.expect("start content");
@@ -9,7 +9,7 @@ use super::common::*;
#[ignore]
async fn reasoning_efforts_fallback_menu_matches_builtin() {
let content = ContentController::start_with_models(vec![
MockModel::new("grok-4.5").with_supports_reasoning_effort(true),
MockModel::new("kigi-4.5").with_supports_reasoning_effort(true),
])
.await
.expect("start content");
@@ -9,7 +9,7 @@ use super::common::*;
#[ignore]
async fn reasoning_efforts_from_config_toml_menu() {
let content = ContentController::start_with_models(vec![
MockModel::new("grok-4.5").with_supports_reasoning_effort(true),
MockModel::new("kigi-4.5").with_supports_reasoning_effort(true),
])
.await
.expect("start content");
@@ -18,10 +18,10 @@ async fn reasoning_efforts_from_config_toml_menu() {
// Seed `~/.kigi/config.toml` with a per-model reasoning-effort menu.
let kigi_home = content.home().join(".kigi");
std::fs::create_dir_all(&kigi_home).expect("create .kigi");
// Quote the dotted model id: bare `[model.kigi-4.5]` is TOML key-path syntax (model.kigi-4.5), not the id "grok-4.5".
// Quote the dotted model id: bare `[model.kigi-4.5]` is TOML key-path syntax (model.kigi-4.5), not the id "kigi-4.5".
std::fs::write(
kigi_home.join("config.toml"),
"[model.\"grok-4.5\"]\nreasoning_efforts = [{ value = \"high\", label = \"ConfigHigh\" }]\n",
"[model.\"kigi-4.5\"]\nreasoning_efforts = [{ value = \"high\", label = \"ConfigHigh\" }]\n",
)
.expect("write config.toml");
@@ -9,7 +9,7 @@ use super::common::*;
#[ignore]
async fn reasoning_efforts_menu_renders_and_remaps_on_wire() {
let content = ContentController::start_with_models(vec![
MockModel::new("grok-4.5")
MockModel::new("kigi-4.5")
.with_supports_reasoning_effort(true)
.with_reasoning_efforts(vec![
json!({ "id": "deep", "value": "xhigh", "label": "Deep", "description": "Maximum reasoning" }),
@@ -68,7 +68,7 @@ async fn removed_queued_prompt_never_sent() {
}
// `queued alpha` vanished optimistically the instant `x` was handled; give
// the `x.ai/queue/remove` RPC time to reach the shell and mutate the
// the `kigi/queue/remove` RPC time to reach the shell and mutate the
// authoritative queue before we let turn 1 complete. Turn 1 stays gated
// throughout, so the removal always lands while `alpha` is still queued
// (never promoted) — the survivor `bravo` is the only thing left to run.
@@ -28,7 +28,7 @@ async fn requirements_version_failure_exits_2_with_guidance() {
)
.expect("spawn pager");
let msg = "Update Grok to a version the policy allows";
let msg = "Update Kigi to a version the policy allows";
// This single budget must cover the child's cold *exec* (a ~680MB unoptimized
// debug binary) plus reaching `main()` and running `validate_requirements` —
// all before the runtime/TUI. Under the ~60-way-parallel `pty_e2e` suite,
@@ -4,15 +4,15 @@ use super::common::*;
// ── Reproduction: horizontal resize must not lose the scroll position ─────
//
// Bug: when the user has scrolled UP into grok's scrollback (NOT pinned to the
// bottom / not following) and the terminal is resized HORIZONTALLY, grok loses
// Bug: when the user has scrolled UP into kigi's scrollback (NOT pinned to the
// bottom / not following) and the terminal is resized HORIZONTALLY, kigi loses
// its scroll position and the view jumps. Root cause:
// `ScrollbackState.scroll_offset` is an ABSOLUTE count of WRAPPED DISPLAY ROWS
// (`scrollback/state/mod.rs`). On a width change `prepare_layout` re-wraps all
// content at the new width and rebuilds the row map, but LEAVES `scroll_offset`
// unchanged (Case 1 full rebuild) — so the same row number now points at
// different content and the viewport jumps. It only happens when NOT following;
// in follow/tail mode grok re-pins to the bottom (no jump).
// in follow/tail mode kigi re-pins to the bottom (no jump).
//
// This test parks the marker in the MIDDLE of the viewport while scrolled into
// the middle of the transcript (TOP and BOTTOM sentinels both scrolled off),
@@ -23,10 +23,10 @@ use super::common::*;
// rebuild and restored after) re-pins the viewport-top content across the
// reflow so the marker stays put.
//
// Runs FULLSCREEN (alt-screen): grok's mode-independent scroll-anchor logic is
// Runs FULLSCREEN (alt-screen): kigi's mode-independent scroll-anchor logic is
// what's under test. `Viewport::Fullscreen` is autoresized on resize with no DSR
// cursor probe, so grok itself re-wraps at the new width, and the alt-screen grid
// is not reflowed by the terminal — so the marker's position reflects grok's own
// cursor probe, so kigi itself re-wraps at the new width, and the alt-screen grid
// is not reflowed by the terminal — so the marker's position reflects kigi's own
// re-layout, with no harness-reflow confound.
/// Unique marker on its own (non-wrapping) line, with WRAPPING content above it.
@@ -75,7 +75,7 @@ const POS_TOLERANCE: i32 = 2;
/// paragraphs, a block of short non-wrapping guard paragraphs, the marker on its
/// own line, a long run of short filler, then a bottom sentinel.
///
/// grok renders markdown with SOFT line breaks (a single `\n` becomes a space),
/// kigi renders markdown with SOFT line breaks (a single `\n` becomes a space),
/// so every logical line is emitted as its own paragraph (blank line between)
/// to get a predictable one-hard-line-per-line layout where only the long
/// paragraphs re-wrap on a width change.
@@ -185,10 +185,10 @@ async fn resize_preserves_scroll_position() {
content.set_response(scroll_anchor_response());
// Spawn FULLSCREEN (alt-screen). `Viewport::Fullscreen` is autoresized on a
// terminal resize with NO DSR cursor probe, so grok re-wraps the scrollback
// at the new width and the stale `scroll_offset` surfaces the jump in grok's
// terminal resize with NO DSR cursor probe, so kigi re-wraps the scrollback
// at the new width and the stale `scroll_offset` surfaces the jump in kigi's
// OWN rendered output. The alt-screen grid is not reflowed by the terminal on
// resize, so this isolates grok's scroll-anchor logic with no harness confound.
// resize, so this isolates kigi's scroll-anchor logic with no harness confound.
let binary = pager_binary().expect("resolve pager binary");
let mut harness =
PtyHarness::spawn_with_content(&binary, DEFAULT_ROWS, WIDE_COLS, &content, &[])
@@ -42,7 +42,7 @@ async fn reverse_agent_type_mismatch_cursor_to_default() {
.wait_for_text(MOCK_RESPONSE_SENTINEL, Duration::from_secs(30))
.expect("response rendered");
// Switch to default-model (different agent type: cursor → grok-build).
// Switch to default-model (different agent type: cursor → kigi).
harness
.inject_keys(b"/model default-model\r")
.expect("type model switch");
@@ -8,7 +8,7 @@ use super::common::*;
#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
#[ignore]
async fn same_agent_type_switch_no_modal() {
// Both models have no agent_type → both use grok-build harness.
// Both models have no agent_type → both use kigi harness.
let content = ContentController::start_with_models(vec![
MockModel::new("model-a"),
MockModel::new("model-b"),
@@ -2,7 +2,7 @@
#[allow(unused_imports)]
use super::common::*;
/// Direct-route e2e: `grok wrap` with a resolvable explicit path runs the
/// Direct-route e2e: `kigi wrap` with a resolvable explicit path runs the
/// command inside the wrap PTY with output passing through, and propagates the
/// child's exit code — both for success and for a nonzero exit.
#[test]
@@ -24,6 +24,6 @@ fn wrap_echo_passthrough_and_exit_code() {
assert_eq!(
code,
Some(7),
"a nonzero child exit must propagate as grok wrap's own exit\nraw:\n{raw}"
"a nonzero child exit must propagate as kigi wrap's own exit\nraw:\n{raw}"
);
}
@@ -5,13 +5,13 @@ use super::common::*;
/// Fail-fast e2e: an explicit path (contains `/`) never routes through the
/// shell, so a nonexistent one must keep the old precise failure — PTY spawn
/// fails, the exec fallback engages ("wrapped mode failed"), exec ENOENTs
/// ("failed to exec"), and grok exits 1. Guards against the shell route ever
/// ("failed to exec"), and kigi exits 1. Guards against the shell route ever
/// swallowing path typos into a confusing shell error.
#[test]
#[ignore = "PTY e2e; run the owning pty_e2e_* Cargo test with --ignored (see Cargo.toml)"]
#[cfg(unix)]
fn wrap_explicit_path_not_found_fails_fast() {
let (code, raw) = run_wrap(&["/nonexistent-grok-wrap-e2e/prog", "arg"], &[]);
let (code, raw) = run_wrap(&["/nonexistent-kigi-wrap-e2e/prog", "arg"], &[]);
assert!(
raw.contains("wrapped mode failed"),
@@ -9,7 +9,7 @@ use super::common::*;
///
/// A fake argv-echoing `$SHELL` makes the assertion deterministic: real alias
/// expansion is the shell's own contract (and rc-file dependent), while the
/// argv shape is the part `grok wrap` owns. The quoting round-trip against a
/// argv shape is the part `kigi wrap` owns. The quoting round-trip against a
/// real shell is covered by `joined_line_roundtrips_words_through_real_sh` in
/// `wrap_cmd_tests`.
#[test]
@@ -18,7 +18,7 @@ use super::common::*;
fn wrap_not_found_alias_routes_via_shell_contract() {
let (_dir, shell) = fake_argv_echo_shell();
let (code, raw) = run_wrap(
&["grok-wrap-e2e-alias-xx", "with space"],
&["kigi-wrap-e2e-alias-xx", "with space"],
&[("SHELL", &shell)],
);
@@ -28,7 +28,7 @@ fn wrap_not_found_alias_routes_via_shell_contract() {
);
assert!(raw.contains("ARG:-c"), "shell must get -c\nraw:\n{raw}");
assert!(
raw.contains("ARG:grok-wrap-e2e-alias-xx 'with space'"),
raw.contains("ARG:kigi-wrap-e2e-alias-xx 'with space'"),
"rejoined line must keep the first word bare and quote the tail\nraw:\n{raw}"
);
assert_eq!(
@@ -3,7 +3,7 @@
use super::common::*;
/// OSC 52 sink advertisement e2e: the wrapped child must see
/// `KIGI_OSC52_SINK=1` (the signal an inner `grok` uses to trust OSC 52 over
/// `KIGI_OSC52_SINK=1` (the signal an inner `kigi` uses to trust OSC 52 over
/// SSH — see `run_wrapped_command`), including through the `$SHELL -i -c` hop.
/// The parent env pins the var to `0` so a pass can only come from the wrap
/// layer's own override, not from an inherited value.
@@ -2,7 +2,7 @@
#[allow(unused_imports)]
use super::common::*;
/// Raw-string route e2e — the original field regression (`grok wrap "mycli ssh
/// Raw-string route e2e — the original field regression (`kigi wrap "mycli ssh
/// host"`): ONE argv element containing spaces must be handed to `$SHELL -i -c`
/// for word-splitting instead of being spawned as a program literally named
/// `echo wrap-e2e one two`. `SHELL` is pinned to `/bin/sh` for determinism.
@@ -1,5 +1,5 @@
//! Basic PTY coverage: startup, input, rendering, permission-mode keys, and
//! `grok wrap` command routing.
//! `kigi wrap` command routing.
//!
//! All cases are ignored for ordinary Cargo runs; Bazel opts in and caps this
//! process-heavy family at four concurrent libtest workers.
@@ -13,7 +13,7 @@ environment:
env:
- key: KIGI_FOLDER_TRUST
value: "1"
# A self-built (unstamped) grok auto-trusts and never prompts; simulate a
# A self-built (unstamped) kigi auto-trusts and never prompts; simulate a
# release build so the folder-trust prompt is actually evaluated.
- key: KIGI_TEST_VERSION
value: "0.0.0-sim"
@@ -3,7 +3,7 @@ description: >
A plain prompt referencing a skill mid-message
("great /test-skill do it") keeps the composer's teal token highlight in the
scrollback echo after submit. The workspace seeds a repo-local
.grok/skills/test-skill/SKILL.md so the real shell advertises the skill; the
.kigi/skills/test-skill/SKILL.md so the real shell advertises the skill; the
screenshots capture the styled composer (pre-submit) and the styled echo
(post-submit) — the styled JSON artifacts carry the per-run fg colors for
visual verification and demo material.
@@ -15,7 +15,7 @@ environment:
workspace:
git_init: true
files:
".grok/skills/test-skill/SKILL.md": "---\nname: test-skill\ndescription: Test skill for echo styling.\n---\n\nDo the thing.\n"
".kigi/skills/test-skill/SKILL.md": "---\nname: test-skill\ndescription: Test skill for echo styling.\n---\n\nDo the thing.\n"
mock:
response: "MIDTEXT_SKILL_ECHO_DONE assistant reply after the mid-text skill prompt."
steps:
+18 -18
View File
@@ -1720,9 +1720,9 @@ fn defaults_round_trip_through_registry() {
"remember_tool_approvals" => SettingValue::Bool(false),
"toolset.ask_user_question.timeout_enabled" => SettingValue::Bool(true),
"keep_text_selection" => SettingValue::Enum("flash"),
"theme" => SettingValue::Enum("groknight"),
"auto_dark_theme" => SettingValue::Enum("groknight"),
"auto_light_theme" => SettingValue::Enum("grokday"),
"theme" => SettingValue::Enum("kiginight"),
"auto_dark_theme" => SettingValue::Enum("kiginight"),
"auto_light_theme" => SettingValue::Enum("kigiday"),
"render_mermaid" => SettingValue::Enum("auto"),
"multiline_mode" => SettingValue::Bool(false),
"permission_mode" => SettingValue::Enum("ask"),
@@ -2515,7 +2515,7 @@ fn pr4_mouse_click_in_theme_picker_is_no_op() {
s.mode = SettingsModalMode::PickingEnum {
key: "theme",
choices_idx: 0,
original_value: SettingValue::Enum("groknight"),
original_value: SettingValue::Enum("kiginight"),
supports_preview: true,
};
synth_rects(&mut s);
@@ -3561,7 +3561,7 @@ fn reset_overlay_dims_all_rows_except_target() {
}
/// User-feedback follow-up: the settings modal renders a 1-line
/// "Ask Grok" tip footer at the bottom of the content area in
/// "Ask Kigi" tip footer at the bottom of the content area in
/// Browse, FilterFocused, and PickingEnum modes (always-on tip).
/// The footer is suppressed in `EditingValue` because the editor
/// needs every line for input + validation. This pins the
@@ -3595,12 +3595,12 @@ fn docs_footer_renders_for_browse_and_picker() {
all_text.push('\n');
}
assert!(
all_text.contains("Ask Grok"),
"[{fixture_label}] docs footer (`Ask Grok`) must appear in the rendered modal:\n\
all_text.contains("Ask Kigi"),
"[{fixture_label}] docs footer (`Ask Kigi`) must appear in the rendered modal:\n\
{all_text}"
);
assert!(
all_text.contains("change theme to grokday"),
all_text.contains("change theme to kigiday"),
"[{fixture_label}] docs footer must include the example phrasing"
);
}
@@ -4008,12 +4008,12 @@ fn pr14_default_model_picker_commits_resolved_model_id() {
let snapshot = PagerLocalSnapshot {
available_models: vec![
(
"Grok 4.5".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("grok-4.5")),
"Kigi 4.5".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("kigi-4.5")),
),
(
"Grok 3".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("grok-3")),
"Kigi 3".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("kigi-3")),
),
],
..PagerLocalSnapshot::default()
@@ -4034,7 +4034,7 @@ fn pr14_default_model_picker_commits_resolved_model_id() {
"Enter must transition to PickingEnum for default_model"
);
// Walk down past row 0 ("(no override)") to row 1 ("Grok 4.5").
// Walk down past row 0 ("(no override)") to row 1 ("Kigi 4.5").
let outcome = handle_settings_key(&mut s, &press(KeyCode::Down));
assert!(
matches!(outcome, SettingsKeyOutcome::Changed),
@@ -4047,7 +4047,7 @@ fn pr14_default_model_picker_commits_resolved_model_id() {
SettingsKeyOutcome::Action(Action::SetDefaultModel(id)) => {
assert_eq!(
id.0.as_ref(),
"grok-4.5",
"kigi-4.5",
"committed id must match snapshot"
);
}
@@ -4064,8 +4064,8 @@ fn pr14_default_model_picker_commits_resolved_model_id() {
fn pr14_default_model_picker_row_zero_commits_clear_action() {
let snapshot = PagerLocalSnapshot {
available_models: vec![(
"Grok 3".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("grok-3")),
"Kigi 3".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("kigi-3")),
)],
..PagerLocalSnapshot::default()
};
@@ -4101,8 +4101,8 @@ fn pr14_default_model_picker_row_zero_commits_clear_action() {
fn pr14_mouse_click_on_dynamic_enum_row_opens_picker() {
let snapshot = PagerLocalSnapshot {
available_models: vec![(
"Grok 3".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("grok-3")),
"Kigi 3".to_string(),
agent_client_protocol::ModelId::new(std::sync::Arc::from("kigi-3")),
)],
..PagerLocalSnapshot::default()
};