@backburner/cli 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -4,6 +4,37 @@ Backburner turns GitHub issues into reviewable pull requests using coding agents
|
|
|
4
4
|
|
|
5
5
|
Open an issue from your phone, get back to your day, and manage the work through GitHub comments, labels, and PR reviews. Your computer does the planning, coding, testing, committing, and pushing through the agent CLIs and credentials you already use. GitHub is the control plane; your computer is the worker.
|
|
6
6
|
|
|
7
|
+
## From phone to pull request
|
|
8
|
+
|
|
9
|
+
Follow work from the GitHub mobile app while Backburner runs the agent workflow on your machine:
|
|
10
|
+
|
|
11
|
+
<table>
|
|
12
|
+
<tr>
|
|
13
|
+
<td align="center" width="50%">
|
|
14
|
+
<strong>1. Open an issue from your phone</strong>
|
|
15
|
+
<br />
|
|
16
|
+
<img src="docs/images/workflow-story/01-issue.jpg" alt="A GitHub issue describing OAuth support for hosted MCP" />
|
|
17
|
+
</td>
|
|
18
|
+
<td align="center" width="50%">
|
|
19
|
+
<strong>2. Review the product direction</strong>
|
|
20
|
+
<br />
|
|
21
|
+
<img src="docs/images/workflow-story/02-product-discovery.jpg" alt="An agent posts product discovery analysis on the GitHub issue" />
|
|
22
|
+
</td>
|
|
23
|
+
</tr>
|
|
24
|
+
<tr>
|
|
25
|
+
<td align="center" width="50%">
|
|
26
|
+
<strong>3. Approve the implementation plan</strong>
|
|
27
|
+
<br />
|
|
28
|
+
<img src="docs/images/workflow-story/03-plan-pr.jpg" alt="Backburner creates a planning pull request with product spec and plan documents" />
|
|
29
|
+
</td>
|
|
30
|
+
<td align="center" width="50%">
|
|
31
|
+
<strong>4. Review the completed work</strong>
|
|
32
|
+
<br />
|
|
33
|
+
<img src="docs/images/workflow-story/04-reviewed-change.jpg" alt="The implemented change is reviewed and ready for a human merge" />
|
|
34
|
+
</td>
|
|
35
|
+
</tr>
|
|
36
|
+
</table>
|
|
37
|
+
|
|
7
38
|
## How it works
|
|
8
39
|
|
|
9
40
|
1. You open an issue in a repository managed by Backburner.
|
|
@@ -746,6 +746,9 @@ export async function runCli(argv, options = {}) {
|
|
|
746
746
|
if (retrospectiveDerivation.tasks.length > 0 || finalSkipContextHydration.changed) {
|
|
747
747
|
await stateStore.writeTaskState(finalTasksToDispatch);
|
|
748
748
|
}
|
|
749
|
+
// Workspace recovery already ran before the initial dispatch. Deferring
|
|
750
|
+
// further recovery until the next outer run preserves completed task
|
|
751
|
+
// handoffs produced earlier in this run.
|
|
749
752
|
dispatchResult = await runDispatchWithMergePrepLifecycle({
|
|
750
753
|
tasks: finalTasksToDispatch,
|
|
751
754
|
worktrees: projectionAwareTriageWorktrees,
|
|
@@ -779,6 +782,7 @@ export async function runCli(argv, options = {}) {
|
|
|
779
782
|
commandRunner,
|
|
780
783
|
gitGateway,
|
|
781
784
|
workspaceRecoveryService,
|
|
785
|
+
skipWorkspaceRecovery: true,
|
|
782
786
|
agentPool
|
|
783
787
|
});
|
|
784
788
|
// Journal new executions (dedup via executionIdsBeforeCycle)
|
|
@@ -298,7 +298,10 @@ export async function runDispatchWithMergePrepLifecycle(input) {
|
|
|
298
298
|
await stateStore.writeTaskState(hydratedInputTasks);
|
|
299
299
|
}
|
|
300
300
|
// ── Phase 0: Recover workspaces of failed workspace-write tasks ─────────────
|
|
301
|
+
// This phase is intentionally skipped for follow-up dispatches in the same
|
|
302
|
+
// outer run so a failed sibling cannot erase a completed task's handoff.
|
|
301
303
|
const seenRecoveryPaths = new Set();
|
|
304
|
+
const recoveryResultByPath = new Map();
|
|
302
305
|
const existingRecoveryRecords = await stateStore.loadWorkspaceRecoveryState();
|
|
303
306
|
const recoveryRecords = [...existingRecoveryRecords];
|
|
304
307
|
let recoveryStateChanged = false;
|
|
@@ -311,11 +314,20 @@ export async function runDispatchWithMergePrepLifecycle(input) {
|
|
|
311
314
|
};
|
|
312
315
|
const recoveryResultByTaskId = new Map();
|
|
313
316
|
for (const task of hydratedInputTasks) {
|
|
314
|
-
if (!workspaceRecoveryService.isRecoveryNeeded(task)) {
|
|
317
|
+
if (input.skipWorkspaceRecovery || !workspaceRecoveryService.isRecoveryNeeded(task)) {
|
|
315
318
|
continue;
|
|
316
319
|
}
|
|
317
320
|
const localPath = workspaceRecoveryService.resolveTaskWorkspacePath(task);
|
|
318
321
|
if (localPath && seenRecoveryPaths.has(localPath)) {
|
|
322
|
+
const sharedRecoveryResult = recoveryResultByPath.get(localPath);
|
|
323
|
+
if (sharedRecoveryResult) {
|
|
324
|
+
recoveryResultByTaskId.set(task.id, sharedRecoveryResult);
|
|
325
|
+
if (sharedRecoveryResult.outcome === "recovered" ||
|
|
326
|
+
sharedRecoveryResult.outcome === "skipped") {
|
|
327
|
+
task.context.recoveryNeeded = false;
|
|
328
|
+
taskStateChangedByRecovery = true;
|
|
329
|
+
}
|
|
330
|
+
}
|
|
319
331
|
continue;
|
|
320
332
|
}
|
|
321
333
|
if (localPath) {
|
|
@@ -329,6 +341,9 @@ export async function runDispatchWithMergePrepLifecycle(input) {
|
|
|
329
341
|
counts[recoveryResult.outcome]++;
|
|
330
342
|
recoveryRecords.push(recoveryResult);
|
|
331
343
|
recoveryResultByTaskId.set(task.id, recoveryResult);
|
|
344
|
+
if (localPath) {
|
|
345
|
+
recoveryResultByPath.set(localPath, recoveryResult);
|
|
346
|
+
}
|
|
332
347
|
recoveryStateChanged = true;
|
|
333
348
|
if (recoveryResult.outcome === "recovered" || recoveryResult.outcome === "skipped") {
|
|
334
349
|
task.context.recoveryNeeded = false;
|