diff options
| author | soryu <soryu@soryu.co> | 2026-01-25 04:39:37 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-01-25 04:39:37 +0000 |
| commit | cb4f2fc40dbabb40de948512eee74c7e46264665 (patch) | |
| tree | 0a4f142609dceaf6cf6eafa4fa6a59beff4b1f80 /makima/src/daemon/task | |
| parent | c908854e7e3571c99cce9f46497ce5337ea0aed1 (diff) | |
| download | soryu-cb4f2fc40dbabb40de948512eee74c7e46264665.tar.gz soryu-cb4f2fc40dbabb40de948512eee74c7e46264665.zip | |
Add automatic phase transitions and fix PR creation
Diffstat (limited to 'makima/src/daemon/task')
| -rw-r--r-- | makima/src/daemon/task/manager.rs | 124 |
1 files changed, 93 insertions, 31 deletions
diff --git a/makima/src/daemon/task/manager.rs b/makima/src/daemon/task/manager.rs index 6ba0f52..74a37bf 100644 --- a/makima/src/daemon/task/manager.rs +++ b/makima/src/daemon/task/manager.rs @@ -840,6 +840,26 @@ Valid phases: `specify`, `plan`, `execute`, `review` - Create checkpoints before major transitions - **Mark contract complete** when PR is created by updating status +## MANDATORY ACTIONS + +### [ACTION REQUIRED] Messages +When you receive an `[ACTION REQUIRED]` message from the system: +1. Read the directive carefully +2. Execute the specified command IMMEDIATELY +3. Do NOT ignore or defer these actions +4. These messages indicate conditions have been met and action is needed NOW + +### Phase Completion Checklist +After all tasks are "done" and merged, you MUST take the following actions: + +**If in execute phase:** +1. Create PR immediately: `makima supervisor pr "makima/{name}" --title "..." --base main` +2. After PR created: + - Simple contract: Mark complete with `makima supervisor complete` + - Specification contract: Advance to review with `makima supervisor advance-phase review` + +**Never leave a contract hanging** - when work is done, create the PR and complete/advance. + --- "#; @@ -2924,58 +2944,100 @@ impl TaskManager { body: Option<String>, base_branch: String, ) -> Result<(), DaemonError> { - // Get task's worktree path - let worktree_path = { + // Get task's worktree path and base branch + let (worktree_path, task_base_branch) = { let tasks = self.tasks.read().await; - tasks.get(&task_id) + let worktree = tasks.get(&task_id) .and_then(|t| t.worktree.as_ref()) - .map(|w| w.path.clone()) + .map(|w| w.path.clone()); + let base = tasks.get(&task_id) + .and_then(|t| t.base_branch.clone()); + (worktree, base) }; + // Use task's base_branch if the provided one is the default "main" and task has a detected one + let effective_base_branch = if base_branch == "main" { + task_base_branch.unwrap_or(base_branch) + } else { + base_branch + }; + + tracing::info!( + task_id = %task_id, + effective_base_branch = %effective_base_branch, + worktree_exists = worktree_path.is_some(), + "Creating PR with effective base branch" + ); + let (success, message, pr_url, pr_number) = if let Some(path) = worktree_path { // Push the current branch first + tracing::info!(path = %path.display(), "Pushing branch to origin"); let push_result = tokio::process::Command::new("git") .current_dir(&path) .args(["push", "-u", "origin", "HEAD"]) .output() .await; - if let Err(e) = push_result { - (false, format!("Failed to push branch: {}", e), None, None) - } else { - // Create PR using gh CLI - let mut pr_cmd = tokio::process::Command::new("gh"); - pr_cmd.current_dir(&path); - pr_cmd.args(["pr", "create", "--title", &title, "--base", &base_branch]); - - if let Some(ref body_text) = body { - pr_cmd.args(["--body", body_text]); - } else { - pr_cmd.args(["--body", ""]); + match push_result { + Err(e) => { + tracing::error!(error = %e, "Failed to execute git push"); + (false, format!("Failed to push branch: {}", e), None, None) } - - match pr_cmd.output().await { - Ok(output) if output.status.success() => { - let stdout = String::from_utf8_lossy(&output.stdout); - // gh pr create outputs the PR URL - let url = stdout.lines().last().map(|s| s.trim().to_string()); - // Extract PR number from URL - let number = url.as_ref().and_then(|u| { - u.split('/').last().and_then(|n| n.parse::<i32>().ok()) - }); - (true, "Pull request created".to_string(), url, number) + Ok(output) if !output.status.success() => { + let stderr = String::from_utf8_lossy(&output.stderr); + tracing::error!(stderr = %stderr, "git push failed"); + (false, format!("Failed to push branch: {}", stderr), None, None) + } + Ok(_) => { + tracing::info!("Branch pushed successfully, creating PR"); + // Create PR using gh CLI + let mut pr_cmd = tokio::process::Command::new("gh"); + pr_cmd.current_dir(&path); + pr_cmd.args(["pr", "create", "--title", &title, "--base", &effective_base_branch]); + + if let Some(ref body_text) = body { + pr_cmd.args(["--body", body_text]); + } else { + pr_cmd.args(["--body", ""]); } - Ok(output) => { - let stderr = String::from_utf8_lossy(&output.stderr); - (false, format!("Failed to create PR: {}", stderr), None, None) + + match pr_cmd.output().await { + Ok(output) if output.status.success() => { + let stdout = String::from_utf8_lossy(&output.stdout); + // gh pr create outputs the PR URL + let url = stdout.lines().last().map(|s| s.trim().to_string()); + // Extract PR number from URL + let number = url.as_ref().and_then(|u| { + u.split('/').last().and_then(|n| n.parse::<i32>().ok()) + }); + tracing::info!(pr_url = ?url, pr_number = ?number, "PR created successfully"); + (true, "Pull request created".to_string(), url, number) + } + Ok(output) => { + let stderr = String::from_utf8_lossy(&output.stderr); + tracing::error!(stderr = %stderr, "gh pr create failed"); + (false, format!("Failed to create PR: {}", stderr), None, None) + } + Err(e) => { + tracing::error!(error = %e, "Failed to execute gh command"); + (false, format!("Failed to run gh: {}", e), None, None) + } } - Err(e) => (false, format!("Failed to run gh: {}", e), None, None), } } } else { + tracing::error!(task_id = %task_id, "Task not found or has no worktree"); (false, format!("Task {} not found or has no worktree", task_id), None, None) }; + tracing::info!( + task_id = %task_id, + success = success, + message = %message, + pr_url = ?pr_url, + "PR creation completed" + ); + let msg = DaemonMessage::PRCreated { task_id, success, |
