Skip to content

fix(shell): discover devcontainer from any subdir of a worktree or repo#9

Open
rosstaco wants to merge 1 commit into
mainfrom
fix/dcode-shell-worktree-subdir
Open

fix(shell): discover devcontainer from any subdir of a worktree or repo#9
rosstaco wants to merge 1 commit into
mainfrom
fix/dcode-shell-worktree-subdir

Conversation

@rosstaco
Copy link
Copy Markdown
Owner

Problem

dcode shell (and dcode <path>) only looked at the exact target
directory for a .git pointer. Running from any subdir of a worktree
fell through to "no devcontainer.json found":

$ cd ~/repos/repo_a/.worktrees/branch_1/src
$ dcode shell
dcode: no devcontainer.json found for /…/branch_1/src; run `dcode doctor` to diagnose

The same blind spot silently affected plain repos: dcode . from a
subdir would fall back to plain code <subdir> with no container.

Fix

Two new helpers in core.py:

  • _find_project_root(target) — walks ancestors looking for a .git
    (file or directory). Returns the directory containing it.
  • resolve_target(target) -> (project_root, container_subdir) — the
    host directory that owns the devcontainer plus the path relative to
    the devcontainer's workspaceFolder that the user actually wants
    opened. For worktrees, project_root stays the main repo (all worktrees
    keep sharing one container) and container_subdir stacks the
    worktree-relative path and the user's subdir. For plain repos it's
    just the repo root + subdir. For non-repo targets it returns
    (target, Path('.')) so the existing "no devcontainer" fallback is
    unchanged.

run_shell, run_dcode, check_devcontainer, check_devcontainer_parses
and the doctor plan summary all switch to resolve_target so they
behave consistently from any depth, including dcode doctor which now
predicts what dcode . will actually do.

After

$ cd ~/repos/repo_a/.worktrees/branch_1/src
$ dcode doctor .
…
╭─ Plan for /…/repo_a/.worktrees/branch_1/src ─╮
│ Detected git worktree.                       │
│ Would anchor at the main repo /…/repo_a so   │
│ all worktrees share one container.           │
│ effective workspaceFolder:                   │
│   /workspaces/repo_a/.worktrees/branch_1/src │

Tests

333 passing, lint clean.

  • tests/test_core.py: TestFindProjectRoot (5 cases),
    TestResolveTarget (5 cases including non-repo fallback),
    TestRunDcodeSubdir (3 end-to-end: plain subdir, worktree subdir,
    non-repo fallback).
  • tests/test_shell.py:
    test_worktree_subdir_uses_main_repo_and_deeper_workdir (regression
    test for the reported bug, asserts find_container keys off the main
    repo and probe_workdir points at the deeper folder), plus
    test_plain_repo_subdir_resolves_devcontainer_at_repo_root.
  • Existing test_worktree_uses_main_repo_for_lookup still passes
    unchanged (worktree-root behaviour is preserved).
  • Three doctor tests updated for new wording ("project root" / "main
    repo" lowercase, and the external-worktree case which now reverts to
    the clean "no devcontainer" plan instead of an alarming "cannot be
    resolved" warning).

Out of scope

  • No changes to container build / metadata logic — this is purely a
    path-resolution fix.
  • check_worktree is unchanged; it's specifically a per-target sanity
    check (is THIS folder a worktree pointer file?) so widening it to
    walk-up would change its semantic.

Previously `dcode shell` (and `dcode <path>`) only looked at the exact
target directory for a `.git` pointer. Running from any subdir of a
worktree (e.g. `~/repos/repo_a/.worktrees/branch_1/src`) fell through
to "no devcontainer.json found" because resolve_worktree only succeeded
when the target itself was the worktree root. The same blind spot
silently affected plain repos: `dcode .` from a subdir would fall back
to plain `code <subdir>` with no container.

Add `_find_project_root` which walks ancestors looking for a `.git`
(file or directory), and `resolve_target` which returns
`(project_root, container_subdir)` — the host directory that owns the
devcontainer plus the path relative to the devcontainer's
`workspaceFolder` that the user actually wants opened. For worktrees,
project_root stays the main repo so all worktrees keep sharing one
container, and container_subdir stacks the worktree-relative path and
the user's subdir.

`run_shell`, `run_dcode`, `check_devcontainer`,
`check_devcontainer_parses` and the doctor plan summary all switch to
`resolve_target` so they behave consistently from any depth.

Tests: `TestFindProjectRoot`, `TestResolveTarget`, `TestRunDcodeSubdir`
in test_core.py; `test_worktree_subdir_uses_main_repo_and_deeper_workdir`
+ `test_plain_repo_subdir_resolves_devcontainer_at_repo_root` in
test_shell.py.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

1 participant