grok-build-upstream-mirror/crates/codegen/xai-grok-pager/src/slash/commands/find.rs
grokkybara[bot] 3af4d5d398 Synced from monorepo
Synced from monorepo

Changes:
- Shell: accept target response id on rewind execute
- Shell: stamp response id on chat user message chunks
- Worktree: optional rebuild and stale git registration cleanup in auto-GC
- Worktree: kind-aware auto-GC TTLs and config knobs
- Worktree: macOS process CWD scan and Unix PID liveness for GC guards
- Worktree: automatic throttled GC on startup (Linux age-based; non-Linux dead-only)
- Pager: add `[ui].combine_queued_prompts` to batch queued follow-ups
- Shell: stop overwriting user skills
- Tools: read markdown in `skills/` directories untruncated
- `/usage` shows per-session token and dollar usage in the TUI
- Security: prompt on environment-dumping `ps` variants
- Security: always-safe `kubectl` no longer runs arbitrary kubeconfig credential plugins without permission
- Tools: make scheduler deletion durable
- Shell: add relocation storage primitives
- Shell: give side model calls their own conversation ids
- Fix five workflow-runtime bugs (budget, pause, cancel, reconnect)
- Security: peel `env -S` / `--split-string` operands in the Bash permission gate (managed deny/ask)
- Pager: expose doctor in the TUI
- Security: block unauthorized RCE via abused safe commands
- Pager idle watcher cue: "1 subagent still running" instead of "watching · 1 subagent"
- Security: block `rg --pre` arbitrary code execution in auto-mode
- Voice: diagnose silent-mic failures (macOS permission) and add doctor/terminal-setup Voice section
- App builder deployer: `allow_forking` and `show_built_with_grok`
- Pager: stop stacking duplicate "Worked for" markers on parked turns
- Shell: support `max` as a distinct reasoning effort tier
- Tools: serialize background `/loop` fires on the whole work unit
- Shell: add working-directory relocation state primitives
- Proto: `ClientToolResult` and `ChatConfig` client-side tools
- Shell: model providers
- Chat: select App Builder product on the Build path
- Shell: attach author identity to feedback when the deployment opts in
- Doctor: fix for SSH wrap setup
- Workflow authoring skills: create-workflow and import-claude-workflow docs
- Add read-only grok doctor
- Sandbox: apply Landlock without a controlling TTY
- Pager: recover image paste over grok wrap on headless remotes
- Pager: make actions screen-mode aware
- Shell: resume sessions when the working directory moves
- Pager: centralize terminal diagnostics
- Workspace: gate inline shell file access
- Pager: centralize terminal probes
- Pager: edit minimal prompts in an external editor
- Pager: standardize backgrounding on Ctrl+B
- Shell: recap rides the parent turn's prompt cache
- Tools: add scheduler lifecycle version clock

Source-Revision: 0f4d7c91b8b2b408333f6de1e8a76cb8eaa71899
2026-07-21 18:10:23 +00:00

133 lines
4 KiB
Rust

//! `/find` -- open an incremental search over the conversation scrollback.
//!
//! In simple mode a bare `/` goes to the prompt, so simple-mode users can't
//! reach the vim `/` scrollback search. `/find` focuses the scrollback pane
//! and opens the same search from either mode.
use crate::app::actions::Action;
use crate::slash::command::{CommandExecCtx, CommandResult, SlashCommand};
/// Open scrollback search via `/find`.
pub struct FindCommand;
impl SlashCommand for FindCommand {
fn name(&self) -> &str {
"find"
}
fn description(&self) -> &str {
"Search the conversation scrollback"
}
fn session_scoped(&self) -> bool {
true
}
fn usage(&self) -> &str {
"/find [text]"
}
fn takes_args(&self) -> bool {
true
}
fn arg_placeholder(&self) -> Option<&str> {
Some("[text]")
}
/// Minimal mode has no interactive scrollback pane to search — the
/// terminal's own search covers it (K7/§6.13). Gated off with a message.
fn available_in_minimal(&self) -> bool {
false
}
fn run(&self, _ctx: &mut CommandExecCtx, args: &str) -> CommandResult {
// whitespace-only args open a blank search.
let initial = args.trim();
let query = (!initial.is_empty()).then(|| initial.to_string());
CommandResult::Action(Action::OpenScrollbackSearch(query))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::acp::model_state::ModelState;
static DEFAULT_BUNDLE_STATE: crate::app::bundle::BundleState =
crate::app::bundle::BundleState {
has_cache: false,
version: String::new(),
personas: Vec::new(),
roles: Vec::new(),
agents: Vec::new(),
skills: Vec::new(),
persona_details: Vec::new(),
role_details: Vec::new(),
};
fn make_ctx(models: &ModelState) -> CommandExecCtx<'_> {
CommandExecCtx {
models,
session_id: None,
bundle_state: &DEFAULT_BUNDLE_STATE,
screen_mode: crate::app::ScreenMode::Inline,
billing_surface_visible: true,
pager_state: crate::settings::PagerLocalSnapshot::default(),
}
}
#[test]
fn find_returns_open_scrollback_search_action() {
let models = ModelState::default();
let mut ctx = make_ctx(&models);
let cmd = FindCommand;
assert!(matches!(
cmd.run(&mut ctx, ""),
CommandResult::Action(Action::OpenScrollbackSearch(None))
));
}
#[test]
fn find_with_word_carries_it_as_initial_query() {
let models = ModelState::default();
let mut ctx = make_ctx(&models);
let cmd = FindCommand;
let CommandResult::Action(Action::OpenScrollbackSearch(query)) = cmd.run(&mut ctx, "foo")
else {
panic!("/find foo must open scrollback search");
};
assert_eq!(query.as_deref(), Some("foo"));
}
#[test]
fn find_with_blank_args_carries_no_initial_query() {
let models = ModelState::default();
let mut ctx = make_ctx(&models);
let cmd = FindCommand;
// Both a bare `/find` and whitespace-only args open a blank search.
for args in ["", " "] {
assert!(matches!(
cmd.run(&mut ctx, args),
CommandResult::Action(Action::OpenScrollbackSearch(None))
));
}
}
#[test]
fn find_advertises_optional_text_arg() {
// Pins the slash-arg contract so completion-accept appends a trailing
// space and the `[text]` placeholder shows while typing; bare `/find`
// stays valid (args not required).
let cmd = FindCommand;
assert!(cmd.takes_args());
assert!(!cmd.args_required());
assert_eq!(cmd.arg_placeholder(), Some("[text]"));
}
#[test]
fn not_available_in_minimal() {
// Native terminal search replaces in-app scrollback search in minimal.
assert!(!FindCommand.available_in_minimal());
}
}