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:
parent
98c3b2438a
commit
7cfcb20d2b
292 changed files with 23315 additions and 9209 deletions
|
|
@ -233,8 +233,8 @@ pub fn persist_trust(store: &mut TrustStore, key: &Path) {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether any repo-local code-exec config is present for `cwd`. When none are
|
||||
/// present there is nothing to gate, so we skip the prompt entirely.
|
||||
/// Whether any repo-local trust-sensitive config is present for `cwd`. When none
|
||||
/// are present there is nothing to gate, so we skip the prompt entirely.
|
||||
///
|
||||
/// Thin wrapper over [`collect_repo_config_kinds`] with `first_only = true`, so
|
||||
/// the gate and the display-only [`repo_config_kinds`] enumerate the EXACT same
|
||||
|
|
@ -244,12 +244,13 @@ pub fn repo_configs_present(cwd: &Path) -> bool {
|
|||
!collect_repo_config_kinds(cwd, true).is_empty()
|
||||
}
|
||||
|
||||
/// Display-only: which repo-local code-exec config KINDS are present for `cwd`
|
||||
/// (`mcp`, `plugins`, `lsp`, `envrc`, `claude`, `hooks`, `agents`), deduped in
|
||||
/// cheap→expensive marker order. Single source with [`repo_configs_present`]
|
||||
/// (which is `!repo_config_kinds(cwd).is_empty()`), so a folder that the gate
|
||||
/// fired on always has a non-empty, accurate kind list — no `[plugins].paths` /
|
||||
/// `.claude` / `.grok/agents` / subdir-launch gaps. NOT itself the trust gate.
|
||||
/// Display-only: which repo-local trust-sensitive config KINDS are present for
|
||||
/// `cwd` (`mcp`, `plugins`, `lsp`, `envrc`, `claude`, `hooks`, `agents`, `roles`,
|
||||
/// `personas`), deduped in cheap→expensive marker order. Single source with
|
||||
/// [`repo_configs_present`] (which is `!repo_config_kinds(cwd).is_empty()`), so a
|
||||
/// folder that the gate fired on always has a non-empty, accurate kind list — no
|
||||
/// `[plugins].paths` / `.claude` / `.grok/agents` / subdir-launch gaps. NOT
|
||||
/// itself the trust gate.
|
||||
pub fn repo_config_kinds(cwd: &Path) -> Vec<&'static str> {
|
||||
collect_repo_config_kinds(cwd, false)
|
||||
}
|
||||
|
|
@ -262,6 +263,14 @@ fn path_present_or_uncertain(path: &Path) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
fn directory_present_or_uncertain(path: &Path) -> bool {
|
||||
match std::fs::metadata(path) {
|
||||
Ok(metadata) => metadata.is_dir(),
|
||||
Err(error) if error.kind() == std::io::ErrorKind::NotFound => false,
|
||||
Err(_) => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared scanner behind [`repo_configs_present`] and [`repo_config_kinds`]. With
|
||||
/// `first_only` it returns immediately after the first marker (the gate's
|
||||
/// historical short-circuit); otherwise it collects every distinct kind.
|
||||
|
|
@ -376,6 +385,14 @@ fn collect_repo_config_kinds(cwd: &Path, first_only: bool) -> Vec<&'static str>
|
|||
if !xai_grok_agent::discovery::project_agent_dirs_in(&chain.dirs).is_empty() {
|
||||
hit!("agents");
|
||||
}
|
||||
// Presence matches exact-cwd discovery without parsing repository content.
|
||||
let grok = cwd.join(".grok");
|
||||
if directory_present_or_uncertain(&grok.join("roles")) {
|
||||
hit!("roles");
|
||||
}
|
||||
if directory_present_or_uncertain(&grok.join("personas")) {
|
||||
hit!("personas");
|
||||
}
|
||||
// `~/.claude.json` `projects.<cwd>.mcpServers`.
|
||||
if claude_project_mcp_present(cwd) {
|
||||
hit!("mcp");
|
||||
|
|
@ -595,6 +612,64 @@ mod tests {
|
|||
assert!(repo_configs_present(&subdir));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repo_configs_present_detects_project_roles() {
|
||||
let tmp = repo_tmp();
|
||||
std::fs::create_dir_all(tmp.path().join(".grok").join("roles")).unwrap();
|
||||
|
||||
assert!(repo_configs_present(tmp.path()));
|
||||
assert!(repo_config_kinds(tmp.path()).contains(&"roles"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repo_configs_present_detects_project_personas() {
|
||||
let tmp = repo_tmp();
|
||||
std::fs::create_dir_all(tmp.path().join(".grok").join("personas")).unwrap();
|
||||
|
||||
assert!(repo_configs_present(tmp.path()));
|
||||
assert!(repo_config_kinds(tmp.path()).contains(&"personas"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_subagent_marker_regular_file_is_absent() {
|
||||
let tmp = repo_tmp();
|
||||
let grok = tmp.path().join(".grok");
|
||||
std::fs::create_dir_all(&grok).unwrap();
|
||||
std::fs::write(grok.join("roles"), "not a directory").unwrap();
|
||||
assert!(!repo_configs_present(tmp.path()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_subagent_marker_at_repo_root_is_absent_from_subdir() {
|
||||
let tmp = repo_tmp();
|
||||
std::fs::create_dir_all(tmp.path().join(".grok/roles")).unwrap();
|
||||
let subdir = tmp.path().join("nested");
|
||||
std::fs::create_dir_all(&subdir).unwrap();
|
||||
assert!(!repo_configs_present(&subdir));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn project_subagent_marker_symlink_to_directory_is_present() {
|
||||
let tmp = repo_tmp();
|
||||
let target = tmp.path().join("target-roles");
|
||||
let grok = tmp.path().join(".grok");
|
||||
std::fs::create_dir_all(&target).unwrap();
|
||||
std::fs::create_dir_all(&grok).unwrap();
|
||||
std::os::unix::fs::symlink(&target, grok.join("roles")).unwrap();
|
||||
assert!(repo_configs_present(tmp.path()));
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn dangling_project_subagent_marker_is_absent() {
|
||||
let tmp = repo_tmp();
|
||||
let grok = tmp.path().join(".grok");
|
||||
std::fs::create_dir_all(&grok).unwrap();
|
||||
std::os::unix::fs::symlink("missing", grok.join("personas")).unwrap();
|
||||
assert!(!repo_configs_present(tmp.path()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn repo_configs_present_detects_claude_settings_from_subdir() {
|
||||
// A `.claude/settings.json` `env` in a SUBDIR (no other repo config),
|
||||
|
|
|
|||
Loading…
Reference in a new issue