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:
2026-07-17 16:05:51 -04:00
parent fe1f885bb3
commit ea0ce9d15f
231 changed files with 4730 additions and 26358 deletions
+7 -66
View File
@@ -363,11 +363,8 @@ pub enum PaletteCommand {
OpenAgentsModal,
}
/// Build the default set of palette entries with section grouping.
///
/// `sharing_enabled` controls whether the `/share` entry is included.
/// Pass `true` to preserve the default behavior (show `/share`).
pub fn default_palette_entries(sharing_enabled: bool) -> Vec<PaletteEntry> {
let mut entries = vec![
pub fn default_palette_entries() -> Vec<PaletteEntry> {
let entries = vec![
PaletteEntry {
label: "Session".into(),
shortcut: String::new(),
@@ -398,11 +395,6 @@ pub fn default_palette_entries(sharing_enabled: bool) -> Vec<PaletteEntry> {
shortcut: "/resume".into(),
command: PaletteCommand::SlashCommand("/resume".into()),
},
PaletteEntry {
label: "Share Session".into(),
shortcut: "/share".into(),
command: PaletteCommand::SlashCommand("/share".into()),
},
PaletteEntry {
label: "Rename Session".into(),
shortcut: "/rename ".into(),
@@ -536,19 +528,12 @@ pub fn default_palette_entries(sharing_enabled: bool) -> Vec<PaletteEntry> {
command: PaletteCommand::Quit,
},
];
if !sharing_enabled {
entries.retain(|e| {
!matches!(
& e.command, PaletteCommand::SlashCommand(s) if s.trim() == "/share"
)
});
}
entries
}
#[allow(clippy::collapsible_if)]
/// Filter palette entries for search, preserving section headers when any item in the section matches.
pub fn filter_palette_entries(query: &str, sharing_enabled: bool) -> Vec<PaletteEntry> {
let all = default_palette_entries(sharing_enabled);
pub fn filter_palette_entries(query: &str) -> Vec<PaletteEntry> {
let all = default_palette_entries();
let query_lower = query.to_lowercase();
if query_lower.is_empty() {
return all;
@@ -1233,26 +1218,11 @@ mod doc_viewer_scroll_tests {
}
}
#[cfg(test)]
mod palette_sharing_tests {
mod palette_tests {
use super::*;
fn has_share(entries: &[PaletteEntry]) -> bool {
entries.iter().any(|e| {
matches!(
& e.command, PaletteCommand::SlashCommand(s) if s.trim() == "/share"
)
})
}
#[test]
fn default_palette_includes_share_when_enabled() {
let entries = default_palette_entries(true);
assert!(
has_share(&entries),
"/share should be present when sharing_enabled=true"
);
}
#[test]
fn default_palette_includes_dashboard() {
let entries = default_palette_entries(true);
let entries = default_palette_entries();
let has_dashboard = entries.iter().any(|e| {
matches!(
& e.command, PaletteCommand::SlashCommand(s) if s.trim() ==
@@ -1270,38 +1240,9 @@ mod palette_sharing_tests {
);
}
#[test]
fn default_palette_omits_share_when_disabled() {
let entries = default_palette_entries(false);
assert!(
!has_share(&entries),
"/share must not appear in palette when sharing_enabled=false"
);
}
#[test]
fn filter_palette_omits_share_when_disabled() {
let entries = filter_palette_entries("", false);
assert!(
!has_share(&entries),
"/share must not appear in unfiltered palette when sharing_enabled=false"
);
let entries = filter_palette_entries("share", false);
assert!(
!has_share(&entries),
"/share must not appear when filtering for 'share' with sharing_enabled=false"
);
}
#[test]
fn filter_palette_includes_share_when_enabled_and_matched() {
let entries = filter_palette_entries("share", true);
assert!(
has_share(&entries),
"/share should match a 'share' query when sharing_enabled=true"
);
}
#[test]
fn palette_tools_section_routes_each_tab_to_itself() {
use crate::views::extensions_modal::ExtensionsTab;
let entries = default_palette_entries(true);
let entries = default_palette_entries();
for (label, expected) in [
("Hooks", ExtensionsTab::Hooks),
("Plugins", ExtensionsTab::Plugins),