TaskAttachmentEntity (+config, cascade FK), TaskAttachmentRepository, and an AttachmentStore that writes files under ~/.todo-app/attachments/<taskId>/ with a path-traversal guard and a 5 MB cap. TaskPromptComposer gains an optional read-only 'Reference files' section. Migration AddTaskAttachments.
39 lines
1.4 KiB
C#
39 lines
1.4 KiB
C#
using System.Text;
|
|
|
|
namespace ClaudeDo.Data;
|
|
|
|
/// <summary>
|
|
/// Single source of truth for the text handed to Claude as a task prompt:
|
|
/// title + description + the OPEN sub-tasks. Resolved sub-tasks are dropped.
|
|
/// Shared by the Worker (real prompt) and the UI (the card's "what Claude gets" preview).
|
|
/// </summary>
|
|
public static class TaskPromptComposer
|
|
{
|
|
public static string Compose(string title, string? description, IEnumerable<(string Title, bool Completed)> subtasks,
|
|
IEnumerable<string>? attachmentPaths = null)
|
|
{
|
|
var sb = new StringBuilder((title ?? "").Trim());
|
|
|
|
if (!string.IsNullOrWhiteSpace(description))
|
|
sb.Append("\n\n").Append(description.Trim());
|
|
|
|
var open = subtasks?.Where(s => !s.Completed).ToList() ?? new List<(string, bool)>();
|
|
if (open.Count > 0)
|
|
{
|
|
sb.Append("\n\n## Sub-Tasks\n");
|
|
foreach (var s in open)
|
|
sb.Append("- [ ] ").Append(s.Title).Append('\n');
|
|
}
|
|
|
|
var paths = attachmentPaths?.ToList();
|
|
if (paths is { Count: > 0 })
|
|
{
|
|
sb.Append("\n\n## Reference files\nThese files were attached to this task as read-only reference (they live outside the repo). Read them as needed:\n");
|
|
foreach (var p in paths)
|
|
sb.Append("- ").Append(p).Append('\n');
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
}
|