Publish harness and TUI open-source

initial sync from the monorepo
This commit is contained in:
grokkybara[bot] 2026-07-16 06:46:02 +01:00
commit c68e39f604
2734 changed files with 1437016 additions and 0 deletions

View file

@ -0,0 +1,2 @@
# Local SDK design notes — not for commit.
GROK_SDK_PLAN.md

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,227 @@
[package]
license = "Apache-2.0"
name = "xai-grok-shell"
version = "0.1.220-alpha.4"
edition.workspace = true
[features]
default = []
unstable = []
default-bazel = [
]
[dependencies]
dunce = { workspace = true }
tonic-prost = { workspace = true, optional = true }
agent-client-protocol = { workspace = true }
anyhow = { workspace = true }
xai-grok-announcements = { workspace = true }
xai-prompt-queue = { workspace = true }
xai-grok-version = { workspace = true }
async-openai = { workspace = true }
async-trait = { workspace = true }
blake3 = { workspace = true }
bm25 = "2.3"
bytes = { workspace = true }
chrono = { workspace = true }
indexmap = { workspace = true, features = ["serde"] }
ignore = { workspace = true }
jsonschema = { workspace = true }
futures = { workspace = true }
glob = { workspace = true }
globset = { workspace = true }
kanal = "0.1"
regex = { workspace = true }
# rmcp 2.1 + reqwest 0.13 are quarantined inside `xai-grok-mcp`. The remaining
# MCP code in this crate (extensions/mcp.rs, mcp_doctor.rs) reaches rmcp model
# types via `xai_grok_mcp::rmcp::model::*`. reqwest 0.13 is a private impl
# detail of xai-grok-mcp::servers; shell never sees it. Every HTTP call site
# in this crate uses workspace reqwest 0.12.
xai-grok-mcp = { workspace = true }
reqwest = { workspace = true, features = ["stream", "blocking"] }
reqwest-middleware = { workspace = true }
# rusqlite 0.37 + bundled = self-contained SQLite (>= 3.50.2) with FTS5.
# Bumped from 0.32 to resolve CVE-2025-29087, CVE-2025-3277, CVE-2025-6965.
# sqlite-vec is C ABI, not Rust-version dependent — any rusqlite with `bundled` works.
rusqlite = { version = "0.37", features = ["bundled"] }
serde = { workspace = true }
serde_ignored = "0.1"
serde_json = { workspace = true, features = ["preserve_order"] }
similar = { workspace = true }
thiserror = { workspace = true }
clap = { workspace = true }
dirs = "6"
tokio-stream = { workspace = true }
tower-http = { workspace = true, features = ["cors"] }
toml = { workspace = true, features = ["preserve_order"] }
toml_edit = { workspace = true }
tokio = { workspace = true, features = [
"io-std",
"process",
"rt",
"macros",
"rt-multi-thread",
"net",
"sync",
] }
tracing = { workspace = true }
tracing-subscriber = { workspace = true, features = [
"env-filter",
"fmt",
"json",
"time",
] }
obfstr = { workspace = true }
tokio-util = { workspace = true, features = ["compat"] }
tokio-retry = { workspace = true }
uuid = { workspace = true, features = ["v4", "v5", "v7"] }
xai-acp-lib = { workspace = true }
axum = { workspace = true, features = ["ws", "multipart"] }
backon = { workspace = true }
webbrowser = { workspace = true }
tokio-tungstenite = { workspace = true, features = ["rustls-tls-native-roots"] }
tokio-rustls = { version = "0.26", default-features = false, features = [
"ring",
"logging",
"tls12",
] }
rustls = { version = "0.23", default-features = false, features = [
"ring",
"logging",
"std",
"tls12",
] }
rustls-native-certs = "0.8"
futures-util = { workspace = true }
urlencoding = { workspace = true }
gethostname = { workspace = true }
gcloud-storage = { workspace = true }
git2 = { version = "0.20", default-features = false, features = [
"vendored-libgit2",
] }
notify = { workspace = true }
notify-debouncer-mini = { workspace = true }
nucleo = { workspace = true }
arc-swap = { workspace = true }
infer = "0.15"
image = { workspace = true, features = ["png", "jpeg", "gif", "webp"] }
moka = { workspace = true, features = ["future"] }
base64 = { workspace = true }
jsonwebtoken = { version = "10", features = ["rust_crypto"] }
sha2 = { workspace = true }
rand = { workspace = true }
shlex = { workspace = true }
strum = { workspace = true }
xai-fast-worktree = { path = "../xai-fast-worktree", features = ["metadata"] }
tonic = { workspace = true, optional = true }
prost = { workspace = true, optional = true }
xai-grok-paths = { path = "../xai-grok-paths" }
xai-grok-shell-base = { workspace = true }
xai-grok-shell-session-support = { workspace = true }
xai-grok-shared = { workspace = true }
xai-tracing-macros = { path = "../xai-tracing-macros" }
xai-fsnotify = { path = "../xai-fsnotify" }
xai-codebase-graph = { path = "../xai-codebase-graph" }
xai-hunk-tracker = { path = "../xai-hunk-tracker" }
xai-agent-lifecycle = { workspace = true }
xai-interjection-core = { workspace = true }
xai-grok-sandbox = { path = "../xai-grok-sandbox", default-features = false }
xai-chat-state = { path = "../xai-chat-state" }
xai-grok-compaction = { path = "../../common/xai-grok-compaction" }
xai-grok-sampler = { path = "../xai-grok-sampler" }
xai-sqlite-journal = { workspace = true }
xai-token-estimation = { workspace = true }
xai-grok-sampling-types = { path = "../xai-grok-sampling-types" }
xai-grok-tools = { path = "../xai-grok-tools" }
xai-tty-utils = { workspace = true }
xai-system-power = { workspace = true }
xai-grok-workspace = { workspace = true }
xai-grok-subagent-resolution = { path = "../xai-grok-subagent-resolution" }
xai-grok-agent = { path = "../xai-grok-agent" }
xai-grok-config = { workspace = true }
xai-grok-config-types = { workspace = true }
xai-grok-memory = { workspace = true }
xai-grok-hooks = { path = "../xai-grok-hooks" }
xai-hooks-plugins-types = { path = "../xai-hooks-plugins-types" }
xai-grok-plugin-marketplace = { path = "../xai-grok-plugin-marketplace" }
xai-file-utils = { path = "../xai-file-utils" }
xai-grok-auth = { workspace = true, features = ["middleware"] }
xai-grok-telemetry = { workspace = true }
xai-grok-http = { workspace = true }
xai-grok-models = { workspace = true }
prod-mc-cli-chat-proxy-types = { path = "../../../prod/mc/cli-chat-proxy-types" }
flate2 = { workspace = true }
fs2 = { workspace = true }
zstd = { workspace = true }
tar = { workspace = true }
url = { workspace = true }
walkdir = { workspace = true }
tdigests = "1.0"
semver = { workspace = true }
process-wrap = { version = "9.0.0", features = ["tokio1", "job-object", "creation-flags"] }
portable-pty = "0.9"
parking_lot.workspace = true
dashmap.workspace = true
# Used by acp_session.rs and mcp_servers.rs for the unified
# xai_tool_runtime::Tool dispatch model and the computer-hub MCP adapter.
xai-computer-hub-sdk = { workspace = true }
xai-tool-runtime = { workspace = true }
xai-tool-protocol = { workspace = true }
xai-tool-types = { workspace = true }
[target.'cfg(unix)'.dependencies]
libc = { workspace = true }
nix = { workspace = true }
[target.'cfg(windows)'.dependencies]
siphasher = { workspace = true }
windows = { workspace = true }
[dev-dependencies]
criterion = { workspace = true }
filetime = { workspace = true }
tempfile = { workspace = true }
xai-grok-memory = { workspace = true, features = [] }
xai-grok-workspace = { workspace = true, features = [] }
# Feature-unification applies the signing seam to the lib when building tests, so
# integration tests can inject a throwaway trusted key; production builds exclude
# dev-deps and compile the seam out.
xai-grok-config = { workspace = true, features = [] }
# Ed25519 signing for the managed-config signature tests.
ring = { workspace = true }
tar = { workspace = true }
flate2 = { workspace = true }
rsa = { workspace = true }
semver = { workspace = true }
serial_test = { workspace = true }
# Test-only builds expose `env::EnvVarGuard` and the cpu_profile test seams to
# this crate's test targets.
xai-grok-shell-base = { workspace = true, features = [] }
xai-grok-test-support = { workspace = true, features = [] }
xai-test-utils = { workspace = true }
# `test-util` enables `#[tokio::test(start_paused = true)]` (paused virtual
# clock with auto-advance) so interval-driven loop tests in `auth::refresh`
# can assert exact tick counts deterministically without real-time sleep.
tokio = { workspace = true, features = ["test-util"] }
[dependencies.tempfile]
workspace = true
[[bench]]
name = "session_list"
harness = false
[lints]
workspace = true
[build-dependencies]
# build.rs only downloads ripgrep — no rmcp involvement. Workspace reqwest
# (0.12) is plenty.
reqwest = { workspace = true, features = ["blocking"] }
flate2 = { workspace = true }
tar = { workspace = true }
[[bin]]
name = "chat-history-downgrade"
path = "src/bin/chat-history-downgrade.rs"

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,678 @@
//! Repeated warm-process benchmark for shell session listing.
//!
//! The shell-core case measures `build_unified_list` after request parsing
//! through local row construction. It excludes response serialization, ACP
//! transport, and pager parsing, filtering, and rendering. Storage cases are
//! diagnostics.
//!
//! The fixture has 3,000 encoded workspaces and 9,864 summaries. Its 32
//! same-repo CWDs are the main checkout, 15 DB/filesystem overlaps, one dead
//! DB-only worktree, and 15 filesystem-only worktrees, all with current labels
//! and interleaved activity. Another 2,968 unrelated CWDs provide scale.
//!
//! Setup and exact assertions are outside timing. Samples reuse the tree and
//! process, so filesystem and JSON work uses a warm OS page cache. Fixed
//! year-2100 timestamps pass the pager cutoff, though pager stages are excluded.
//!
//! Run: `cargo bench -p xai-grok-shell --bench session_list`
//! Allow roughly 4-8 minutes after compilation for the configured samples.
use std::collections::HashSet;
use std::fs;
use std::hint::black_box;
use std::path::{Path, PathBuf};
use std::time::Duration;
use agent_client_protocol as acp;
use chrono::{DateTime, Duration as ChronoDuration, Utc};
use criterion::{
BenchmarkId, Criterion, SamplingMode, Throughput, criterion_group, criterion_main,
};
use filetime::{FileTime, set_file_mtime};
use tempfile::TempDir;
use xai_fast_worktree::{ListFilter, WorktreeDb, WorktreeKind, WorktreeRecord, WorktreeStatus};
use xai_grok_shell::session::info::Info;
use xai_grok_shell::session::persistence::Summary;
use xai_grok_shell::session::storage::{JsonlStorageAdapter, StorageAdapter};
use xai_grok_shell::session::unified_list::{ListReq, UnifiedListResult, build_unified_list};
const WORKSPACE_COUNT: usize = 3_000;
// Bump whenever workload semantics change, even if aggregate counts do not.
const FIXTURE_SCHEMA_VERSION: usize = 1;
const MAIN_CHECKOUT_COUNT: usize = 1;
const LINKED_WORKTREE_COUNT: usize = 30;
const DB_OVERLAP_WORKTREE_COUNT: usize = 15;
const DB_ONLY_WORKTREE_COUNT: usize = 1;
const FILESYSTEM_ONLY_WORKTREE_COUNT: usize = LINKED_WORKTREE_COUNT - DB_OVERLAP_WORKTREE_COUNT;
const DB_TRACKED_WORKTREE_COUNT: usize = DB_OVERLAP_WORKTREE_COUNT + DB_ONLY_WORKTREE_COUNT;
const SAME_REPO_CANDIDATE_COUNT: usize =
MAIN_CHECKOUT_COUNT + LINKED_WORKTREE_COUNT + DB_ONLY_WORKTREE_COUNT;
const SESSIONS_PER_SAME_REPO_CWD: usize = 30;
const SESSIONS_PER_UNRELATED_WORKSPACE: usize = 3;
const SAME_REPO_SUMMARY_COUNT: usize = SAME_REPO_CANDIDATE_COUNT * SESSIONS_PER_SAME_REPO_CWD;
const TOTAL_SUMMARY_COUNT: usize = SAME_REPO_SUMMARY_COUNT
+ (WORKSPACE_COUNT - SAME_REPO_CANDIDATE_COUNT) * SESSIONS_PER_UNRELATED_WORKSPACE;
const RECENT_LIMIT: usize = 30;
const SAMPLE_SIZE: usize = 10;
const ACTIVITY_ROTATION: usize = 2;
const COOPERATIVE_PEER_DELAY: Duration = Duration::from_millis(50);
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum CandidateSource {
Main,
Overlap,
DbOnly,
FilesystemOnly,
}
#[derive(Clone)]
struct ExpectedSession {
active_at: DateTime<Utc>,
id: String,
workspace_index: usize,
}
struct Fixture {
_home: TempDir,
adapter: JsonlStorageAdapter,
picker_cwd: String,
same_repo_cwds: Vec<String>,
same_repo_labels: Vec<Option<String>>,
same_repo_sources: Vec<CandidateSource>,
all_ids_desc: Vec<String>,
picker_ids_desc: Vec<String>,
same_repo_ids_desc: Vec<String>,
unified_sources: Vec<CandidateSource>,
recent_ids_desc: Vec<String>,
}
impl Fixture {
fn new(home: TempDir) -> Self {
let sessions_root = home.path().join("sessions");
fs::create_dir(&sessions_root).expect("create sessions root");
let topology = create_same_repo_cwds(home.path());
let base = DateTime::parse_from_rfc3339("2100-01-01T00:00:00Z")
.expect("valid fixture timestamp")
.with_timezone(&Utc);
let picker_cwd = topology.cwds[0].clone();
let mut all_sessions = Vec::with_capacity(TOTAL_SUMMARY_COUNT);
let mut picker_sessions = Vec::with_capacity(SESSIONS_PER_SAME_REPO_CWD);
let mut same_repo_sessions = Vec::with_capacity(SAME_REPO_SUMMARY_COUNT);
for workspace_index in 0..WORKSPACE_COUNT {
let same_repo = workspace_index < SAME_REPO_CANDIDATE_COUNT;
let cwd = if same_repo {
topology.cwds[workspace_index].clone()
} else {
benchmark_unrelated_cwd(workspace_index - SAME_REPO_CANDIDATE_COUNT)
};
let encoded = xai_grok_shell::util::grok_home::encode_cwd_dirname(&cwd);
let cwd_dir = sessions_root.join(encoded);
fs::create_dir(&cwd_dir).expect("create encoded cwd directory");
let session_count = if same_repo {
SESSIONS_PER_SAME_REPO_CWD
} else {
SESSIONS_PER_UNRELATED_WORKSPACE
};
for session_index in 0..session_count {
let ordinal = all_sessions.len();
let session_id = format!("bench-session-{workspace_index:04}-{session_index:02}");
let activity_offset = if same_repo {
same_repo_activity_offset(workspace_index, session_index)
} else {
SAME_REPO_SUMMARY_COUNT
+ (workspace_index - SAME_REPO_CANDIDATE_COUNT)
* SESSIONS_PER_UNRELATED_WORKSPACE
+ session_index
};
let active_at = base + ChronoDuration::seconds(activity_offset as i64);
let worktree_label = topology
.labels
.get(workspace_index)
.and_then(Option::as_deref);
write_summary(
&cwd_dir,
&cwd,
&session_id,
active_at,
ordinal,
worktree_label,
);
let expected = ExpectedSession {
active_at,
id: session_id,
workspace_index,
};
if workspace_index == 0 {
picker_sessions.push(expected.clone());
}
if same_repo {
same_repo_sessions.push(expected.clone());
}
all_sessions.push(expected);
}
}
sort_expected_sessions(&mut all_sessions);
sort_expected_sessions(&mut picker_sessions);
sort_expected_sessions(&mut same_repo_sessions);
let all_ids: Vec<_> = all_sessions
.iter()
.map(|session| session.id.clone())
.collect();
let picker_ids: Vec<String> = picker_sessions
.iter()
.map(|session| session.id.clone())
.collect();
let same_repo_ids: Vec<String> = same_repo_sessions
.iter()
.map(|session| session.id.clone())
.collect();
let unified_sources: Vec<CandidateSource> = same_repo_sessions
.iter()
.take(RECENT_LIMIT)
.map(|session| topology.sources[session.workspace_index])
.collect();
let recent_ids = all_ids.iter().take(RECENT_LIMIT).cloned().collect();
assert_eq!(all_ids.len(), TOTAL_SUMMARY_COUNT);
assert_eq!(same_repo_ids.len(), SAME_REPO_SUMMARY_COUNT);
let adapter = JsonlStorageAdapter::with_root(home.path().to_path_buf());
Self {
_home: home,
adapter,
picker_cwd,
same_repo_cwds: topology.cwds,
same_repo_labels: topology.labels,
same_repo_sources: topology.sources,
all_ids_desc: all_ids,
picker_ids_desc: picker_ids,
same_repo_ids_desc: same_repo_ids,
unified_sources,
recent_ids_desc: recent_ids,
}
}
fn assert_correct(&self, runtime: &tokio::runtime::Runtime) {
let discovered = xai_grok_shell::session::worktree::candidate_worktree_cwds_for_same_repo(
Path::new(&self.picker_cwd),
)
.expect("discover same-repo candidate cwd paths");
assert_eq!(discovered, self.same_repo_cwds);
for (index, (cwd, expected_label)) in self
.same_repo_cwds
.iter()
.zip(&self.same_repo_labels)
.enumerate()
{
let summaries = runtime
.block_on(self.adapter.list_sessions(Some(cwd)))
.expect("list same-repo cwd sessions");
assert_eq!(summaries.len(), SESSIONS_PER_SAME_REPO_CWD);
assert!(
summaries
.iter()
.all(|summary| summary.worktree_label.as_deref() == expected_label.as_deref())
);
if index == 0 {
assert_eq!(summary_ids(&summaries), self.picker_ids_desc);
}
}
let all = runtime
.block_on(self.adapter.list_sessions(None))
.expect("list all sessions");
assert_eq!(summary_ids(&all), self.all_ids_desc);
let recent = runtime
.block_on(self.adapter.list_sessions_recent(RECENT_LIMIT))
.expect("list recent sessions");
assert_eq!(recent.len(), RECENT_LIMIT);
assert_eq!(summary_ids(&recent), self.recent_ids_desc);
let unified = runtime.block_on(build_local_list_with_delayed_peer(self.picker_cwd.clone()));
let unified_ids: Vec<_> = unified
.rows
.iter()
.map(|row| row.legacy.session_id.clone())
.collect();
assert_eq!(
unified_ids.as_slice(),
&self.same_repo_ids_desc[..RECENT_LIMIT]
);
let mut actual_sources = Vec::with_capacity(RECENT_LIMIT);
let mut top_cwds = HashSet::with_capacity(RECENT_LIMIT);
for row in &unified.rows {
let workspace_index = self
.same_repo_cwds
.iter()
.position(|cwd| cwd == &row.legacy.cwd)
.expect("unified row cwd belongs to same-repo topology");
actual_sources.push(self.same_repo_sources[workspace_index]);
top_cwds.insert(row.legacy.cwd.as_str());
assert_eq!(
row.legacy.worktree_label.as_deref(),
self.same_repo_labels[workspace_index].as_deref()
);
}
assert_eq!(actual_sources, self.unified_sources);
assert_eq!(top_cwds.len(), RECENT_LIMIT);
let source_count = |source| {
actual_sources
.iter()
.filter(|candidate| **candidate == source)
.count()
};
assert_eq!(source_count(CandidateSource::Main), MAIN_CHECKOUT_COUNT);
assert_eq!(
source_count(CandidateSource::Overlap),
DB_OVERLAP_WORKTREE_COUNT
);
assert_eq!(
source_count(CandidateSource::DbOnly),
DB_ONLY_WORKTREE_COUNT
);
assert_eq!(
source_count(CandidateSource::FilesystemOnly),
RECENT_LIMIT - MAIN_CHECKOUT_COUNT - DB_OVERLAP_WORKTREE_COUNT - DB_ONLY_WORKTREE_COUNT
);
}
}
struct SameRepoTopology {
cwds: Vec<String>,
labels: Vec<Option<String>>,
sources: Vec<CandidateSource>,
}
fn create_same_repo_cwds(home: &Path) -> SameRepoTopology {
let repo_dir = home.join("fixture").join("main");
fs::create_dir_all(&repo_dir).expect("create main checkout directory");
let repo = git2::Repository::init(&repo_dir).expect("initialize main git repository");
repo.remote(
"origin",
"https://github.com/xai-org/session-list-benchmark.git",
)
.expect("create benchmark git remote");
let signature = git2::Signature::new(
"session-list-benchmark",
"benchmark@localhost",
&git2::Time::new(1_700_000_000, 0),
)
.expect("create git signature");
let tree_id = repo
.index()
.expect("open git index")
.write_tree()
.expect("write empty git tree");
let tree = repo.find_tree(tree_id).expect("find empty git tree");
let commit_id = repo
.commit(Some("HEAD"), &signature, &signature, "fixture", &tree, &[])
.expect("create initial git commit");
let main = dunce::canonicalize(&repo_dir).expect("canonicalize main checkout");
let worktree_base = xai_grok_shell::session::worktree::worktree_base_dir(&main);
fs::create_dir_all(&worktree_base).expect("create worktree base");
let canonical_worktree_base =
dunce::canonicalize(&worktree_base).expect("canonicalize worktree base");
let mut linked = Vec::with_capacity(LINKED_WORKTREE_COUNT);
for index in 1..=LINKED_WORKTREE_COUNT {
let name = format!("session-list-{index:02}");
let path = worktree_base.join(&name);
repo.worktree(&name, &path, None)
.expect("create linked worktree");
linked.push((
dunce::canonicalize(path)
.expect("canonicalize linked worktree")
.to_string_lossy()
.into_owned(),
name,
));
}
let db_only_label = "session-list-db-only".to_owned();
let db_only_cwd = canonical_worktree_base
.join(&db_only_label)
.to_string_lossy()
.into_owned();
assert!(!Path::new(&db_only_cwd).exists());
let db = WorktreeDb::open(home).expect("open isolated worktree database");
for (index, (path, label)) in linked.iter().enumerate().take(DB_OVERLAP_WORKTREE_COUNT) {
db.register(&WorktreeRecord {
id: label.clone(),
path: PathBuf::from(path),
source_repo: main.clone(),
repo_name: "session-list-benchmark".to_owned(),
kind: WorktreeKind::Session,
creation_mode: "linked".to_owned(),
git_ref: None,
head_commit: Some(commit_id.to_string()),
session_id: None,
creator_pid: None,
created_at: index as i64 + 1,
last_accessed_at: None,
status: WorktreeStatus::Alive,
metadata: Some(xai_grok_shell::session::worktree::build_label_metadata(
label, false,
)),
})
.expect("register linked worktree");
}
db.register(&WorktreeRecord {
id: db_only_label.clone(),
path: PathBuf::from(&db_only_cwd),
source_repo: main.clone(),
repo_name: "session-list-benchmark".to_owned(),
kind: WorktreeKind::Session,
creation_mode: "linked".to_owned(),
git_ref: None,
head_commit: Some(commit_id.to_string()),
session_id: None,
creator_pid: None,
created_at: DB_TRACKED_WORKTREE_COUNT as i64,
last_accessed_at: None,
status: WorktreeStatus::Dead,
metadata: Some(xai_grok_shell::session::worktree::build_label_metadata(
&db_only_label,
false,
)),
})
.expect("register DB-only worktree");
let tracked = db
.list(&ListFilter {
source_repo: Some(main.clone()),
include_dead: true,
..ListFilter::default()
})
.expect("list registered worktrees");
assert_eq!(tracked.len(), DB_TRACKED_WORKTREE_COUNT);
let overlap_cwd = linked[0].0.clone();
let filesystem_only_cwd = linked[DB_OVERLAP_WORKTREE_COUNT].0.clone();
assert!(
tracked
.iter()
.any(|record| record.path == Path::new(&overlap_cwd))
);
assert!(
tracked
.iter()
.all(|record| record.path != Path::new(&filesystem_only_cwd))
);
assert!(
tracked
.iter()
.any(|record| record.path == Path::new(&db_only_cwd))
);
for record in &tracked {
let expected_label = record
.path
.file_name()
.expect("worktree basename")
.to_string_lossy();
assert_eq!(
record
.metadata
.as_ref()
.and_then(|metadata| metadata.get("label"))
.and_then(|label| label.as_str()),
Some(expected_label.as_ref())
);
}
let mut cwds = vec![main.to_string_lossy().into_owned()];
let mut labels = vec![None];
let mut sources = vec![CandidateSource::Main];
for (path, label) in linked.iter().take(DB_OVERLAP_WORKTREE_COUNT) {
cwds.push(path.clone());
labels.push(Some(label.clone()));
sources.push(CandidateSource::Overlap);
}
cwds.push(db_only_cwd.clone());
labels.push(Some(db_only_label));
sources.push(CandidateSource::DbOnly);
for (path, label) in linked.iter().skip(DB_OVERLAP_WORKTREE_COUNT) {
cwds.push(path.clone());
labels.push(Some(label.clone()));
sources.push(CandidateSource::FilesystemOnly);
}
assert_eq!(cwds.len(), SAME_REPO_CANDIDATE_COUNT);
assert_eq!(labels.len(), SAME_REPO_CANDIDATE_COUNT);
assert_eq!(sources.len(), SAME_REPO_CANDIDATE_COUNT);
SameRepoTopology {
cwds,
labels,
sources,
}
}
fn same_repo_activity_offset(workspace_index: usize, session_index: usize) -> usize {
session_index * SAME_REPO_CANDIDATE_COUNT
+ (workspace_index + ACTIVITY_ROTATION) % SAME_REPO_CANDIDATE_COUNT
}
fn sort_expected_sessions(sessions: &mut [ExpectedSession]) {
sessions.sort_by(|a, b| b.active_at.cmp(&a.active_at).then_with(|| a.id.cmp(&b.id)));
}
fn benchmark_unrelated_cwd(index: usize) -> String {
format!("/benchmark/unrelated-workspaces/workspace-{index:04}")
}
fn fixture_id() -> String {
format!(
"schema_v{FIXTURE_SCHEMA_VERSION}_sources_main{MAIN_CHECKOUT_COUNT}_\
overlap{DB_OVERLAP_WORKTREE_COUNT}_db_only{DB_ONLY_WORKTREE_COUNT}_\
fs_only{FILESYSTEM_ONLY_WORKTREE_COUNT}_labels_current_activity_interleaved_r\
{ACTIVITY_ROTATION}_{WORKSPACE_COUNT}_workspaces_{SAME_REPO_CANDIDATE_COUNT}_\
same_repo_cwds_{TOTAL_SUMMARY_COUNT}_summaries"
)
}
fn write_summary(
cwd_dir: &Path,
cwd: &str,
session_id: &str,
active_at: DateTime<Utc>,
ordinal: usize,
worktree_label: Option<&str>,
) {
let session_dir = cwd_dir.join(session_id);
fs::create_dir(&session_dir).expect("create session directory");
let summary = Summary {
info: Info {
id: acp::SessionId::new(session_id),
cwd: cwd.to_owned(),
},
session_summary: format!("Deterministic benchmark session {ordinal}"),
created_at: active_at - ChronoDuration::minutes(5),
updated_at: active_at,
num_messages: 8 + ordinal % 24,
num_chat_messages: 8 + ordinal % 24,
current_model_id: acp::ModelId::new("benchmark-model"),
parent_session_id: None,
forked_at: None,
collection_id: None,
next_trace_turn: 0,
chat_format_version: 1,
prompt_display_cwd: None,
session_kind: None,
fork_context_source: None,
fork_parent_prompt_id: None,
inherited_prefix_len: None,
hidden: None,
source_workspace_dir: None,
git_root_dir: Some(cwd.to_owned()),
git_remotes: vec!["git@github.com:xai-org/benchmark.git".to_owned()],
head_commit: Some(format!("{ordinal:040x}")),
head_branch: Some("main".to_owned()),
request_id: None,
grok_home: None,
last_active_at: Some(active_at),
generated_title: Some(format!("Benchmark session {ordinal}")),
title_is_manual: false,
worktree_label: worktree_label.map(str::to_owned),
agent_name: Some("benchmark-agent".to_owned()),
sandbox_profile: Some("workspace".to_owned()),
reasoning_effort: None,
};
let summary_path = session_dir.join("summary.json");
let bytes = serde_json::to_vec_pretty(&summary).expect("serialize summary");
fs::write(&summary_path, bytes).expect("write summary");
let mtime = FileTime::from_unix_time(active_at.timestamp(), 0);
set_file_mtime(summary_path, mtime).expect("set summary mtime");
}
fn summary_ids(summaries: &[Summary]) -> Vec<String> {
summaries
.iter()
.map(|summary| summary.info.id.to_string())
.collect()
}
async fn build_local_list_with_delayed_peer(cwd: String) -> UnifiedListResult {
let local = build_unified_list(
None,
None,
ListReq {
cwd: Some(cwd),
limit: Some(RECENT_LIMIT),
..ListReq::default()
},
);
let delayed_peer = async {
tokio::time::sleep(COOPERATIVE_PEER_DELAY).await;
};
let (result, ()) = tokio::join!(biased; local, delayed_peer);
result
}
fn bench_session_list(c: &mut Criterion) {
let home = TempDir::new().expect("create fixture root");
// SAFETY: no runtime or benchmark worker activity exists during setup.
unsafe {
std::env::set_var("GROK_HOME", home.path());
}
assert_eq!(xai_grok_shell::util::grok_home::grok_home(), home.path());
let fixture = Fixture::new(home);
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
.expect("create runtime");
fixture.assert_correct(&runtime);
eprintln!(
"session-list fixture: {WORKSPACE_COUNT} workspaces, {TOTAL_SUMMARY_COUNT} summaries, \
{SAME_REPO_CANDIDATE_COUNT} same-repo cwd candidates, \
{SAME_REPO_SUMMARY_COUNT} same-repo summaries; repeated samples use a warm process and \
warm OS page cache"
);
let fixture_id = fixture_id();
let mut storage = c.benchmark_group("session_list_storage_diagnostics_warm_os_page_cache");
storage
.sample_size(SAMPLE_SIZE)
.sampling_mode(SamplingMode::Flat)
.warm_up_time(Duration::from_secs(1));
storage.measurement_time(Duration::from_secs(120));
storage.throughput(Throughput::Elements(TOTAL_SUMMARY_COUNT as u64));
storage.bench_function(
BenchmarkId::new("full_all_workspaces_json", &fixture_id),
|b| {
b.iter_with_large_drop(|| {
black_box(
runtime
.block_on(fixture.adapter.list_sessions(None))
.expect("list all sessions"),
)
})
},
);
storage.measurement_time(Duration::from_secs(5));
storage.throughput(Throughput::Elements(SESSIONS_PER_SAME_REPO_CWD as u64));
storage.bench_function(BenchmarkId::new("cwd_scoped_json", &fixture_id), |b| {
b.iter_with_large_drop(|| {
black_box(
runtime
.block_on(
fixture
.adapter
.list_sessions(Some(black_box(&fixture.picker_cwd))),
)
.expect("list cwd sessions"),
)
})
});
storage.measurement_time(Duration::from_secs(20));
storage.throughput(Throughput::Elements(TOTAL_SUMMARY_COUNT as u64));
storage.bench_function(
BenchmarkId::new(
format!("recent_stat_first_limit_{RECENT_LIMIT}"),
&fixture_id,
),
|b| {
b.iter_with_large_drop(|| {
black_box(
runtime
.block_on(fixture.adapter.list_sessions_recent(RECENT_LIMIT))
.expect("list recent sessions"),
)
})
},
);
storage.finish();
let mut shell = c.benchmark_group("session_list_shell_core_repeated_warm_process");
shell
.sample_size(SAMPLE_SIZE)
.sampling_mode(SamplingMode::Flat)
.warm_up_time(Duration::from_secs(1))
.measurement_time(Duration::from_secs(30))
.throughput(Throughput::Elements(SAME_REPO_SUMMARY_COUNT as u64));
shell.bench_function(
BenchmarkId::new(format!("local_only_cwd_limit_{RECENT_LIMIT}"), &fixture_id),
|b| {
b.iter_with_large_drop(|| {
black_box(runtime.block_on(build_unified_list(
None,
None,
ListReq {
cwd: Some(black_box(fixture.picker_cwd.clone())),
limit: Some(RECENT_LIMIT),
..ListReq::default()
},
)))
})
},
);
shell.bench_function(
BenchmarkId::new(
format!(
"cooperative_overlap_local_only_cwd_limit_{RECENT_LIMIT}_peer_delay_{}ms",
COOPERATIVE_PEER_DELAY.as_millis()
),
&fixture_id,
),
|b| {
b.iter_with_large_drop(|| {
black_box(
runtime.block_on(build_local_list_with_delayed_peer(black_box(
fixture.picker_cwd.clone(),
))),
)
})
},
);
shell.finish();
}
criterion_group!(benches, bench_session_list);
criterion_main!(benches);

View file

@ -0,0 +1,166 @@
//! Build script for bundling ripgrep for the grok-shell crate.
//!
//! - If `GROK_SHELL_BUNDLE_RG_PATH` is set, always bundle it
//! - Otherwise, only bundle in release builds
use std::env;
use std::fs;
use std::io;
use std::path::{Path, PathBuf};
const RG_VER: &str = "15.0.0";
fn main() -> Result<(), Box<dyn std::error::Error>> {
// Only bundle in release builds to avoid slowing down cargo check.
println!("cargo:rerun-if-env-changed=GROK_SHELL_BUNDLE_RG_PATH");
println!("cargo:rerun-if-env-changed=GROK_SHELL_RG_DOWNLOAD_BASE");
// Declare our custom cfg to the compiler so cfg(bundle_rg) is recognized by lints
println!("cargo:rustc-check-cfg=cfg(bundle_rg)");
// Decide whether to bundle: path override OR release build. Bail before
// touching the filesystem so debug `cargo check` needs no environment.
let path_override = env::var("GROK_SHELL_BUNDLE_RG_PATH").ok();
let is_release = env::var("PROFILE").as_deref() == Ok("release");
if path_override.is_none() && !is_release {
return Ok(());
}
// In Bazel builds, write into OUT_DIR (which is writable) rather than
// XAI_ROOT/target/tmp (which is read-only inside the sandbox). Outside
// Bazel, prefer XAI_ROOT's shared cache dir (monorepo behavior) and fall
// back to OUT_DIR for standalone checkouts where XAI_ROOT is not a thing.
let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
let in_bazel = is_bazel_build(&manifest_dir);
let gen_dir = if in_bazel {
// OUT_DIR is always set by Cargo/Bazel for build scripts.
PathBuf::from(env::var("OUT_DIR")?)
} else if let Ok(xai_root) = env::var("XAI_ROOT") {
PathBuf::from(xai_root).join("target/tmp/grok-shell-bundle-rg")
} else {
PathBuf::from(env::var("OUT_DIR")?)
};
fs::create_dir_all(&gen_dir)?;
// Skip auto-bundling on Windows: ripgrep ships .zip there (not .tar.gz)
// and we do not yet have a zip-extraction path. Returning here BEFORE
// emitting `cargo:rustc-cfg=bundle_rg` keeps the include_bytes! macros
// gated on cfg(bundle_rg) compiled-out, so the runtime falls back to
// `rg` on PATH (see src/util/ripgrep.rs::rg_path). Users install via
// `winget install BurntSushi.ripgrep.MSVC` or `scoop install ripgrep`.
// An explicit GROK_SHELL_BUNDLE_RG_PATH still bundles on Windows (the
// override path below copies any binary regardless of target).
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
if target_os == "windows" && path_override.is_none() {
return Ok(());
}
// Expose cfg so the crate can include the bundled bytes.
println!("cargo:rustc-cfg=bundle_rg");
println!("cargo:rustc-env=GROK_SHELL_RG_VER={}", RG_VER);
println!(
"cargo:rustc-env=GROK_SHELL_RG_GEN_DIR={}",
gen_dir.display()
);
// If a local rg binary is provided, copy it directly (skips target check).
if let Some(path) = path_override {
let dest = gen_dir.join(format!("rg-{}-override.bin", RG_VER));
println!("cargo:rustc-env=GROK_SHELL_RG_TARGET=override");
let _ = fs::remove_file(&dest);
fs::copy(PathBuf::from(path.clone()), &dest).map_err(|e| {
format!(
"Failed copying GROK_SHELL_BUNDLE_RG_PATH: {e} from path {path} to dest {}",
dest.display()
)
})?;
return Ok(());
}
// Determine supported ripgrep asset triple for auto-download.
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default();
let asset_triple = match (target_os.as_str(), target_arch.as_str()) {
("macos", "aarch64") => "aarch64-apple-darwin",
("macos", "x86_64") => "x86_64-apple-darwin",
("linux", "x86_64") => "x86_64-unknown-linux-musl",
("linux", "aarch64") => "aarch64-unknown-linux-gnu",
_ => {
return Err(format!(
"Unsupported target for ripgrep bundling: {os}-{arch}. Set GROK_SHELL_BUNDLE_RG_PATH to a local rg binary for offline or unsupported builds.",
os = target_os,
arch = target_arch
).into());
}
};
println!("cargo:rustc-env=GROK_SHELL_RG_TARGET={}", asset_triple);
let dest = gen_dir.join(format!("rg-{}-{}.bin", RG_VER, asset_triple));
let _ = fs::remove_file(&dest);
// Download base is overridable so sandboxed/offline CI can point at an
// internal mirror (e.g. GROK_SHELL_RG_DOWNLOAD_BASE=http://<mirror>/github/
// BurntSushi/ripgrep/releases/download). Defaults to the public GitHub
// releases URL.
let download_base = env::var("GROK_SHELL_RG_DOWNLOAD_BASE")
.unwrap_or_else(|_| "https://github.com/BurntSushi/ripgrep/releases/download".to_string());
let url = format!(
"{base}/{v}/ripgrep-{v}-{t}.tar.gz",
base = download_base.trim_end_matches('/'),
v = RG_VER,
t = asset_triple
);
let bytes: Vec<u8> = {
let resp = reqwest::blocking::get(&url).map_err(|e| {
format!(
"Failed to download ripgrep: {}\nSet GROK_SHELL_BUNDLE_RG_PATH to a local rg for offline builds.",
e
)
})?;
if !resp.status().is_success() {
return Err(format!(
"HTTP {} downloading ripgrep. Set GROK_SHELL_BUNDLE_RG_PATH for offline builds.",
resp.status()
)
.into());
}
resp.bytes()?.to_vec()
};
let gz = flate2::read::GzDecoder::new(&bytes[..]);
let mut ar = tar::Archive::new(gz);
let mut found = false;
for entry in ar.entries()? {
let mut e = entry?;
let p = e.path()?;
if p.file_name().is_some_and(|n| n == "rg") {
let data: Vec<u8> = {
let mut v = Vec::new();
io::copy(&mut e, &mut v)?;
v
};
fs::write(&dest, &data)?;
found = true;
break;
}
}
if !found {
return Err(format!(
"Could not find 'rg' in ripgrep archive {}. Set GROK_SHELL_BUNDLE_RG_PATH for offline builds.",
url
)
.into());
}
Ok(())
}
fn is_bazel_build(manifest_dir: &Path) -> bool {
let manifest_dir_str = manifest_dir.to_string_lossy();
env::var_os("BAZEL_WORKSPACE").is_some()
|| env::var_os("BUILD_WORKSPACE_DIRECTORY").is_some()
|| env::var_os("BAZEL_EXECUTION_ROOT").is_some()
|| env::var_os("BAZEL_OUTPUT_BASE").is_some()
|| manifest_dir_str.contains("/execroot/")
|| manifest_dir_str.contains("/bazel-out/")
}

View file

@ -0,0 +1,7 @@
[
{
"category": "performance",
"description": "**Large chat sessions** now use substantially less memory and run faster during forks, rewinds, and compaction.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.0
## Performance
- **Large chat sessions** now use substantially less memory and run faster during forks, rewinds, and compaction.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "**Pasting or dropping images** now succeeds for truncated, CRC-corrupt, or tiny files instead of failing silently.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.1
## Bug Fixes
- **Pasting or dropping images** now succeeds for truncated, CRC-corrupt, or tiny files instead of failing silently.

View file

@ -0,0 +1,12 @@
[
{
"category": "fixes",
"description": "**Images smaller than 8×8 pixels** are now rejected with a clear message instead of producing blocky results.",
"breaking_change": false
},
{
"category": "features",
"description": "**`/check`** has been renamed to **`/check-work`**; old command continues to work during transition.",
"breaking_change": false
}
]

View file

@ -0,0 +1,10 @@
# 0.2.10
## Features
- **`/check`** has been renamed to **`/check-work`**; old command continues to work during transition.
## Bug Fixes
- **Images smaller than 8×8 pixels** are now rejected with a clear message instead of producing blocky results.

View file

@ -0,0 +1,47 @@
[
{
"category": "features",
"description": "**Session picker** now discovers and resumes recent Claude Code, Codex, and Cursor sessions.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Web fetch tool** preserves full truncated page content as readable artifacts instead of discarding it.",
"breaking_change": false
},
{
"category": "features",
"description": "**Welcome screen** now offers a one-click resume nudge for recent Claude, Codex, or Cursor sessions.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Multiline mode** now correctly sends the top queued message on empty Enter when a turn is running.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Queued commands** no longer disappear or delay when pressing Enter twice quickly during a running turn.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Minimal mode** text is now readable on dark terminals with proper contrast and highlighted user prompts.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Grok no longer crashes** when printing resume hints after the terminal pane has closed.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Long-running turns** with multiple waits now show updated status markers in the transcript instead of appearing stuck.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Claude and Cursor hooks** are now correctly disabled at session start when disabled in config.",
"breaking_change": false
}
]

View file

@ -0,0 +1,17 @@
# 0.2.100 — 2026-07-13
## Features
- **Session picker** now discovers and resumes recent Claude Code, Codex, and Cursor sessions.
- **Welcome screen** now offers a one-click resume nudge for recent Claude, Codex, or Cursor sessions.
## Bug Fixes
- **Web fetch tool** preserves full truncated page content as readable artifacts instead of discarding it.
- **Multiline mode** now correctly sends the top queued message on empty Enter when a turn is running.
- **Queued commands** no longer disappear or delay when pressing Enter twice quickly during a running turn.
- **Minimal mode** text is now readable on dark terminals with proper contrast and highlighted user prompts.
- **Grok no longer crashes** when printing resume hints after the terminal pane has closed.
- **Long-running turns** with multiple waits now show updated status markers in the transcript instead of appearing stuck.
- **Claude and Cursor hooks** are now correctly disabled at session start when disabled in config.

View file

@ -0,0 +1,37 @@
[
{
"category": "fixes",
"description": "**Parked subagent status** no longer duplicates or interleaves incorrectly in scrollback.",
"breaking_change": false
},
{
"category": "features",
"description": "**grok inspect** now shows effective compatibility settings for Cursor, Claude, and Codex sessions.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Status line** during waits now shows elapsed time before the queued-message hint.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Queued messages sent with Enter** now appear immediately instead of vanishing briefly.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Resume hint** after quitting minimal mode now prints the correct grok --minimal --resume command.",
"breaking_change": false
},
{
"category": "features",
"description": "**New setting** \"Match display refresh rate\" lets high-refresh displays run the TUI at native cadence.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Rate-limit messages** now correctly direct API-key users to team plans instead of personal upgrades.",
"breaking_change": false
}
]

View file

@ -0,0 +1,15 @@
# 0.2.101 — 2026-07-13
## Features
- **grok inspect** now shows effective compatibility settings for Cursor, Claude, and Codex sessions.
- **New setting** "Match display refresh rate" lets high-refresh displays run the TUI at native cadence.
## Bug Fixes
- **Parked subagent status** no longer duplicates or interleaves incorrectly in scrollback.
- **Status line** during waits now shows elapsed time before the queued-message hint.
- **Queued messages sent with Enter** now appear immediately instead of vanishing briefly.
- **Resume hint** after quitting minimal mode now prints the correct grok --minimal --resume command.
- **Rate-limit messages** now correctly direct API-key users to team plans instead of personal upgrades.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "Minor bug fixes",
"breaking_change": false
}
]

View file

@ -0,0 +1,5 @@
# 0.2.11
## Bug Fixes
- Minor bug fixes

View file

@ -0,0 +1,42 @@
[
{
"category": "features",
"description": "**Computer connection status** now shows a connecting pill during terminal session initialization.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**--max-turns** now correctly counts tool-use cycles instead of total messages.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**@-mention file search** now works again for local agent sessions.",
"breaking_change": false
},
{
"category": "features",
"description": "**/check** and subagents now read and follow full AGENTS.md rules from the repo.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Rendered images, files, and citations** now replay correctly in chunk-mode history.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**`/context`** now displays the correct auto-compact threshold for the active model instead of always 85%.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Model responses** are no longer silently dropped when the gateway emits legacy channel values.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Prompt responses** no longer resolve before the turn's final output chunks reach the client.",
"breaking_change": false
}
]

View file

@ -0,0 +1,16 @@
# 0.2.12
## Features
- **Computer connection status** now shows a connecting pill during terminal session initialization.
- **/check** and subagents now read and follow full AGENTS.md rules from the repo.
## Bug Fixes
- **--max-turns** now correctly counts tool-use cycles instead of total messages.
- **@-mention file search** now works again for local agent sessions.
- **Rendered images, files, and citations** now replay correctly in chunk-mode history.
- **`/context`** now displays the correct auto-compact threshold for the active model instead of always 85%.
- **Model responses** are no longer silently dropped when the gateway emits legacy channel values.
- **Prompt responses** no longer resolve before the turn's final output chunks reach the client.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "Miscellaneous bug fixes",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.13
## Bug Fixes
- Miscellaneous bug fixes

View file

@ -0,0 +1,22 @@
[
{
"category": "features",
"description": "**Generated images and videos** can now be opened directly from the terminal UI via buttons or clicks.",
"breaking_change": false
},
{
"category": "features",
"description": "**Background tasks panel** now groups items, supports collapsible sections, and has clearer styling for monitors and loops.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Session titles** are now generated reliably using a fixed default model.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**--permission-mode** now correctly overrides the permission_mode setting from config.toml when launching sessions.",
"breaking_change": false
}
]

View file

@ -0,0 +1,12 @@
# 0.2.14
## Features
- **Generated images and videos** can now be opened directly from the terminal UI via buttons or clicks.
- **Background tasks panel** now groups items, supports collapsible sections, and has clearer styling for monitors and loops.
## Bug Fixes
- **Session titles** are now generated reliably using a fixed default model.
- **--permission-mode** now correctly overrides the permission_mode setting from config.toml when launching sessions.

View file

@ -0,0 +1,7 @@
[
{
"category": "features",
"description": "**Permission prompts** now remember your last choice across tools and let you configure the first-prompt default in config.toml.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.15
## Features
- **Permission prompts** now remember your last choice across tools and let you configure the first-prompt default in config.toml.

View file

@ -0,0 +1,72 @@
[
{
"category": "fixes",
"description": "**Streaming tool output** (bash/write_file) now renders completely in the pager instead of only the latest chunk.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Streaming bash tool output** now appears correctly in the pager scrollback.",
"breaking_change": false
},
{
"category": "features",
"description": "**New segments compaction mode** writes per-segment markdown files that the model can read to recover pre-compaction detail.",
"breaking_change": false
},
{
"category": "features",
"description": "**Claude and Cursor compatibility scanning** (skills, rules, AGENTS.md) can now be toggled individually via env vars or config.toml.",
"breaking_change": false
},
{
"category": "performance",
"description": "**Large pasted images** no longer bust the prompt cache or exceed the 50 MiB request limit.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Routing a native tool** (e.g. scheduler_create) through use_tool now gives a clear corrective error instead of an unrecoverable loop.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**\"Starting session...\"** spinner no longer gets stuck when zero MCP servers are configured.",
"breaking_change": false
},
{
"category": "features",
"description": "**grok inspect** now shows the resolved on/off state and source for every Claude/Cursor compatibility toggle.",
"breaking_change": false
},
{
"category": "features",
"description": "**Cursor MCP servers and hooks** are now discovered and can be disabled independently via GROK_CURSOR_MCPS_ENABLED / GROK_CURSOR_HOOKS_ENABLED.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Subagents** now use the correct harness after switching models mid-session.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed long startup delays** when an external auth provider binary hangs or fails.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Subagent conversations** no longer receive unrelated monitor events or background task completions from the parent.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**The /loop command** now accepts natural-language intervals instead of always defaulting to 10 minutes.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed blank output** on completed bash or code-execution cards after shell restart or reconnect.",
"breaking_change": false
}
]

View file

@ -0,0 +1,25 @@
# 0.2.16
## Features
- **New segments compaction mode** writes per-segment markdown files that the model can read to recover pre-compaction detail.
- **Claude and Cursor compatibility scanning** (skills, rules, AGENTS.md) can now be toggled individually via env vars or config.toml.
- **grok inspect** now shows the resolved on/off state and source for every Claude/Cursor compatibility toggle.
- **Cursor MCP servers and hooks** are now discovered and can be disabled independently via GROK_CURSOR_MCPS_ENABLED / GROK_CURSOR_HOOKS_ENABLED.
## Bug Fixes
- **Streaming tool output** (bash/write_file) now renders completely in the pager instead of only the latest chunk.
- **Streaming bash tool output** now appears correctly in the pager scrollback.
- **Routing a native tool** (e.g. scheduler_create) through use_tool now gives a clear corrective error instead of an unrecoverable loop.
- **"Starting session..."** spinner no longer gets stuck when zero MCP servers are configured.
- **Subagents** now use the correct harness after switching models mid-session.
- **Fixed long startup delays** when an external auth provider binary hangs or fails.
- **Subagent conversations** no longer receive unrelated monitor events or background task completions from the parent.
- **The /loop command** now accepts natural-language intervals instead of always defaulting to 10 minutes.
- **Fixed blank output** on completed bash or code-execution cards after shell restart or reconnect.
## Performance
- **Large pasted images** no longer bust the prompt cache or exceed the 50 MiB request limit.

View file

@ -0,0 +1,37 @@
[
{
"category": "fixes",
"description": "**--restore-code** no longer detaches the source repository when resuming a forked-worktree session from a different directory.",
"breaking_change": false
},
{
"category": "features",
"description": "**Image and video generation** tools now emit structured paths so the pager renders media without regex scraping.",
"breaking_change": false
},
{
"category": "features",
"description": "**Compaction summaries** now use a more detailed structure that improves recovery after context reset.",
"breaking_change": false
},
{
"category": "features",
"description": "**image_gen** can now be enabled via the harness model using [features] in config.toml or the GROK_IMAGE_GEN_HARNESS env var.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Read tool** string coercion bug fixes.",
"breaking_change": false
},
{
"category": "features",
"description": "**Improved config refresh** on new sessions from the shell.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**ICO images** pasted or read from disk are now automatically converted to PNG before being sent to the model.",
"breaking_change": false
}
]

View file

@ -0,0 +1,14 @@
# 0.2.17
## Features
- **Image and video generation** tools now emit structured paths so the pager renders media without regex scraping.
- **Compaction summaries** now use a more detailed structure that improves recovery after context reset.
- **image_gen** can now be enabled via the harness model using [features] in config.toml or the GROK_IMAGE_GEN_HARNESS env var.
- **Improved config refresh** on new sessions from the shell.
## Bug Fixes
- **--restore-code** no longer detaches the source repository when resuming a forked-worktree session from a different directory.
- **Read tool** string coercion bug fixes.
- **ICO images** pasted or read from disk are now automatically converted to PNG before being sent to the model.

View file

@ -0,0 +1,37 @@
[
{
"category": "features",
"description": "**Official xAI plugin marketplace** now appears automatically in the Marketplace tab on first launch.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**image_edit** now correctly resolves pasted or attached images referenced as [Image #N].",
"breaking_change": false
},
{
"category": "features",
"description": "**Image and video generation** now use api.x.ai directly for all users.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Background subagent completions** are no longer reported twice when the agent is idle.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Subagents** now use the same model as the parent session by default.",
"breaking_change": false
},
{
"category": "features",
"description": "**New image-to-video and reference-to-video tools** are now available for generating videos from images.",
"breaking_change": false
},
{
"category": "features",
"description": "**New imagine skill** provides prompt-craft and workflow guidance for image generation and editing tools.",
"breaking_change": false
}
]

View file

@ -0,0 +1,15 @@
# 0.2.18
## Features
- **Official xAI plugin marketplace** now appears automatically in the Marketplace tab on first launch.
- **Image and video generation** now use api.x.ai directly for all users.
- **New image-to-video and reference-to-video tools** are now available for generating videos from images.
- **New imagine skill** provides prompt-craft and workflow guidance for image generation and editing tools.
## Bug Fixes
- **image_edit** now correctly resolves pasted or attached images referenced as [Image #N].
- **Background subagent completions** are no longer reported twice when the agent is idle.
- **Subagents** now use the same model as the parent session by default.

View file

@ -0,0 +1,12 @@
[
{
"category": "features",
"description": "**Monitors** now appear labeled in background-task reminders after compaction and can be terminated by name.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Reading images** with text-only models no longer triggers repeated 400 errors that brick the session.",
"breaking_change": false
}
]

View file

@ -0,0 +1,10 @@
# 0.2.19
## Features
- **Monitors** now appear labeled in background-task reminders after compaction and can be terminated by name.
## Bug Fixes
- **Reading images** with text-only models no longer triggers repeated 400 errors that brick the session.

View file

@ -0,0 +1,7 @@
[
{
"category": "bug_fixes",
"description": "**Emergency rollback release** — reverts to known-good 0.1.219 codebase.",
"breaking_change": false
}
]

View file

@ -0,0 +1,2 @@
# 0.2.2

View file

@ -0,0 +1,12 @@
[
{
"category": "fixes",
"description": "**MCP servers** declared in both a plugin's .mcp.json and plugin.json are now registered instead of dropped.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Git operations** now correctly target the repository for each session's working directory.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.20
## Bug Fixes
- **MCP servers** declared in both a plugin's .mcp.json and plugin.json are now registered instead of dropped.
- **Git operations** now correctly target the repository for each session's working directory.

View file

@ -0,0 +1,12 @@
[
{
"category": "features",
"description": "**allowed_models** in config.toml now restricts which models appear in the picker and `/model` command.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Code navigation** now returns correct results for secondary project windows with different working directories.",
"breaking_change": false
}
]

View file

@ -0,0 +1,9 @@
# 0.2.21
## Features
- **allowed_models** in config.toml now restricts which models appear in the picker and `/model` command.
## Bug Fixes
- **Code navigation** now returns correct results for secondary project windows with different working directories.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "**Authentication errors** with static API keys now surface a clear error instead of hanging the turn.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.22
## Bug Fixes
- **Authentication errors** with static API keys now surface a clear error instead of hanging the turn.

View file

@ -0,0 +1,17 @@
[
{
"category": "features",
"description": "**Leader sessions** can now be viewed and controlled from multiple clients with a live dashboard.",
"breaking_change": false
},
{
"category": "features",
"description": "**Sessions** can now be deleted directly from the /resume history picker.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**MCP plugin servers** with bundled OAuth client IDs now authenticate correctly.",
"breaking_change": false
}
]

View file

@ -0,0 +1,10 @@
# 0.2.23
## Features
- **Leader sessions** can now be viewed and controlled from multiple clients with a live dashboard.
- **Sessions** can now be deleted directly from the /resume history picker.
## Bug Fixes
- **MCP plugin servers** with bundled OAuth client IDs now authenticate correctly.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "Minor bug fixes",
"breaking_change": false
}
]

View file

@ -0,0 +1,5 @@
# 0.2.24
## Bug Fixes
- Minor bug fixes

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "**Session titles** now generate reliably even for very long initial messages.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.25
## Bug Fixes
- **Session titles** now generate reliably even for very long initial messages.

View file

@ -0,0 +1,27 @@
[
{
"category": "fixes",
"description": "**Large pasted content** no longer triggers context-window errors or breaks compaction and memory flush.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**API-key users** can now run `grok agent --leader` without forced interactive login or timeouts.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Compaction** no longer retries endlessly on credit, size, or auth failures; shows a clear message instead.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Windows PowerShell and cmd.exe** no longer falsely reject commands containing `&`.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**web_fetch** no longer crashes the CLI on pages whose root element matches a cleaning selector.",
"breaking_change": false
}
]

View file

@ -0,0 +1,9 @@
# 0.2.26
## Bug Fixes
- **Large pasted content** no longer triggers context-window errors or breaks compaction and memory flush.
- **API-key users** can now run `grok agent --leader` without forced interactive login or timeouts.
- **Compaction** no longer retries endlessly on credit, size, or auth failures; shows a clear message instead.
- **Windows PowerShell and cmd.exe** no longer falsely reject commands containing `&`.
- **web_fetch** no longer crashes the CLI on pages whose root element matches a cleaning selector.

View file

@ -0,0 +1,22 @@
[
{
"category": "fixes",
"description": "**Monitor output** no longer appears as raw XML in the conversation view during leader sessions.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Windows commands** containing `&` are no longer incorrectly rejected by `run_terminal_cmd`.",
"breaking_change": false
},
{
"category": "features",
"description": "**Image and video generation** tools now include the saved filename and session folder in their output.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Python -c** save-to-file reminder now suggests correct commands on Windows.",
"breaking_change": false
}
]

View file

@ -0,0 +1,12 @@
# 0.2.27
## Features
- **Image and video generation** tools now include the saved filename and session folder in their output.
## Bug Fixes
- **Monitor output** no longer appears as raw XML in the conversation view during leader sessions.
- **Windows commands** containing `&` are no longer incorrectly rejected by `run_terminal_cmd`.
- **Python -c** save-to-file reminder now suggests correct commands on Windows.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "**Images** read via read_file are now downscaled even when small in bytes but large in pixels.",
"breaking_change": false
}
]

View file

@ -0,0 +1,5 @@
# 0.2.28
## Bug Fixes
- **Images** read via read_file are now downscaled even when small in bytes but large in pixels.

View file

@ -0,0 +1,12 @@
[
{
"category": "performance",
"description": "**Resuming large sessions** is now substantially faster with no data loss.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**`/rewind`** before a compaction boundary no longer leaves later prompts in context.",
"breaking_change": false
}
]

View file

@ -0,0 +1,10 @@
# 0.2.29
## Bug Fixes
- **`/rewind`** before a compaction boundary no longer leaves later prompts in context.
## Performance
- **Resuming large sessions** is now substantially faster with no data loss.

View file

@ -0,0 +1,27 @@
[
{
"category": "features",
"description": "Memory system: /remember command, note modal with raw/enhanced preview, x.ai/memory/rewrite ACP extension, Ctrl+F fullscreen toggle for /memory modal.",
"breaking_change": false
},
{
"category": "features",
"description": "Agent configuration: /config-agents modal with agents, personas, and defaults.",
"breaking_change": false
},
{
"category": "features",
"description": "Goal classifier: end-to-end goal tracking with subagent-powered classification.",
"breaking_change": false
},
{
"category": "improvements",
"description": "Image handling: process-wide moka cache, hardened pipeline against truncated/CRC errors.",
"breaking_change": false
},
{
"category": "bug_fixes",
"description": "Fixed cache regression from raw_output always being populated. Fixed channel switch so grok update --stable works correctly across version series.",
"breaking_change": false
}
]

View file

@ -0,0 +1,8 @@
# 0.2.3
## Features
- Memory system: /remember command, note modal with raw/enhanced preview, x.ai/memory/rewrite ACP extension, Ctrl+F fullscreen toggle for /memory modal.
- Agent configuration: /config-agents modal with agents, personas, and defaults.
- Goal classifier: end-to-end goal tracking with subagent-powered classification.

View file

@ -0,0 +1,22 @@
[
{
"category": "features",
"description": "A new plugin install suggestion appears above the prompt when you type a known marketplace plugin name or domain.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Trace uploads** and remote session restores now succeed with a deployment key and no browser login.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Resumed sessions** no longer pad the sticky prompt with empty rows; cancelling a turn now keeps the rest of the prompt queue intact.",
"breaking_change": false
},
{
"category": "fixes",
"description": "Cancelling a running prompt no longer leaves the interface stuck on the cancelling spinner.",
"breaking_change": false
}
]

View file

@ -0,0 +1,12 @@
# 0.2.30
## Features
- A new plugin install suggestion appears above the prompt when you type a known marketplace plugin name or domain.
## Bug Fixes
- **Trace uploads** and remote session restores now succeed with a deployment key and no browser login.
- **Resumed sessions** no longer pad the sticky prompt with empty rows; cancelling a turn now keeps the rest of the prompt queue intact.
- Cancelling a running prompt no longer leaves the interface stuck on the cancelling spinner.

View file

@ -0,0 +1,17 @@
[
{
"category": "fixes",
"description": "**Marketplace skills** without proper descriptions are now hidden from listings instead of flooding the model with tables.",
"breaking_change": false
},
{
"category": "performance",
"description": "**Grep searches** on large repositories are now substantially faster and no longer hit the 60-second timeout.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Prompts submitted rapidly** now stay in correct submission order in the queue.",
"breaking_change": false
}
]

View file

@ -0,0 +1,11 @@
# 0.2.31
## Bug Fixes
- **Marketplace skills** without proper descriptions are now hidden from listings instead of flooding the model with tables.
- **Prompts submitted rapidly** now stay in correct submission order in the queue.
## Performance
- **Grep searches** on large repositories are now substantially faster and no longer hit the 60-second timeout.

View file

@ -0,0 +1,17 @@
[
{
"category": "features",
"description": "**Slash commands** from project plugins now appear correctly in every open conversation after a plugin change.",
"breaking_change": false
},
{
"category": "performance",
"description": "**Grep searches** on large repositories are now substantially faster and no longer hit the 60-second timeout.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Prompts submitted rapidly** now stay in correct submission order in the queue.",
"breaking_change": false
}
]

View file

@ -0,0 +1,14 @@
# 0.2.32
## Features
- **Slash commands** from project plugins now appear correctly in every open conversation after a plugin change.
## Bug Fixes
- **Prompts submitted rapidly** now stay in correct submission order in the queue.
## Performance
- **Grep searches** on large repositories are now substantially faster and no longer hit the 60-second timeout.

View file

@ -0,0 +1,12 @@
[
{
"category": "fixes",
"description": "**Fixed duplicate turn output** when attaching a second client to an active leader session.",
"breaking_change": false
},
{
"category": "fixes",
"description": "Fixed **Send now** on queued prompts.",
"breaking_change": false
}
]

View file

@ -0,0 +1,7 @@
# 0.2.33
## Bug Fixes
- **Fixed duplicate turn output** when attaching a second client to an active leader session.
- Fixed **Send now** on queued prompts.

View file

@ -0,0 +1,12 @@
[
{
"category": "features",
"description": "**`grok login`** now defaults to device code flow, which works reliably in SSH, WSL, VPN, and browser-restricted environments.",
"breaking_change": true
},
{
"category": "fixes",
"description": "**Fixed a hang during auth refresh.**",
"breaking_change": false
}
]

View file

@ -0,0 +1,10 @@
# 0.2.34
## Features
- **`grok login`** now defaults to device code flow, which works reliably in SSH, WSL, VPN, and browser-restricted environments.
## Bug Fixes
- **Fixed a hang during auth refresh.**

View file

@ -0,0 +1 @@
[]

View file

@ -0,0 +1,2 @@
# 0.2.35

View file

@ -0,0 +1,17 @@
[
{
"category": "features",
"description": "**Large MCP tool results** are now saved with the correct extension and the model receives better hints for querying them.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed false-positive doom-loop terminations** when many parallel tool calls fail together in one batch.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed a crash** that could occur during auto-compaction when resuming a session containing reasoning content.",
"breaking_change": false
}
]

View file

@ -0,0 +1,11 @@
# 0.2.36
## Features
- **Large MCP tool results** are now saved with the correct extension and the model receives better hints for querying them.
## Bug Fixes
- **Fixed false-positive doom-loop terminations** when many parallel tool calls fail together in one batch.
- **Fixed a crash** that could occur during auto-compaction when resuming a session containing reasoning content.

View file

@ -0,0 +1,22 @@
[
{
"category": "features",
"description": "**MCP tool result queries** now list only command-line tools actually present on your system.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Subagents** now correctly receive web_search and x_search tools from the parent session.",
"breaking_change": false
},
{
"category": "features",
"description": "**`grok update`** now restarts any older running leader so all clients get the new binary.",
"breaking_change": false
},
{
"category": "features",
"description": "**Long-running bash commands** that hit the timeout are now moved to the background by default instead of killed.",
"breaking_change": false
}
]

View file

@ -0,0 +1,12 @@
# 0.2.37
## Features
- **MCP tool result queries** now list only command-line tools actually present on your system.
- **`grok update`** now restarts any older running leader so all clients get the new binary.
- **Long-running bash commands** that hit the timeout are now moved to the background by default instead of killed.
## Bug Fixes
- **Subagents** now correctly receive web_search and x_search tools from the parent session.

View file

@ -0,0 +1,17 @@
[
{
"category": "features",
"description": "**Watching status line** now appears when background monitors, loops, or subagents can wake the agent.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Default model selection** now correctly chooses the intended entry when multiple models share a slug.",
"breaking_change": false
},
{
"category": "fixes",
"description": "Minor bug fixes",
"breaking_change": false
}
]

View file

@ -0,0 +1,11 @@
# 0.2.38
## Features
- **Watching status line** now appears when background monitors, loops, or subagents can wake the agent.
## Bug Fixes
- **Default model selection** now correctly chooses the intended entry when multiple models share a slug.
- Minor bug fixes

View file

@ -0,0 +1,37 @@
[
{
"category": "features",
"description": "**run_terminal_cmd** can stream live stdout/stderr chunks when the workspace flag is enabled.",
"breaking_change": false
},
{
"category": "features",
"description": "**/session-info** now displays the current turn index.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Resumed subagents** no longer loop forever during auto-compaction on large context windows.",
"breaking_change": false
},
{
"category": "features",
"description": "Server-synced and bundled skills are now discovered from launcher-injected directories.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Background task** descriptions and & rejection messages now correctly name the real parameters.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Doom-loop detection** no longer falsely triggers on distinct failing tool calls.",
"breaking_change": false
},
{
"category": "features",
"description": "**Background `&` operator** is now allowed by default in terminal commands.",
"breaking_change": false
}
]

View file

@ -0,0 +1,15 @@
# 0.2.39
## Features
- **run_terminal_cmd** can stream live stdout/stderr chunks when the workspace flag is enabled.
- **/session-info** now displays the current turn index.
- Server-synced and bundled skills are now discovered from launcher-injected directories.
- **Background `&` operator** is now allowed by default in terminal commands.
## Bug Fixes
- **Resumed subagents** no longer loop forever during auto-compaction on large context windows.
- **Background task** descriptions and & rejection messages now correctly name the real parameters.
- **Doom-loop detection** no longer falsely triggers on distinct failing tool calls.

View file

@ -0,0 +1,12 @@
[
{
"category": "fixes",
"description": "**read_file** now correctly passes embedded base64 images to the model as vision tokens instead of truncated fragments.",
"breaking_change": false
},
{
"category": "features",
"description": "**image_gen** now uses the higher-quality grok-imagine-image-quality model.",
"breaking_change": false
}
]

View file

@ -0,0 +1,10 @@
# 0.2.4
## Features
- **image_gen** now uses the higher-quality grok-imagine-image-quality model.
## Bug Fixes
- **read_file** now correctly passes embedded base64 images to the model as vision tokens instead of truncated fragments.

View file

@ -0,0 +1,17 @@
[
{
"category": "features",
"description": "**`grok --debug`** now produces per-session log files under ~/.grok/debug/ even with a leader process.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Doom-loop warnings** now correctly describe cycles and distinct edit failures instead of claiming identical arguments.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Model list changes** from config or cache now appear in already-connected TUI and IDE clients without restart.",
"breaking_change": false
}
]

View file

@ -0,0 +1,11 @@
# 0.2.40
## Features
- **`grok --debug`** now produces per-session log files under ~/.grok/debug/ even with a leader process.
## Bug Fixes
- **Doom-loop warnings** now correctly describe cycles and distinct edit failures instead of claiming identical arguments.
- **Model list changes** from config or cache now appear in already-connected TUI and IDE clients without restart.

View file

@ -0,0 +1,22 @@
[
{
"category": "performance",
"description": "**Fixed memory context injection** on resume so the prompt prefix stays byte-stable and KV cache is preserved.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed token count after compaction** so the displayed number no longer jumps back up on the next model response.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed plugin skill loading** when a manifest lists skill directories directly instead of a parent skills/ folder.",
"breaking_change": false
},
{
"category": "features",
"description": "**Compaction completion message** now shows the before → after token reduction instead of only the final count.",
"breaking_change": false
}
]

View file

@ -0,0 +1,15 @@
# 0.2.41
## Features
- **Compaction completion message** now shows the before → after token reduction instead of only the final count.
## Bug Fixes
- **Fixed token count after compaction** so the displayed number no longer jumps back up on the next model response.
- **Fixed plugin skill loading** when a manifest lists skill directories directly instead of a parent skills/ folder.
## Performance
- **Fixed memory context injection** on resume so the prompt prefix stays byte-stable and KV cache is preserved.

View file

@ -0,0 +1,12 @@
[
{
"category": "fixes",
"description": "**ask_user_question** tool can now be enabled in allowlists without requiring plan-mode tools.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**MCP servers** provided at session start now persist across config hot-reloads.",
"breaking_change": false
}
]

View file

@ -0,0 +1,7 @@
# 0.2.42
## Bug Fixes
- **ask_user_question** tool can now be enabled in allowlists without requiring plan-mode tools.
- **MCP servers** provided at session start now persist across config hot-reloads.

View file

@ -0,0 +1,17 @@
[
{
"category": "fixes",
"description": "**ask_user_question** tool can now be enabled in allowlists without requiring plan-mode tools.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Shift+Tab** mode cycling (Normal → Plan → Auto-Approve) works again in the agent view.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Ctrl+C** now cancels a blocking `grok update` cleanly instead of leaving an orphaned download repainting the terminal.",
"breaking_change": false
}
]

View file

@ -0,0 +1,8 @@
# 0.2.43
## Bug Fixes
- **ask_user_question** tool can now be enabled in allowlists without requiring plan-mode tools.
- **Shift+Tab** mode cycling (Normal → Plan → Auto-Approve) works again in the agent view.
- **Ctrl+C** now cancels a blocking `grok update` cleanly instead of leaving an orphaned download repainting the terminal.

View file

@ -0,0 +1,37 @@
[
{
"category": "performance",
"description": "**Inference requests** recover faster from silent engine stalls instead of waiting the full idle timeout.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Interjecting** while editing a queued prompt no longer strands the composer or blocks the queue.",
"breaking_change": false
},
{
"category": "features",
"description": "**K/J** keys now snap the viewport to the top of previous or next assistant responses.",
"breaking_change": false
},
{
"category": "features",
"description": "**J/K** (vim mode) now navigate between assistant responses in scrollback.",
"breaking_change": false
},
{
"category": "features",
"description": "**sequenceDiagram** mermaid blocks now render as Unicode lifeline diagrams instead of source fallback.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Mid-turn interjections** now appear as separate user messages instead of being appended to tool results.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Project MCP config** touches no longer trigger repeated reload storms.",
"breaking_change": false
}
]

View file

@ -0,0 +1,18 @@
# 0.2.44
## Features
- **K/J** keys now snap the viewport to the top of previous or next assistant responses.
- **J/K** (vim mode) now navigate between assistant responses in scrollback.
- **sequenceDiagram** mermaid blocks now render as Unicode lifeline diagrams instead of source fallback.
## Bug Fixes
- **Interjecting** while editing a queued prompt no longer strands the composer or blocks the queue.
- **Mid-turn interjections** now appear as separate user messages instead of being appended to tool results.
- **Project MCP config** touches no longer trigger repeated reload storms.
## Performance
- **Inference requests** recover faster from silent engine stalls instead of waiting the full idle timeout.

View file

@ -0,0 +1,37 @@
[
{
"category": "features",
"description": "**Mermaid diagrams** now render to images when you click Open in a code block (on by default).",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed** rare conversation corruption when skills changed while a tool call was still running.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed** `grok --resume` failing on empty image-only session folders left by cross-directory pastes.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed** pasted images and relative paths using the wrong directory after resuming a session from another folder.",
"breaking_change": false
},
{
"category": "internal",
"description": "**--debug and --debug-file** flags now show simpler, clearer descriptions in --help output.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Welcome screen logo** no longer renders as invalid characters on legacy Windows command prompts and PowerShell.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed** \"unknown session id\" errors that occurred after the leader process crashed or was killed.",
"breaking_change": false
}
]

View file

@ -0,0 +1,14 @@
# 0.2.45
## Features
- **Mermaid diagrams** now render to images when you click Open in a code block (on by default).
## Bug Fixes
- **Fixed** rare conversation corruption when skills changed while a tool call was still running.
- **Fixed** `grok --resume` failing on empty image-only session folders left by cross-directory pastes.
- **Fixed** pasted images and relative paths using the wrong directory after resuming a session from another folder.
- **Welcome screen logo** no longer renders as invalid characters on legacy Windows command prompts and PowerShell.
- **Fixed** "unknown session id" errors that occurred after the leader process crashed or was killed.

View file

@ -0,0 +1,42 @@
[
{
"category": "fixes",
"description": "**Fixed `grok --resume`** failing on empty image-only session folders left by cross-directory pastes.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed pasted images** and relative paths using the wrong directory after cross-cwd resume.",
"breaking_change": false
},
{
"category": "performance",
"description": "**Parallel tool calls** on the same path (multiple greps etc.) now execute concurrently.",
"breaking_change": false
},
{
"category": "features",
"description": "**Mermaid flowcharts** now render with fewer avoidable edge crossings.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed Mermaid flowcharts** that silently rendered wrong diagrams for & groups, circle/cross endings and self-loops.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed zsh tab-completion** for subcommands after the optional prompt argument was added.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed \"unknown session id\" errors** after the leader process crashed or was killed.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed repeated auto-compaction attempts** when the session is credit-blocked or auth is non-refreshable.",
"breaking_change": false
}
]

View file

@ -0,0 +1,19 @@
# 0.2.46
## Features
- **Mermaid flowcharts** now render with fewer avoidable edge crossings.
## Bug Fixes
- **Fixed `grok --resume`** failing on empty image-only session folders left by cross-directory pastes.
- **Fixed pasted images** and relative paths using the wrong directory after cross-cwd resume.
- **Fixed Mermaid flowcharts** that silently rendered wrong diagrams for & groups, circle/cross endings and self-loops.
- **Fixed zsh tab-completion** for subcommands after the optional prompt argument was added.
- **Fixed "unknown session id" errors** after the leader process crashed or was killed.
- **Fixed repeated auto-compaction attempts** when the session is credit-blocked or auth is non-refreshable.
## Performance
- **Parallel tool calls** on the same path (multiple greps etc.) now execute concurrently.

View file

@ -0,0 +1,17 @@
[
{
"category": "features",
"description": "**stateDiagram** Mermaid blocks now render as diagrams instead of source fallback.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Pasted images** now survive interjections and queue edits instead of being dropped.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Managed MCP connectors** (Slack, Linear, etc.) now appear correctly when using leader mode.",
"breaking_change": false
}
]

View file

@ -0,0 +1,11 @@
# 0.2.47
## Features
- **stateDiagram** Mermaid blocks now render as diagrams instead of source fallback.
## Bug Fixes
- **Pasted images** now survive interjections and queue edits instead of being dropped.
- **Managed MCP connectors** (Slack, Linear, etc.) now appear correctly when using leader mode.

View file

@ -0,0 +1,52 @@
[
{
"category": "fixes",
"description": "**Skill reloads** no longer corrupt active tool calls or produce duplicate results in the conversation.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**grok --resume** now correctly finds the real session instead of failing on empty image-only folders.",
"breaking_change": false
},
{
"category": "fixes",
"description": "Pasted images and relative paths now use the correct directory when resuming a session created elsewhere.",
"breaking_change": false
},
{
"category": "features",
"description": "Marketplace plugin listings now show skills, MCP servers, and commands when the catalog is published.",
"breaking_change": false
},
{
"category": "features",
"description": "Mermaid flowcharts now render with fewer avoidable edge crossings.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Mermaid flowcharts** now correctly render node groups, arrow endings, self-loops and line styles.",
"breaking_change": false
},
{
"category": "features",
"description": "**stateDiagram** mermaid blocks now render as Unicode diagrams instead of source fallback.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Fixed** \"unknown session id\" errors that occurred after the leader process crashed or was killed.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Pasted images** now survive interjections and queue edits instead of being dropped.",
"breaking_change": false
},
{
"category": "fixes",
"description": "**Managed MCP connectors** (Slack, Linear, etc.) now appear correctly when using leader mode.",
"breaking_change": false
}
]

View file

@ -0,0 +1,18 @@
# 0.2.49
## Features
- Marketplace plugin listings now show skills, MCP servers, and commands when the catalog is published.
- Mermaid flowcharts now render with fewer avoidable edge crossings.
- **stateDiagram** mermaid blocks now render as Unicode diagrams instead of source fallback.
## Bug Fixes
- **Skill reloads** no longer corrupt active tool calls or produce duplicate results in the conversation.
- **grok --resume** now correctly finds the real session instead of failing on empty image-only folders.
- Pasted images and relative paths now use the correct directory when resuming a session created elsewhere.
- **Mermaid flowcharts** now correctly render node groups, arrow endings, self-loops and line styles.
- **Fixed** "unknown session id" errors that occurred after the leader process crashed or was killed.
- **Pasted images** now survive interjections and queue edits instead of being dropped.
- **Managed MCP connectors** (Slack, Linear, etc.) now appear correctly when using leader mode.

View file

@ -0,0 +1,7 @@
[
{
"category": "fixes",
"description": "**Drag-and-drop** and pasting images or files now works correctly on Windows.",
"breaking_change": false
}
]

View file

@ -0,0 +1,6 @@
# 0.2.5
## Bug Fixes
- **Drag-and-drop** and pasting images or files now works correctly on Windows.

Some files were not shown because too many files have changed in this diff Show more