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,134 @@
#!/usr/bin/env node
// Assemble the six per-platform npm packages prior to `npm publish`.
//
// For each supported (platform, arch) target this:
// 1. Brotli-compresses the built binary into `../grok-<platform>/bin/<bin>.br`
// 2. Stamps the sub-package's version to match the meta package
//
// Each per-platform package is its own npm publish target. The meta package
// (`@xai-official/grok`) lists all six as `optionalDependencies` pinned to
// the same version; npm installs only the one matching the host's
// `os` + `cpu` filters.
//
// Why brotli? npm's tarball ceiling is ~200 MB and the raw grok binary is
// 100150 MB per platform. Brotli at max quality cuts that to 3040 MB,
// leaves plenty of headroom for binary growth, and is decoded by Node's
// built-in zlib.brotliDecompressSync (no native deps required).
//
// Source paths come from environment variables (set in CI) and fall back to
// the default cargo target dirs for local testing.
const fs = require('fs');
const path = require('path');
const { promisify } = require('util');
const zlib = require('zlib');
const brotliCompress = promisify(zlib.brotliCompress);
const xaiRoot = process.env.XAI_ROOT || path.resolve(__dirname, '..', '..', '..', '..', '..');
const npmRoot = path.resolve(__dirname, '..', '..');
const NOTICES_SOURCE = path.resolve(
npmRoot, '..', '..', 'kigi-tools', 'THIRD_PARTY_NOTICES.md');
const NOTICES_NAME = 'THIRD_PARTY_NOTICES.md';
const META_PKG_JSON = path.resolve(__dirname, '..', 'package.json');
const meta = JSON.parse(fs.readFileSync(META_PKG_JSON, 'utf8'));
const VERSION = meta.version;
function ensureDir(p) { fs.mkdirSync(path.dirname(p), { recursive: true }); }
async function packPlatform({ platform, arch, envVar, defaultSource, binName }) {
const pkgDir = path.join(npmRoot, `grok-${platform}-${arch}`);
const pkgJsonPath = path.join(pkgDir, 'package.json');
if (!fs.existsSync(pkgJsonPath)) {
console.error(`[assemble] Missing per-platform package at ${pkgDir}`);
return false;
}
const source = process.env[envVar] || defaultSource;
if (!fs.existsSync(source)) {
console.error(`[assemble] Missing binary for ${platform}-${arch}: ${source}`);
console.error(` Set ${envVar} or build to the default location.`);
return false;
}
// Stamp the sub-package's version to match the meta package.
const subPkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8'));
subPkg.version = VERSION;
fs.writeFileSync(pkgJsonPath, JSON.stringify(subPkg, null, 4) + '\n');
if (!fs.existsSync(NOTICES_SOURCE)) {
console.error(`[assemble] Missing third-party notices file: ${NOTICES_SOURCE}`);
return false;
}
fs.copyFileSync(NOTICES_SOURCE, path.join(pkgDir, NOTICES_NAME));
// Brotli-compress into the sub-package's bin/.
const outBr = path.join(pkgDir, 'bin', `${binName}.br`);
ensureDir(outBr);
const raw = fs.readFileSync(source);
const compressed = await brotliCompress(raw, {
params: { [zlib.constants.BROTLI_PARAM_QUALITY]: zlib.constants.BROTLI_MAX_QUALITY },
});
fs.writeFileSync(outBr, compressed);
console.log(
`[assemble] grok-${platform}-${arch}@${VERSION}: ` +
`${(raw.length / 1048576).toFixed(1)} MB -> ${(compressed.length / 1048576).toFixed(1)} MB ` +
`(${path.relative(npmRoot, outBr)})`
);
return true;
}
async function main() {
const targets = [
{
platform: 'darwin', arch: 'arm64', binName: 'grok',
envVar: 'KIGI_DARWIN_ARM64',
defaultSource: path.join(xaiRoot, 'target', 'release', 'kigi-tui'),
},
{
platform: 'darwin', arch: 'x64', binName: 'grok',
envVar: 'KIGI_DARWIN_X64',
defaultSource: path.join(xaiRoot, 'target', 'x86_64-apple-darwin', 'release', 'kigi-tui'),
},
{
platform: 'linux', arch: 'x64', binName: 'grok',
envVar: 'KIGI_LINUX_X64',
defaultSource: path.join(xaiRoot, 'target',
'explorer_cross_x86_64-unknown-linux-gnu',
'x86_64-unknown-linux-gnu', 'release', 'kigi-tui'),
},
{
platform: 'linux', arch: 'arm64', binName: 'grok',
envVar: 'KIGI_LINUX_ARM64',
defaultSource: path.join(xaiRoot, 'target',
'explorer_cross_aarch64-unknown-linux-gnu',
'aarch64-unknown-linux-gnu', 'release', 'kigi-tui'),
},
{
platform: 'win32', arch: 'x64', binName: 'grok.exe',
envVar: 'KIGI_WIN32_X64',
defaultSource: path.join(xaiRoot, 'target', 'x86_64-pc-windows-msvc', 'release', 'kigi-tui.exe'),
},
{
platform: 'win32', arch: 'arm64', binName: 'grok.exe',
envVar: 'KIGI_WIN32_ARM64',
defaultSource: path.join(xaiRoot, 'target', 'aarch64-pc-windows-msvc', 'release', 'kigi-tui.exe'),
},
];
// Compress in parallel — brotliCompress runs on the libuv thread pool so
// calls genuinely overlap (set UV_THREADPOOL_SIZE>=6 in CI for full
// parallelism; Node's default pool size is 4).
const results = await Promise.all(targets.map(packPlatform));
const failed = results.filter(r => !r).length;
if (failed > 0) {
console.error(`[assemble] ${failed} target(s) failed.`);
process.exit(1);
}
console.log(`[assemble] All 6 per-platform packages assembled at version ${VERSION}.`);
}
main().catch((err) => { console.error(err); process.exit(1); });