Feat/dwm extensions#7
Conversation
Workspaces are now stored alongside the repo at <repo-root>/.dwm/<name>/ instead of in a centralized ~/.dwm/ tree keyed by basename+hash. This also drops the .main-repo and .vcs-type marker files (the parent of .dwm/ is the repo root and vcs::detect already walks up looking for .jj/.git), introduces a cross-platform registry at dirs::data_dir()/dwm/repos.txt for `dwm list --all`, and auto-appends .dwm/ to .git/info/exclude (or .gitignore for jj-only repos) the first time a workspace is created in a repo. The hashing/marker-file machinery (`hash_path`, `repo_dir_name`, `detect_from_dwm_dir`, `read_vcs_type`, the `repo_name_from` override) is gone, along with the related tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Update README, site landing page, and CLAUDE.md to reflect that workspaces now live at <repo>/.dwm/<name>/ rather than under a centralized ~/.dwm/ tree, and that dwm auto-manages the relevant ignore file the first time a workspace is created in a repo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds src/hooks.rs reading <repo>/.dwm.toml or <repo>/conductor.json, runs scripts.setup after workspace_add. Sets DWM_* env vars plus CONDUCTOR_ROOT_PATH for drop-in compat.
Deploying with
|
| Status | Name | Latest Commit | Updated (UTC) |
|---|---|---|---|
| ✅ Deployment successful! View logs |
dwm | a2bfcbf | May 12 2026, 08:14 AM |
drivasperez
left a comment
There was a problem hiding this comment.
Review
Solid refactor — moving from ~/.dwm/<repo-hash>/ to in-repo <repo>/.dwm/<name>/ removes a class of "which clone is this?" ambiguity, and the new hooks system is well-scoped with thorough tests. cargo build / cargo t (281/281) / cargo clippy all clean on macOS; the two clippy warnings are pre-existing and unrelated to this branch.
A handful of findings inline. Highlights:
find_dwm_workspacehappily returns.agent-statusas a workspace name when invoked from inside<root>/.dwm/.agent-status/…. The dot-prefix guard exists innew/renamebut not indelete/switchwhen the name is inferred from cwd. The blast radius is limited (the VCS call will fail rather than corrupt anything), but it would surface as a confusing error.ensure_dwm_ignoreddoesn't handle git worktrees (.gitas a file rather than a directory). It falls through to writing.gitignore, which is tracked, instead of the per-cloneinfo/excludeunder the common dir.DWM_FROM_WORKSPACEenv leaks from the parent process when--fromis absent — already noted in a test SAFETY comment but worth fixing properly by always setting (or always removing) the var on the child.register_repodoesn't canonicalize the path before storing, so a symlinked invocation and a real-path invocation will both end up inrepos.txtanddwm list --allwill show duplicates.detect_backend_from_cwdis a no-op wrapper aroundvcs::detectwith a comment that doesn't describe a behavioral difference. Inline or drop.
Not flagged inline: this is a breaking change for users with existing ~/.dwm/ workspaces (they'll appear to lose them all). Pre-1.0 so probably acceptable, but a one-line note in the PR body and/or a CHANGELOG entry would soften the landing.
| ) | ||
| let (root, ws, _) = find_dwm_workspace(&deps.cwd) | ||
| .context("not inside a dwm workspace; provide a workspace name")?; | ||
| (root, ws) | ||
| } |
There was a problem hiding this comment.
Dot-prefix bypass: find_dwm_workspace will return .agent-status as the workspace name if cwd is <root>/.dwm/.agent-status/<file>. new_workspace_inner and rename_workspace_inner reject names starting with ., but here ws_name flows straight through to workspace_remove and fs::remove_dir_all. In practice the VCS call (jj workspace forget .agent-status / git worktree remove) errors out before any damage, so this is a confusing-error issue rather than a data-loss one. Easiest fix: reject dot-prefixed names from find_dwm_workspace here and in switch_workspace_inner/infer_workspace_name_from_cwd, parallel to the check at line 262.
| continue; | ||
| }; | ||
| return Some((repo_path, ws_name.to_string())); | ||
| return Some((dwm, ws_name.to_string())); |
There was a problem hiding this comment.
Symmetry nit: this hardcodes "default" and "main-worktree" while vcs.rs exposes main_workspace_name() on VcsBackend. Since you're staying subprocess-free here that's fine, but consider exposing the names as associated consts on VcsType (or a free function in vcs.rs) so the two sites can't drift apart.
…agent-status/ Gives workspaces and internal metadata each their own namespace under .dwm/, removing the dot-prefix collision risk that .agent-status had with workspace names. Workspace names can now start with '.', and find_dwm_workspace no longer needs to guess based on filename prefix.
It was a one-liner around vcs::detect with a comment that didn't describe a behavioral difference. Inline the call at the four sites and drop the wrapper.
Previously the function fell through to writing tracked .gitignore whenever .git was a file (worktree gitlink) rather than a dir. Switch to 'git rev-parse --git-path info/exclude' so we always write to the untracked per-clone (or per-worktree) exclude file when git is present, and only fall back to .gitignore for jj-only repos with no .git at all.
A symlinked invocation and a real-path invocation of dwm previously produced two entries in the registry, surfacing as duplicate workspaces in 'dwm list --all'. fs::canonicalize gives a single canonical form; fall back to the original on error (e.g. path doesn't exist yet).
The .envs(...map(...)) pattern set the child's DWM_FROM_WORKSPACE only when from_workspace was Some, silently inheriting any value the parent already had otherwise. Switch to explicit env/env_remove so the child sees the var set exactly when --from was passed.
agent.rs hardcoded "default"/"main-worktree" duplicating the strings already returned by JjBackend/GitBackend::main_workspace_name. Add VcsType::main_workspace_name as the single source of truth, have both backends delegate to it, and call it from agent.rs.
No description provided.