M0: compilable skeleton — Kigi 0.1.0 fork surgery

Hard fork of xai-org/grok-build (Apache-2.0) re-targeted as Kigi, an
unofficial Kimi Code CLI community build.

Rename & identity
- 72 xai-*/xai-grok-* crates -> kigi-* (explicit: xai-grok-pager-bin ->
  kigi-bin [binary `kigi`], xai-grok-pager -> kigi-tui; rest mechanical);
  ptyctl, ptyctl-cli, third_party/ unchanged; proto package
  xai.grok.tools.v1 -> kigi.tools.v1
- Config home ~/.kigi (KIGI_SHARE_DIR override), env prefix GROK_* ->
  KIGI_*, `kigi --version` carries the unofficial-community-build notice
- clap identity, help text, startup banner, prompt templates rebranded
  (templates re-encrypted)

Deletions (PRD removal list #5/#6/#7/#9/#10)
- voice input (xai-grok-voice) and all TUI wiring
- telemetry: Mixpanel client, external OTel stream, Sentry, OTLP layers,
  trace/GCS/S3 upload queues (kigi-file-utils halved), workspace upload
  module & dc_log, heap-profile uploader, auth-diagnostics uploader,
  session-analytics halves of feedback; local zero-egress observability
  preserved in new kigi-log crate (unified log, --debug firehose,
  subsystem file logs, opt-in instrumentation)
- announcements (crate, remote-settings fields, TUI surfaces)
- plugin marketplace (crate, sources/browse/CTA/extensions-modal tab);
  direct plugin install/uninstall/update via kigi-agent git_install kept
- relay/gateway/assets endpoints and features (agent relay, headless
  relay transport, gateway bridge, LeaderEnvUrls); leader IPC socket now
  ~/.kigi/leader.sock + KIGI_LEADER_SOCKET, no ws-url derivation
- functional types rehomed instead of deleted: PermissionMode ->
  kigi-config-types, McpInitStrategy -> kigi-mcp, PrCreationSource ->
  session signals, TerminalDiagnostics -> kigi-pager-render, agent_id ->
  shell util

Endpoints
- kigi-env rewritten: single production KigiEndpoints {coding_api_base_url
  https://api.kimi.com/coding/v1 (KIGI_CODE_BASE_URL), oauth_host
  https://auth.kimi.com (KIGI_OAUTH_HOST), update_base_url (GitHub
  Releases API), upgrade_page_url}; GrokBuildEnvironment enum deleted

Toolchain & workspace hygiene
- Rust 1.97.0 pinned; edition 2024; full cargo update; git2 hoisted to
  workspace at 0.21 (Option->Result API migration), quick-xml 0.41
- Root Cargo.toml hand-maintained (PRD §8.1): version 0.1.0 inherited by
  all members, members sorted, unused deps pruned
- cargo-deny advisories gate (deny.toml with documented transitive
  exceptions); CI workflow (check/clippy/fmt/deny/test, macOS+Linux)
- cross-crate test seams re-gated behind `test-support` cargo feature;
  insta snapshot baselines renamed to the kigi_tui prefix
- clippy --workspace --all-targets: zero warnings; fmt clean

Fixes surfaced by the port
- updater probe/installer divergence (bin/kigi vs bin/grok symlink set)
- idle model-metadata refresh dead under KIGI_CODE_BASE_URL override
  (new is_effective_coding_endpoint_url, loopback+override aware)
- macOS symlinked-TMPDIR fixture canonicalization (foreign_sessions,
  fast-worktree); RSS measurement tests serialized via serial_test

Docs & legal (Apache §4)
- NOTICE added (upstream attribution + change statement); THIRD-PARTY
  notices sustained; kigi-tools ported-code notices extended; README,
  CONTRIBUTING, SECURITY, AGENTS.md rewritten

Out of scope for M0 (tracked): Kimi auth/inference (M1), search/fetch,
command parity, config import (M2), Computer Hub excision & final
brand-token sweep (M2), distribution & self-update rewrite (M3).
This commit is contained in:
2026-07-17 05:31:01 -04:00
commit d6c20fc13f
2612 changed files with 1353757 additions and 0 deletions
@@ -0,0 +1,577 @@
//! Unit tests for the turn-finalize rails in [`super`] (`turn_completion`),
//! split out via `#[path]` to keep the module itself small.
use super::*;
use crate::app::agent::AgentState;
use crate::scrollback::block::RenderBlock;
use crate::scrollback::blocks::SessionEventBlock;
use crate::scrollback::state::ScrollbackState;
use std::path::PathBuf;
use std::time::Instant;
fn last_session_event(sb: &ScrollbackState) -> Option<SessionEvent> {
(0..sb.len())
.rev()
.find_map(|i| match sb.get(i).map(|e| &e.block) {
Some(RenderBlock::SessionEvent(b)) => Some(b.event.clone()),
_ => None,
})
}
/// A viewer in TurnRunning with an adopted prompt id, ready to be finalized.
fn running_viewer(prompt_id: &str) -> AgentView {
let mut agent = super::super::agent_view::test_agent_view(Some("s1"), PathBuf::from("/tmp"));
agent.attached_as_viewer = true;
agent.session.start_turn(&mut agent.scrollback);
agent.session.current_prompt_id = Some(prompt_id.into());
agent.turn_started_at = Some(Instant::now());
agent
}
/// A driver in TurnRunning with a local prompt id (default
/// `attached_as_viewer == false`).
fn running_driver(prompt_id: &str) -> AgentView {
let mut agent = super::super::agent_view::test_agent_view(Some("s1"), PathBuf::from("/tmp"));
agent.session.start_turn(&mut agent.scrollback);
agent.session.current_prompt_id = Some(prompt_id.into());
agent.turn_started_at = Some(Instant::now());
agent
}
#[test]
fn viewer_finalize_idles_and_pushes_completed_marker() {
let mut agent = running_viewer("p1");
let outcome =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
assert!(matches!(outcome, TerminalApply::ViewerFinalized));
assert!(agent.session.state.is_idle());
assert!(agent.session.current_prompt_id.is_none());
assert!(agent.turn_started_at.is_none());
assert!(matches!(
last_session_event(&agent.scrollback),
Some(SessionEvent::TurnCompleted { .. })
));
}
fn one_stop_group() -> Vec<(String, Vec<crate::scrollback::blocks::tool::HookRunEntry>)> {
use crate::scrollback::blocks::tool::{HookRunEntry, HookRunStatus};
vec![(
"stop".to_string(),
vec![HookRunEntry {
name: "global/notify".into(),
status: HookRunStatus::Success {
elapsed: std::time::Duration::from_millis(12),
},
output: None,
}],
)]
}
/// Stop-hook groups attached to the last session-event marker.
fn last_marker_groups(sb: &ScrollbackState) -> Option<usize> {
(0..sb.len())
.rev()
.find_map(|i| match sb.get(i).map(|e| &e.block) {
Some(RenderBlock::SessionEvent(b)) => Some(b.stop_hooks.len()),
_ => None,
})
}
fn count_lifecycle_blocks(sb: &ScrollbackState) -> usize {
use crate::scrollback::blocks::tool::ToolCallBlock;
(0..sb.len())
.filter(|i| {
matches!(
sb.get(*i).map(|e| &e.block),
Some(RenderBlock::ToolCall(ToolCallBlock::Lifecycle(_)))
)
})
.count()
}
#[test]
fn marker_push_consumes_matching_stop_hook_stash() {
let mut agent = running_driver("p1");
agent.pending_stop_hooks = Some(super::super::agent_view::PendingStopHooks {
prompt_id: Some("p1".into()),
groups: one_stop_group(),
});
push_turn_terminal_marker(
&mut agent,
Some(SessionEvent::TurnCompleted {
elapsed: Some(std::time::Duration::from_secs(2)),
}),
Some("p1"),
false,
);
assert_eq!(
last_marker_groups(&agent.scrollback),
Some(1),
"the stash must fold into the marker"
);
assert!(agent.pending_stop_hooks.is_none());
assert_eq!(count_lifecycle_blocks(&agent.scrollback), 0);
}
#[test]
fn marker_push_flushes_stale_stash_standalone() {
// A stash stamped with another turn's prompt id must not attach to
// this marker — it flushes as the legacy standalone block.
let mut agent = running_driver("p2");
agent.pending_stop_hooks = Some(super::super::agent_view::PendingStopHooks {
prompt_id: Some("p1".into()),
groups: one_stop_group(),
});
push_turn_terminal_marker(
&mut agent,
Some(SessionEvent::TurnCompleted {
elapsed: Some(std::time::Duration::from_secs(2)),
}),
Some("p2"),
false,
);
assert_eq!(
last_marker_groups(&agent.scrollback),
Some(0),
"a stale stash must not attach to the new marker"
);
assert_eq!(count_lifecycle_blocks(&agent.scrollback), 1);
assert!(agent.pending_stop_hooks.is_none());
}
#[test]
fn marker_without_ending_pid_flushes_stamped_stash_standalone() {
// A stamped stash can't be confirmed against a marker whose ending
// turn id is missing — it flushes standalone instead of folding into
// a marker it may not belong to.
let mut agent = running_driver("p1");
agent.pending_stop_hooks = Some(super::super::agent_view::PendingStopHooks {
prompt_id: Some("p1".into()),
groups: one_stop_group(),
});
push_turn_terminal_marker(
&mut agent,
Some(SessionEvent::TurnCompleted {
elapsed: Some(std::time::Duration::from_secs(2)),
}),
None,
false,
);
assert_eq!(
last_marker_groups(&agent.scrollback),
Some(0),
"an unconfirmable stamped stash must not attach to the marker"
);
assert_eq!(count_lifecycle_blocks(&agent.scrollback), 1);
assert!(agent.pending_stop_hooks.is_none());
}
#[test]
fn no_marker_flushes_stash_as_standalone_block() {
// Turn ends without a marker (bash turn / rate-limit UX): the held
// hooks still surface, in the legacy standalone form.
let mut agent = running_driver("p1");
agent.pending_stop_hooks = Some(super::super::agent_view::PendingStopHooks {
prompt_id: Some("p1".into()),
groups: one_stop_group(),
});
push_turn_terminal_marker(&mut agent, None, Some("p1"), false);
assert_eq!(count_lifecycle_blocks(&agent.scrollback), 1);
assert!(agent.pending_stop_hooks.is_none());
}
#[test]
fn viewer_finalize_consumes_stop_hook_stash() {
// A viewer that stashed hooks mid-turn folds them into the marker the
// finalize pushes.
let mut agent = running_viewer("p1");
agent.pending_stop_hooks = Some(super::super::agent_view::PendingStopHooks {
prompt_id: Some("p1".into()),
groups: one_stop_group(),
});
let _ = finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
assert_eq!(last_marker_groups(&agent.scrollback), Some(1));
assert!(agent.pending_stop_hooks.is_none());
}
#[test]
fn viewer_finalize_duplicate_terminal_is_noop() {
let mut agent = running_viewer("p1");
let _ = finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
let len_after_first = agent.scrollback.len();
// A duplicate/stale terminal for the now-finished turn does nothing.
let outcome =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
assert!(matches!(outcome, TerminalApply::Ignored));
assert!(agent.session.state.is_idle());
assert_eq!(
agent.scrollback.len(),
len_after_first,
"a duplicate terminal must not push a second marker"
);
}
#[test]
fn viewer_finalize_stop_reason_to_marker_mapping() {
// cancelled → Turn cancelled.
let mut agent = running_viewer("p1");
let _ =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("cancelled"), None, None);
assert!(matches!(
last_session_event(&agent.scrollback),
Some(SessionEvent::TurnCancelled { .. })
));
// error (+agentResult) → Turn failed carrying the error text.
let mut agent = running_viewer("p1");
let _ = finalize_turn_from_terminal(
&mut agent,
"s1",
Some("p1"),
Some("error"),
Some("boom"),
None,
);
match last_session_event(&agent.scrollback) {
Some(SessionEvent::TurnFailed { error, .. }) => assert_eq!(error, "boom"),
other => panic!("expected TurnFailed, got {other:?}"),
}
// rate_limit → finished, but no marker (not actionable from a viewer).
let mut agent = running_viewer("p1");
let _ =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("rate_limit"), None, None);
assert!(agent.session.state.is_idle());
assert!(
last_session_event(&agent.scrollback).is_none(),
"rate_limit must not push a marker on a viewer"
);
// unknown/other reason → Turn completed (the catch-all).
let mut agent = running_viewer("p1");
let _ =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("max_tokens"), None, None);
assert!(matches!(
last_session_event(&agent.scrollback),
Some(SessionEvent::TurnCompleted { .. })
));
}
#[test]
fn driver_arms_reconcile_and_does_not_finish() {
let mut agent = running_driver("p1");
let outcome =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("cancelled"), None, None);
assert!(matches!(outcome, TerminalApply::ReconcileArmed));
assert!(
matches!(agent.session.state, AgentState::TurnRunning),
"the driver's turn must NOT be finished — the PromptResponse RPC owns it"
);
let pending = agent
.pending_turn_end_reconcile
.as_ref()
.expect("the driver's awaited turn must arm a reconcile");
assert_eq!(pending.prompt_id, "p1");
assert_eq!(pending.stop_reason.as_deref(), Some("cancelled"));
}
#[test]
fn driver_mismatched_prompt_id_does_not_arm() {
// Stale/peer terminal must not arm reconcile on a different live turn.
let mut agent = running_driver("p1");
let outcome = finalize_turn_from_terminal(
&mut agent,
"s1",
Some("p-other"),
Some("end_turn"),
None,
None,
);
assert!(matches!(outcome, TerminalApply::Ignored));
assert!(agent.pending_turn_end_reconcile.is_none());
assert!(matches!(agent.session.state, AgentState::TurnRunning));
}
#[test]
fn driver_missing_prompt_id_arms_against_current_when_idle_in_turn() {
let mut agent = running_driver("p1");
let outcome = finalize_turn_from_terminal(&mut agent, "s1", None, Some("end_turn"), None, None);
assert!(matches!(outcome, TerminalApply::ReconcileArmed));
assert_eq!(
agent.pending_turn_end_reconcile.as_ref().unwrap().prompt_id,
"p1"
);
}
fn stream_agent_text(agent: &mut AgentView, text: &str) {
use crate::acp::meta::NotificationMeta;
use agent_client_protocol as acp;
let meta = NotificationMeta::default();
let _ = agent.session.tracker.handle_update(
acp::SessionUpdate::AgentMessageChunk(acp::ContentChunk::new(acp::ContentBlock::Text(
acp::TextContent::new(text),
))),
&meta,
&mut agent.scrollback,
);
}
/// Missing wire pid still arms lost-PR reconcile (full teardown
/// lives in `reconcile_overdue_turn_ends` / PromptResponse).
#[test]
fn repro_terminal_without_prompt_id_arms_reconcile_for_lost_pr() {
let mut agent = running_driver("p1");
stream_agent_text(&mut agent, "done");
let outcome = finalize_turn_from_terminal(&mut agent, "s1", None, Some("end_turn"), None, None);
assert!(matches!(outcome, TerminalApply::ReconcileArmed));
assert!(agent.pending_turn_end_reconcile.is_some());
assert!(
matches!(agent.session.state, AgentState::TurnRunning),
"driver stays TurnRunning until PR or overdue reconcile"
);
assert_eq!(
agent.session.tracker.activity(),
Some(crate::acp::tracker::TurnActivity::Responding)
);
}
/// Exact pid still arms (control).
#[test]
fn recovery_mode_matching_turn_completed_arms_reconcile_for_lost_pr() {
let mut agent = running_driver("p1");
stream_agent_text(&mut agent, "done");
let outcome =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
assert!(matches!(outcome, TerminalApply::ReconcileArmed));
assert!(matches!(agent.session.state, AgentState::TurnRunning));
assert!(agent.pending_turn_end_reconcile.is_some());
}
/// Re-arm same pid keeps earliest received_at (does not extend grace forever).
#[test]
fn driver_rearm_same_pid_preserves_received_at() {
let mut agent = running_driver("p1");
let _ = finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
let first = agent
.pending_turn_end_reconcile
.as_ref()
.unwrap()
.received_at;
std::thread::sleep(std::time::Duration::from_millis(5));
let _ = finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("end_turn"), None, None);
let second = agent
.pending_turn_end_reconcile
.as_ref()
.unwrap()
.received_at;
assert_eq!(first, second);
}
// ── EndLine snapshots: work suffix + between-turns status window ──
use crate::scrollback::blocks::EndWork;
fn insert_bg_task(agent: &mut AgentView, task_id: &str, is_monitor: bool) {
agent.session.bg_tasks.insert(
task_id.into(),
crate::app::agent::BgTaskState {
task_id: task_id.into(),
tool_call_id: format!("call-{task_id}"),
command: "sleep 5".into(),
description: None,
cwd: "/tmp".into(),
output_file: "/tmp/out".into(),
status: crate::app::agent::BgTaskStatus::Running,
start_time: std::time::SystemTime::now(),
end_time: None,
exit_code: None,
signal: None,
stdout: String::new(),
stdout_line_count: 0,
truncated: false,
pending_kill: false,
kill_requested_at: None,
scrollback_entry_id: None,
is_monitor,
restored_from_replay: false,
},
);
}
/// The newest session-event marker block.
fn last_marker_block(agent: &AgentView) -> &SessionEventBlock {
(0..agent.scrollback.len())
.rev()
.find_map(|i| match agent.scrollback.get(i).map(|e| &e.block) {
Some(RenderBlock::SessionEvent(b)) => Some(b),
_ => None,
})
.expect("a session-event marker must exist")
}
#[test]
fn real_end_marker_snapshots_running_work() {
let mut agent = running_driver("p1");
insert_bg_task(&mut agent, "bg-1", false);
push_turn_terminal_marker(
&mut agent,
Some(SessionEvent::TurnCompleted {
elapsed: Some(std::time::Duration::from_secs(2)),
}),
Some("p1"),
false,
);
let block = last_marker_block(&agent);
assert!(!block.parked);
assert_eq!(block.prompt_id.as_deref(), Some("p1"));
assert_eq!(
block.end_work,
Some(EndWork {
running_commands: 1,
..EndWork::default()
})
);
assert_eq!(
block.marker_text(),
"Worked for 2.0s. 1 command still running."
);
assert!(
agent.end_work_announced,
"announcing work opens the between-turns status window"
);
}
#[test]
fn workless_marker_stays_legacy_and_closes_window() {
let mut agent = running_driver("p1");
agent.end_work_announced = true;
push_turn_terminal_marker(
&mut agent,
Some(SessionEvent::TurnCompleted {
elapsed: Some(std::time::Duration::from_secs(2)),
}),
Some("p1"),
false,
);
let block = last_marker_block(&agent);
assert!(block.end_work.is_none(), "legacy marker: no work suffix");
assert_eq!(block.marker_text(), "Worked for 2.0s.");
assert!(
!agent.end_work_announced,
"a workless marker proves nothing is running — window closed"
);
}
#[test]
fn marker_snapshot_never_mutates() {
// The suffix is a push-time snapshot: later completions re-emit a
// fresh status line instead of editing the marker.
let mut agent = running_driver("p1");
insert_bg_task(&mut agent, "bg-1", false);
push_turn_terminal_marker(
&mut agent,
Some(SessionEvent::TurnCompleted {
elapsed: Some(std::time::Duration::from_secs(2)),
}),
Some("p1"),
false,
);
agent.session.bg_tasks.get_mut("bg-1").unwrap().status = crate::app::agent::BgTaskStatus::Done;
assert_eq!(
last_marker_block(&agent).marker_text(),
"Worked for 2.0s. 1 command still running.",
"the marker keeps its push-time counts"
);
}
// ── Send-now cancel marker suppression (viewer finalize rail) ────────
/// A viewer finalizing a `send_now`-stamped `cancelled` terminal pushes no marker.
#[test]
fn viewer_finalize_suppresses_send_now_cancel_marker() {
let mut agent = running_viewer("p1");
let outcome = finalize_turn_from_terminal(
&mut agent,
"s1",
Some("p1"),
Some("cancelled"),
None,
Some("send_now"),
);
assert!(matches!(outcome, TerminalApply::ViewerFinalized));
assert!(agent.session.state.is_idle(), "the turn still finishes");
assert!(
last_session_event(&agent.scrollback).is_none(),
"a send-now cancel pushes no marker on a viewer"
);
// A non-send-now trigger keeps the marker even with a local expectation armed (wire is authoritative).
let mut agent = running_viewer("p1");
agent.expect_send_now_cancel = Some("p-mine".into());
let _ = finalize_turn_from_terminal(
&mut agent,
"s1",
Some("p1"),
Some("cancelled"),
None,
Some("ctrl_c"),
);
assert!(matches!(
last_session_event(&agent.scrollback),
Some(SessionEvent::TurnCancelled { .. })
));
// Older shell (no meta): the armed expectation is the fallback.
let mut agent = running_viewer("p1");
agent.expect_send_now_cancel = Some("p-mine".into());
let _ =
finalize_turn_from_terminal(&mut agent, "s1", Some("p1"), Some("cancelled"), None, None);
assert!(
last_session_event(&agent.scrollback).is_none(),
"the armed expectation suppresses the marker without wire meta"
);
assert!(
agent.expect_send_now_cancel.is_none(),
"the expectation is consumed on the viewer finalize"
);
}
/// The driver arm records the broadcast's `cancelTrigger` for a lost-RPC reconcile.
#[test]
fn driver_arm_records_cancel_trigger_for_reconcile() {
let mut agent = running_driver("p1");
let outcome = finalize_turn_from_terminal(
&mut agent,
"s1",
Some("p1"),
Some("cancelled"),
None,
Some("send_now"),
);
assert!(matches!(outcome, TerminalApply::ReconcileArmed));
assert_eq!(
agent
.pending_turn_end_reconcile
.as_ref()
.and_then(|p| p.cancel_trigger.as_deref()),
Some("send_now")
);
}