fix(dream-macos): auto-detect install dir from script location when DREAM_HOME unset#916
Merged
Lightheartdevs merged 1 commit intoLight-Heart-Labs:mainfrom Apr 15, 2026
Conversation
…REAM_HOME unset
Running `bash /path/to/install/dream-macos.sh status` from a non-default
install without DREAM_HOME set would error with
`Dream Server not found at $HOME/dream-server`, even though the script
itself was physically inside the install. External-drive installs,
custom Homebrew prefixes, CI automation and any launchd/cron invocation
by absolute path all hit this.
Resolve it by teaching `resolve_install_dir()` a new `DREAM_SCRIPT_HINT`
tier between the DREAM_HOME and DS_INSTALL_DIR branches, guarded by a
`.env` sentinel file at the hinted root so that PATH symlinks
(e.g. /usr/local/bin) or scratch copies never false-positive.
`dream-macos.sh` exports `DREAM_SCRIPT_HINT="$SCRIPT_DIR"` before sourcing
`constants.sh`, then unsets it after all sources complete so the hint
does not leak into docker-compose/curl subprocesses spawned later.
While verifying the fix end-to-end, I discovered that
`installers/macos/lib/constants.sh` had a latent off-by-one in its
`path-utils.sh` lookup: `MACOS_SCRIPT_DIR="$(cd ...)/../.."` resolved to
the wrong depth in both source-tree and installed layouts, and the
lookup path then re-appended `installers/lib/path-utils.sh` producing
e.g. `dream-server/installers/installers/lib/path-utils.sh` (source) or
`/Volumes/X/installers/lib/path-utils.sh` (installed) - neither exists.
The `if` branch never fired; `resolve_install_dir()` was never actually
called from `dream-macos.sh`, and the ELSE fallback
`DS_INSTALL_DIR="${DREAM_HOME:-$HOME/dream-server}"` was the only live
code path. Without fixing this, the new `DREAM_SCRIPT_HINT` tier would
have been dead on both layouts. Replace the broken single-path lookup
with a two-candidate loop (`../../lib/path-utils.sh` for source tree,
`../installers/lib/path-utils.sh` for installed) and drop the
`MACOS_SCRIPT_DIR` variable (no other consumers after grep).
BATS coverage in `tests/bats-tests/path-utils.bats` gets two new cases
for the new tier (hint + sentinel present, hint + sentinel absent) and
a `setup`/`teardown` that clears `DREAM_SCRIPT_HINT` alongside the
existing env vars so the file stays isolation-safe.
Closes #339
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.
What
bash /path/to/install/dream-macos.sh statusnow works from any non-default install without requiringDREAM_HOMEto be exported, by auto-detecting the install from the script's own location. Also fixes a latent off-by-one ininstallers/macos/lib/constants.sh'spath-utils.shlookup that rendered the originalresolve_install_dir()dead code in both source-tree and installed layouts.Why
External-drive installs, custom Homebrew prefixes, CI automation, cron jobs, and any launchd plist that invokes the CLI by absolute path without inheriting the user shell's env all hit "Dream Server not found at $HOME/dream-server" even when the script itself lives in a populated install. The workaround (always
export DREAM_HOME=<install>in.zshrc) is not discoverable from the error message.Second-order: while verifying the fix, tracing showed
MACOS_SCRIPT_DIRininstallers/macos/lib/constants.shresolved to the wrong depth in both layouts. Theif [[ -f $MACOS_SCRIPT_DIR/installers/lib/path-utils.sh ]]; then . $MACOS_SCRIPT_DIR/installers/lib/path-utils.sh; fiblock was dead in both source-tree (dream-server/installers/installers/lib/path-utils.sh, extrainstallers/) and installed (/Volumes/X/installers/lib/path-utils.sh, one too many dirs up) layouts.resolve_install_dir()was never actually called fromdream-macos.sh; the ELSE fallback was the only live code path. Without fixing this, the newDREAM_SCRIPT_HINTtier would be dead on both layouts too.How
installers/lib/path-utils.sh— new resolution tier inresolve_install_dir()betweenDREAM_HOMEandDS_INSTALL_DIR. Fires only whenDREAM_SCRIPT_HINTis set AND${DREAM_SCRIPT_HINT}/.envexists. Sentinel prevents false positives from PATH symlinks or scratch copies.installers/macos/dream-macos.sh— exportsDREAM_SCRIPT_HINT="$SCRIPT_DIR"before sourcingconstants.sh, unsets after. Updatedtest_install()error message to point users at the new behavior.installers/macos/lib/constants.sh— replaces the broken single-pathpath-utils.shlookup with a two-candidate for-loop:../../lib/path-utils.shmatches the source tree,../installers/lib/path-utils.shmatches the installed layout. Each candidate matches exactly one layout; both verified withrealpath. Drops the unusedMACOS_SCRIPT_DIRvariable.tests/bats-tests/path-utils.bats— two new tests for theDREAM_SCRIPT_HINTtier (sentinel present / sentinel absent) plussetup/teardownthat clears all four env vars for test isolation.Testing
Automated
bash -nall modified shell files: PASSmake lint: PASSmake test: PASS (82/82 tier-map, 17/17 AMD/Lemonade contracts, all installer contracts, all preflight fixtures)shellcheckon the 3 modified shell files: PASS (only preexisting SC2034 info findings onconstants.sh, identical set present onmain)pre-commit(gitleaks, private-key, large-files): PASSconstants.shverified empirically withrealpathagainst both layouts — each candidate matches exactly one.Runtime (against a macOS install at a non-$HOME volume)
Before fix:
```
$ env -u DREAM_HOME -u INSTALL_DIR -u DS_INSTALL_DIR bash /Volumes/X/dream-server-test/dream-macos.sh status
[XX] Dream Server not found at /Users//dream-server.
```
After fix:
```
$ env -u DREAM_HOME -u INSTALL_DIR -u DS_INSTALL_DIR bash /Volumes/X/dream-server-test/dream-macos.sh status
Dream Server Status (macOS)
Chip: Apple M4
RAM: 24 GB (unified memory)
[OK] llama-server (native Metal): running PID 13757 (healthy)
Health Checks
[OK] LLM API: healthy
[OK] Chat UI: healthy
[OK] Dashboard: healthy
[OK] OpenCode (IDE): healthy
```
Happy-path regression check — `DREAM_HOME` still takes precedence when set:
```
$ DREAM_HOME=/Volumes/X/dream-server-test bash /Volumes/X/dream-server-test/dream-macos.sh status
identical full status output — no regression
```
Sentinel guard sanity — hint pointing at a dir without `.env` falls through to default:
```
$ DREAM_SCRIPT_HINT=/tmp resolve_install_dir
returns $HOME/dream-server (correctly falls through)
```
Manual (per platform for reviewer)
unset DREAM_HOME INSTALL_DIR DS_INSTALL_DIR; bash /path/to/install/dream-macos.sh statusfrom any install path should produce status output, not "not found".installers/macos/lib/constants.shis macOS-only.installers/lib/path-utils.shis shared, but the new tier is guarded byDREAM_SCRIPT_HINTwhich onlydream-macos.shsets; Linux'sdream-cliandinstall-core.shnever set it, so the new branch is structurally dead there. Verified viamake testpassing unchanged.dream.ps1.Platform Impact
make testunchanged.Known Considerations
\$BATS_TEST_TMPDIR/dream-install-hint. On macOS developer machines with Homebrewcoreutilsinstalled,grealpathcanonicalizes/var/folders/...→/private/var/folders/..., which would break the assertion locally. CI runs BATS on Linux (/tmp/...has no symlink layer) so it stays green. Flagged non-blocking for any reviewer attempting local Mac runs.DREAM_SCRIPT_HINTis an ephemeral shell var (export→ source chain →unset), never written to.envor.env.schema.json. No schema entry needed.Fork issue
Closes yasinBursali#339