diff --git a/crates/db/.sqlx/query-042b2ce19cfb648ef55aeb807b265e343faab9608ee52cc6bac52bc2562df870.json b/crates/db/.sqlx/query-042b2ce19cfb648ef55aeb807b265e343faab9608ee52cc6bac52bc2562df870.json new file mode 100644 index 0000000000..062128776b --- /dev/null +++ b/crates/db/.sqlx/query-042b2ce19cfb648ef55aeb807b265e343faab9608ee52cc6bac52bc2562df870.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n project_id as \"project_id!: Uuid\",\n repo_id as \"repo_id!: Uuid\",\n setup_script,\n cleanup_script,\n copy_files,\n parallel_setup_script as \"parallel_setup_script!: bool\",\n default_branch\n FROM project_repos\n WHERE repo_id = $1", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "project_id!: Uuid", + "ordinal": 1, + "type_info": "Blob" + }, + { + "name": "repo_id!: Uuid", + "ordinal": 2, + "type_info": "Blob" + }, + { + "name": "setup_script", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "cleanup_script", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "copy_files", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "parallel_setup_script!: bool", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "default_branch", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "042b2ce19cfb648ef55aeb807b265e343faab9608ee52cc6bac52bc2562df870" +} diff --git a/crates/db/.sqlx/query-0aa72a50b347c42962b3e48c11c9ddd1874e3e807cc1563d2aaa77a473ac3aae.json b/crates/db/.sqlx/query-0aa72a50b347c42962b3e48c11c9ddd1874e3e807cc1563d2aaa77a473ac3aae.json new file mode 100644 index 0000000000..0b972f93a5 --- /dev/null +++ b/crates/db/.sqlx/query-0aa72a50b347c42962b3e48c11c9ddd1874e3e807cc1563d2aaa77a473ac3aae.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO projects (\n id,\n name\n ) VALUES (\n $1, $2\n )\n RETURNING id as \"id!: Uuid\",\n name,\n dev_script,\n dev_script_working_dir,\n default_agent_working_dir,\n dev_server_timeout,\n dev_server_port,\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": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + true, + false, + true, + false, + false, + true, + true, + true, + false, + false + ] + }, + "hash": "0aa72a50b347c42962b3e48c11c9ddd1874e3e807cc1563d2aaa77a473ac3aae" +} diff --git a/crates/db/.sqlx/query-30d3d5b5d1b601fe43ff5daca40587aa65941fbcef471a39e933a36ff34d4d96.json b/crates/db/.sqlx/query-30d3d5b5d1b601fe43ff5daca40587aa65941fbcef471a39e933a36ff34d4d96.json new file mode 100644 index 0000000000..5824e64249 --- /dev/null +++ b/crates/db/.sqlx/query-30d3d5b5d1b601fe43ff5daca40587aa65941fbcef471a39e933a36ff34d4d96.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n project_id as \"project_id!: Uuid\",\n repo_id as \"repo_id!: Uuid\",\n setup_script,\n cleanup_script,\n copy_files,\n parallel_setup_script as \"parallel_setup_script!: bool\",\n default_branch\n FROM project_repos\n WHERE project_id = $1", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "project_id!: Uuid", + "ordinal": 1, + "type_info": "Blob" + }, + { + "name": "repo_id!: Uuid", + "ordinal": 2, + "type_info": "Blob" + }, + { + "name": "setup_script", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "cleanup_script", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "copy_files", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "parallel_setup_script!: bool", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "default_branch", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "30d3d5b5d1b601fe43ff5daca40587aa65941fbcef471a39e933a36ff34d4d96" +} diff --git a/crates/db/.sqlx/query-4d24da063ad43ca873e7140cbc4507ad74e36a0239902410c468e2539ae2d629.json b/crates/db/.sqlx/query-4d24da063ad43ca873e7140cbc4507ad74e36a0239902410c468e2539ae2d629.json new file mode 100644 index 0000000000..6a331e3c60 --- /dev/null +++ b/crates/db/.sqlx/query-4d24da063ad43ca873e7140cbc4507ad74e36a0239902410c468e2539ae2d629.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n name,\n dev_script,\n dev_script_working_dir,\n default_agent_working_dir,\n dev_server_timeout,\n dev_server_port,\n remote_project_id as \"remote_project_id: Uuid\",\n created_at as \"created_at!: DateTime\",\n updated_at as \"updated_at!: DateTime\"\n FROM projects\n WHERE remote_project_id = $1\n LIMIT 1", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "4d24da063ad43ca873e7140cbc4507ad74e36a0239902410c468e2539ae2d629" +} diff --git a/crates/db/.sqlx/query-793205e37a2ef5ae12369d9ff8b82a921ebd30b7acbf7350d5710a4fab3b5d78.json b/crates/db/.sqlx/query-793205e37a2ef5ae12369d9ff8b82a921ebd30b7acbf7350d5710a4fab3b5d78.json new file mode 100644 index 0000000000..4e042ec57e --- /dev/null +++ b/crates/db/.sqlx/query-793205e37a2ef5ae12369d9ff8b82a921ebd30b7acbf7350d5710a4fab3b5d78.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n project_id as \"project_id!: Uuid\",\n repo_id as \"repo_id!: Uuid\",\n setup_script,\n cleanup_script,\n copy_files,\n parallel_setup_script as \"parallel_setup_script!: bool\",\n default_branch\n FROM project_repos\n WHERE project_id = $1 AND repo_id = $2", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "project_id!: Uuid", + "ordinal": 1, + "type_info": "Blob" + }, + { + "name": "repo_id!: Uuid", + "ordinal": 2, + "type_info": "Blob" + }, + { + "name": "setup_script", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "cleanup_script", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "copy_files", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "parallel_setup_script!: bool", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "default_branch", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 2 + }, + "nullable": [ + true, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "793205e37a2ef5ae12369d9ff8b82a921ebd30b7acbf7350d5710a4fab3b5d78" +} diff --git a/crates/db/.sqlx/query-97dad9913b60650871180864e456423bc92d6d305cf909451e21bc9c45fb5f97.json b/crates/db/.sqlx/query-97dad9913b60650871180864e456423bc92d6d305cf909451e21bc9c45fb5f97.json new file mode 100644 index 0000000000..7977928857 --- /dev/null +++ b/crates/db/.sqlx/query-97dad9913b60650871180864e456423bc92d6d305cf909451e21bc9c45fb5f97.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "\n SELECT p.id as \"id!: Uuid\", p.name, p.dev_script, p.dev_script_working_dir,\n p.default_agent_working_dir, p.dev_server_timeout, p.dev_server_port,\n p.remote_project_id as \"remote_project_id: Uuid\",\n p.created_at as \"created_at!: DateTime\", p.updated_at as \"updated_at!: DateTime\"\n FROM projects p\n WHERE p.id IN (\n SELECT DISTINCT t.project_id\n FROM tasks t\n INNER JOIN workspaces w ON w.task_id = t.id\n ORDER BY w.updated_at DESC\n )\n LIMIT $1\n ", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "97dad9913b60650871180864e456423bc92d6d305cf909451e21bc9c45fb5f97" +} diff --git a/crates/db/.sqlx/query-a26746f5dcc1262d76d9c883ec312980964c0f06ab18f2925e92c7135cb6863c.json b/crates/db/.sqlx/query-a26746f5dcc1262d76d9c883ec312980964c0f06ab18f2925e92c7135cb6863c.json new file mode 100644 index 0000000000..8b50627fa4 --- /dev/null +++ b/crates/db/.sqlx/query-a26746f5dcc1262d76d9c883ec312980964c0f06ab18f2925e92c7135cb6863c.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n name,\n dev_script,\n dev_script_working_dir,\n default_agent_working_dir,\n dev_server_timeout,\n dev_server_port,\n remote_project_id as \"remote_project_id: Uuid\",\n created_at as \"created_at!: DateTime\",\n updated_at as \"updated_at!: DateTime\"\n FROM projects\n WHERE rowid = $1", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "a26746f5dcc1262d76d9c883ec312980964c0f06ab18f2925e92c7135cb6863c" +} diff --git a/crates/db/.sqlx/query-b52c4727b5cc647215467d74b08436e67f221c59a59b42f6a923a64e9a9f1221.json b/crates/db/.sqlx/query-b52c4727b5cc647215467d74b08436e67f221c59a59b42f6a923a64e9a9f1221.json new file mode 100644 index 0000000000..65a06ca724 --- /dev/null +++ b/crates/db/.sqlx/query-b52c4727b5cc647215467d74b08436e67f221c59a59b42f6a923a64e9a9f1221.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "INSERT INTO project_repos (id, project_id, repo_id)\n VALUES ($1, $2, $3)\n RETURNING id as \"id!: Uuid\",\n project_id as \"project_id!: Uuid\",\n repo_id as \"repo_id!: Uuid\",\n setup_script,\n cleanup_script,\n copy_files,\n parallel_setup_script as \"parallel_setup_script!: bool\",\n default_branch", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "project_id!: Uuid", + "ordinal": 1, + "type_info": "Blob" + }, + { + "name": "repo_id!: Uuid", + "ordinal": 2, + "type_info": "Blob" + }, + { + "name": "setup_script", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "cleanup_script", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "copy_files", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "parallel_setup_script!: bool", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "default_branch", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 3 + }, + "nullable": [ + true, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "b52c4727b5cc647215467d74b08436e67f221c59a59b42f6a923a64e9a9f1221" +} diff --git a/crates/db/.sqlx/query-c3390d68d841bd5802cce574df7cc459610690f99bbe5dc85ac7a4d08a6122f8.json b/crates/db/.sqlx/query-c3390d68d841bd5802cce574df7cc459610690f99bbe5dc85ac7a4d08a6122f8.json new file mode 100644 index 0000000000..7fb0f50bec --- /dev/null +++ b/crates/db/.sqlx/query-c3390d68d841bd5802cce574df7cc459610690f99bbe5dc85ac7a4d08a6122f8.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n name,\n dev_script,\n dev_script_working_dir,\n default_agent_working_dir,\n dev_server_timeout,\n dev_server_port,\n remote_project_id as \"remote_project_id: Uuid\",\n created_at as \"created_at!: DateTime\",\n updated_at as \"updated_at!: DateTime\"\n FROM projects\n WHERE id = $1", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 1 + }, + "nullable": [ + true, + false, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "c3390d68d841bd5802cce574df7cc459610690f99bbe5dc85ac7a4d08a6122f8" +} diff --git a/crates/db/.sqlx/query-d42253b8170e254767c2fe6d6817ddd5ab4fc957d799c09cd1562a438165c3d4.json b/crates/db/.sqlx/query-d42253b8170e254767c2fe6d6817ddd5ab4fc957d799c09cd1562a438165c3d4.json new file mode 100644 index 0000000000..25f989d5ff --- /dev/null +++ b/crates/db/.sqlx/query-d42253b8170e254767c2fe6d6817ddd5ab4fc957d799c09cd1562a438165c3d4.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "SELECT id as \"id!: Uuid\",\n name,\n dev_script,\n dev_script_working_dir,\n default_agent_working_dir,\n dev_server_timeout,\n dev_server_port,\n remote_project_id as \"remote_project_id: Uuid\",\n created_at as \"created_at!: DateTime\",\n updated_at as \"updated_at!: DateTime\"\n FROM projects\n ORDER BY created_at DESC", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 0 + }, + "nullable": [ + true, + false, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "d42253b8170e254767c2fe6d6817ddd5ab4fc957d799c09cd1562a438165c3d4" +} diff --git a/crates/db/.sqlx/query-e9d7b66c708a132e43fedac6ec01cfd168937cd39823e8dafee02255d7b54ddd.json b/crates/db/.sqlx/query-e9d7b66c708a132e43fedac6ec01cfd168937cd39823e8dafee02255d7b54ddd.json new file mode 100644 index 0000000000..aa623d3ef4 --- /dev/null +++ b/crates/db/.sqlx/query-e9d7b66c708a132e43fedac6ec01cfd168937cd39823e8dafee02255d7b54ddd.json @@ -0,0 +1,62 @@ +{ + "db_name": "SQLite", + "query": "UPDATE project_repos\n SET setup_script = $1,\n cleanup_script = $2,\n copy_files = $3,\n parallel_setup_script = $4,\n default_branch = $5\n WHERE project_id = $6 AND repo_id = $7\n RETURNING id as \"id!: Uuid\",\n project_id as \"project_id!: Uuid\",\n repo_id as \"repo_id!: Uuid\",\n setup_script,\n cleanup_script,\n copy_files,\n parallel_setup_script as \"parallel_setup_script!: bool\",\n default_branch", + "describe": { + "columns": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "project_id!: Uuid", + "ordinal": 1, + "type_info": "Blob" + }, + { + "name": "repo_id!: Uuid", + "ordinal": 2, + "type_info": "Blob" + }, + { + "name": "setup_script", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "cleanup_script", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "copy_files", + "ordinal": 5, + "type_info": "Text" + }, + { + "name": "parallel_setup_script!: bool", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "default_branch", + "ordinal": 7, + "type_info": "Text" + } + ], + "parameters": { + "Right": 7 + }, + "nullable": [ + true, + false, + false, + true, + true, + true, + false, + true + ] + }, + "hash": "e9d7b66c708a132e43fedac6ec01cfd168937cd39823e8dafee02255d7b54ddd" +} diff --git a/crates/db/.sqlx/query-ecffdea9549e5bcdbf0bff135c670671a79ee300e3242f20d1a5ffe96b8b5a97.json b/crates/db/.sqlx/query-ecffdea9549e5bcdbf0bff135c670671a79ee300e3242f20d1a5ffe96b8b5a97.json new file mode 100644 index 0000000000..3292258ba3 --- /dev/null +++ b/crates/db/.sqlx/query-ecffdea9549e5bcdbf0bff135c670671a79ee300e3242f20d1a5ffe96b8b5a97.json @@ -0,0 +1,74 @@ +{ + "db_name": "SQLite", + "query": "UPDATE projects\n SET name = $2, dev_script = $3, dev_script_working_dir = $4, default_agent_working_dir = $5, dev_server_timeout = $6, dev_server_port = $7\n WHERE id = $1\n RETURNING id as \"id!: Uuid\",\n name,\n dev_script,\n dev_script_working_dir,\n default_agent_working_dir,\n dev_server_timeout,\n dev_server_port,\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": [ + { + "name": "id!: Uuid", + "ordinal": 0, + "type_info": "Blob" + }, + { + "name": "name", + "ordinal": 1, + "type_info": "Text" + }, + { + "name": "dev_script", + "ordinal": 2, + "type_info": "Text" + }, + { + "name": "dev_script_working_dir", + "ordinal": 3, + "type_info": "Text" + }, + { + "name": "default_agent_working_dir", + "ordinal": 4, + "type_info": "Text" + }, + { + "name": "dev_server_timeout", + "ordinal": 5, + "type_info": "Integer" + }, + { + "name": "dev_server_port", + "ordinal": 6, + "type_info": "Integer" + }, + { + "name": "remote_project_id: Uuid", + "ordinal": 7, + "type_info": "Blob" + }, + { + "name": "created_at!: DateTime", + "ordinal": 8, + "type_info": "Text" + }, + { + "name": "updated_at!: DateTime", + "ordinal": 9, + "type_info": "Text" + } + ], + "parameters": { + "Right": 7 + }, + "nullable": [ + true, + false, + true, + true, + true, + true, + true, + true, + false, + false + ] + }, + "hash": "ecffdea9549e5bcdbf0bff135c670671a79ee300e3242f20d1a5ffe96b8b5a97" +} diff --git a/crates/db/migrations/20260104140419_add_default_branch_to_project_repos.sql b/crates/db/migrations/20260104140419_add_default_branch_to_project_repos.sql new file mode 100644 index 0000000000..642b787db1 --- /dev/null +++ b/crates/db/migrations/20260104140419_add_default_branch_to_project_repos.sql @@ -0,0 +1,4 @@ +-- Add default_branch column to project_repos table +-- This allows users to configure which branch to use as the default for new task attempts +-- When NULL, the system will auto-detect from remote HEAD or fall back to current branch +ALTER TABLE project_repos ADD COLUMN default_branch TEXT; diff --git a/crates/db/src/models/project_repo.rs b/crates/db/src/models/project_repo.rs index f1ff36162d..b70f628800 100644 --- a/crates/db/src/models/project_repo.rs +++ b/crates/db/src/models/project_repo.rs @@ -28,6 +28,8 @@ pub struct ProjectRepo { pub cleanup_script: Option, pub copy_files: Option, pub parallel_setup_script: bool, + /// The default branch to use for new task attempts. When None, auto-detects from remote HEAD. + pub default_branch: Option, } /// ProjectRepo with the associated repo name (for script execution in worktrees) @@ -56,6 +58,8 @@ pub struct UpdateProjectRepo { pub cleanup_script: Option, pub copy_files: Option, pub parallel_setup_script: Option, + /// The default branch to use for new task attempts. Use null to auto-detect from remote. + pub default_branch: Option, } impl ProjectRepo { @@ -71,7 +75,8 @@ impl ProjectRepo { setup_script, cleanup_script, copy_files, - parallel_setup_script as "parallel_setup_script!: bool" + parallel_setup_script as "parallel_setup_script!: bool", + default_branch FROM project_repos WHERE project_id = $1"#, project_id @@ -92,7 +97,8 @@ impl ProjectRepo { setup_script, cleanup_script, copy_files, - parallel_setup_script as "parallel_setup_script!: bool" + parallel_setup_script as "parallel_setup_script!: bool", + default_branch FROM project_repos WHERE repo_id = $1"#, repo_id @@ -160,7 +166,8 @@ impl ProjectRepo { setup_script, cleanup_script, copy_files, - parallel_setup_script as "parallel_setup_script!: bool" + parallel_setup_script as "parallel_setup_script!: bool", + default_branch FROM project_repos WHERE project_id = $1 AND repo_id = $2"#, project_id, @@ -235,7 +242,8 @@ impl ProjectRepo { setup_script, cleanup_script, copy_files, - parallel_setup_script as "parallel_setup_script!: bool""#, + parallel_setup_script as "parallel_setup_script!: bool", + default_branch"#, id, project_id, repo_id @@ -259,6 +267,7 @@ impl ProjectRepo { let parallel_setup_script = payload .parallel_setup_script .unwrap_or(existing.parallel_setup_script); + let default_branch = payload.default_branch.clone(); sqlx::query_as!( ProjectRepo, @@ -266,19 +275,22 @@ impl ProjectRepo { SET setup_script = $1, cleanup_script = $2, copy_files = $3, - parallel_setup_script = $4 - WHERE project_id = $5 AND repo_id = $6 + parallel_setup_script = $4, + default_branch = $5 + WHERE project_id = $6 AND repo_id = $7 RETURNING id as "id!: Uuid", project_id as "project_id!: Uuid", repo_id as "repo_id!: Uuid", setup_script, cleanup_script, copy_files, - parallel_setup_script as "parallel_setup_script!: bool""#, + parallel_setup_script as "parallel_setup_script!: bool", + default_branch"#, setup_script, cleanup_script, copy_files, parallel_setup_script, + default_branch, project_id, repo_id ) diff --git a/crates/server/src/routes/projects.rs b/crates/server/src/routes/projects.rs index b5c856629d..629549176a 100644 --- a/crates/server/src/routes/projects.rs +++ b/crates/server/src/routes/projects.rs @@ -431,6 +431,14 @@ pub async fn get_project_repositories( Ok(ResponseJson(ApiResponse::success(repositories))) } +pub async fn get_project_repository_configs( + Extension(project): Extension, + State(deployment): State, +) -> Result>>, ApiError> { + let configs = ProjectRepo::find_by_project_id(&deployment.db().pool, project.id).await?; + Ok(ResponseJson(ApiResponse::success(configs))) +} + pub async fn add_project_repository( Extension(project): Extension, State(deployment): State, @@ -600,6 +608,7 @@ pub fn router(deployment: &DeploymentImpl) -> Router { "/repositories", get(get_project_repositories).post(add_project_repository), ) + .route("/repository-configs", get(get_project_repository_configs)) .layer(from_fn_with_state( deployment.clone(), load_project_middleware, diff --git a/crates/services/src/services/git.rs b/crates/services/src/services/git.rs index 5562ec0a8b..ef4c607570 100644 --- a/crates/services/src/services/git.rs +++ b/crates/services/src/services/git.rs @@ -61,6 +61,8 @@ pub struct GitBranch { pub name: String, pub is_current: bool, pub is_remote: bool, + /// True if this is the default branch (detected from origin/HEAD) + pub is_default: bool, #[ts(type = "Date")] pub last_commit_date: DateTime, } @@ -1212,6 +1214,9 @@ impl GitService { let current_branch = self.get_current_branch(repo_path).unwrap_or_default(); let mut branches = Vec::new(); + // Detect the default branch from origin/HEAD symbolic reference + let default_branch = self.get_default_branch_from_remote(&repo); + // Helper function to get last commit date for a branch let get_last_commit_date = |branch: &git2::Branch| -> Result, git2::Error> { if let Some(target) = branch.get().target() @@ -1229,10 +1234,14 @@ impl GitService { let (branch, _) = branch_result?; if let Some(name) = branch.name()? { let last_commit_date = get_last_commit_date(&branch)?; + let is_default = default_branch + .as_ref() + .is_some_and(|default| default == name); branches.push(GitBranch { name: name.to_string(), is_current: name == current_branch, is_remote: false, + is_default, last_commit_date, }); } @@ -1246,22 +1255,31 @@ impl GitService { // Skip remote HEAD references if !name.ends_with("/HEAD") { let last_commit_date = get_last_commit_date(&branch)?; + // Check if this remote branch is the default (e.g., origin/main matches "main") + let is_default = default_branch.as_ref().is_some_and(|default| { + name.ends_with(&format!("/{}", default)) + }); branches.push(GitBranch { name: name.to_string(), is_current: false, is_remote: true, + is_default, last_commit_date, }); } } } - // Sort branches: current first, then by most recent commit date + // Sort branches: current first, then default, then by most recent commit date branches.sort_by(|a, b| { if a.is_current && !b.is_current { std::cmp::Ordering::Less } else if !a.is_current && b.is_current { std::cmp::Ordering::Greater + } else if a.is_default && !b.is_default { + std::cmp::Ordering::Less + } else if !a.is_default && b.is_default { + std::cmp::Ordering::Greater } else { // Sort by most recent commit date (newest first) b.last_commit_date.cmp(&a.last_commit_date) @@ -1271,6 +1289,21 @@ impl GitService { Ok(branches) } + /// Detect the default branch from origin/HEAD symbolic reference. + /// Returns the branch name (e.g., "main" or "master") if detectable. + fn get_default_branch_from_remote(&self, repo: &Repository) -> Option { + // Try to resolve origin/HEAD symbolic reference + if let Ok(reference) = repo.find_reference("refs/remotes/origin/HEAD") { + if let Ok(resolved) = reference.resolve() { + if let Some(name) = resolved.shorthand() { + // name will be like "origin/main", strip the "origin/" prefix + return name.strip_prefix("origin/").map(String::from); + } + } + } + None + } + /// Perform a squash merge of task branch into base branch, but fail on conflicts fn perform_squash_merge( &self, diff --git a/frontend/src/components/dialogs/tasks/CreateAttemptDialog.tsx b/frontend/src/components/dialogs/tasks/CreateAttemptDialog.tsx index 3a0ce7b9a6..6586c08421 100644 --- a/frontend/src/components/dialogs/tasks/CreateAttemptDialog.tsx +++ b/frontend/src/components/dialogs/tasks/CreateAttemptDialog.tsx @@ -17,7 +17,7 @@ import { useTask, useAttempt, useRepoBranchSelection, - useProjectRepos, + useProjectReposWithDefaults, } from '@/hooks'; import { useTaskAttemptsWithSessions } from '@/hooks/useTaskAttempts'; import { useProject } from '@/contexts/ProjectContext'; @@ -68,7 +68,7 @@ const CreateAttemptDialogImpl = NiceModal.create( ); const { data: projectRepos = [], isLoading: isLoadingRepos } = - useProjectRepos(projectId, { enabled: modal.visible }); + useProjectReposWithDefaults(projectId, { enabled: modal.visible }); const { configs: repoBranchConfigs, diff --git a/frontend/src/hooks/index.ts b/frontend/src/hooks/index.ts index 8d2a492d2a..843ce06cd4 100644 --- a/frontend/src/hooks/index.ts +++ b/frontend/src/hooks/index.ts @@ -17,7 +17,7 @@ export { useGitOperations } from './useGitOperations'; export { useTask } from './useTask'; export { useAttempt } from './useAttempt'; export { useRepoBranches } from './useRepoBranches'; -export { useProjectRepos } from './useProjectRepos'; +export { useProjectRepos, useProjectReposWithDefaults } from './useProjectRepos'; export { useRepoBranchSelection } from './useRepoBranchSelection'; export type { RepoBranchConfig } from './useRepoBranchSelection'; export { useTaskAttempts } from './useTaskAttempts'; diff --git a/frontend/src/hooks/useProjectRepos.ts b/frontend/src/hooks/useProjectRepos.ts index e8ca8feb62..484a6b08d9 100644 --- a/frontend/src/hooks/useProjectRepos.ts +++ b/frontend/src/hooks/useProjectRepos.ts @@ -1,6 +1,7 @@ -import { useQuery } from '@tanstack/react-query'; +import { useQuery, useQueries } from '@tanstack/react-query'; import { projectsApi } from '@/lib/api'; import type { Repo } from 'shared/types'; +import type { RepoWithDefaultBranch } from './useRepoBranchSelection'; type Options = { enabled?: boolean; @@ -15,3 +16,48 @@ export function useProjectRepos(projectId?: string, opts?: Options) { enabled, }); } + +/** + * Fetch project repositories with their configured default branches. + * This merges data from both the repos and project_repos tables. + */ +export function useProjectReposWithDefaults(projectId?: string, opts?: Options) { + const enabled = (opts?.enabled ?? true) && !!projectId; + + const queries = useQueries({ + queries: [ + { + queryKey: ['projectRepositories', projectId], + queryFn: () => projectsApi.getRepositories(projectId!), + enabled, + }, + { + queryKey: ['projectRepositoryConfigs', projectId], + queryFn: () => projectsApi.getRepositoryConfigs(projectId!), + enabled, + }, + ], + }); + + const [reposQuery, configsQuery] = queries; + const isLoading = reposQuery.isLoading || configsQuery.isLoading; + + // Merge repos with their configured default branches + const data: RepoWithDefaultBranch[] | undefined = + reposQuery.data && configsQuery.data + ? reposQuery.data.map((repo) => { + const config = configsQuery.data?.find((c) => c.repo_id === repo.id); + return { + ...repo, + configuredDefaultBranch: config?.default_branch ?? null, + }; + }) + : undefined; + + return { + data, + isLoading, + isError: reposQuery.isError || configsQuery.isError, + error: reposQuery.error ?? configsQuery.error, + }; +} diff --git a/frontend/src/hooks/useRepoBranchSelection.ts b/frontend/src/hooks/useRepoBranchSelection.ts index 3805fdb738..4f5c06bfb1 100644 --- a/frontend/src/hooks/useRepoBranchSelection.ts +++ b/frontend/src/hooks/useRepoBranchSelection.ts @@ -11,8 +11,14 @@ export type RepoBranchConfig = { branches: GitBranch[]; }; +/** Repo with optional configured default branch from project settings */ +export type RepoWithDefaultBranch = Repo & { + /** User-configured default branch for this repo (from ProjectRepo.default_branch) */ + configuredDefaultBranch?: string | null; +}; + type UseRepoBranchSelectionOptions = { - repos: Repo[]; + repos: RepoWithDefaultBranch[]; initialBranch?: string | null; enabled?: boolean; }; @@ -55,11 +61,42 @@ export function useRepoBranchSelection({ let targetBranch: string | null = userOverrides[repo.id] ?? null; if (targetBranch === null) { + // Priority order: + // 1. initialBranch (e.g., from parent attempt) + // 2. User-configured default branch from project settings + // 3. Auto-detected default branch from remote (is_default) + // 4. Currently checked out branch (is_current) + // 5. First branch in the list if (initialBranch && branches.some((b) => b.name === initialBranch)) { targetBranch = initialBranch; - } else { + } else if (repo.configuredDefaultBranch) { + // Check for exact match first + const exactMatch = branches.find( + (b) => b.name === repo.configuredDefaultBranch + ); + if (exactMatch) { + targetBranch = exactMatch.name; + } else { + // Try matching without origin/ prefix (e.g., "origin/main" -> "main") + const withoutPrefix = repo.configuredDefaultBranch.replace( + /^origin\//, + '' + ); + const prefixMatch = branches.find((b) => b.name === withoutPrefix); + if (prefixMatch) { + targetBranch = prefixMatch.name; + } + } + } + + if (targetBranch === null) { + const defaultBranch = branches.find((b) => b.is_default && !b.is_remote); const currentBranch = branches.find((b) => b.is_current); - targetBranch = currentBranch?.name ?? branches[0]?.name ?? null; + targetBranch = + defaultBranch?.name ?? + currentBranch?.name ?? + branches[0]?.name ?? + null; } } diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 152358a322..918beda8fa 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -332,6 +332,13 @@ export const projectsApi = { return handleApiResponse(response); }, + getRepositoryConfigs: async (projectId: string): Promise => { + const response = await makeRequest( + `/api/projects/${projectId}/repository-configs` + ); + return handleApiResponse(response); + }, + addRepository: async ( projectId: string, data: CreateProjectRepo diff --git a/frontend/src/pages/settings/ProjectSettings.tsx b/frontend/src/pages/settings/ProjectSettings.tsx index 6e28c897b7..7830a069cc 100644 --- a/frontend/src/pages/settings/ProjectSettings.tsx +++ b/frontend/src/pages/settings/ProjectSettings.tsx @@ -30,7 +30,7 @@ import { CopyFilesField } from '@/components/projects/CopyFilesField'; import { AutoExpandingTextarea } from '@/components/ui/auto-expanding-textarea'; import { RepoPickerDialog } from '@/components/dialogs/shared/RepoPickerDialog'; import { projectsApi } from '@/lib/api'; -import { repoBranchKeys } from '@/hooks/useRepoBranches'; +import { repoBranchKeys, useRepoBranches } from '@/hooks/useRepoBranches'; import type { Project, ProjectRepo, Repo, UpdateProject } from 'shared/types'; interface ProjectFormState { @@ -45,6 +45,7 @@ interface RepoScriptsFormState { parallel_setup_script: boolean; cleanup_script: string; copy_files: string; + default_branch: string | null; } function projectToFormState(project: Project): ProjectFormState { @@ -64,6 +65,7 @@ function projectRepoToScriptsFormState( parallel_setup_script: projectRepo?.parallel_setup_script ?? false, cleanup_script: projectRepo?.cleanup_script ?? '', copy_files: projectRepo?.copy_files ?? '', + default_branch: projectRepo?.default_branch ?? null, }; } @@ -116,6 +118,11 @@ export function ProjectSettings() { // Get OS-appropriate script placeholders const placeholders = useScriptPlaceholders(); + // Fetch branches for selected repo + const { data: branches = [], isLoading: loadingBranches } = useRepoBranches( + selectedScriptsRepoId ?? undefined + ); + // Check for unsaved changes (project name) const hasUnsavedProjectChanges = useMemo(() => { if (!draft || !selectedProject) return false; @@ -426,6 +433,7 @@ export function ProjectSettings() { cleanup_script: scriptsDraft.cleanup_script.trim() || null, copy_files: scriptsDraft.copy_files.trim() || null, parallel_setup_script: scriptsDraft.parallel_setup_script, + default_branch: scriptsDraft.default_branch || null, } ); setSelectedProjectRepo(updatedRepo); @@ -813,6 +821,44 @@ export function ProjectSettings() { ) : scriptsDraft ? ( <> +
+ + +

+ The default branch to use when starting new task + attempts. If not set, it will be auto-detected from + the remote. +

+
+