F3: Kimi inference pipeline + full grok cloud-surface excision

Sampler / inference (PRD F3):
- kimi_compat.rs: single adaptation point for the Kimi chat/completions
  dialect (thinking-field mapping, model_id stripping, empty-content
  tool-call message fix, stream_options.include_usage), with kimi-cli
  source citations
- Rate-limit handling reworked for Kimi/Moonshot semantics; UA kigi/{version}
- /models replaces the xAI models-v2 endpoint everywhere; idle model
  refresh carries X-Msh-* device headers only (X-XAI-Token-Auth and
  x-grok-client-mode/CLIENT_MODE_HEADER machinery deleted)

Cloud-surface excision (PRD §5, zero-egress):
- remote/ conversations lane, cli-chat-proxy-types crate, prod/ dir,
  share command, credit bar: deleted (single local session lane;
  paginate() replaces merge_and_paginate)
- Subscription/tier gate stack deleted end-to-end: AppView
  gate/tier/team/ZDR fields, app/subscription.rs watch loop,
  dispatch/billing.rs paywall + SuperGrok upsell, free-usage-exhausted
  chain, tier-restricted commands, GateInfo, RemoteSettings gate fields,
  SettingsUpdateNotification gate fields
- /privacy + coding-data-sharing setting deleted (backed by a dead xAI
  RPC; Kigi is zero-egress — nothing to share or retain remotely)

Auth UX correctness (user-reported):
- Device-flow fixtures now mirror the live Kimi payload shape
  (https://www.kimi.com/code/authorize_device?user_code=..., verified
  against auth.kimi.com); the fabricated auth.kimi.com/device?code=...
  URLs are gone
- open_browser_detached is a no-op under cfg(test): unit tests drove
  wiremock fixture URLs into the real browser (root cause of the
  "garbage mock link" ABCD-1234 tabs)
- Welcome/pager-minimal rebrand: Grok Build -> Kigi, grok.com ->
  kimi.com, "Sign in to Grok" -> "Sign in to Kimi"
This commit is contained in:
ZacharyZhang-NY committed 2026-07-17 16:05:51 -04:00
1 parent fe1f885bb3
commit ea0ce9d15f
231 files changed
+4730 -26358

No files matched your search

@@ -41,7 +41,6 @@ pub mod new;
pub mod personas;
pub mod plan;
pub mod plugin;
pub mod privacy;
pub mod queue;
pub mod recap;
pub mod release_notes;
@@ -53,7 +52,6 @@ pub mod screen_mode_switch;
pub mod scroll_debug;
pub mod session_info;
pub mod settings_cmd;
pub mod share;
pub mod tasks;
pub mod terminal_setup;
pub mod theme;
@@ -98,7 +96,6 @@ pub fn builtin_commands() -> Vec<Arc<dyn SlashCommand>> {
Arc::new(plugin::HooksCommand),
Arc::new(plugin::PluginsCommand),
Arc::new(plugin::SkillsCommand),
Arc::new(share::ShareCommand),
Arc::new(session_info::SessionInfoCommand),
Arc::new(rename::RenameCommand),
Arc::new(dashboard::DashboardCommand),
@@ -120,7 +117,6 @@ pub fn builtin_commands() -> Vec<Arc<dyn SlashCommand>> {
Arc::new(timeline::TimelineCommand),
Arc::new(toggle_mouse_reporting::ToggleMouseReportingCommand),
Arc::new(settings_cmd::SettingsCommand),
Arc::new(privacy::PrivacyCommand),
Arc::new(rewind::RewindCommand),
Arc::new(jump::JumpCommand),
Arc::new(login::LoginCommand),
@@ -455,83 +451,24 @@ mod tests {
usage::UsageCommand.run(&mut ctx, args)
}
#[test]
fn usage_no_args_returns_show_usage() {
fn usage_returns_show_usage() {
assert!(matches!(
run_usage(""),
CommandResult::Action(Action::ShowUsage)
));
}
#[test]
fn usage_show_returns_show_usage() {
fn usage_ignores_stray_args() {
assert!(matches!(
run_usage("show"),
run_usage(" anything "),
CommandResult::Action(Action::ShowUsage)
));
}
#[test]
fn usage_manage_returns_open_url() {
match run_usage("manage") {
CommandResult::Action(Action::OpenUrl(url)) => {
assert_eq!(url, "https://grok.com/?_s=usage");
}
other => panic!("expected Action(OpenUrl), got {other:?}"),
}
}
#[test]
fn usage_invalid_arg_returns_error() {
match run_usage("delete") {
CommandResult::Error(msg) => {
assert!(msg.contains("delete"), "got: {msg}");
}
other => panic!("expected Error, got {other:?}"),
}
}
#[test]
fn usage_whitespace_only_treated_as_no_args() {
assert!(matches!(
run_usage(" "),
CommandResult::Action(Action::ShowUsage)
));
}
#[test]
fn usage_show_with_leading_whitespace() {
assert!(matches!(
run_usage(" show "),
CommandResult::Action(Action::ShowUsage)
));
}
#[test]
fn usage_manage_with_leading_whitespace() {
match run_usage(" manage ") {
CommandResult::Action(Action::OpenUrl(url)) => {
assert_eq!(url, "https://grok.com/?_s=usage");
}
other => panic!("expected Action(OpenUrl), got {other:?}"),
}
}
#[test]
fn usage_suggest_args_returns_show_and_manage() {
let models = ModelState::default();
let ctx = crate::slash::command::AppCtx {
models: &models,
cwd: std::path::Path::new("."),
screen_mode: crate::app::ScreenMode::Fullscreen,
};
let items = usage::UsageCommand
.suggest_args(&ctx, "")
.expect("should have suggestions");
assert_eq!(items.len(), 2);
assert_eq!(items[0].display, "show");
assert_eq!(items[0].insert_text, "show");
assert_eq!(items[1].display, "manage");
assert_eq!(items[1].insert_text, "manage");
}
#[test]
fn usage_metadata() {
let cmd = usage::UsageCommand;
assert_eq!(cmd.name(), "usage");
assert!(cmd.takes_args());
assert_eq!(cmd.arg_placeholder(), Some("show | manage"));
assert!(!cmd.takes_args());
assert!(!cmd.description().is_empty());
assert!(!cmd.usage().is_empty());
}
@@ -1,212 +0,0 @@
//! `/privacy` -- show or toggle privacy and data retention status.
use crate::app::actions::Action;
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
/// Show or toggle privacy and data retention status.
///
/// Usage:
/// - `/privacy` show current status
/// - `/privacy opt-in` opt in to coding data sharing
/// - `/privacy opt-out` opt out of coding data sharing
///
/// Case-insensitive. Only unambiguous aliases are accepted (e.g. `in`,
/// `share`, `out`, `private`) — generic toggles like `on`/`off` are
/// rejected because they're ambiguous in privacy context.
pub struct PrivacyCommand;
impl SlashCommand for PrivacyCommand {
fn name(&self) -> &str {
"privacy"
}
fn description(&self) -> &str {
"Show or toggle privacy & data retention status"
}
fn usage(&self) -> &str {
"/privacy [opt-in|opt-out]"
}
fn takes_args(&self) -> bool {
true
}
fn run(&self, _ctx: &mut CommandExecCtx, args: &str) -> CommandResult {
let arg = args.trim();
if arg.is_empty() {
return CommandResult::Action(Action::ShowPrivacyInfo);
}
match parse_privacy_arg(arg) {
Some(opted_in) => CommandResult::Action(Action::SetCodingDataSharing { opted_in }),
None => CommandResult::Error(format!(
"Unknown argument `{arg}`. Valid options: opt-in (aliases: in, share) | \
opt-out (aliases: out, private)."
)),
}
}
}
/// Parse `/privacy <arg>` into `Some(true)` (opt-in), `Some(false)`
/// (opt-out), or `None` (unknown). Case-insensitive ASCII matching.
#[doc(hidden)]
pub fn parse_privacy_arg(arg: &str) -> Option<bool> {
const OPT_IN_ALIASES: &[&str] = &["opt-in", "in", "share"];
const OPT_OUT_ALIASES: &[&str] = &["opt-out", "out", "private"];
if OPT_IN_ALIASES.iter().any(|a| arg.eq_ignore_ascii_case(a)) {
return Some(true);
}
if OPT_OUT_ALIASES.iter().any(|a| arg.eq_ignore_ascii_case(a)) {
return Some(false);
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_opt_in_canonical() {
assert_eq!(parse_privacy_arg("opt-in"), Some(true));
}
#[test]
fn parse_opt_out_canonical() {
assert_eq!(parse_privacy_arg("opt-out"), Some(false));
}
/// Case-insensitive matching.
#[test]
fn parse_case_insensitive() {
for variant in &["OPT-IN", "Opt-In", "opt-IN", "OpT-iN"] {
assert_eq!(
parse_privacy_arg(variant),
Some(true),
"case-insensitive parse must accept `{variant}` as opt-in",
);
}
for variant in &["OPT-OUT", "Opt-Out", "opt-OUT", "OpT-oUt"] {
assert_eq!(
parse_privacy_arg(variant),
Some(false),
"case-insensitive parse must accept `{variant}` as opt-out",
);
}
}
/// Pins the accepted alias catalog.
#[test]
fn parse_opt_in_aliases() {
for alias in &["in", "share"] {
assert_eq!(
parse_privacy_arg(alias),
Some(true),
"alias `{alias}` must map to opt-in",
);
}
}
#[test]
fn parse_opt_out_aliases() {
for alias in &["out", "private"] {
assert_eq!(
parse_privacy_arg(alias),
Some(false),
"alias `{alias}` must map to opt-out",
);
}
}
/// Ambiguous generic-toggle aliases must be rejected — `/privacy on`
/// is ambiguous (could mean opt-in or opt-out).
#[test]
fn parse_rejects_ambiguous_generic_aliases() {
for ambiguous in &[
"on", "off", "true", "false", "enable", "enabled", "disable", "disabled",
] {
assert_eq!(
parse_privacy_arg(ambiguous),
None,
"ambiguous alias `{ambiguous}` MUST be rejected — it would let a user typing \
`/privacy {ambiguous}` get the OPPOSITE of their intent in privacy context. \
See Security Issue 10 in PR 9 R1.",
);
}
}
/// Unknown arguments return None → the command surfaces an error
/// listing valid options. Pins the "no silent fallback" contract.
#[test]
fn parse_unknown_returns_none() {
for unknown in &["yes", "no", "maybe", "opt-maybe", "", " ", "1", "0"] {
assert_eq!(
parse_privacy_arg(unknown),
None,
"unknown arg `{unknown}` must NOT parse",
);
}
}
/// Alias families must not overlap.
#[test]
fn alias_families_disjoint() {
let opt_in_results: Vec<bool> = ["opt-in", "in", "share"]
.iter()
.map(|a| parse_privacy_arg(a).unwrap())
.collect();
assert!(
opt_in_results.iter().all(|b| *b),
"every opt-in alias must parse to true",
);
let opt_out_results: Vec<bool> = ["opt-out", "out", "private"]
.iter()
.map(|a| parse_privacy_arg(a).unwrap())
.collect();
assert!(
opt_out_results.iter().all(|b| !*b),
"every opt-out alias must parse to false",
);
}
/// Error message must list every accepted alias.
#[test]
fn error_message_lists_all_accepted_aliases() {
use crate::acp::model_state::ModelState;
use crate::app::bundle::BundleState;
let cmd = PrivacyCommand;
let models = ModelState::default();
let bundle = BundleState::default();
let mut ctx = CommandExecCtx {
models: &models,
session_id: None,
bundle_state: &bundle,
screen_mode: crate::app::ScreenMode::Inline,
pager_state: crate::settings::PagerLocalSnapshot::default(),
};
let result = cmd.run(&mut ctx, "garbage-input");
match result {
CommandResult::Error(msg) => {
// Every accepted alias appears in the error message.
for alias in &["opt-in", "in", "share", "opt-out", "out", "private"] {
assert!(
msg.contains(alias),
"error message must mention alias `{alias}` so the user knows \
what to type; msg = {msg:?}",
);
}
// Dropped ambiguous aliases must not appear.
for dropped in &["off", "true", "false", "enable", "disable"] {
assert!(
!msg.contains(dropped),
"dropped alias `{dropped}` must NOT appear in error message \
(would suggest it's still accepted); msg = {msg:?}",
);
}
}
other => panic!("expected Error result for unknown arg, got {other:?}"),
}
}
}
@@ -1,34 +0,0 @@
//! `/share` -- share current session via URL.
use crate::app::actions::Action;
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
/// Share the current session via a public URL.
pub struct ShareCommand;
impl SlashCommand for ShareCommand {
fn name(&self) -> &str {
"share"
}
fn description(&self) -> &str {
"Share this session via URL"
}
fn session_scoped(&self) -> bool {
true
}
fn usage(&self) -> &str {
"/share"
}
fn run(&self, ctx: &mut CommandExecCtx, _args: &str) -> CommandResult {
// Check if we have an active session
if ctx.session_id.is_none() {
return CommandResult::Error("No active session to share".to_string());
}
CommandResult::Action(Action::ShareSession)
}
}
@@ -1,13 +1,9 @@
//! `/usage` -- show credit usage or open billing management page.
//! `/usage` -- display Kimi API usage and quota information.
use crate::app::actions::Action;
use crate::slash::command::{AppCtx, ArgItem, CommandExecCtx, CommandResult, SlashCommand};
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
/// Show coding credit usage or manage billing.
///
/// `/usage` -- show current credit usage
/// `/usage show` -- same as above
/// `/usage manage` -- open billing management page in browser
/// Display API usage and quota information.
pub struct UsageCommand;
impl SlashCommand for UsageCommand {
@@ -15,56 +11,22 @@ impl SlashCommand for UsageCommand {
"usage"
}
/// `/cost` is the minimal-mode name for the same credit-usage summary:
/// it commits a usage/cost system block rather than opening a
/// pane, so it's an alias rather than a separate command.
/// `/cost` is the minimal-mode name for the same usage summary: it
/// commits a usage system block rather than opening a pane, so it's
/// an alias rather than a separate command.
fn aliases(&self) -> &[&str] {
&["cost"]
}
fn description(&self) -> &str {
"View credit usage or manage billing"
"Display API usage and quota information"
}
fn usage(&self) -> &str {
"/usage [show|manage]"
"/usage"
}
fn takes_args(&self) -> bool {
true
}
fn arg_placeholder(&self) -> Option<&str> {
Some("show | manage")
}
fn suggest_args(&self, _ctx: &AppCtx, _args_query: &str) -> Option<Vec<ArgItem>> {
Some(vec![
ArgItem {
display: "show".to_string(),
match_text: "show".to_string(),
insert_text: "show".to_string(),
description: "View credit usage".to_string(),
},
ArgItem {
display: "manage".to_string(),
match_text: "manage".to_string(),
insert_text: "manage".to_string(),
description: "Open billing management page".to_string(),
},
])
}
fn run(&self, _ctx: &mut CommandExecCtx, args: &str) -> CommandResult {
let arg = args.trim();
match arg {
"" | "show" => CommandResult::Action(Action::ShowUsage),
"manage" => {
CommandResult::Action(Action::OpenUrl("https://grok.com/?_s=usage".to_string()))
}
_ => CommandResult::Error(format!(
"Unknown argument: {arg}. Use /usage show or /usage manage"
)),
}
fn run(&self, _ctx: &mut CommandExecCtx, _args: &str) -> CommandResult {
CommandResult::Action(Action::ShowUsage)
}
}
-1
View File
@@ -1828,7 +1828,6 @@ mod tests {
"/compact",
"/fork",
"/rewind",
"/share",
"/context",
"/copy",
"/export",
+9 -41
View File
@@ -351,12 +351,6 @@ impl CommandRegistry {
self.available_tools = Some(tools);
}
/// Show or hide the /share command.
/// When hidden, it won't appear in the dropdown or be executable.
pub fn set_share_visible(&mut self, visible: bool) {
self.set_command_visible("share", visible);
}
/// Show or hide the /usage command.
/// When hidden, it won't appear in the dropdown or be executable.
pub fn set_usage_visible(&mut self, visible: bool) {
@@ -699,35 +693,6 @@ mod tests {
assert!(registry.get("flush").is_none());
}
#[test]
fn set_share_visible_hides_and_restores_share_command() {
let share: Arc<dyn SlashCommand> = Arc::new(DummyCommand {
name: "share",
aliases: &[],
});
let other: Arc<dyn SlashCommand> = Arc::new(DummyCommand {
name: "exit",
aliases: &[],
});
let mut registry = CommandRegistry::new(vec![share, other]);
// Default: /share is visible.
assert!(registry.get("share").is_some());
assert!(registry.triggers().iter().any(|t| t.canonical == "share"));
// Hiding /share removes it from lookup and triggers.
registry.set_share_visible(false);
assert!(registry.get("share").is_none());
assert!(!registry.triggers().iter().any(|t| t.canonical == "share"));
// Other commands are unaffected.
assert!(registry.get("exit").is_some());
// Re-enabling restores it.
registry.set_share_visible(true);
assert!(registry.get("share").is_some());
assert!(registry.triggers().iter().any(|t| t.canonical == "share"));
}
#[test]
fn set_usage_visible_hides_and_restores_usage_command() {
let usage: Arc<dyn SlashCommand> = Arc::new(DummyCommand {
@@ -1110,9 +1075,9 @@ mod tests {
/// unresolvable for dispatch, exactly like `get()`.
#[test]
fn get_for_dispatch_respects_hard_gates() {
// Hard-hidden by name (e.g. /dashboard default, /share toggle).
let share: Arc<dyn SlashCommand> = Arc::new(DummyCommand {
name: "share",
// Hard-hidden by name (e.g. /dashboard default).
let dashboard: Arc<dyn SlashCommand> = Arc::new(DummyCommand {
name: "dashboard",
aliases: &[],
});
// Tier-restricted.
@@ -1125,11 +1090,14 @@ mod tests {
name: "loop",
required: &["scheduler_create"],
});
let mut reg = CommandRegistry::new(vec![share, usage, gated]);
reg.set_share_visible(false);
let mut reg = CommandRegistry::new(vec![dashboard, usage, gated]);
reg.set_dashboard_visible(false);
reg.set_restricted_commands(&["usage".to_string()]);
assert!(reg.get_for_dispatch("share").is_none(), "hidden stays hard");
assert!(
reg.get_for_dispatch("dashboard").is_none(),
"hidden stays hard"
);
assert!(
reg.get_for_dispatch("usage").is_none(),
"restricted stays blocked (upsell path owns it)"