feat(worker): swap mkdtemp+clone for persistent worktree #14

Closed
claude-desktop wants to merge 0 commits from boss/5 into main
Collaborator

Swap runAgent's per-task mkdtemp + git clone for the workdir module's cache-clone + worktree lifecycle, so Forgejo is fetched (not re-cloned) per dispatch and worktree state carries across turns for the same (agent, issue).

Summary

  • runAgent rewrite (src/main.ts) — replaces the mkdtemp + git clone block with ensureCacheClone + fetchLatest + acquireWorktree. Branch is derived via the new deriveIssueBranch(branch_prefix, issue_number) helper to match what the webhook feeds into the skill template. gitIdentityEnv + gitAuthEnv are merged into query({ env }) so the SDK's own git invocations carry the agent identity without writing user.name/user.email or tokens to .git/config. The finally { rm(workdir) } is replaced with releaseWorktree(..., { keep: true }).
  • Dirty-state warninginspectWorktree runs at task start and emits a progress-stream warning when a previous dispatch left the worktree dirty or on an unexpected branch, so the inherited state is visible in the dashboard.
  • Fail-fast on acquisition — if ensureCacheClone / fetchLatest / acquireWorktree throws, the task fails with the underlying git error surfaced (no silent retry).
  • Cleanup wired up (src/cleanup.ts, src/webhook.ts)cleanupIssue and cleanupBranch now take the registered agent list and call releaseWorktree(..., { keep: false }) per agent. Webhook handlers for issues.closed and pull_request.closed build that list from the loaded config and call cleanup fire-and-forget.
  • Single branch-derivation helperderiveIssueBranch lives in workdir.ts and is used by the webhook (template interpolation), the worker (worktree acquisition) and cleanup (worktree release), so there's one source of truth for the prefix/number formula.

Notes

This branch is based on boss/3 (#13) with dev/4 (#12) cherry-picked on top — those are the workdir module and the cleanup webhook hooks this story integrates. When they merge into main, the diff here will collapse down to the runAgent rewrite + cleanup-signature changes.

Closes #5

Test plan

  • just qa — typecheck, biome check, biome format, bun test (33 tests across main / webhook / workdir)
  • Manual: dispatch a test issue twice; confirm the worktree directory is reused (mtime preserved) and Forgejo access log shows fetches, not clones
  • Manual: close the test issue; confirm releaseWorktree({ keep: false }) runs and the worktree directory is gone
Swap `runAgent`'s per-task `mkdtemp` + `git clone` for the workdir module's cache-clone + worktree lifecycle, so Forgejo is fetched (not re-cloned) per dispatch and worktree state carries across turns for the same `(agent, issue)`. ## Summary - **`runAgent` rewrite (`src/main.ts`)** — replaces the `mkdtemp` + `git clone` block with `ensureCacheClone` + `fetchLatest` + `acquireWorktree`. Branch is derived via the new `deriveIssueBranch(branch_prefix, issue_number)` helper to match what the webhook feeds into the skill template. `gitIdentityEnv` + `gitAuthEnv` are merged into `query({ env })` so the SDK's own git invocations carry the agent identity without writing `user.name`/`user.email` or tokens to `.git/config`. The `finally { rm(workdir) }` is replaced with `releaseWorktree(..., { keep: true })`. - **Dirty-state warning** — `inspectWorktree` runs at task start and emits a progress-stream warning when a previous dispatch left the worktree dirty or on an unexpected branch, so the inherited state is visible in the dashboard. - **Fail-fast on acquisition** — if `ensureCacheClone` / `fetchLatest` / `acquireWorktree` throws, the task fails with the underlying git error surfaced (no silent retry). - **Cleanup wired up (`src/cleanup.ts`, `src/webhook.ts`)** — `cleanupIssue` and `cleanupBranch` now take the registered agent list and call `releaseWorktree(..., { keep: false })` per agent. Webhook handlers for `issues.closed` and `pull_request.closed` build that list from the loaded config and call cleanup fire-and-forget. - **Single branch-derivation helper** — `deriveIssueBranch` lives in `workdir.ts` and is used by the webhook (template interpolation), the worker (worktree acquisition) and cleanup (worktree release), so there's one source of truth for the `prefix/number` formula. ## Notes This branch is based on `boss/3` (#13) with `dev/4` (#12) cherry-picked on top — those are the workdir module and the cleanup webhook hooks this story integrates. When they merge into `main`, the diff here will collapse down to the `runAgent` rewrite + cleanup-signature changes. Closes #5 ## Test plan - [x] `just qa` — typecheck, biome check, biome format, `bun test` (33 tests across main / webhook / workdir) - [ ] Manual: dispatch a test issue twice; confirm the worktree directory is reused (mtime preserved) and Forgejo access log shows fetches, not clones - [ ] Manual: close the test issue; confirm `releaseWorktree({ keep: false })` runs and the worktree directory is gone
charles force-pushed boss/5 from 86f943767f
All checks were successful
qa / qa (pull_request) Successful in 44s
to 4b4c36d59f
All checks were successful
qa / qa (pull_request) Successful in 45s
2026-04-17 09:16:55 +00:00
Compare
charles closed this pull request 2026-04-17 09:17:13 +00:00
All checks were successful
qa / qa (pull_request) Successful in 45s
Required
Details

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!14
No description provided.