* fix(daemon, packaged): unbreak GUI-launched agent detection on minimal PATHs (#442)
GUI-launched daemons (Finder/Dock on macOS, .desktop on Linux) inherit a
stripped PATH from launchd / the desktop session and don't read the
user's interactive shell rc files, so any CLI installed via `npm i -g`
under a sudo-free prefix like ~/.npm-global was silently undetected.
Two layers maintained their own copies of the user-toolchain bin list
(`apps/daemon/src/agents.ts:userToolchainDirs` for the resolver,
`apps/packaged/src/sidecars.ts:resolvePackagedPathEnv` for the packaged
sidecar PATH builder) and had already drifted on `~/.asdf/shims` and
`~/Library/pnpm`. Adding ~/.npm-global to one side would have
preserved the same anti-pattern.
Extracts `wellKnownUserToolchainBins` into @open-design/platform as the
single source of truth, has both layers consume it, and extends the
list to cover ~/.npm-global/bin, ~/.npm-packages/bin, plus
$NPM_CONFIG_PREFIX/bin / $npm_config_prefix/bin for users with a
non-standard prefix. New vitest coverage in the platform package and
a regression test in apps/daemon/tests/agents.test.ts modelled on the
existing mise case.
Verified end-to-end: under PATH=/usr/bin:/bin:/usr/sbin:/sbin (the
launchd default a `.app` actually inherits), `resolveAgentExecutable`
now returns ~/.npm-global/bin/gemini instead of null.
* fix(daemon): isolate OD_AGENT_HOME resolution from $NPM_CONFIG_PREFIX leakage
Address review feedback on PR #614:
- mrcfps spotted that the daemon wrapper called wellKnownUserToolchainBins
without passing `env`, so the helper read its default process.env. A
developer or CI runner with NPM_CONFIG_PREFIX / npm_config_prefix
exported would inject that real <prefix>/bin into resolveOnPath() even
while the OD_AGENT_HOME hook pointed home at a temp fixture, making
agent-detection tests environment-dependent. Reproduced locally: with
OD_AGENT_HOME=<tmp> + NPM_CONFIG_PREFIX=/Users/me/.npm-global,
resolveAgentExecutable({ bin: 'codex' }) returned the real machine's
binary instead of null. Wrapper now passes `env: {}` whenever
homeOverride is set, alongside the existing includeSystemBins gate.
- lefarcen suggested also handling whitespace-only NPM_CONFIG_PREFIX
values (e.g. NPM_CONFIG_PREFIX=" ") so the helper does not emit a
bogus "<whitespace>/bin" entry. Added a .trim() check before
appending.
- lefarcen also suggested a comment pointer from the daemon wrapper to
the platform helper so readers don't have to grep. Added the
reference inline.
Coverage:
- packages/platform/tests/index.test.ts: new whitespace-prefix case.
- apps/daemon/tests/agents.test.ts: new env-isolation regression
asserting that OD_AGENT_HOME + NPM_CONFIG_PREFIX cannot leak the
real prefix bin into the sandbox.
* test(daemon): preserve $NPM_CONFIG_PREFIX across the env-isolation case (#614)
Address mrcfps's second-round review on PR #614: the env-isolation
regression sets `process.env.NPM_CONFIG_PREFIX = realPrefix` in its
body and then unconditionally `delete`s it in `finally`. On a developer
machine or CI runner that already exported `NPM_CONFIG_PREFIX`, that
mutates the worker-wide env for every later test, making downstream
env-sensitive assertions order-dependent.
Move the save/restore into the file's existing afterEach hook (mirroring
the OD_AGENT_HOME / OD_DAEMON_URL / OD_TOOL_TOKEN pattern) and drop the
in-test `delete`. Same coverage, no worker-state mutation.
* fix(platform): prioritise $NPM_CONFIG_PREFIX over the conventional npm guesses (#614)
Address mrcfps's third-round review on PR #614: when the user has
explicitly configured a prefix via $NPM_CONFIG_PREFIX (or
$npm_config_prefix), that's where `npm i -g` puts the *current*
binaries. The conventional guesses ~/.npm-global / ~/.npm-packages
often hold *stale* installs from an older prefix the user has since
rewritten — searching the env-driven prefix first matches npm's own
resolution order (env > .npmrc > default) and gives "explicit beats
convention" semantics.
Move the env-driven push above the conventional `dirs.push(.npm-global,
.npm-packages)`. Add a vitest case in the platform package that asserts
$NPM_CONFIG_PREFIX/bin's index in the result is strictly less than
~/.npm-global/bin's and ~/.npm-packages/bin's.
`resolveOnPath()` and the packaged PATH builder both preserve insertion
order, so first hit wins and the new ordering propagates to both
layers.
* fix(platform): lift $NPM_CONFIG_PREFIX above every conventional bin (#614)
Address mrcfps's fourth-round review on PR #614: the previous fix only
moved $NPM_CONFIG_PREFIX/bin ahead of ~/.npm-global / ~/.npm-packages,
but ~/.local/bin still appeared earlier in the array. Under a minimal
GUI-launch PATH a stale agent in ~/.local/bin (also a shared dumping
ground for pip --user / cargo install / hand-built binaries) could
outrank the user's *current* explicit npm prefix.
Move the env-driven push to the head of `dirs` so the explicit prefix
wins over every conventional location below — ~/.local/bin included.
Matches npm's own resolution order (env > .npmrc > default) across the
whole list, not just the npm-prefix block.
Tightened the existing order test to assert `explicitIdx === 0` and
that ~/.local/bin's index is strictly greater than the explicit
prefix's index, so a future drift would fail loudly.
* chore: enforce test directory conventions
Move package, app, and tool tests out of src and add guard enforcement so source directories stay source-only.
* ci: use guard and package-scoped tests
Run the new repository guard in CI and keep test execution aligned with package-scoped commands after removing root aliases.
* ci: align stable release guard check
Use the new repository guard in stable release verification after replacing the residual-JS-only script.
* chore: tighten test layout enforcement
Enforce sibling tests directories, typecheck moved test suites with dedicated configs, and refresh remaining guidance that pointed at src-based tests.
* chore: clarify no-emit test tsconfigs
Explicitly disable declaration-only emit in test tsconfigs so review tooling sees they are no-emit typecheck configs.
* feat(dev): add desktop tools-dev control plane
* refactor(sidecar): split Open Design contracts
Move Open Design-specific sidecar protocol definitions into @open-design/contracts so sidecar and platform can remain descriptor-driven primitives.
* refactor(daemon): organize package sources
Keep daemon app code, tests, and sidecar entrypoints in separate package directories so each layer can be built and verified independently.
* chore(repo): streamline maintenance entrypoints
Centralize agent guidance by directory and reduce root command chains while preserving the existing build scope.
* docs: translate agent guidance to English
* fix(sidecar): tolerate stale IPC sockets
Remove stale Unix socket files only after confirming no listener is active, so tools-dev can restart after unclean shutdowns.