feat(create): make a new worktree usable the moment it exists - #10
Open
murdore wants to merge 1 commit into
Open
feat(create): make a new worktree usable the moment it exists#10murdore wants to merge 1 commit into
murdore wants to merge 1 commit into
Conversation
Two gaps between 'workforge created a worktree' and 'you can work in it'.
## It was not necessarily runnable
Installing dependencies is not always enough. Some repos need a one-time
bootstrap afterwards, and a worktree that skipped it fails in ways that do not
name the missing step: in juspay/lighthouse the Playwright mock suite aborts
with `Cannot find package '$models'`, which reads as a broken module alias and
sends you looking at svelte.config and node_modules instead of at a bootstrap
you never ran.
Reproduced on a fresh worktree before changing anything:
no setup -> 2 $models errors, 0 tests ran
after -> 0 errors, 83 tests ran
The synced .env is byte-identical either way — same 244 keys, same values — so
env syncing is not what closes the gap, and 'workforge already syncs .env' is
not a reason to skip this.
So: after install, run `<manager> run setup` when package.json declares it.
Conventional rather than configurable; a repo without that script is
unaffected. Failures warn and continue, exactly like the install step it
follows. WORKFORGE_SKIP_SETUP=1 opts out.
## You still had to cd there yourself
--switch (-s) opens a shell in the new worktree when it is ready.
Stated plainly in the flag description and again in the banner, because the
alternative is people reporting it as broken: this is a SUBSHELL. A process
cannot change its parent shell's working directory, so no flag can genuinely cd
you anywhere — `exit` unwinds back to where you started, and someone expecting
a real cd will read that unwind as a failure. The only way to move the parent
shell is a wrapper the user installs themselves:
wf() { cd "$(workforge create "$@" --print-path)"; }
which is a different feature; this flag is for the common case where a subshell
is enough.
Skipped without a TTY — in CI or a piped run an interactive shell has nothing to
read from and would hang the run rather than fail it, which is the worse
outcome. It prints the cd line instead. The subshell also carries
WORKFORGE_WORKSPACE and WORKFORGE_BRANCH so a prompt can show the worktree
without parsing the path.
## Verified
✅ Dependencies installed successfully using pnpm
ℹ Running the repo's setup script (pnpm run setup)...
✅ Repo setup script completed
ℹ --switch ignored: not an interactive terminal.
ℹ cd /…/chore/BZ-4139-switch-flag-test
The non-TTY guard is proven (no hang), and the subshell's cwd/env plumbing is
proven by spawning a shell with the same options. The interactive handover
itself is not machine-testable from a non-TTY harness and wants a human to try
it once. tsc clean.
murdore
force-pushed
the
feat/run-repo-setup-script
branch
from
August 26, 2026 02:03
814d297 to
df81bde
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two gaps between "workforge created a worktree" and "you can work in it".
1. It was not necessarily runnable
Installing dependencies is not always enough. Some repos need a one-time bootstrap afterwards, and a worktree that skipped it fails in ways that do not name the missing step. In
juspay/lighthousethe Playwright mock suite aborts with:That reads as a broken module alias, so you go looking at
svelte.config.jsandnode_modules— not at a bootstrap you never ran.Evidence
Reproduced on a fresh worktree before changing anything, then again after:
$modelserrorsnode scripts/setup.jsWorth pre-empting the obvious objection: the synced
.envis byte-identical either way — same 244 keys, same values, diffed. So "workforge already syncs.env" is not a reason to skip this; env syncing is not what closes the gap.I could not pin the precise mechanism inside lighthouse's
setup, and I would rather say so than invent one. The dependency itself reproduces in both directions, which is what this acts on.Change
After a successful install, run
<manager> run setupwhenpackage.jsondeclares that script.setupis the name the ecosystem already uses; a repo without it is completely unaffected.WORKFORGE_SKIP_SETUP=1.It also returns early when install itself failed, rather than bootstrapping over a broken
node_modules.2. You still had to
cdthere yourselfNew
--switch/-s: opens a shell in the new worktree once it is ready.The caveat is the feature's main design problem, so it is stated three times
This is a SUBSHELL. A process cannot change its parent shell's working directory, so no CLI flag can genuinely
cdyou anywhere.exitunwinds back to where you started — and someone expecting a realcdwill read that unwind as the feature failing. So it is spelled out in the flag description, in the banner at spawn time, and in the code comment:The only way to move the parent shell is a wrapper the user installs:
That is a different feature (it needs a
--print-pathmode and a documented shell function). This flag covers the common case where a subshell is enough.Non-TTY
Skipped when either stdin or stdout is not a TTY. In CI or a piped invocation an interactive shell has nothing to read from and would hang the run rather than fail it — the worse of the two outcomes. It prints the
cdline instead:The subshell also carries
WORKFORGE_WORKSPACEandWORKFORGE_BRANCH, so a prompt or rc file can show the worktree without parsing the path.Verified
cwd+ env plumbing proven by spawning a shell with the same options and assertingpwdand both variables.pnpm run build(tsc) clean.Not verified: the interactive handover itself. It is not machine-testable from a non-TTY harness, so it wants one human run of
workforge create -t feat -n x --switchbefore merge.Note if you test this from a clone
The global
workforgeshim symlinks to the installed npm package, not to a local clone'sdist/:So
pnpm run buildin a clone does not change whatworkforgeruns. Invokenode /path/to/clone/dist/index.jsdirectly — otherwise a working change looks like a no-op.