Add worktrees, per-hunk review, effort per message, regenerate, voice input
- Isolated git worktree per session (create, status, merge, discard) - Permission card: accept file-edit hunks individually; agent learns what was rejected - Reasoning effort per message; regenerate the last answer with another model/effort - Voice input via the Web Speech API - Folder-up button in the file browser; ssh, rsync and mc in the image Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
df1924b0a1
commit
fca1c41087
22 files changed
+821
-32
No files matched your search
+9
-6
@@ -25,7 +25,7 @@ pub enum PermissionReply {
|
||||
|
||||
struct PendingPermission {
|
||||
event: Event,
|
||||
tx: oneshot::Sender<(PermissionReply, Option<String>)>,
|
||||
tx: oneshot::Sender<(PermissionReply, Option<String>, Option<Vec<usize>>)>,
|
||||
}
|
||||
|
||||
struct PendingQuestion {
|
||||
@@ -41,6 +41,8 @@ pub struct Runtime {
|
||||
pub approved: HashSet<String>,
|
||||
/// The model request currently running (for clients that connect mid-step).
|
||||
pub step: Option<Value>,
|
||||
/// Reasoning effort chosen for the current turn (overrides the model's default).
|
||||
pub effort: Option<String>,
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
@@ -436,7 +438,7 @@ impl App {
|
||||
input: Value,
|
||||
diff: Option<String>,
|
||||
cancel: CancellationToken,
|
||||
) -> (PermissionReply, Option<String>) {
|
||||
) -> (PermissionReply, Option<String>, Option<Vec<usize>>) {
|
||||
let id = crate::types::new_id();
|
||||
let event = Event::PermissionRequest {
|
||||
id: id.clone(),
|
||||
@@ -451,17 +453,18 @@ impl App {
|
||||
self.permissions.lock().unwrap().insert(id.clone(), PendingPermission { event: event.clone(), tx });
|
||||
self.emit(event);
|
||||
let res = tokio::select! {
|
||||
r = rx => r.unwrap_or((PermissionReply::Reject, None)),
|
||||
_ = cancel.cancelled() => (PermissionReply::Reject, Some("aborted".into())),
|
||||
r = rx => r.unwrap_or((PermissionReply::Reject, None, None)),
|
||||
_ = cancel.cancelled() => (PermissionReply::Reject, Some("aborted".into()), None),
|
||||
};
|
||||
self.permissions.lock().unwrap().remove(&id);
|
||||
self.emit(Event::PermissionResolved { id, session_id: session_id.to_string() });
|
||||
res
|
||||
}
|
||||
|
||||
pub fn reply_permission(&self, id: &str, reply: PermissionReply, message: Option<String>) -> Result<()> {
|
||||
/// `hunks`: for file edits, the indices of the diff hunks the user accepted (None = all).
|
||||
pub fn reply_permission(&self, id: &str, reply: PermissionReply, message: Option<String>, hunks: Option<Vec<usize>>) -> Result<()> {
|
||||
let p = self.permissions.lock().unwrap().remove(id).ok_or_else(|| anyhow!("permission not pending"))?;
|
||||
let _ = p.tx.send((reply, message));
|
||||
let _ = p.tx.send((reply, message, hunks));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user