From 43f5c3736c2dd3ed6d4ddb9f9a867de37912b51c Mon Sep 17 00:00:00 2001 From: shiv Date: Fri, 14 Aug 2026 16:25:33 -0400 Subject: [PATCH 1/2] fix: widen CycleState.mode from Literal to str for plugin modes Plugin modes registered via add_modes() failed Pydantic validation when headless mode created a CycleState, since the Literal type only accepted hardcoded built-in mode names. Closes #1262 Co-Authored-By: Claude Opus 4.6 (1M context) --- factory/models.py | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/factory/models.py b/factory/models.py index 99304f6d0..1cdd5235d 100644 --- a/factory/models.py +++ b/factory/models.py @@ -491,24 +491,7 @@ class CycleState(BaseModel): cycle_id: str started_at: datetime - mode: Literal[ - "build", - "create", - "deep-qa", - "deep-research", - "design", - "discover", - "founder", - "improve", - "meta", - "parallel-improve", - "qa", - "refine", - "research", - "review", - "study", - "swebench", - ] + mode: str initial_prompt: str = "" respawns: int = 0 runner_name: str | None = None From fb516dea78ae3327ed6371d9b65ff15cf6791551 Mon Sep 17 00:00:00 2001 From: shiv Date: Fri, 14 Aug 2026 16:26:34 -0400 Subject: [PATCH 2/2] fix: carry plugin-created .factory/ subdirs into worktrees After the existing symlink/copy logic and per-cycle fresh dirs, iterate over remaining subdirectories in source .factory/ and copy any not already handled. Skips entries already present (symlinked, copied, or created fresh) to avoid duplication. Closes #1263 Co-Authored-By: Claude Opus 4.6 (1M context) --- factory/worktree.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/factory/worktree.py b/factory/worktree.py index 13961247e..d0d036d06 100644 --- a/factory/worktree.py +++ b/factory/worktree.py @@ -140,6 +140,16 @@ def create_worktree( if backlog_src.exists(): shutil.copy2(backlog_src, wt_factory / "strategy" / "backlog.md") + # Copy remaining plugin-created subdirectories not already handled. + _handled = set(_SHARED_SYMLINK_ENTRIES) | set(_COPY_ENTRIES) + if factory_dir.is_dir(): + for child in factory_dir.iterdir(): + if child.name in _handled or not child.is_dir(): + continue + dst = wt_factory / child.name + if not dst.exists(): + shutil.copytree(child, dst) + log.info("worktree_created", branch=branch, path=str(wt_dir)) try: