Skip to content

feat: per-project worktree.path config option#1117

Closed
joelsb wants to merge 3 commits intocoleam00:devfrom
joelsb:feat/per-project-worktree-path
Closed

feat: per-project worktree.path config option#1117
joelsb wants to merge 3 commits intocoleam00:devfrom
joelsb:feat/per-project-worktree-path

Conversation

@joelsb
Copy link
Copy Markdown
Contributor

@joelsb joelsb commented Apr 12, 2026

Summary

  • Adds worktree.path to repo-level .archon/config.yaml — a relative path from repo root where worktrees should be created
  • When set, worktrees are created at <repoRoot>/<path>/<branchName> instead of ~/.archon/worktrees/
  • Per-project path takes highest priority, overriding both project-scoped workspaces and legacy global paths

Motivation

When working with Archon on a project, worktrees are created in ~/.archon/worktrees/ by default — invisible to the IDE and far from the project. This PR allows repos to opt in to keeping worktrees co-located:

# .archon/config.yaml
worktree:
  path: .worktrees

Worktrees then appear at myproject/.worktrees/archon/task-fix-bug — visible in the IDE file tree and easy to navigate.

Changes

File Change
packages/isolation/src/types.ts Added path?: string to WorktreeCreateConfig
packages/core/src/config/config-types.ts Added path?: string to RepoConfig.worktree
packages/isolation/src/providers/worktree.ts getWorktreePath() checks config.path first; create() loads config early; createWorktree() handles custom path mkdir
packages/isolation/src/providers/worktree.test.ts 4 new tests covering custom path, empty/whitespace path, null config fallback, priority over project-scoped

Test plan

  • All existing tests pass (0 failures across all packages)
  • New tests verify: custom path resolution, empty/whitespace ignored, null config falls back to defaults, custom path overrides project-scoped path
  • Manual: set worktree.path: .worktrees in a repo's .archon/config.yaml and run archon workflow run — worktree should appear under .worktrees/

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Per-project worktree path configuration: specify a repo-relative directory for worktrees instead of the global default.
  • Chores

    • Updated ignore rules to exclude .worktrees directories.
  • Tests

    • Added tests covering per-project worktree path behavior, validation of empty/whitespace handling, and precedence over other path strategies.

joelsb and others added 2 commits April 12, 2026 13:46
Allows repositories to configure a custom worktree directory relative
to the repo root (e.g. `.worktrees`) via `.archon/config.yaml`:

```yaml
worktree:
  path: .worktrees
```

When set, worktrees are created at `<repoRoot>/<path>/<branchName>`
instead of the global `~/.archon/worktrees/` directory. This keeps
worktrees co-located with the project and visible in the IDE.

The per-project path takes highest priority, overriding both the
project-scoped workspaces path and the legacy global path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 12, 2026

📝 Walkthrough

Walkthrough

Adds per-repository worktree directory support via a new optional worktree.path config; updates path resolution and creation to honor per-project paths with early config loading; adds tests and .gitignore entry for .worktrees.

Changes

Cohort / File(s) Summary
Config Types
packages/core/src/config/config-types.ts, packages/isolation/src/types.ts
Add optional path?: string to repo/worktree config and add worktreePath?: string to merged config to carry effective per-project worktree path.
Worktree Provider Logic
packages/isolation/src/providers/worktree.ts
Early config load in create(), extend getWorktreePath(...) to accept optional config and prefer <repoRoot>/<worktree.path>/<branch> when set; createWorktree() accepts optional preloaded config and ensures parent dir under repo root when using worktree.path.
Config Loader
packages/core/src/config/config-loader.ts
mergeRepoConfig propagates repo.worktree.path into result.worktreePath when non-empty; warns (config.worktree_path_whitespace_ignored) if trimmed value is empty.
Tests
packages/isolation/src/providers/worktree.test.ts
Add tests for per-project worktree.path behavior: correct path formation, whitespace-as-empty handling, fallback when config missing, and precedence over other path strategies.
Ignore Rules
.gitignore
Add .worktrees to .gitignore.

Sequence Diagram(s)

sequenceDiagram
    participant Caller as Isolation Request
    participant Provider as WorktreeProvider
    participant Config as Config Loader
    participant FS as FileSystem
    participant Git as Worktree Tool

    Caller->>Provider: create(request)
    Provider->>Config: loadConfig(canonicalRepoPath)
    Config-->>Provider: WorktreeCreateConfig | null

    Provider->>Provider: getWorktreePath(request, branchName, config)
    alt config.path exists
        Note right of Provider: use <repoRoot>/<config.path>/<branch>
    else
        Note right of Provider: fallback to project-scoped or legacy path
    end
    Provider->>Provider: worktreePath

    Provider->>Provider: createWorktree(request, worktreePath, branchName, preloadedConfig)
    alt config.path is set
        Provider->>FS: mkdirAsync(join(repoRoot, config.path))
    else
        Provider->>FS: ensure base-layout directories
    end
    FS-->>Provider: dirs ready

    Provider->>Git: create worktree at worktreePath
    Git-->>Provider: warnings[]
    Provider-->>Caller: { warnings }
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through configs, sniffed each repo tree,
A path for each branch now lives where it should be,
No more one-size worktrees wandering afar,
Per-project burrows now cozy and smart,
Hooray — tidy roots for every branch we see! 🥕

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description covers key sections (Summary, Motivation, Changes table) and explains the feature well, but several required template sections are missing or incomplete. Add missing sections: UX Journey (Before/After flows), Architecture Diagram (Before/After with module connections), Label Snapshot, Validation Evidence with command results, Security Impact assessment, Compatibility details, Human Verification details, Side Effects/Blast Radius analysis, and Rollback Plan. Complete the manual test verification checkbox and provide evidence.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: adding per-project worktree.path config option support.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Exposes the per-project worktree.path through MergedConfig so tools,
the web UI, and API endpoints can read and display both the global
paths.worktrees and the per-project worktreePath override.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/core/src/config/config-loader.ts`:
- Around line 389-395: The code calls repo.worktree.path.trim() after checking
!== undefined which will throw if path is non-string (e.g., null); update the
branch in config-loader.ts to first assert the type is string (e.g., typeof
repo.worktree.path === 'string') before calling .trim(), set result.worktreePath
when trimmed is non-empty, and otherwise either log the whitespace-warning using
getLog().warn or throw a clear error for unsupported non-string values (per
guidelines) so the unsafe state is rejected explicitly; reference symbols:
repo.worktree.path, result.worktreePath, and getLog().warn.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ec9164cc-04c1-40ff-be9f-4d9ec639025e

📥 Commits

Reviewing files that changed from the base of the PR and between b7bd6e9 and 6a630d8.

📒 Files selected for processing (2)
  • packages/core/src/config/config-loader.ts
  • packages/core/src/config/config-types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/core/src/config/config-types.ts

Comment on lines +389 to +395
if (repo.worktree?.path !== undefined) {
const trimmed = repo.worktree.path.trim();
if (trimmed) {
result.worktreePath = trimmed;
} else {
getLog().warn({ rawValue: repo.worktree.path }, 'config.worktree_path_whitespace_ignored');
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard repo.worktree.path type before calling .trim().

This branch can throw if YAML contains a non-string value (e.g., path: null), because !== undefined still passes and .trim() is invoked on a non-string.

Suggested fix
   // Propagate per-project worktree path for isolation providers
   if (repo.worktree?.path !== undefined) {
-    const trimmed = repo.worktree.path.trim();
+    if (typeof repo.worktree.path !== 'string') {
+      throw new Error('Invalid .archon/config.yaml: worktree.path must be a string');
+    }
+    const trimmed = repo.worktree.path.trim();
     if (trimmed) {
       result.worktreePath = trimmed;
     } else {
       getLog().warn({ rawValue: repo.worktree.path }, 'config.worktree_path_whitespace_ignored');
     }
   }

As per coding guidelines, “Throw early with a clear error for unsupported or unsafe states” and “keep unsupported paths explicit (error out) rather than adding partial fake support.”

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (repo.worktree?.path !== undefined) {
const trimmed = repo.worktree.path.trim();
if (trimmed) {
result.worktreePath = trimmed;
} else {
getLog().warn({ rawValue: repo.worktree.path }, 'config.worktree_path_whitespace_ignored');
}
if (repo.worktree?.path !== undefined) {
if (typeof repo.worktree.path !== 'string') {
throw new Error('Invalid .archon/config.yaml: worktree.path must be a string');
}
const trimmed = repo.worktree.path.trim();
if (trimmed) {
result.worktreePath = trimmed;
} else {
getLog().warn({ rawValue: repo.worktree.path }, 'config.worktree_path_whitespace_ignored');
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/core/src/config/config-loader.ts` around lines 389 - 395, The code
calls repo.worktree.path.trim() after checking !== undefined which will throw if
path is non-string (e.g., null); update the branch in config-loader.ts to first
assert the type is string (e.g., typeof repo.worktree.path === 'string') before
calling .trim(), set result.worktreePath when trimmed is non-empty, and
otherwise either log the whitespace-warning using getLog().warn or throw a clear
error for unsupported non-string values (per guidelines) so the unsafe state is
rejected explicitly; reference symbols: repo.worktree.path, result.worktreePath,
and getLog().warn.

@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Apr 15, 2026

Hey @joelsb — thanks for this! The motivation is real (worktrees in ~/.archon/worktrees/ being invisible in IDEs is a genuine UX papercut) and the wiring through RepoConfig.worktree.pathWorktreeCreateConfig.path → provider is clean and follows the existing pattern for baseBranch/copyFiles. I'd like to land this — but the primitive and a few of the side effects need tightening before it's safe to ship.

The primitive

The config field is a free-form relative path string, but the actual semantics is "a directory inside this repo". That mismatch leaves a few foot-guns the PR doesn't address:

  • No path-traversal guardpath: ../sibling would create worktrees outside the repo. Untested.
  • No absolute-path guardpath: /tmp/foo silently bypasses repoRoot. Untested.
  • No symlink-escape consideration.

The actual user need is "put them somewhere under the repo so I can see them in my IDE". Two cheaper-to-validate primitives that express that intent more precisely:

  • worktree.coLocate: true — fixed conventional dirname (e.g. .archon-worktrees/)
  • worktree.dirname: string — single segment, validated to not contain / or ..

If you want to keep the full path flexibility, please add validation that rejects (or warns + ignores) absolute paths and any path that resolves outside repoRoot (use path.resolve and check the result startsWith(repoRoot)), with tests for each rejection.

The side effects

A few things that aren't quite right yet:

1. Asymmetric config-load error handling.

try { earlyConfig = await this.loadConfig(...); earlyConfigLoaded = true; }
catch { /* swallowed */ }

The early load silently swallows errors and falls back to defaults; the later load in createWorktree throws. So one config error produces two different behaviors depending on whether the second load also fails the same way. That violates our "Fail Fast + Explicit Errors" rule (CLAUDE.md). Pick one model — either both warn-and-default, or both throw — and apply it once.

2. generateEnvId() is now stale.

The PR replaces envId = this.generateEnvId(request) with envId = worktreePath (correct, because generateEnvId doesn't take config). But the method is left on the class unmodified — any future caller will get the default path even when config overrides it. Either delete generateEnvId (it's only used here) or make it config-aware.

3. MergedConfig.worktreePath is added but never read.

The PR plumbs worktree.path into MergedConfig.worktreePath in config-loader.ts, but no code consumes it — the worktree provider gets path via WorktreeCreateConfig (the RepoConfigLoader path), not via MergedConfig. That field is dead on arrival. Please remove it (or wire an actual consumer if you have one in mind).

4. Implicit .gitignore requirement.

A user opting into worktree.path: .worktrees needs to add .worktrees to their .gitignore, or git status immediately shows the worktree dir as untracked. The PR adds it to Archon's own .gitignore but doesn't surface this for end users. Cheap, high-value addition: at worktree-create time, check whether the configured path is gitignored in the parent repo, and log a warn-level message if not. (Don't error — let the user decide, but make the foot-gun visible.)

5. Worktree-inside-repo recursion hazard (worth thinking about, not necessarily blocking).

When the worktree lives at <repo>/.worktrees/foo/, the worktree contains a working copy of the repo, which contains .worktrees/. Git itself handles this OK, but downstream tooling can get confused:

  • copyFiles (which already copies .archon/ into worktrees) could shovel worktree state around
  • IDE indexers, TypeScript project references, ESLint globs, test runners scanning **/*.test.ts — all need to be told to skip the new dir
  • Workflows running inside a worktree may discover and re-execute their own siblings if any tooling walks .worktrees/

Probably not a blocker, but worth a note in the doc/changelog so users opt in with eyes open.

Suggested cleanup checklist

  • Validate path (reject absolute, reject .. traversal, reject anything resolving outside repoRoot) — with tests
  • Pick a single error-handling model for config load and apply consistently
  • Drop MergedConfig.worktreePath (dead) OR wire a real consumer
  • Either delete generateEnvId or make it config-aware
  • Add a startup warn when worktree.path is set but not present in the repo's .gitignore
  • (Optional) consider coLocate: true or dirname: string instead of free-form path
  • Document the recursion/IDE-scan caveat in the feature docs

Happy to review the next iteration. Thanks again for digging into this one!

Wirasm added a commit that referenced this pull request Apr 20, 2026
Adds an opt-in `worktree.path` to .archon/config.yaml so a repo can co-locate
worktrees with its own checkout (`<repoRoot>/<path>/<branch>`) instead of the
default `~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`. Requested in
joelsb's #1117.

Primitive changes (clean up the graveyard rather than add parallel code paths):

- Collapse worktree layouts from three to two. The old "legacy global" layout
  (`~/.archon/worktrees/<owner>/<repo>/<branch>`) is gone — every repo resolves
  to the workspace-scoped layout (`~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`),
  whether it was archon-cloned or locally registered. `extractOwnerRepo()` on
  the repo path is the stable identity fallback. Ends the divergence where
  workspace-cloned and local repos had visibly different worktree trees.

- `getWorktreeBase()` in @archon/git now returns `{ base, layout }` and accepts
  an optional `{ repoLocal }` override. The layout value replaces the old
  `isProjectScopedWorktreeBase()` classification at the call sites
  (`isProjectScopedWorktreeBase` stays exported as deprecated back-compat).

- `WorktreeCreateConfig.path` carries the validated override from repo config.
  `resolveRepoLocalOverride()` fails loudly on absolute paths, `..` escapes,
  and resolve-escape edge cases (Fail Fast — no silent default fallback when
  the config is syntactically wrong).

- `WorktreeProvider.create()` now loads repo config exactly once and threads it
  through `getWorktreePath()` + `createWorktree()`. Replaces the prior
  swallow-then-retry pattern flagged on #1117. `generateEnvId()` is gone —
  envId is assigned directly from the resolved path (the invariant was already
  documented on `destroy(envId)`).

Tests (packages/git + packages/isolation):
- Update the pre-existing `getWorktreeBase` / `isProjectScopedWorktreeBase`
  suite for the new two-layout return shape and precedence.
- Add 8 tests for `worktree.path`: default fallthrough, empty/whitespace
  ignored, override wins for workspace-scoped repos, rejects absolute, rejects
  `../` escapes (three variants), accepts nested relative paths.

Docs: add `worktree.path` to the repo config reference with explicit precedence
and the `.gitignore` responsibility note.

Co-authored-by: Joel Bastos <joelsb2001@gmail.com>
Wirasm added a commit that referenced this pull request Apr 20, 2026
Adds an opt-in `worktree.path` to .archon/config.yaml so a repo can co-locate
worktrees with its own checkout (`<repoRoot>/<path>/<branch>`) instead of the
default `~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`. Requested in
joelsb's #1117.

Primitive changes (clean up the graveyard rather than add parallel code paths):

- Collapse worktree layouts from three to two. The old "legacy global" layout
  (`~/.archon/worktrees/<owner>/<repo>/<branch>`) is gone — every repo resolves
  to the workspace-scoped layout (`~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`),
  whether it was archon-cloned or locally registered. `extractOwnerRepo()` on
  the repo path is the stable identity fallback. Ends the divergence where
  workspace-cloned and local repos had visibly different worktree trees.

- `getWorktreeBase()` in @archon/git now returns `{ base, layout }` and accepts
  an optional `{ repoLocal }` override. The layout value replaces the old
  `isProjectScopedWorktreeBase()` classification at the call sites
  (`isProjectScopedWorktreeBase` stays exported as deprecated back-compat).

- `WorktreeCreateConfig.path` carries the validated override from repo config.
  `resolveRepoLocalOverride()` fails loudly on absolute paths, `..` escapes,
  and resolve-escape edge cases (Fail Fast — no silent default fallback when
  the config is syntactically wrong).

- `WorktreeProvider.create()` now loads repo config exactly once and threads it
  through `getWorktreePath()` + `createWorktree()`. Replaces the prior
  swallow-then-retry pattern flagged on #1117. `generateEnvId()` is gone —
  envId is assigned directly from the resolved path (the invariant was already
  documented on `destroy(envId)`).

Tests (packages/git + packages/isolation):
- Update the pre-existing `getWorktreeBase` / `isProjectScopedWorktreeBase`
  suite for the new two-layout return shape and precedence.
- Add 8 tests for `worktree.path`: default fallthrough, empty/whitespace
  ignored, override wins for workspace-scoped repos, rejects absolute, rejects
  `../` escapes (three variants), accepts nested relative paths.

Docs: add `worktree.path` to the repo config reference with explicit precedence
and the `.gitignore` responsibility note.

Co-authored-by: Joel Bastos <joelsb2001@gmail.com>
Wirasm added a commit that referenced this pull request Apr 20, 2026
… policy (#1310)

* feat(isolation): per-project worktree.path + collapse to two layouts

Adds an opt-in `worktree.path` to .archon/config.yaml so a repo can co-locate
worktrees with its own checkout (`<repoRoot>/<path>/<branch>`) instead of the
default `~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`. Requested in
joelsb's #1117.

Primitive changes (clean up the graveyard rather than add parallel code paths):

- Collapse worktree layouts from three to two. The old "legacy global" layout
  (`~/.archon/worktrees/<owner>/<repo>/<branch>`) is gone — every repo resolves
  to the workspace-scoped layout (`~/.archon/workspaces/<owner>/<repo>/worktrees/<branch>`),
  whether it was archon-cloned or locally registered. `extractOwnerRepo()` on
  the repo path is the stable identity fallback. Ends the divergence where
  workspace-cloned and local repos had visibly different worktree trees.

- `getWorktreeBase()` in @archon/git now returns `{ base, layout }` and accepts
  an optional `{ repoLocal }` override. The layout value replaces the old
  `isProjectScopedWorktreeBase()` classification at the call sites
  (`isProjectScopedWorktreeBase` stays exported as deprecated back-compat).

- `WorktreeCreateConfig.path` carries the validated override from repo config.
  `resolveRepoLocalOverride()` fails loudly on absolute paths, `..` escapes,
  and resolve-escape edge cases (Fail Fast — no silent default fallback when
  the config is syntactically wrong).

- `WorktreeProvider.create()` now loads repo config exactly once and threads it
  through `getWorktreePath()` + `createWorktree()`. Replaces the prior
  swallow-then-retry pattern flagged on #1117. `generateEnvId()` is gone —
  envId is assigned directly from the resolved path (the invariant was already
  documented on `destroy(envId)`).

Tests (packages/git + packages/isolation):
- Update the pre-existing `getWorktreeBase` / `isProjectScopedWorktreeBase`
  suite for the new two-layout return shape and precedence.
- Add 8 tests for `worktree.path`: default fallthrough, empty/whitespace
  ignored, override wins for workspace-scoped repos, rejects absolute, rejects
  `../` escapes (three variants), accepts nested relative paths.

Docs: add `worktree.path` to the repo config reference with explicit precedence
and the `.gitignore` responsibility note.

Co-authored-by: Joel Bastos <joelsb2001@gmail.com>

* feat(workflows): per-workflow worktree.enabled policy

Introduces a declarative top-level `worktree:` block on a workflow so
authors can pin isolation behavior regardless of invocation surface. Solves
the case where read-only workflows (e.g. `repo-triage`) should always run in
the live checkout, without every CLI/web/scheduled-trigger caller having to
remember to set the right flag.

Schema (packages/workflows/src/schemas/workflow.ts + loader.ts):

- New optional `worktree.enabled: boolean` on `workflowBaseSchema`. Loader
  parses with the same warn-and-ignore discipline used for `interactive`
  and `modelReasoningEffort` — invalid shapes log and drop rather than
  killing workflow discovery.

Policy reconciliation (packages/cli/src/commands/workflow.ts):

- Three hard-error cases when YAML policy contradicts invocation flags:
  • `enabled: false` + `--branch`       (worktree required by flag, forbidden by policy)
  • `enabled: false` + `--from`         (start-point only meaningful with worktree)
  • `enabled: true`  + `--no-worktree`  (policy requires worktree, flag forbids it)
- `enabled: false` + `--no-worktree` is redundant, accepted silently.
- `--resume` ignores the pinned policy (it reuses the existing run's worktree
  even when policy would disable — avoids disturbing a paused run).

Orchestrator wiring (packages/core/src/orchestrator/orchestrator-agent.ts):

- `dispatchOrchestratorWorkflow` short-circuits `validateAndResolveIsolation`
  when `workflow.worktree?.enabled === false` and runs directly in
  `codebase.default_cwd`. Web chat/slack/telegram callers have no flag
  equivalent to `--no-worktree`, so the YAML field is their only control.
- Logged as `workflow.worktree_disabled_by_policy` for operator visibility.

First consumer (.archon/workflows/repo-triage.yaml):

- `worktree: { enabled: false }` — triage reads issues/PRs and writes gh
  labels; no code mutations, no reason to spin up a worktree per run.

Tests:

- Loader: parses `worktree.enabled: true|false`, omits block when absent.
- CLI: four new integration tests for the reconciliation matrix (skip when
  policy false, three hard-error cases, redundant `--no-worktree` accepted,
  `--no-worktree` + `enabled: true` rejected).

Docs: authoring-workflows.md gets the new top-level field in the schema
example with a comment explaining the precedence and the `enabled: true|false`
semantics.

* fix(isolation): use path.sep for repo-containment check on Windows

resolveRepoLocalOverride was hardcoding '/' as the separator in the
startsWith check, so on Windows (where `resolve()` returns backslash
paths like `D:\Users\dev\Projects\myapp`) every otherwise-valid
relative `worktree.path` was rejected with "resolves outside the repo
root". Fixed by importing `path.sep` and using it in the sentinel.

Fixes the 3 Windows CI failures in `worktree.path repo-local override`.

---------

Co-authored-by: Joel Bastos <joelsb2001@gmail.com>
@Wirasm Wirasm closed this in #1310 Apr 20, 2026
@Wirasm Wirasm mentioned this pull request Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants