fix(cli): 修复符号链接下主模块判断失效 / Fix main-module detection under symlinked paths - #25
Merged
Merged
Conversation
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.
Pull Request
Change
Six CLI entry points decide whether they are being run directly with:
import.meta.urlreports the resolved real path, whilepath.resolve(process.argv[1])keeps the pathas it was invoked. When the installation directory is reached through a symlink the two differ, the
guard is false, and the CLI block never runs: the process exits 0 with no output and no output file.
Affected entry points:
validate.mjs,render.mjs,render-constraints.mjs,discover-constraints.mjs,compile-constraint-rules.mjs,constraint-freshness.mjs.Reproduction on
d9e9da0:scripts/birdview.mjsdoes not use this guard — it locates files withnew URL('...', import.meta.url)—so it is unaffected, and
doctorreports a healthy installation through the same path that silentlydisables the other six:
node /tmp/bv-link/scripts/birdview.mjs doctor # OK: example validation, renderer dependencies and template assets. exit 0This PR changes only the guard. Whether
doctorshould detect this is a design question and israised separately in #26.
Fix
A shared
isMainModulehelper resolves both sides with the same call:Resolving only
process.argv[1]was tried first and rejected:fs.realpathSyncthrows wherepath.resolvedid not, so an entry path that cannot be resolved turns the guard into a crash, andunder
--preserve-symlinks-main— whereimport.meta.urlkeeps the symlinked path — it moves thesilent failure instead of removing it. Normalizing both sides covers symlinks,
--preserve-symlinks-mainand Windows path casing, and an unresolvable entry simply leaves the guardfalse. The helper is placed in
src/main-module.mtsrather than repeated in six files so the edgecases can be covered once.
src/validate.mtsno longer usespathorpathToFileURLand drops both imports.Scope note
docs/installation.mddocuments installing into a real directory (~/.claude/skills/birdview); thesymlinked layout that surfaced this is not the documented one. It arose from sharing a single
installation between agents, which the docs encourage ("An existing
~/.agents/skills/birdviewinstallation is also discoverable; avoid duplicates"). Independently of layout, exiting 0 with no
output and no file is a failure mode worth removing.
Verification
All commands from CONTRIBUTING.md, run on Linux with Node.js 24:
npm cinpm run typechecknpm run check:buildnpm testnpm run validate:examplesnode scripts/check-docs.mjsnpm run build:demonpm run check:installtest/main-module.test.mtswas checked against three builds to confirm it fails for the rightreasons:
d9e9da0: fails with empty stdout and exit 0, the reported failure mode;process.argv[1]: fails withENOENT: lstat 'no-such-entry.mjs', and fails the--preserve-symlinks-maincase;The test creates the link with
fs.symlinkSync(target, link, 'junction')so it does not requiresymlink privileges on Windows, and skips with a message if the link cannot be created. Not run
locally: Windows, Node.js 18, and the Chromium suites — CI covers these. No UI change, so no
screenshots.
Checklist