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
+419
View File
@@ -0,0 +1,419 @@
//! Built-in files extracted to `~/.kigi/` on startup.
const BUNDLED_FILES: &[(&str, &str)] = &[("README.md", include_str!("../README.md"))];
const HELP_SKILL_MD: &str = include_str!("../skills/help/SKILL.md");
const CREATE_SKILL_MD: &str = include_str!("../skills/create-skill/SKILL.md");
const CODE_REVIEW_SKILL_MD: &str = include_str!("../skills/code-review/SKILL.md");
const IMAGINE_SKILL_MD: &str = include_str!("../skills/imagine/SKILL.md");
/// Compiled-in SKILL.md content for `/check-work` (available to headless mode).
pub const CHECK_SKILL_MD: &str = include_str!("../skills/check-work/SKILL.md");
/// Compiled-in SKILL.md content for headless `--best-of-n` (not extracted as
/// a bundled skill).
pub const BEST_OF_N_SKILL_MD: &str = include_str!("../skills/best-of-n/SKILL.md");
/// Legacy bundled skill names (renamed or removed).
///
/// These directories under `~/.kigi/skills/` will be deleted on startup
/// (during bundled file extraction). This ensures that when a bundled
/// skill is renamed (e.g. `check` → `check-work`), the old slash command
/// does not linger on users' machines after an upgrade.
///
/// Important behavior:
/// - Deletion happens **early** in `extract_bundled_files`, before we write
/// any current bundled skills.
/// - We **never** delete a name that is currently present in `BUNDLED_SKILLS`
/// (see `remove_legacy_bundled_skills`).
///
/// This means:
/// - If you later re-introduce a skill with a name that is still in this
/// legacy list (e.g. you ship a new "check" skill years later), the legacy
/// cleanup will **skip** it and the new skill will be created normally.
/// - The legacy list is a "delete old user copies of names we no longer ship",
/// not a permanent blacklist.
///
/// Lifecycle / maintenance:
/// - Add an old name here when you rename/remove a bundled skill.
/// - Once the directory is gone on a user's machine, further checks are
/// cheap no-ops.
/// - You do **not** have to remove entries immediately. It is safe to leave
/// them for many releases.
/// - After the rename has had time to propagate, you **may** clean old
/// strings out of this list for hygiene.
const LEGACY_BUNDLED_SKILL_NAMES: &[&str] = &["check", "best-of-n", "docx", "pptx", "xlsx"];
/// All bundled skill SKILL.md files. Single source of truth used by both
/// the full extraction path (version bump) and the missing-file fast path
/// (same version). Adding a new skill here is all that's needed.
///
/// When renaming a bundled skill (e.g. "check" → "check-work"), also add the
/// old name to `LEGACY_BUNDLED_SKILL_NAMES` so `remove_legacy_bundled_skills`
/// will clean up the old directory on user machines on the next upgrade.
///
/// See the docs on `LEGACY_BUNDLED_SKILL_NAMES` for the full lifecycle
/// (including when it is safe/optional to remove old entries later).
const BUNDLED_SKILLS: &[(&str, &str)] = &[
("help", HELP_SKILL_MD),
("create-skill", CREATE_SKILL_MD),
("code-review", CODE_REVIEW_SKILL_MD),
("imagine", IMAGINE_SKILL_MD),
("check-work", CHECK_SKILL_MD),
];
/// True when a discovered skill is the copy `extract_bundled_files` wrote to
/// `<kigi_home>/skills/<name>/SKILL.md`. Exact-path (not prefix) so a
/// user-authored skill that reuses a bundled name — even elsewhere under
/// `<kigi_home>/skills/` — is never labeled bundled. Lives beside the
/// extraction code so the target layout and this predicate move together.
/// Used by inspect, which otherwise sees extracted copies as user skills.
pub(crate) fn is_extracted_bundled_skill(
name: &str,
path: &std::path::Path,
kigi_home: &std::path::Path,
) -> bool {
BUNDLED_SKILLS.iter().any(|&(n, _)| n == name)
&& path == kigi_home.join("skills").join(name).join("SKILL.md")
}
/// Resolve the content for a skill, applying any name-specific transforms.
fn resolve_skill_content(name: &str, raw: &str, kigi_home: &std::path::Path) -> String {
match name {
// Help skill needs path substitution so absolute paths work.
"help" => {
let kigi_home_str = format!("{}/", kigi_home.to_string_lossy());
raw.replace("~/.kigi/", &kigi_home_str)
}
_ => raw.to_string(),
}
}
/// Extract bundled files to `~/.kigi/` on startup.
///
/// Full extraction runs on every version bump. On same-version startups,
/// a lightweight check ensures all expected skill files exist on disk —
/// any missing files are extracted individually.
///
/// Legacy/renamed bundled skills (see `LEGACY_BUNDLED_SKILL_NAMES`) are
/// always cleaned up first so that old slash commands disappear after
/// a rename (e.g. the previous `/check` after the move to `/check-work`).
pub fn extract_bundled_files(kigi_home: &std::path::Path) {
// Always remove legacy/renamed bundled skills first (e.g. the old
// `check` directory after the rename to `check-work`). This runs on
// every startup so users get cleaned up even without hitting a
// version-bump marker change.
remove_legacy_bundled_skills(kigi_home);
let version = kigi_version::VERSION;
let marker = kigi_home.join(".metadata_version");
if let Ok(existing) = std::fs::read_to_string(&marker)
&& existing.trim() == version
{
// Same version — only extract skill files that are missing on disk.
// This handles skills added between version bumps.
extract_missing_skills(kigi_home);
return;
}
let _ = std::fs::create_dir_all(kigi_home);
// Clean up cached changelog files from previous version so
// /release-notes fetches fresh content for the new version.
for stale in &["CHANGELOG.json", "CHANGELOG.md"] {
let _ = std::fs::remove_file(kigi_home.join(stale));
}
for &(filename, content) in BUNDLED_FILES {
if let Err(e) = std::fs::write(kigi_home.join(filename), content) {
tracing::debug!(error = %e, filename, "Failed to extract bundled file");
}
}
// Skill SKILL.md files.
for &(name, raw) in BUNDLED_SKILLS {
let skill_dir = kigi_home.join("skills").join(name);
let _ = std::fs::create_dir_all(&skill_dir);
let content = resolve_skill_content(name, raw, kigi_home);
if let Err(e) = std::fs::write(skill_dir.join("SKILL.md"), content) {
tracing::debug!(error = %e, name, "Failed to write skill");
}
}
let _ = std::fs::write(&marker, version);
tracing::debug!(version, "Extracted bundled files");
}
/// Extract only missing skill SKILL.md files (same-version fast path).
/// Iterates `BUNDLED_SKILLS` so adding a new skill there is sufficient.
fn extract_missing_skills(kigi_home: &std::path::Path) {
for &(name, raw) in BUNDLED_SKILLS {
let skill_md = kigi_home.join("skills").join(name).join("SKILL.md");
if skill_md.exists() {
continue;
}
let _ = std::fs::create_dir_all(skill_md.parent().unwrap());
let content = resolve_skill_content(name, raw, kigi_home);
let _ = std::fs::write(&skill_md, content);
}
}
/// Remove directories for legacy/renamed bundled skills (e.g. old `check`
/// after it was renamed to `check-work`).
///
/// Called on every startup from `extract_bundled_files`. Safe and idempotent.
///
/// Key guarantees (see `LEGACY_BUNDLED_SKILL_NAMES` docs for details):
/// - If a name is still present in `BUNDLED_SKILLS`, we deliberately skip
/// deletion. This allows safe re-use of a skill name in the future.
/// - If the target directory no longer exists, this is a trivial no-op.
fn remove_legacy_bundled_skills(kigi_home: &std::path::Path) {
remove_legacy_skills(kigi_home, LEGACY_BUNDLED_SKILL_NAMES, BUNDLED_SKILLS);
}
/// Core implementation, extracted for testability.
fn remove_legacy_skills(
kigi_home: &std::path::Path,
legacy_names: &[&str],
bundled_skills: &[(&str, &str)],
) {
for name in legacy_names {
// Safety: Never delete a name that we are currently shipping.
// This protects against re-introducing a skill name that still has
// an entry in the legacy list.
if bundled_skills.iter().any(|(n, _)| *n == *name) {
continue;
}
let dir = kigi_home.join("skills").join(name);
if dir.exists() {
if let Err(e) = std::fs::remove_dir_all(&dir) {
tracing::debug!(error = %e, name, "Failed to remove legacy bundled skill");
} else {
tracing::debug!(name, "Removed legacy bundled skill directory");
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn version_bump_re_extracts_all_files() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
extract_bundled_files(home);
for &(filename, _) in BUNDLED_FILES {
std::fs::write(home.join(filename), "old").unwrap();
}
std::fs::write(home.join("skills/help/SKILL.md"), "old").unwrap();
for name in ["check-work", "imagine", "code-review"] {
std::fs::write(home.join(format!("skills/{name}/SKILL.md")), "old").unwrap();
}
std::fs::write(home.join(".metadata_version"), "0.0.0-stale").unwrap();
// Simulate legacy skills that should be cleaned up.
for name in ["check", "best-of-n", "docx", "pptx", "xlsx"] {
std::fs::create_dir_all(home.join(format!("skills/{name}"))).unwrap();
std::fs::write(
home.join(format!("skills/{name}/SKILL.md")),
"old legacy skill",
)
.unwrap();
}
extract_bundled_files(home);
for &(filename, _) in BUNDLED_FILES {
assert_ne!(
std::fs::read_to_string(home.join(filename)).unwrap(),
"old",
"{filename} was not re-extracted after version bump"
);
}
assert_ne!(
std::fs::read_to_string(home.join("skills/help/SKILL.md")).unwrap(),
"old"
);
for name in ["check-work", "imagine", "code-review"] {
assert_ne!(
std::fs::read_to_string(home.join(format!("skills/{name}/SKILL.md"))).unwrap(),
"old",
"{name} skill was not re-extracted after version bump"
);
}
// Legacy skill directories must have been removed (the key part of
// supporting renames like check → check-work without leaving orphans).
for name in ["check", "best-of-n", "docx", "pptx", "xlsx"] {
assert!(
!home.join(format!("skills/{name}")).exists(),
"legacy '{name}' skill directory should have been deleted during version bump"
);
}
}
#[test]
fn office_skills_not_bundled() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
extract_bundled_files(home);
// Former office document skills must NOT be extracted as bundled.
for name in ["docx", "pptx", "xlsx"] {
assert!(
!home.join(format!("skills/{name}")).exists(),
"{name} should not be a bundled skill"
);
}
}
#[tokio::test]
async fn help_skill_discovered_by_skill_pipeline() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
extract_bundled_files(home);
let workspace = tmp.path().join("workspace");
std::fs::create_dir_all(workspace.join(".kigi").join("skills").join("help")).unwrap();
std::fs::copy(
home.join("skills/help/SKILL.md"),
workspace.join(".kigi/skills/help/SKILL.md"),
)
.unwrap();
let skills = kigi_agent::prompt::skills::list_skills(
Some(workspace.to_str().unwrap()),
&Default::default(),
kigi_agent::prompt::skills::CompatConfig::default(),
)
.await;
let help = skills.iter().find(|s| s.name == "help");
assert!(
help.is_some(),
"help skill not found. skills: {:?}",
skills.iter().map(|s| &s.name).collect::<Vec<_>>()
);
let help = help.unwrap();
assert!(help.description.contains("configuration"));
assert!(help.user_invocable);
}
// ---------------------------------------------------------------------
// Tests for legacy bundled skill removal (the rename migration system)
// ---------------------------------------------------------------------
#[test]
fn remove_legacy_deletes_old_skill_when_not_currently_shipped() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
// Simulate an old legacy "check" directory from before a rename.
let legacy_dir = home.join("skills/check");
std::fs::create_dir_all(&legacy_dir).unwrap();
std::fs::write(legacy_dir.join("SKILL.md"), "old check").unwrap();
// "check" is in legacy list but NOT in current BUNDLED_SKILLS
remove_legacy_skills(home, &["check"], BUNDLED_SKILLS);
assert!(
!legacy_dir.exists(),
"legacy skill directory should have been deleted"
);
}
#[test]
fn remove_legacy_does_not_delete_when_name_is_reused_in_current_bundled() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
// User still has an old "check" directory.
let legacy_dir = home.join("skills/check");
std::fs::create_dir_all(&legacy_dir).unwrap();
std::fs::write(legacy_dir.join("SKILL.md"), "user had old check").unwrap();
// Simulate the situation where we later re-ship a skill named "check".
// In this case the legacy entry should be ignored.
let fake_bundled: &[(&str, &str)] = &[("check", "fake content"), ("help", "help")];
remove_legacy_skills(home, &["check"], fake_bundled);
// The directory must still exist (we did not nuke the user's copy
// or a skill we're about to (re)create).
assert!(
legacy_dir.exists(),
"should not delete a name that is currently being shipped"
);
}
#[test]
fn remove_legacy_handles_multiple_names_some_current_some_legacy() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
std::fs::create_dir_all(home.join("skills/old-renamed")).unwrap();
std::fs::write(home.join("skills/old-renamed/SKILL.md"), "old").unwrap();
std::fs::create_dir_all(home.join("skills/another-legacy")).unwrap();
std::fs::write(home.join("skills/another-legacy/SKILL.md"), "old2").unwrap();
// Current bundled skills include one name that used to be legacy
let current: &[(&str, &str)] = &[("another-legacy", "now shipping again")];
// Legacy list contains both the truly removed one and the reintroduced one
remove_legacy_skills(home, &["old-renamed", "another-legacy"], current);
assert!(
!home.join("skills/old-renamed").exists(),
"truly legacy name should be removed"
);
assert!(
home.join("skills/another-legacy").exists(),
"reintroduced name must not be deleted"
);
}
#[test]
fn remove_legacy_is_noop_when_directory_does_not_exist() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
// No directory exists for the legacy name
remove_legacy_skills(home, &["check"], BUNDLED_SKILLS);
// Should not panic or create anything
assert!(!home.join("skills/check").exists());
}
#[test]
fn legacy_cleanup_runs_even_on_same_version_fast_path() {
let tmp = tempfile::tempdir().unwrap();
let home = tmp.path();
// First run: extract current state
extract_bundled_files(home);
// Simulate user still having an old legacy directory
let legacy_dir = home.join("skills/check");
std::fs::create_dir_all(&legacy_dir).unwrap();
std::fs::write(legacy_dir.join("SKILL.md"), "stale").unwrap();
// Force the "same version" fast path by writing the current version marker
let version = kigi_version::VERSION;
std::fs::write(home.join(".metadata_version"), version).unwrap();
// This should still run legacy cleanup even though we're in fast path
extract_bundled_files(home);
assert!(
!legacy_dir.exists(),
"legacy cleanup must run even on same-version fast path"
);
}
}