Synced from monorepo

Synced from monorepo

Changes:
- Cache growing transcripts on the messages backend
- Tell the model when a wait was clamped instead of re-inviting it
- Stop the stationarity nudge from claiming results are identical
- Deliver the stationarity nudge after the tool result
- Run auth provider commands through the platform shell (fixes Windows)
- Keep monitor tool stdout short and prescriptive
- Use UUIDs for analytics event insert IDs
- Stop crashing at startup when the host runs out of threads
- Delete the current session from within the session
- Add project forking-settings toggle (backend and deploy-time control)
- Reap a session’s bash and background commands when it closes
- Reap a session’s hook child processes when it closes
- Track coding-data consent decisions
- Fail open the access gate to stop false CLI paywalls
- Ship Agent Dashboard user guide
- Enable doom-loop recovery by default
- Kill agent children and the idle inhibitor when the parent process dies
- Fix multi-process credential wipe and orphaned session log writers

Source-Revision: 6372e41d828b8a6ee82c29e01a69e27ec895cca9
This commit is contained in:
grokkybara[bot] 2026-07-29 17:17:54 +00:00
commit 500129c714
89 changed files with 3841 additions and 771 deletions

View file

@ -63,7 +63,7 @@ enum Msg {
struct Daemon {
shared: Arc<Mutex<Snapshot>>,
tx: SyncSender<Msg>,
_handle: JoinHandle<()>,
handle: Option<JoinHandle<()>>,
}
const MAX_RESULTS: usize = 100;
@ -74,7 +74,7 @@ impl Daemon {
let (tx, rx) = sync_channel::<Msg>(256);
let out = shared.clone();
let handle = thread::spawn(move || {
let worker = move || {
let mut pattern = MultiPattern::new(1);
let mut matcher = Matcher::new(Config::DEFAULT);
let mut items: Vec<(String, Utf32String)> = Vec::new();
@ -82,7 +82,6 @@ impl Daemon {
let mut prev_q = String::new();
while let Ok(msg) = rx.recv() {
// Drain to latest — skip intermediate queries.
let msg = drain_to_latest(msg, &rx);
match msg {
@ -144,13 +143,23 @@ impl Daemon {
Msg::Stop => break,
}
}
});
};
let handle = thread::Builder::new()
.name("history-search".into())
.spawn(worker);
Self {
shared,
tx,
_handle: handle,
}
let handle = match handle {
Ok(h) => Some(h),
Err(e) => {
tracing::error!(
error = %e,
"history search daemon thread spawn failed; history search disabled"
);
None
}
};
Self { shared, tx, handle }
}
}
@ -355,6 +364,9 @@ impl HistorySearchState {
}
fn activate_inner(&mut self, history: &[HistoryEntry], current_text: &str, browse: bool) {
if !self.is_available() {
return;
}
self.active = true;
self.browse = browse;
self.saved_text = current_text.to_string();
@ -369,6 +381,12 @@ impl HistorySearchState {
self.selected = self.snapshot.items.len().saturating_sub(1);
}
/// False when the matcher thread never started, so the overlay cannot open
/// and callers must leave the composer alone.
pub fn is_available(&self) -> bool {
self.daemon.handle.is_some()
}
/// True while the overlay is in browse mode (see [`Self::activate_browse`]).
pub fn is_browse(&self) -> bool {
self.active && self.browse

View file

@ -399,6 +399,11 @@ pub(crate) fn default_palette_entries(
shortcut: "/home".into(),
command: PaletteCommand::Home,
},
PaletteEntry {
label: "Delete This Session".into(),
shortcut: "/delete".into(),
command: PaletteCommand::SlashCommand("/delete".into()),
},
PaletteEntry {
label: "Resume Session".into(),
shortcut: "/resume".into(),

View file

@ -131,6 +131,7 @@ pub enum LocalQuestionKind {
target: crate::app::actions::DoctorFixTarget,
plan: Box<crate::diagnostics::FixPlan>,
},
DeleteCurrentSession,
}
// ── State ──────────────────────────────────────────────────────────────