Add web terminal, git credentials, OpenSCAD, review loops, automations
- Web terminal (PTY over WebSocket, xterm.js, sandboxed, reattach with replay) - Per-user git credentials and commit identity (credential store in the user's home) - OpenSCAD tool (STL/3MF + preview renders, bounding box) and cad skill; 3D model card - Craft phase inferred from tool activity when the agent does not report it - Configurable review loop per mode (rounds, reviewer model, criteria) - Delete config and Markdown agents from the agent editor - Automations: cron-scheduled agents from Markdown job files, schedule tool, page - change_directory tool (only on the user's request) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a0d0e707f2
commit
df1924b0a1
41 files changed
+2809
-34
No files matched your search
+7
-1
@@ -42,6 +42,8 @@ const SAFE_OPTS: &[&str] = &["-c", "core.hooksPath=/dev/null", "-c", "core.fsmon
|
||||
tokio::task_local! {
|
||||
/// Sandbox of the requesting user for all git calls of this request.
|
||||
static SANDBOX: Option<crate::sandbox::SandboxSpec>;
|
||||
/// The user's git config (credentials, identity) for unsandboxed runs.
|
||||
static GITCONFIG: Option<std::path::PathBuf>;
|
||||
}
|
||||
|
||||
async fn git(dir: &Path, args: &[&str], timeout: u64) -> Result<Out, ApiError> {
|
||||
@@ -58,6 +60,9 @@ async fn git(dir: &Path, args: &[&str], timeout: u64) -> Result<Out, ApiError> {
|
||||
None => {
|
||||
let mut c = Command::new("git");
|
||||
c.args(&all).current_dir(dir).env("GIT_TERMINAL_PROMPT", "0").env("GIT_PAGER", "cat").env("LC_ALL", "C");
|
||||
if let Some(cfg) = GITCONFIG.try_with(|g| g.clone()).ok().flatten() {
|
||||
c.env("GIT_CONFIG_GLOBAL", cfg);
|
||||
}
|
||||
c
|
||||
}
|
||||
};
|
||||
@@ -165,7 +170,8 @@ fn parse_status(raw: &str) -> Value {
|
||||
|
||||
pub async fn handle(Extension(user): Extension<User>, State(app): State<AppState>, Json(b): Json<GitBody>) -> ApiResult {
|
||||
let spec = crate::sandbox::spec_for(&app, Some(&user.id));
|
||||
SANDBOX.scope(spec, handle_inner(user, app, b)).await
|
||||
let cfg = crate::gitcreds::global_config(&app, &user);
|
||||
SANDBOX.scope(spec, GITCONFIG.scope(cfg, handle_inner(user, app, b))).await
|
||||
}
|
||||
|
||||
async fn handle_inner(user: User, app: AppState, b: GitBody) -> ApiResult {
|
||||
|
||||
Reference in new issue
Block a user