summaryrefslogtreecommitdiff
path: root/makima/src/daemon
diff options
context:
space:
mode:
Diffstat (limited to 'makima/src/daemon')
-rw-r--r--makima/src/daemon/task/manager.rs124
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,