@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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backburner/cli",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "type": "module",
5
5
  "description": "Local GitHub-based agent orchestration CLI",
6
6
  "license": "MIT",