Merge pull request #3636 from lucasyounger/codex/fix-3629-worktree-plan-path
fix(boulder): resolve continuation progress from worktree plan
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, test, beforeEach, afterEach } from "bun:test"
|
||||
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
|
||||
import { join } from "node:path"
|
||||
import { dirname, join } from "node:path"
|
||||
import { tmpdir } from "node:os"
|
||||
import {
|
||||
readBoulderState,
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
createBoulderState,
|
||||
findPrometheusPlans,
|
||||
getTaskSessionState,
|
||||
resolveBoulderPlanPath,
|
||||
upsertTaskSessionState,
|
||||
} from "./storage"
|
||||
import type { BoulderState } from "./types"
|
||||
@@ -778,4 +779,46 @@ describe("boulder-state", () => {
|
||||
expect(state.agent).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe("resolveBoulderPlanPath", () => {
|
||||
test("should prefer the mirrored worktree plan when it exists", () => {
|
||||
// given
|
||||
const planPath = join(TEST_DIR, ".sisyphus", "plans", "worktree-plan.md")
|
||||
const worktreeDir = join(tmpdir(), `boulder-state-worktree-${Date.now()}`)
|
||||
const worktreePlanPath = join(worktreeDir, ".sisyphus", "plans", "worktree-plan.md")
|
||||
mkdirSync(dirname(planPath), { recursive: true })
|
||||
mkdirSync(dirname(worktreePlanPath), { recursive: true })
|
||||
writeFileSync(planPath, "# Plan\n- [ ] Main repo task\n")
|
||||
writeFileSync(worktreePlanPath, "# Plan\n- [x] Worktree task\n")
|
||||
|
||||
try {
|
||||
// when
|
||||
const resolvedPath = resolveBoulderPlanPath(TEST_DIR, {
|
||||
active_plan: planPath,
|
||||
worktree_path: worktreeDir,
|
||||
})
|
||||
|
||||
// then
|
||||
expect(resolvedPath).toBe(worktreePlanPath)
|
||||
} finally {
|
||||
rmSync(worktreeDir, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
|
||||
test("should fall back to the tracked plan when the mirrored worktree plan is missing", () => {
|
||||
// given
|
||||
const planPath = join(TEST_DIR, ".sisyphus", "plans", "fallback-plan.md")
|
||||
mkdirSync(dirname(planPath), { recursive: true })
|
||||
writeFileSync(planPath, "# Plan\n- [ ] Main repo task\n")
|
||||
|
||||
// when
|
||||
const resolvedPath = resolveBoulderPlanPath(TEST_DIR, {
|
||||
active_plan: planPath,
|
||||
worktree_path: join(tmpdir(), `missing-worktree-${Date.now()}`),
|
||||
})
|
||||
|
||||
// then
|
||||
expect(resolvedPath).toBe(planPath)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync } from "node:fs"
|
||||
import { dirname, join, basename } from "node:path"
|
||||
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path"
|
||||
import type { BoulderState, PlanProgress, TaskSessionState } from "./types"
|
||||
import { BOULDER_DIR, BOULDER_FILE, PROMETHEUS_PLANS_DIR } from "./constants"
|
||||
|
||||
@@ -15,6 +15,39 @@ export function getBoulderFilePath(directory: string): string {
|
||||
return join(directory, BOULDER_DIR, BOULDER_FILE)
|
||||
}
|
||||
|
||||
function resolveTrackedPath(baseDirectory: string, trackedPath: string): string {
|
||||
return isAbsolute(trackedPath)
|
||||
? resolve(trackedPath)
|
||||
: resolve(baseDirectory, trackedPath)
|
||||
}
|
||||
|
||||
export function resolveBoulderPlanPath(
|
||||
directory: string,
|
||||
state: Pick<BoulderState, "active_plan" | "worktree_path">,
|
||||
): string {
|
||||
const absolutePlanPath = resolveTrackedPath(directory, state.active_plan)
|
||||
const worktreePath = state.worktree_path?.trim()
|
||||
if (!worktreePath) {
|
||||
return absolutePlanPath
|
||||
}
|
||||
|
||||
const absoluteDirectory = resolve(directory)
|
||||
const relativePlanPath = relative(absoluteDirectory, absolutePlanPath)
|
||||
if (
|
||||
relativePlanPath.length === 0
|
||||
|| relativePlanPath.startsWith("..")
|
||||
|| isAbsolute(relativePlanPath)
|
||||
) {
|
||||
return absolutePlanPath
|
||||
}
|
||||
|
||||
const absoluteWorktreePath = resolveTrackedPath(directory, worktreePath)
|
||||
const worktreePlanPath = resolve(absoluteWorktreePath, relativePlanPath)
|
||||
return existsSync(worktreePlanPath)
|
||||
? worktreePlanPath
|
||||
: absolutePlanPath
|
||||
}
|
||||
|
||||
export function readBoulderState(directory: string): BoulderState | null {
|
||||
const filePath = getBoulderFilePath(directory)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user