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,142 @@
//! Minimal-mode welcome card.
//!
//! Minimal skips the full-screen welcome view entirely, so the start of a
//! session is otherwise invisible — you land straight at the prompt. To make a
//! fresh session obvious (and on `/new` / `Ctrl+N`), this commits a compact,
//! rounded card once into native scrollback: the braille logo, the version, the
//! cwd, the model, and a one-line hint. It mirrors the full-TUI hero box's style
//! (rounded dim border + logo) without its menu/onboarding.
//!
//! It is printed via [`kigi_ratatui_inline::Terminal::insert_before`] — the same
//! one-shot mechanism the commit pipeline uses — gated on an `AppView` flag set
//! at session creation, so it prints exactly once per session and re-prints when
//! a new session starts.
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, BorderType, Borders, Widget};
use kigi_tui::app::PagerTerminal;
use kigi_tui::app::app_view::{ActiveView, AppView};
use kigi_tui::minimal_api;
use kigi_tui::theme::Theme;
/// Commit the welcome card when one is pending (set at session start / `/new`).
///
/// Called at the top of the minimal draw, before `commit_active`, so the card
/// lands above the first conversation block in native scrollback.
pub fn maybe_commit_welcome(app: &mut AppView, terminal: &mut PagerTerminal) {
if !minimal_api::minimal_welcome_pending(app) {
return;
}
let width = terminal.viewport_area().width;
// Too narrow to draw a bordered card — leave the flag set and retry next
// frame (e.g. during an initial 0-width probe).
if width < 8 {
return;
}
// NB: the pending flag is cleared only after the `insert_before` at the
// bottom SUCCEEDS — clearing it up front meant a failed insert silently
// dropped the card forever (bugbot). A failed frame retries next draw.
// Reset the live viewport to the TOP of the screen and clear what's visible,
// so the welcome card commits at row 0 and the app "owns" the window. The
// viewport is not bottom-pinned, so subsequent commits flow downward from
// here. Pre-existing native scrollback is untouched — scrolling up still
// shows whatever was there before.
let live_h = terminal.viewport_area().height;
terminal.set_viewport_area(ratatui::layout::Rect {
x: 0,
y: 0,
width,
height: live_h,
});
let _ = terminal.clear();
let theme = Theme::current();
let version = kigi_version::VERSION;
let (cwd, model) = match &app.active_view {
ActiveView::Agent(id) => {
let agent = app.agents.get(id);
(
agent
.map(|a| a.session.cwd.display().to_string())
.unwrap_or_default(),
agent.and_then(|a| a.session.models.current_model_name()),
)
}
_ => (app.cwd.display().to_string(), None),
};
// Info lines below the logo: title + version, cwd, optional model, hint.
let mut info: Vec<Line<'static>> = Vec::new();
info.push(Line::from(vec![
Span::styled(
"Grok Build",
Style::default()
.fg(theme.accent_user)
.add_modifier(Modifier::BOLD),
),
Span::styled(format!(" v{version}"), theme.muted()),
]));
if !cwd.is_empty() {
info.push(Line::from(Span::styled(cwd, theme.muted())));
}
if let Some(model) = model {
info.push(Line::from(Span::styled(
format!("Model · {model}"),
theme.muted(),
)));
}
info.push(Line::from(Span::styled("/help for commands", theme.dim())));
let logo_lines = minimal_api::compact_logo_line_count();
// logo (+ a blank separator row) when present, then the info lines, wrapped
// in a border with one row of vertical padding top and bottom.
let logo_block = if logo_lines > 0 { logo_lines + 1 } else { 0 };
let height = 2 + 1 + logo_block + info.len() as u16 + 1;
// RGB themes: blend a soft border. Terminal-native (both Reset): fall
// through to Reset so the terminal default fg draws the chrome.
let border_color = kigi_tui::render::color::blend_color(theme.bg_base, theme.gray_dim, 0.45)
.unwrap_or(theme.gray_dim);
let inserted = terminal.insert_before(height, move |buf| {
let area = buf.area;
Block::new()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(border_color))
.render(area, buf);
let inner_x = area.x + 2;
let inner_w = area.width.saturating_sub(4);
// Top border + one row of vertical padding.
let mut y = area.y + 2;
if logo_lines > 0 {
let logo_area = ratatui::layout::Rect {
x: area.x + 1,
y,
width: area.width.saturating_sub(2),
height: logo_lines,
};
minimal_api::render_compact_logo(logo_area, buf, &Theme::current());
y += logo_lines + 1;
}
for line in &info {
buf.set_line(inner_x, y, line, inner_w);
y += 1;
}
});
if inserted.is_err() {
// Terminal write failed — keep the flag pending so the card retries on
// the next frame instead of being dropped forever.
return;
}
minimal_api::set_minimal_welcome_pending(app, false);
// Trailing gap, matching every committed block, so the first conversation
// block is separated from the card.
super::commit::insert_gap(terminal);
}