Synced from monorepo

Changes:
- Non-blocking coding-data sharing upsell banner
- Consolidate remediation in Doctor
- Auto mode defers fail-closed gate asks to the classifier
- Coalesce marketplace list fetches
- Allow removing a marketplace source by name
- Contain hung git marketplace sources (timeouts, non-blocking refresh, unbrick modal)
- Label failed workspace RPCs with error_kind
- Drop redundant explicit tonic/prost deps from xai-grok-shell
- Report real exit codes for completed background shells
- Narrow the date-rollover reminder to date-bearing templates
- Wire toolOverrides through the session and agent
- Security: Bash(git:*) allowlist matches whole command chain by prefix
- Split prompt-trigger telemetry and record classifier provenance
- Raise connectors-manager timeout to 60s
- Auto classifier honors recorded approvals for repeat actions
- Apply doctor fixes in the TUI
- Auto-mode classifier timeouts prompt instead of silently denying
- Scope subagent completion drains to the owning session
- Add the toolOverrides wire types
- Set client_identifier=grok-agent-sdk
- Accept both spellings of the workspace-teleport kill switch
- Persist one-shot occurrence journal
- Stop turns that poll the exact same tool call 16x in a row
- Copy compaction checkpoint files when forking sessions
- Auto-focus permission prompt from scrollback
- Esc cancels the running turn in non-vim and minimal modes
- List Ctrl+Z undo and redo in keyboard shortcuts
- Out-of-process macOS mic capture
- Show active auth mode on session-info
- Install the npm binary under $GROK_HOME
- Remove hover/click dead zones between dashboard items
- Route startup warnings to doctor
- Document [feedback.user] author identity config
- Extend bang command timeout
- Close combine-queued edit-hold race
- Integrate relocation recovery
- Expose privacy notice rollout flag
- Break harness discovery ref cycle so connections can idle-evict
- Shift/Alt+Enter inserts newline when editing a queued prompt
- Gate project Claude permissions on folder trust
- Echo response.create.event_id on response.created
- Toast when session creation fails from disk full
- Add shared test process lifecycle
- Enable dynamic workflows by default
- Add relocation transaction state machine
- Add shared test sandbox
- Surface auth failures on model-switch compact
- Persist durable scheduler expiry
- Confirm before removing extensions-modal items
- Re-run compact and prompt after login when compact hit expired auth
- Recap sends hosted tools under backend search
This commit is contained in:
grokkybara[bot] 2026-07-22 19:18:53 +01:00
commit a5727c5960
482 changed files with 37627 additions and 13402 deletions

View file

@ -983,6 +983,19 @@ impl SlashController {
self.arg_suggestions(command.as_ref(), models, &input.args_query)
}
fn argument_highlight_indices(&mut self, query: &str, display: &str) -> Vec<u32> {
let token = query.split_whitespace().next_back().unwrap_or("");
let fragment = token.rsplit(['/', '\\']).next().unwrap_or(token);
self.matcher
.indices_for(fragment, display)
.or_else(|| {
fragment
.rsplit_once('.')
.and_then(|(_, suffix)| self.matcher.indices_for(suffix, display))
})
.unwrap_or_default()
}
/// Generate argument suggestions for a specific command.
fn arg_suggestions(
&mut self,
@ -1012,7 +1025,7 @@ impl SlashController {
hits.into_iter()
.map(|(idx, _)| {
let mut row = SuggestionRow::from_arg(&items[idx]);
row.indices = self.matcher.indices(row.display.as_str());
row.indices = self.argument_highlight_indices(trimmed, &row.display);
row
})
.collect()
@ -2684,6 +2697,11 @@ mod tests {
.collect();
assert_eq!(rows, vec![("first", true), ("second", false)]);
ctrl.refresh(&state, "/chain fir", 10, &models);
let snap = state.snapshot();
assert!(snap.open);
assert_eq!(snap.matches[0].indices, vec![0, 1, 2]);
// Typing "first " triggers the phase-2 sub-menu of terminal rows.
ctrl.refresh(&state, "/chain first ", 13, &models);
let snap = state.snapshot();
@ -2693,6 +2711,11 @@ mod tests {
.map(|r| (r.display.as_str(), r.insert_text.ends_with(' ')))
.collect();
assert_eq!(rows, vec![("alpha", false), ("beta", false)]);
ctrl.refresh(&state, "/chain first al", 15, &models);
let snap = state.snapshot();
assert!(snap.open);
assert_eq!(snap.matches[0].indices, vec![0, 1]);
}
#[test]
@ -2712,6 +2735,39 @@ mod tests {
assert!(displays.contains(&"/doctor"), "matches: {displays:?}");
assert!(!displays.contains(&"/terminal-setup"));
for text in ["/doctor ", "/terminal-setup "] {
ctrl.refresh(&state, text, text.len(), &models);
let snapshot = state.snapshot();
assert!(!snapshot.open, "bare args opened for {text:?}");
assert!(snapshot.matches.is_empty(), "matches for {text:?}");
}
for (text, inserted, indices) in [
("/doctor f", "fix", vec![0]),
("/doctor fix s", "fix ssh-wrap", vec![0]),
("/doctor fix ssh", "fix ssh-wrap", vec![0, 1, 2]),
("/doctor fix terminal.s", "fix ssh-wrap", vec![0]),
("/terminal-setup f", "fix", vec![0]),
("/terminal-setup fix s", "fix ssh-wrap", vec![0]),
] {
ctrl.refresh(&state, text, text.len(), &models);
let snapshot = state.snapshot();
assert!(snapshot.open, "no matches for {text:?}");
assert_eq!(snapshot.matches[0].insert_text, inserted);
assert_eq!(snapshot.matches[0].indices, indices, "{text:?}");
}
for text in [
"/doctor fix ssh-wrap",
"/doctor fix terminal.ssh-wrap",
"/terminal-setup fix ssh-wrap",
"/terminal-setup fix terminal.ssh-wrap",
] {
ctrl.refresh(&state, text, text.len(), &models);
let snapshot = state.snapshot();
assert!(!snapshot.open, "exact form left picker open for {text:?}");
assert!(snapshot.matches.is_empty(), "matches for {text:?}");
}
let text = "/terminal-setup";
ctrl.refresh(&state, text, text.len(), &models);
let snapshot = state.snapshot();