From c85ae5f0dec45f47520b4d2a00cfdced5569eb70 Mon Sep 17 00:00:00 2001 From: Gabriel Gordon-Hall Date: Wed, 7 Jan 2026 18:52:33 +0000 Subject: [PATCH 1/3] remove configurable agent_working_dir (cherry picked from commit 285b3e04abceeb8e4a4ee1be16e3de97a8f32299) --- ...7d2217281d0082965cca6b15a9f3e9be1c3b.json} | 6 ++-- ...aef5e16eb58d847540b1d998a741996967643.json | 12 -------- crates/db/src/models/project.rs | 20 +------------ crates/server/src/routes/task_attempts.rs | 21 +++++++------- crates/services/src/services/container.rs | 29 ------------------- crates/services/src/services/project.rs | 28 ------------------ frontend/src/i18n/locales/en/settings.json | 5 ---- frontend/src/i18n/locales/es/settings.json | 5 ---- frontend/src/i18n/locales/ja/settings.json | 5 ---- frontend/src/i18n/locales/ko/settings.json | 5 ---- .../src/i18n/locales/zh-Hans/settings.json | 5 ---- .../src/pages/settings/ProjectSettings.tsx | 24 --------------- shared/types.ts | 2 +- 13 files changed, 16 insertions(+), 151 deletions(-) rename crates/db/.sqlx/{query-e3f01fc53c00ee217b823ca588dc9a5320c9ba6ddf2bd718c817dfbf5fefd21c.json => query-38d1abbfb839e62833308d65b9417d2217281d0082965cca6b15a9f3e9be1c3b.json} (59%) delete mode 100644 crates/db/.sqlx/query-43c10bbafd851c362132fd0657eaef5e16eb58d847540b1d998a741996967643.json diff --git a/crates/db/.sqlx/query-e3f01fc53c00ee217b823ca588dc9a5320c9ba6ddf2bd718c817dfbf5fefd21c.json b/crates/db/.sqlx/query-38d1abbfb839e62833308d65b9417d2217281d0082965cca6b15a9f3e9be1c3b.json similarity index 59% rename from crates/db/.sqlx/query-e3f01fc53c00ee217b823ca588dc9a5320c9ba6ddf2bd718c817dfbf5fefd21c.json rename to crates/db/.sqlx/query-38d1abbfb839e62833308d65b9417d2217281d0082965cca6b15a9f3e9be1c3b.json index 5dfa4f8648..c046a0f2a6 100644 --- a/crates/db/.sqlx/query-e3f01fc53c00ee217b823ca588dc9a5320c9ba6ddf2bd718c817dfbf5fefd21c.json +++ b/crates/db/.sqlx/query-38d1abbfb839e62833308d65b9417d2217281d0082965cca6b15a9f3e9be1c3b.json @@ -1,6 +1,6 @@ { "db_name": "SQLite", - "query": "UPDATE projects\n SET name = $2, default_agent_working_dir = $3\n WHERE id = $1\n RETURNING id as \"id!: Uuid\",\n name,\n default_agent_working_dir,\n remote_project_id as \"remote_project_id: Uuid\",\n created_at as \"created_at!: DateTime\",\n updated_at as \"updated_at!: DateTime\"", + "query": "UPDATE projects\n SET name = $2\n WHERE id = $1\n RETURNING id as \"id!: Uuid\",\n name,\n default_agent_working_dir,\n remote_project_id as \"remote_project_id: Uuid\",\n created_at as \"created_at!: DateTime\",\n updated_at as \"updated_at!: DateTime\"", "describe": { "columns": [ { @@ -35,7 +35,7 @@ } ], "parameters": { - "Right": 3 + "Right": 2 }, "nullable": [ true, @@ -46,5 +46,5 @@ false ] }, - "hash": "e3f01fc53c00ee217b823ca588dc9a5320c9ba6ddf2bd718c817dfbf5fefd21c" + "hash": "38d1abbfb839e62833308d65b9417d2217281d0082965cca6b15a9f3e9be1c3b" } diff --git a/crates/db/.sqlx/query-43c10bbafd851c362132fd0657eaef5e16eb58d847540b1d998a741996967643.json b/crates/db/.sqlx/query-43c10bbafd851c362132fd0657eaef5e16eb58d847540b1d998a741996967643.json deleted file mode 100644 index 1e5b0e98c2..0000000000 --- a/crates/db/.sqlx/query-43c10bbafd851c362132fd0657eaef5e16eb58d847540b1d998a741996967643.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "db_name": "SQLite", - "query": "UPDATE projects\n SET default_agent_working_dir = ''\n WHERE id = $1", - "describe": { - "columns": [], - "parameters": { - "Right": 1 - }, - "nullable": [] - }, - "hash": "43c10bbafd851c362132fd0657eaef5e16eb58d847540b1d998a741996967643" -} diff --git a/crates/db/src/models/project.rs b/crates/db/src/models/project.rs index e22086f881..c4c2ca0117 100644 --- a/crates/db/src/models/project.rs +++ b/crates/db/src/models/project.rs @@ -38,7 +38,6 @@ pub struct CreateProject { #[derive(Debug, Deserialize, TS)] pub struct UpdateProject { pub name: Option, - pub default_agent_working_dir: Option, } #[derive(Debug, Serialize, TS)] @@ -196,12 +195,11 @@ impl Project { .ok_or(sqlx::Error::RowNotFound)?; let name = payload.name.clone().unwrap_or(existing.name); - let default_agent_working_dir = payload.default_agent_working_dir.clone(); sqlx::query_as!( Project, r#"UPDATE projects - SET name = $2, default_agent_working_dir = $3 + SET name = $2 WHERE id = $1 RETURNING id as "id!: Uuid", name, @@ -211,27 +209,11 @@ impl Project { updated_at as "updated_at!: DateTime""#, id, name, - default_agent_working_dir, ) .fetch_one(pool) .await } - pub async fn clear_default_agent_working_dir( - pool: &SqlitePool, - id: Uuid, - ) -> Result<(), sqlx::Error> { - sqlx::query!( - r#"UPDATE projects - SET default_agent_working_dir = '' - WHERE id = $1"#, - id - ) - .execute(pool) - .await?; - Ok(()) - } - pub async fn set_remote_project_id( pool: &SqlitePool, id: Uuid, diff --git a/crates/server/src/routes/task_attempts.rs b/crates/server/src/routes/task_attempts.rs index 9a2811dbd5..2c953bcd4f 100644 --- a/crates/server/src/routes/task_attempts.rs +++ b/crates/server/src/routes/task_attempts.rs @@ -176,16 +176,17 @@ pub async fn create_task_attempt( .await? .ok_or(SqlxError::RowNotFound)?; - let project = task - .parent_project(pool) - .await? - .ok_or(SqlxError::RowNotFound)?; - - let agent_working_dir = project - .default_agent_working_dir - .as_ref() - .filter(|dir| !dir.is_empty()) - .cloned(); + // Compute agent_working_dir based on repo count: + // - Single repo: use repo name as working dir (agent runs in repo directory) + // - Multiple repos: use None (agent runs in workspace root) + let agent_working_dir = if payload.repos.len() == 1 { + let repo = Repo::find_by_id(pool, payload.repos[0].repo_id) + .await? + .ok_or(RepoError::NotFound)?; + Some(repo.name) + } else { + None + }; let attempt_id = Uuid::new_v4(); let git_branch_name = deployment diff --git a/crates/services/src/services/container.rs b/crates/services/src/services/container.rs index ae46a06cdc..b49c722a62 100644 --- a/crates/services/src/services/container.rs +++ b/crates/services/src/services/container.rs @@ -18,8 +18,6 @@ use db::{ execution_process_repo_state::{ CreateExecutionProcessRepoState, ExecutionProcessRepoState, }, - project::{Project, UpdateProject}, - project_repo::ProjectRepo, repo::Repo, session::{CreateSession, Session, SessionError}, task::{Task, TaskStatus}, @@ -371,33 +369,6 @@ pub trait ContainerService { .to_string(); Repo::update_name(pool, repo.id, &name, &name).await?; - - // Update agent_working_dir for single-repo projects - let project_repos = ProjectRepo::find_by_repo_id(pool, repo.id).await?; - for pr in project_repos { - let all_repos = ProjectRepo::find_by_project_id(pool, pr.project_id).await?; - if all_repos.len() == 1 - && let Some(project) = Project::find_by_id(pool, pr.project_id).await? - { - let needs_default_agent_working_dir = project - .default_agent_working_dir - .as_ref() - .map(|s| s.is_empty()) - .unwrap_or(true); - - if needs_default_agent_working_dir { - Project::update( - pool, - pr.project_id, - &UpdateProject { - name: Some(project.name.clone()), - default_agent_working_dir: Some(name.clone()), - }, - ) - .await?; - } - } - } } Ok(()) diff --git a/crates/services/src/services/project.rs b/crates/services/src/services/project.rs index b56c8a02d1..a11acfa990 100644 --- a/crates/services/src/services/project.rs +++ b/crates/services/src/services/project.rs @@ -110,29 +110,11 @@ impl ProjectService { .await .map_err(|e| ProjectServiceError::Project(ProjectError::CreateFailed(e.to_string())))?; - let mut created_repo: Option = None; for repo in &normalized_repos { let repo_entity = Repo::find_or_create(pool, Path::new(&repo.git_repo_path), &repo.display_name) .await?; ProjectRepo::create(pool, project.id, repo_entity.id).await?; - if created_repo.is_none() { - created_repo = Some(repo_entity); - } - } - - if normalized_repos.len() == 1 - && let Some(repo) = created_repo - { - Project::update( - pool, - project.id, - &UpdateProject { - name: None, - default_agent_working_dir: Some(repo.name), - }, - ) - .await?; } Ok(project) @@ -203,11 +185,6 @@ impl ProjectService { let path = repo_service.normalize_path(&payload.git_repo_path)?; repo_service.validate_git_repo_path(&path)?; - // Count repos before adding - let repo_count_before = ProjectRepo::find_by_project_id(pool, project_id) - .await? - .len(); - let repository = ProjectRepo::add_repo_to_project( pool, project_id, @@ -225,11 +202,6 @@ impl ProjectService { _ => ProjectServiceError::RepositoryNotFound, })?; - // If project just went from 1 to 2 repos, clear default_agent_working_dir - if repo_count_before == 1 { - Project::clear_default_agent_working_dir(pool, project_id).await?; - } - tracing::info!( "Added repository {} to project {} (path: {})", repository.id, diff --git a/frontend/src/i18n/locales/en/settings.json b/frontend/src/i18n/locales/en/settings.json index 8b109cfd01..e417be7d26 100644 --- a/frontend/src/i18n/locales/en/settings.json +++ b/frontend/src/i18n/locales/en/settings.json @@ -333,11 +333,6 @@ "helper": "The absolute path to your git repository on disk." } }, - "agentWorkingDir": { - "label": "Agent Working Directory", - "placeholder": "e.g., my-repo", - "helper": "Default directory for new workspaces to run the coding agent from, relative to the workspace root. This value is captured when a workspace is created and won't affect existing workspaces. For single-repo projects, this defaults to the repo name. Leave empty to run from the workspace root." - }, "save": { "button": "Save Project Settings", "success": "✓ Project settings saved successfully!", diff --git a/frontend/src/i18n/locales/es/settings.json b/frontend/src/i18n/locales/es/settings.json index 33295a501b..81ada94032 100644 --- a/frontend/src/i18n/locales/es/settings.json +++ b/frontend/src/i18n/locales/es/settings.json @@ -333,11 +333,6 @@ "helper": "La ruta absoluta a tu repositorio git en disco." } }, - "agentWorkingDir": { - "label": "Directorio de Trabajo del Agente", - "placeholder": "ej., mi-repo", - "helper": "Directorio predeterminado para nuevos workspaces donde ejecutar el agente de codificación, relativo a la raíz del workspace. Este valor se captura cuando se crea un workspace y no afectará a los workspaces existentes. Para proyectos de un solo repositorio, esto se establece por defecto al nombre del repositorio. Déjalo vacío para ejecutar desde la raíz del workspace." - }, "save": { "button": "Guardar Configuración del Proyecto", "success": "✓ ¡Configuración del proyecto guardada exitosamente!", diff --git a/frontend/src/i18n/locales/ja/settings.json b/frontend/src/i18n/locales/ja/settings.json index 4ee1b39971..8c52b7e24e 100644 --- a/frontend/src/i18n/locales/ja/settings.json +++ b/frontend/src/i18n/locales/ja/settings.json @@ -333,11 +333,6 @@ "helper": "ディスク上のgitリポジトリへの絶対パス。" } }, - "agentWorkingDir": { - "label": "エージェント作業ディレクトリ", - "placeholder": "例:my-repo", - "helper": "新しいワークスペースでコーディングエージェントを実行するデフォルトディレクトリ。ワークスペースルートからの相対パス。この値はワークスペース作成時に保存され、既存のワークスペースには影響しません。単一リポジトリプロジェクトの場合、リポジトリ名がデフォルトになります。空欄にするとワークスペースルートから実行します。" - }, "save": { "button": "プロジェクト設定を保存", "success": "✓ プロジェクト設定が正常に保存されました!", diff --git a/frontend/src/i18n/locales/ko/settings.json b/frontend/src/i18n/locales/ko/settings.json index 3e9ce49d70..b639f54c03 100644 --- a/frontend/src/i18n/locales/ko/settings.json +++ b/frontend/src/i18n/locales/ko/settings.json @@ -333,11 +333,6 @@ "helper": "디스크에 있는 git 저장소의 절대 경로입니다." } }, - "agentWorkingDir": { - "label": "에이전트 작업 디렉토리", - "placeholder": "예: my-repo", - "helper": "새 워크스페이스에서 코딩 에이전트를 실행할 기본 디렉토리로, 워크스페이스 루트 기준 상대 경로입니다. 이 값은 워크스페이스 생성 시 저장되며 기존 워크스페이스에는 영향을 주지 않습니다. 단일 저장소 프로젝트의 경우 저장소 이름이 기본값입니다. 비워두면 워크스페이스 루트에서 실행됩니다." - }, "save": { "button": "프로젝트 설정 저장", "success": "✓ 프로젝트 설정이 성공적으로 저장되었습니다!", diff --git a/frontend/src/i18n/locales/zh-Hans/settings.json b/frontend/src/i18n/locales/zh-Hans/settings.json index 92cb7122be..809c0c8a3d 100644 --- a/frontend/src/i18n/locales/zh-Hans/settings.json +++ b/frontend/src/i18n/locales/zh-Hans/settings.json @@ -333,11 +333,6 @@ "helper": "磁盘上 git 仓库的绝对路径。" } }, - "agentWorkingDir": { - "label": "代理工作目录", - "placeholder": "例如:my-repo", - "helper": "新工作区运行编码代理的默认目录,相对于工作区根目录。此值在创建工作区时保存,不会影响现有工作区。对于单仓库项目,默认为仓库名称。留空则从工作区根目录运行。" - }, "save": { "button": "保存项目设置", "success": "✓ 项目设置保存成功!", diff --git a/frontend/src/pages/settings/ProjectSettings.tsx b/frontend/src/pages/settings/ProjectSettings.tsx index a116930d8a..d1ec5f7b1d 100644 --- a/frontend/src/pages/settings/ProjectSettings.tsx +++ b/frontend/src/pages/settings/ProjectSettings.tsx @@ -31,13 +31,11 @@ import type { Project, Repo, UpdateProject } from 'shared/types'; interface ProjectFormState { name: string; - default_agent_working_dir: string; } function projectToFormState(project: Project): ProjectFormState { return { name: project.name, - default_agent_working_dir: project.default_agent_working_dir ?? '', }; } @@ -294,8 +292,6 @@ export function ProjectSettings() { try { const updateData: UpdateProject = { name: draft.name.trim(), - default_agent_working_dir: - draft.default_agent_working_dir.trim() || null, }; updateProject.mutate({ @@ -429,26 +425,6 @@ export function ProjectSettings() {

-
- - - updateDraft({ default_agent_working_dir: e.target.value }) - } - placeholder={t( - 'settings.projects.agentWorkingDir.placeholder' - )} - className="font-mono" - /> -

- {t('settings.projects.agentWorkingDir.helper')} -

-
- {/* Save Button */}
{hasUnsavedChanges ? ( diff --git a/shared/types.ts b/shared/types.ts index 4c4db60df6..c04c9abaf4 100644 --- a/shared/types.ts +++ b/shared/types.ts @@ -16,7 +16,7 @@ export type Project = { id: string, name: string, default_agent_working_dir: str export type CreateProject = { name: string, repositories: Array, }; -export type UpdateProject = { name: string | null, default_agent_working_dir: string | null, }; +export type UpdateProject = { name: string | null, }; export type SearchResult = { path: string, is_file: boolean, match_type: SearchMatchType, /** From fb6101586b4066471abd7b3929f81ac2b192eb62 Mon Sep 17 00:00:00 2001 From: Gabriel Gordon-Hall Date: Fri, 9 Jan 2026 16:06:51 +0000 Subject: [PATCH 2/3] calculate agent_working_dir on create and start task --- crates/server/src/routes/tasks.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/crates/server/src/routes/tasks.rs b/crates/server/src/routes/tasks.rs index c194033c56..c37d186d4b 100644 --- a/crates/server/src/routes/tasks.rs +++ b/crates/server/src/routes/tasks.rs @@ -14,8 +14,7 @@ use axum::{ }; use db::models::{ image::TaskImage, - project::{Project, ProjectError}, - repo::Repo, + repo::{Repo, RepoError}, task::{CreateTask, Task, TaskWithAttemptStatus, UpdateTask}, workspace::{CreateWorkspace, Workspace}, workspace_repo::{CreateWorkspaceRepo, WorkspaceRepo}, @@ -178,21 +177,23 @@ pub async fn create_task_and_start( ) .await; - let project = Project::find_by_id(pool, task.project_id) - .await? - .ok_or(ProjectError::ProjectNotFound)?; - let attempt_id = Uuid::new_v4(); let git_branch_name = deployment .container() .git_branch_from_workspace(&attempt_id, &task.title) .await; - let agent_working_dir = project - .default_agent_working_dir - .as_ref() - .filter(|dir: &&String| !dir.is_empty()) - .cloned(); + // Compute agent_working_dir based on repo count: + // - Single repo: use repo name as working dir (agent runs in repo directory) + // - Multiple repos: use None (agent runs in workspace root) + let agent_working_dir = if payload.repos.len() == 1 { + let repo = Repo::find_by_id(pool, payload.repos[0].repo_id) + .await? + .ok_or(RepoError::NotFound)?; + Some(repo.name) + } else { + None + }; let workspace = Workspace::create( pool, From 14be50322133728270749da5782914fa25a60a76 Mon Sep 17 00:00:00 2001 From: Gabriel Gordon-Hall Date: Fri, 9 Jan 2026 16:08:56 +0000 Subject: [PATCH 3/3] i18n --- frontend/src/i18n/locales/zh-Hant/settings.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/frontend/src/i18n/locales/zh-Hant/settings.json b/frontend/src/i18n/locales/zh-Hant/settings.json index 0b48784126..0c2e67d530 100644 --- a/frontend/src/i18n/locales/zh-Hant/settings.json +++ b/frontend/src/i18n/locales/zh-Hant/settings.json @@ -333,11 +333,6 @@ "helper": "磁碟上的 Git 儲存庫絕對路徑。" } }, - "agentWorkingDir": { - "label": "代理工作目錄", - "placeholder": "例如:my-repo", - "helper": "新工作區執行編碼代理的預設目錄,相對於工作區根目錄。此值在建立工作區時保存,不會影響現有工作區。單一儲存庫專案預設為儲存庫名稱。留空則從工作區根目錄執行。" - }, "save": { "button": "儲存專案設定", "success": "✓ 專案設定儲存成功!",