Approval mode of automations in the list; Telegram switch per chat
- Automations: the approval mode is a selection in the list; PATCH /jobs/{id}
writes permission_mode into the job file's frontmatter (rest of the file
unchanged, invalid modes rejected). "Allow everything" lets nightly runs work
without waiting for approvals via Telegram until the timeout.
- Session.telegram_quiet: approvals and questions of a chat (and its subagents)
are not sent to Telegram; the chat open in Telegram always reports. Toggle in
the chat's ⋯ menu when a bot is paired. New chats from the web UI and
automation runs start quiet; chats started from Telegram and existing chats
keep reporting.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9339e2db41
commit
bd490efda5
13 files changed
+148
-2
No files matched your search
@@ -165,6 +165,8 @@ pub async fn run_with(app: &Arc<App>, job: &Job, trigger: &str, payload: Option<
|
||||
archived: false,
|
||||
folder: None,
|
||||
instructions: String::new(),
|
||||
// New chats keep their approvals and questions out of Telegram (⋯ menu turns it on).
|
||||
telegram_quiet: true,
|
||||
};
|
||||
let session = app.save_session(session)?;
|
||||
app.store.job_started(&job.id, &session.id, now)?;
|
||||
@@ -284,6 +286,49 @@ pub fn write_file(path: &Path, j: &NewJob) -> Result<JobSpec> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Set `permission_mode` in the frontmatter of a job file (replaces the line or adds it
|
||||
/// before the closing `---`); the rest of the file stays as it is.
|
||||
pub fn set_permission_mode(path: &Path, mode: &str) -> Result<JobSpec> {
|
||||
if !crate::permission::MODES.contains(&mode) {
|
||||
bail!("invalid permission_mode '{mode}'");
|
||||
}
|
||||
let text = std::fs::read_to_string(path).with_context(|| format!("cannot read {}", path.display()))?;
|
||||
let updated = set_frontmatter_key(&text, "permission_mode", mode).ok_or_else(|| anyhow!("{} has no frontmatter", path.display()))?;
|
||||
std::fs::write(path, &updated)?;
|
||||
match parse(path) {
|
||||
Ok(spec) => Ok(spec),
|
||||
Err(e) => {
|
||||
let _ = std::fs::write(path, &text);
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_frontmatter_key(text: &str, key: &str, value: &str) -> Option<String> {
|
||||
let bom = if text.starts_with('\u{feff}') { "\u{feff}" } else { "" };
|
||||
let t = &text[bom.len()..];
|
||||
let rest = t.strip_prefix("---")?;
|
||||
let end = rest.find("\n---")?;
|
||||
let (head, tail) = (&rest[..end], &rest[end..]);
|
||||
let prefix = format!("{key}:");
|
||||
let mut found = false;
|
||||
let mut lines: Vec<String> = head
|
||||
.split('\n')
|
||||
.map(|l| {
|
||||
if !found && l.trim_start().starts_with(&prefix) {
|
||||
found = true;
|
||||
format!("{key}: {value}")
|
||||
} else {
|
||||
l.to_string()
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
if !found {
|
||||
lines.push(format!("{key}: {value}"));
|
||||
}
|
||||
Some(format!("{bom}---{}{tail}", lines.join("\n")))
|
||||
}
|
||||
|
||||
/// Free file name for a new job in `<project>/.codecraft/jobs/`.
|
||||
pub fn new_job_path(project: &Path, name: &str) -> PathBuf {
|
||||
let dir = project.join(".codecraft/jobs");
|
||||
@@ -446,6 +491,12 @@ mod tests {
|
||||
let s = parse(&p).unwrap();
|
||||
assert_eq!((s.name.as_str(), s.schedule.as_str(), s.agent.as_str(), s.permission_mode.as_str()), ("Nightly", "0 3 * * *", "build", "auto"));
|
||||
assert_eq!(job_cwd(&p, &s), dir);
|
||||
// Added when missing, replaced when present; comments and the prompt stay.
|
||||
assert_eq!(set_permission_mode(&p, "bypass").unwrap().permission_mode, "bypass");
|
||||
std::fs::write(&p, "---\nname: N\npermission_mode: auto # comment\nschedule: \"0 3 * * *\"\n---\nPrompt\n---\nmore\n").unwrap();
|
||||
assert_eq!(set_permission_mode(&p, "accept_edits").unwrap().permission_mode, "accept_edits");
|
||||
assert_eq!(std::fs::read_to_string(&p).unwrap(), "---\nname: N\npermission_mode: accept_edits\nschedule: \"0 3 * * *\"\n---\nPrompt\n---\nmore\n");
|
||||
assert!(set_permission_mode(&p, "yolo").is_err());
|
||||
std::fs::remove_dir_all(&dir).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user