This commit is contained in:
Ian Gulliver
2026-10-20 22:00:42 -07:00
parent a1d498bac8
commit ccbbb5807f
2 changed files with 6 additions and 22 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ Every task worktree is made by `createTask` (`internal/agents/tasks.go`): new ta
## Closing a task
A task ends `merged` or `discarded`; either way its sessions are stopped, its snapshot refs, worktree and branch are removed, its `open` inbox items become `dismissed` (resolved by whoever closed it), and its record, summary and events remain. `GET /api/tasks/{id}/unmerged` reports what would be lost or merged: commits on the branch that aren't on the default branch, and files, lines and uncommitted paths that differ from the merge base. The UI's Merge and Discard buttons each ask a confirmation, Discard's just below its button like the task picker's switcher and Merge's centred in the right pane, and are disabled while the task's session is `running`. Merge is also disabled until `unmerged` reports a commit or a changed file; the transcript fetches it when the task is opened and again shortly after each tool result or turn end. Merge's confirmation (`confirmMerge` in `mac/Sources/Byre/MergeDialog.swift`) is kept brief: the commit title as text with a ✎ button that swaps in an input, a collapsed "N co-authors" line holding the trailers, and one warning line for each thing worth stopping for. Those are the latest snapshot's review still running, failed, missing or with findings that weren't ignored (counted by severity); the task's open inbox questions, which merging dismisses; the worktree differing from the latest snapshot (`changes?since=` its commit), or no snapshot at all; and "Review status unavailable" when those fetches fail. Earlier snapshots' reviews aren't mentioned. Warnings never block Merge. When the latest snapshot's review is running as the dialog opens, its buttons are Cancel, **Merge & complete now** and **Merge & complete after review**, the default (Enter picks it); otherwise Cancel and **Merge & complete**, named like the ready card's button. The buttons are chosen once at opening, so a review that finishes while the dialog is open leaves **Merge & complete after review** there and choosing it is refused. The review and question warnings link to that snapshot's review or the oldest open question in the task's transcript; following one closes the dialog and keeps the title, so the next Merge opens with it. While open, the dialog refetches on the task's `snapshot.created` and `review.*` events and redraws on inbox changes.
A task ends `merged` or `discarded`; either way its sessions are stopped, its snapshot refs, worktree and branch are removed, its `open` inbox items become `dismissed` (resolved by whoever closed it), and its record, summary and events remain. `GET /api/tasks/{id}/unmerged` reports what would be lost or merged: commits on the branch that aren't on the default branch, and files, lines and uncommitted paths that differ from the merge base. Its file and line totals sum the same `git.Compare` result as the Changes view, sharing merge-base selection, rename detection and NUL-delimited diff parsing. The UI's Merge and Discard buttons each ask a confirmation, Discard's just below its button like the task picker's switcher and Merge's centred in the right pane, and are disabled while the task's session is `running`. Merge is also disabled until `unmerged` reports a commit or a changed file; the transcript fetches it when the task is opened and again shortly after each tool result or turn end. Merge's confirmation (`confirmMerge` in `mac/Sources/Byre/MergeDialog.swift`) is kept brief: the commit title as text with a ✎ button that swaps in an input, a collapsed "N co-authors" line holding the trailers, and one warning line for each thing worth stopping for. Those are the latest snapshot's review still running, failed, missing or with findings that weren't ignored (counted by severity); the task's open inbox questions, which merging dismisses; the worktree differing from the latest snapshot (`changes?since=` its commit), or no snapshot at all; and "Review status unavailable" when those fetches fail. Earlier snapshots' reviews aren't mentioned. Warnings never block Merge. When the latest snapshot's review is running as the dialog opens, its buttons are Cancel, **Merge & complete now** and **Merge & complete after review**, the default (Enter picks it); otherwise Cancel and **Merge & complete**, named like the ready card's button. The buttons are chosen once at opening, so a review that finishes while the dialog is open leaves **Merge & complete after review** there and choosing it is refused. The review and question warnings link to that snapshot's review or the oldest open question in the task's transcript; following one closes the dialog and keeps the title, so the next Merge opens with it. While open, the dialog refetches on the task's `snapshot.created` and `review.*` events and redraws on inbox changes.
A task's summary is what its agent writes, before the task closes, about the whole task: what it set out to do, what was built or tried, the key decisions and why, and what was left out. The agent sets it with the `set_task_summary` MCP tool (`internal/agents/summary.go`), any time while the task is active; each call replaces `tasks.summary` and records a `task.summary` event carrying it, which the transcript shows as a note. The Merge turn's prompt and the discard turn's prompt (`summaryRequest`) both ask for it. Turn summaries don't stand in for it: each covers only its own turn, and a merged task's last one is always the Merge turn's. Tasks closed before the column existed have none. `sqlite3 byre.db "SELECT id, status, summary FROM tasks WHERE status != 'active' ORDER BY closed_at DESC LIMIT 5"` shows recent ones.
+5 -21
View File
@@ -148,30 +148,14 @@ func UnmergedChanges(worktree, target string) (Unmerged, error) {
if err != nil {
return u, err
}
base, err := run(worktree, "merge-base", target, "HEAD")
changes, err := Compare(worktree, target, "HEAD", tree, "")
if err != nil {
return u, err
}
numstat, err := run(worktree, "diff", "--numstat", base, tree)
if err != nil {
return u, err
}
for _, line := range strings.Split(numstat, "\n") {
if line == "" {
continue
}
fields := strings.SplitN(line, "\t", 3)
u.Files++
adds, err := strconv.Atoi(fields[0])
if err != nil {
continue
}
dels, err := strconv.Atoi(fields[1])
if err != nil {
continue
}
u.Insertions += adds
u.Deletions += dels
u.Files = len(changes.Files)
for _, file := range changes.Files {
u.Insertions += file.Additions
u.Deletions += file.Deletions
}
return u, nil