feat(data): add merge-helper prompt templates
This commit is contained in:
@@ -2,7 +2,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace ClaudeDo.Data;
|
namespace ClaudeDo.Data;
|
||||||
|
|
||||||
public enum PromptKind { System, Planning, PlanningInitial, Retry, DailyPrep, WeeklyReport, ImprovementChild, Refine }
|
public enum PromptKind { System, Planning, PlanningInitial, Retry, DailyPrep, WeeklyReport, ImprovementChild, Refine, MergeHelper, MergeHelperInitial }
|
||||||
|
|
||||||
public static class PromptFiles
|
public static class PromptFiles
|
||||||
{
|
{
|
||||||
@@ -18,6 +18,8 @@ public static class PromptFiles
|
|||||||
PromptKind.WeeklyReport => Path.Combine(Root, "weekly-report.md"),
|
PromptKind.WeeklyReport => Path.Combine(Root, "weekly-report.md"),
|
||||||
PromptKind.ImprovementChild => Path.Combine(Root, "improvement-child.md"),
|
PromptKind.ImprovementChild => Path.Combine(Root, "improvement-child.md"),
|
||||||
PromptKind.Refine => Path.Combine(Root, "refine.md"),
|
PromptKind.Refine => Path.Combine(Root, "refine.md"),
|
||||||
|
PromptKind.MergeHelper => Path.Combine(Root, "merge-helper-system.md"),
|
||||||
|
PromptKind.MergeHelperInitial => Path.Combine(Root, "merge-helper-initial.md"),
|
||||||
_ => throw new ArgumentOutOfRangeException(nameof(kind))
|
_ => throw new ArgumentOutOfRangeException(nameof(kind))
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -63,6 +65,8 @@ public static class PromptFiles
|
|||||||
PromptKind.WeeklyReport => WeeklyReportDefault,
|
PromptKind.WeeklyReport => WeeklyReportDefault,
|
||||||
PromptKind.ImprovementChild => ImprovementChildDefault,
|
PromptKind.ImprovementChild => ImprovementChildDefault,
|
||||||
PromptKind.Refine => RefineDefault,
|
PromptKind.Refine => RefineDefault,
|
||||||
|
PromptKind.MergeHelper => MergeHelperDefault,
|
||||||
|
PromptKind.MergeHelperInitial => MergeHelperInitialDefault,
|
||||||
_ => ""
|
_ => ""
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -224,6 +228,52 @@ public static class PromptFiles
|
|||||||
task, stop.
|
task, stop.
|
||||||
""";
|
""";
|
||||||
|
|
||||||
|
private const string MergeHelperDefault = """
|
||||||
|
You are the ClaudeDo Merge Helper, running as an interactive session with the user watching. Ask them questions whenever you are unsure — that is the point of this session.
|
||||||
|
|
||||||
|
Your job: take the tasks listed in the brief and drive each one to a merged, Done state, then print a summary of everything that changed. You act through the mcp__claudedo__* tools. Read the brief file first (the kickoff message gives its path); it lists each task's id, title, status, list and repo.
|
||||||
|
|
||||||
|
Handle the tasks in the order listed, one at a time. For each task, act on its current status:
|
||||||
|
- Idle or Queued: run it with run_task_now, then poll get_task until it leaves Running (it lands in WaitingForReview on success, or Failed).
|
||||||
|
- Running or WaitingForChildren: poll get_task until it surfaces for review.
|
||||||
|
- Failed: this usually needs human judgement — ask the user whether to reset_failed_task and re-run, or skip it.
|
||||||
|
- WaitingForReview: review, then merge it (below).
|
||||||
|
|
||||||
|
Reviewing and merging a WaitingForReview task:
|
||||||
|
1. Inspect the change with get_task_diff (stat first, then the full diff if it is non-trivial) and sanity-check it against the task's title/description.
|
||||||
|
2. If the change looks wrong, incomplete, or risky, STOP and ask the user before merging — offer reject_rerun (with feedback) or skip.
|
||||||
|
3. Otherwise merge it with review_task(taskId, decision="approve", leaveConflictsInTree=true).
|
||||||
|
- Clean merge → the task is Done; move on.
|
||||||
|
- Conflict (markers left in the working tree, repoPath returned) → resolve it (below).
|
||||||
|
|
||||||
|
Resolving a conflict:
|
||||||
|
- Open each conflicted file under repoPath (Read/Edit) and resolve the <<<<<<< ======= >>>>>>> markers, guided by BOTH sides' intent. Then call continue_merge(taskId). If markers remain it tells you — fix and call again. Use abort_merge(taskId) to cancel a merge you cannot safely resolve.
|
||||||
|
- For a task WITH children (a unit merge), pass the PARENT task id to continue_merge / abort_merge.
|
||||||
|
- If a resolution is non-obvious, ambiguous, or might drop someone's work, ASK THE USER before continuing.
|
||||||
|
- Prefer the MCP tools whenever they apply. Only if the MCP tools cannot reach an in-progress merge may you finish it by hand: resolve the markers, then `git add -- <the resolved paths>` and `git commit` — NEVER `git add -A` or a bare commit, because the checkout is shared with other sessions.
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Never use raw `git merge`, `git reset`, or `git checkout` to force a merge. Drive merges through the MCP tools; hand-resolution is only for markers the tools left and cannot finish.
|
||||||
|
- Ask the user for anything ambiguous, risky, or destructive.
|
||||||
|
|
||||||
|
When every task is handled, print a SUMMARY:
|
||||||
|
- one line per task: title — final status — merge commit (if any) — conflicts resolved (if any)
|
||||||
|
- anything you skipped or left for the user, and why
|
||||||
|
- suggested follow-ups, if any.
|
||||||
|
""";
|
||||||
|
|
||||||
|
private const string MergeHelperInitialDefault = """
|
||||||
|
# Merge Helper brief
|
||||||
|
|
||||||
|
Scope: {scope}
|
||||||
|
|
||||||
|
Handle the following tasks, in order. For each, drive it to a merged/Done state per your instructions, asking me when unsure.
|
||||||
|
|
||||||
|
{tasks}
|
||||||
|
|
||||||
|
When every task is handled, print the summary.
|
||||||
|
""";
|
||||||
|
|
||||||
private const string WeeklyReportDefault = """
|
private const string WeeklyReportDefault = """
|
||||||
You are generating a concise weekly standup report for a software developer,
|
You are generating a concise weekly standup report for a software developer,
|
||||||
covering {start} to {end}.
|
covering {start} to {end}.
|
||||||
|
|||||||
@@ -43,4 +43,41 @@ public class PromptFilesTests
|
|||||||
{
|
{
|
||||||
Assert.EndsWith("planning-system.md", PromptFiles.PathFor(PromptKind.Planning));
|
Assert.EndsWith("planning-system.md", PromptFiles.PathFor(PromptKind.Planning));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void PathFor_merge_helper_kinds_map_to_their_files()
|
||||||
|
{
|
||||||
|
Assert.EndsWith("merge-helper-system.md", PromptFiles.PathFor(PromptKind.MergeHelper));
|
||||||
|
Assert.EndsWith("merge-helper-initial.md", PromptFiles.PathFor(PromptKind.MergeHelperInitial));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DefaultFor_merge_helper_is_non_empty_and_mentions_the_merge_tools()
|
||||||
|
{
|
||||||
|
var d = PromptFiles.DefaultFor(PromptKind.MergeHelper);
|
||||||
|
Assert.False(string.IsNullOrWhiteSpace(d));
|
||||||
|
Assert.Contains("review_task", d);
|
||||||
|
Assert.Contains("continue_merge", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void DefaultFor_merge_helper_initial_has_scope_and_tasks_tokens()
|
||||||
|
{
|
||||||
|
var d = PromptFiles.DefaultFor(PromptKind.MergeHelperInitial);
|
||||||
|
Assert.False(string.IsNullOrWhiteSpace(d));
|
||||||
|
Assert.Contains("{scope}", d);
|
||||||
|
Assert.Contains("{tasks}", d);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void RenderTemplate_merge_helper_initial_substitutes_scope_and_tasks()
|
||||||
|
{
|
||||||
|
var outp = PromptFiles.RenderTemplate(
|
||||||
|
PromptFiles.DefaultFor(PromptKind.MergeHelperInitial),
|
||||||
|
new Dictionary<string, string> { ["scope"] = "All lists", ["tasks"] = "- [Idle] T1" });
|
||||||
|
Assert.Contains("Scope: All lists", outp);
|
||||||
|
Assert.Contains("- [Idle] T1", outp);
|
||||||
|
Assert.DoesNotContain("{scope}", outp);
|
||||||
|
Assert.DoesNotContain("{tasks}", outp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user