Synced from monorepo

Changes:
- Gate session-lifecycle heap steady state with a dhat soak
- Unbreak merge lifecycle e2e after default model → grok-4.5
- Scan home-scope rules dirs at <root>/rules
- Complete text-input paste and terminal parity
- Gate project roles and personas
- Use canonical editing in dialogs
- Use canonical editing in search bars
- Reject ambiguous MCP tool IDs
- Harden Git operands for plugins
- Simplify queue drain API
- Pass RFC 9207 iss through MCP OAuth token exchange
- Show leader roster when local agents map is empty
- Use canonical editing in Persona views
- Remove marketplace default-skills auto-install and purge old installs
- Use canonical editing in extension forms
- Add canonical dashboard text editing
- Use canonical editing in settings
- Add /summarize as a /recap alias
- Restore previous agent when exiting dashboard
- Use tool_choice auto for compaction
- Settings toggle for snap-prompt-to-top on send
- Update default models to grok-4.5
- Source login shell once for local bash (env + alias/function snapshot)
- Template hardcoded param names in server-native tool descriptions
- Fix System-Reminder XML tag injection in CLAUDE.md via agents_md
- Fix remote workspace-server hardcoding LSP trust (repo code execution risk)
- Clear orphaned tool-call updates at turn end
- Suppress task wake after cancel
- Send x-grok-client-identifier on direct API tool calls
- Harden dashboard peek lease transitions
- Host /btw side panel in live region (minimal mode)
- Bound scroll presentation latency
- Highlight multi-line constructs correctly in diffs and the file viewer
- Block web_fetch non-public IPs; local opt-in is explicit-host only
- Seed coding_data_retention_opt_out=false for OAuth e2es in pty-harness
- Follow up clipboard delivery feedback
- Use canonical editing in pickers
- Route TextArea through canonical editor
- Persistent "watching" status row; quieter turn markers
- Gate sensitive edit targets
- Expose agent registry counts and gate session churn on them
- Default coding data sharing to opt-out until server preference applies
- Wire chat attachment ids through gateway prompts
- On auth refresh failure, issue retry
- Forward preview provenance and computer lifecycle state
- Document independent privacy controls and scope /privacy output
- Strip SamplingError Display prefix on rate-limit UI copy
- Stop dumping Cloudflare HTML into Retry failed
- Disable in-place prompt edit (scroll jank on enter)
- Strip forced ANSI color from gh pr view JSON
- Plumb bash tool description onto ToolUsageCard wire
This commit is contained in:
grokkybara[bot] 2026-07-18 19:48:28 +01:00
commit 7cfcb20d2b
292 changed files with 23315 additions and 9209 deletions

View file

@ -432,28 +432,6 @@ mod tests {
use serial_test::serial;
use std::sync::{Arc, Mutex};
use tempfile::TempDir;
struct HomeGuard {
previous: Option<std::ffi::OsString>,
}
impl Drop for HomeGuard {
fn drop(&mut self) {
match self.previous.take() {
Some(previous) => unsafe {
std::env::set_var("HOME", previous);
},
None => unsafe {
std::env::remove_var("HOME");
},
}
}
}
fn with_bundled_home(tmp: &TempDir) -> HomeGuard {
let previous = std::env::var_os("HOME");
unsafe {
std::env::set_var("HOME", tmp.path());
}
HomeGuard { previous }
}
fn sample_bundle() -> SubagentBundle {
let mut bundle = SubagentBundle::empty("bundle-v1");
bundle.personas.insert(
@ -588,8 +566,8 @@ mod tests {
#[serial]
fn status_reports_no_cache_when_manifest_missing() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let status = status_bundle_at(&bundle::bundled_root()).unwrap();
let root = tmp.path().join("bundled");
let status = status_bundle_at(&root).unwrap();
assert_eq!(
status,
BundleStatusResult {
@ -608,15 +586,14 @@ mod tests {
#[serial]
fn status_reports_cached_entries_from_manifest_and_disk() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle()).unwrap();
std::fs::write(
root.join("personas/local-only.toml"),
"instructions = \"ignore\"",
)
.unwrap();
let status = status_bundle_at(&bundle::bundled_root()).unwrap();
let status = status_bundle_at(&root).unwrap();
assert!(status.has_cache);
assert_eq!(status.version.as_deref(), Some("bundle-v1"));
assert_eq!(status.personas, vec!["researcher"]);
@ -628,14 +605,13 @@ mod tests {
#[serial]
async fn sync_success_writes_cache_and_returns_counts() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let bundle = sample_bundle();
let (proxy_base_url, _seen_headers, server) = start_bundle_server(
axum::http::StatusCode::OK,
serde_json::to_value(&bundle).unwrap(),
)
.await;
let root = bundle::bundled_root();
let am = test_auth_manager();
let result = sync_bundle_to_root(&root, &proxy_base_url, Some(&am), None, None, false)
.await
@ -654,11 +630,10 @@ mod tests {
#[serial]
async fn sync_force_true_has_same_write_semantics() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let bundle = sample_bundle();
let (proxy_base_url, _seen_headers, server) =
start_bundle_server(StatusCode::OK, serde_json::to_value(&bundle).unwrap()).await;
let root = bundle::bundled_root();
let am = test_auth_manager();
let normal = sync_bundle_to_root(&root, &proxy_base_url, Some(&am), None, None, false)
.await
@ -673,23 +648,16 @@ mod tests {
#[serial]
async fn sync_http_failure_surfaces_error() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let (proxy_base_url, _seen_headers, server) = start_bundle_server(
StatusCode::UNAUTHORIZED,
serde_json::json!({ "error" : "unauthorized" }),
)
.await;
let am = test_auth_manager();
let error = sync_bundle_to_root(
&bundle::bundled_root(),
&proxy_base_url,
Some(&am),
None,
None,
false,
)
.await
.unwrap_err();
let error = sync_bundle_to_root(&root, &proxy_base_url, Some(&am), None, None, false)
.await
.unwrap_err();
assert!(error.to_string().contains("401"));
server.abort();
}
@ -697,13 +665,13 @@ mod tests {
#[serial]
async fn sync_uses_deployment_key_auth_mode() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let bundle = sample_bundle();
let (proxy_base_url, seen_headers, server) =
start_bundle_server(StatusCode::OK, serde_json::to_value(&bundle).unwrap()).await;
let am = test_auth_manager();
let result = sync_bundle_to_root(
&bundle::bundled_root(),
&root,
&proxy_base_url,
Some(&am),
Some("deploy-key"),
@ -726,8 +694,7 @@ mod tests {
#[serial]
fn status_only_reports_bundled_cache_not_higher_priority_sources() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle()).unwrap();
let project_root = tmp.path().join("workspace");
std::fs::create_dir_all(project_root.join(".grok/personas")).unwrap();
@ -742,23 +709,26 @@ mod tests {
"description = \"project role\"\n",
)
.unwrap();
let config = crate::config::SubagentsConfig::resolve(
let base = crate::config::SubagentsConfig::resolve_base_with_sources(
false,
&toml::Value::Table(Default::default()),
Some(&project_root),
None,
&root,
);
let (roles, personas) = crate::config::SubagentsConfig::effective_definition_maps(
&base.roles,
&base.personas,
&project_root,
true,
);
assert_eq!(
config
.personas
personas
.get("researcher")
.and_then(|persona| persona.instructions.as_deref()),
Some("project persona")
);
assert_eq!(
config
.roles
.get("reviewer")
.map(|role| role.description.as_str()),
roles.get("reviewer").map(|role| role.description.as_str()),
Some("project role")
);
let status = status_bundle_at(&root).unwrap();
@ -771,9 +741,9 @@ mod tests {
#[serial]
fn sync_requires_auth_or_deployment_key() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let error = futures::executor::block_on(sync_bundle_to_root(
&bundle::bundled_root(),
&root,
"http://127.0.0.1:1/v1",
None,
None,
@ -790,8 +760,7 @@ mod tests {
#[serial]
fn get_entry_reads_persona_file() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle()).unwrap();
let result = get_entry_at(&root, "persona", "researcher").unwrap();
assert_eq!(result.kind, "persona");
@ -802,8 +771,7 @@ mod tests {
#[serial]
fn get_entry_unknown_kind_returns_error() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
let err = get_entry_at(&root, "widget", "foo").unwrap_err();
assert!(err.to_string().contains("unknown entry kind: widget"));
}
@ -811,8 +779,7 @@ mod tests {
#[serial]
fn get_entry_missing_file_returns_error() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle()).unwrap();
let err = get_entry_at(&root, "persona", "nonexistent").unwrap_err();
assert!(err.to_string().contains("not found in bundle cache"));
@ -840,8 +807,7 @@ mod tests {
#[serial]
fn status_includes_persona_and_role_details() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle()).unwrap();
let status = status_bundle_at(&root).unwrap();
assert_eq!(status.persona_details.len(), 1);
@ -862,8 +828,7 @@ mod tests {
#[serial]
fn status_without_toml_files_returns_empty_details() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
let mut bundle = SubagentBundle::empty("v1");
bundle
.personas
@ -912,12 +877,12 @@ mod tests {
#[serial]
async fn sync_with_skills_reports_skills_count() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let bundle = sample_bundle_with_skills();
let (proxy_base_url, _seen_headers, server) =
start_bundle_server(StatusCode::OK, serde_json::to_value(&bundle).unwrap()).await;
let result = sync_bundle_to_root(
&bundle::bundled_root(),
&root,
&proxy_base_url,
Some(&test_auth_manager()),
None,
@ -936,8 +901,7 @@ mod tests {
#[serial]
fn status_lists_skill_names_from_manifest() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle_with_skills()).unwrap();
let status = status_bundle_at(&root).unwrap();
assert!(status.has_cache);
@ -948,8 +912,7 @@ mod tests {
#[serial]
fn status_skills_only_lists_files_present_on_disk() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = bundle::bundled_root();
let root = tmp.path().join("bundled");
bundle::write_bundle_to_cache(&root, &sample_bundle_with_skills()).unwrap();
std::fs::remove_file(root.join("skills/commit/SKILL.md")).unwrap();
let status = status_bundle_at(&root).unwrap();
@ -981,7 +944,7 @@ mod tests {
#[serial]
async fn sync_with_archive_endpoint_extracts_and_reports_counts() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let archive = make_test_archive(&[
("bundle.json", br#"{"version":"archive-v1"}"#),
(
@ -993,7 +956,7 @@ mod tests {
]);
let (proxy_base_url, server) = start_archive_bundle_server(archive).await;
let result = sync_bundle_to_root(
&bundle::bundled_root(),
&root,
&proxy_base_url,
Some(&test_auth_manager()),
None,
@ -1007,28 +970,20 @@ mod tests {
assert_eq!(result.roles_count, 1);
assert_eq!(result.agents_count, 0);
assert_eq!(result.skills_count, 1);
assert!(
bundle::bundled_root()
.join("personas/researcher.toml")
.exists()
);
assert!(
bundle::bundled_root()
.join("skills/commit/SKILL.md")
.exists()
);
assert!(root.join("personas/researcher.toml").exists());
assert!(root.join("skills/commit/SKILL.md").exists());
server.abort();
}
#[tokio::test(flavor = "current_thread")]
#[serial]
async fn sync_falls_back_to_legacy_when_archive_unavailable() {
let tmp = TempDir::new().unwrap();
let _home = with_bundled_home(&tmp);
let root = tmp.path().join("bundled");
let bundle = sample_bundle_with_skills();
let (proxy_base_url, _seen_headers, server) =
start_bundle_server(StatusCode::OK, serde_json::to_value(&bundle).unwrap()).await;
let result = sync_bundle_to_root(
&bundle::bundled_root(),
&root,
&proxy_base_url,
Some(&test_auth_manager()),
None,