Repository navigation
fix(cli): resolve Windows CLI detection for long PATH and npm/mise/scoop shims (#221) - #2381
Conversation
|
Thanks for opening this — it has been seen, and it is queued. This note is automated, but it is not a brush-off: it exists so you know where your PR stands instead of having to guess from silence. Current review status: working through a backlog. What that means for this PR, concretely:
Things that will genuinely speed it up whenever review does happen:
If this fixes a bug, a reproduction we can run is worth more than a description of the symptom. Thanks for contributing, and sorry in advance for the wait. |
DeusData
left a comment
There was a problem hiding this comment.
Thank you so much, @wcy12378, for picking up #221 within a day of our root-cause note and implementing both halves of it: the full-length PATH copy, and Windows-aware npm/mise/scoop fallbacks. You read the diagnosis carefully, and the PR body explains the why clearly. This is the right fix direction and we'd love to merge it. A few things need to change first; here is each one and why:
find_in_pathleaks the PATH copy on success. The tworeturn true;statements inside the loop skipfree(path_copy), so every detected CLI leaks a full copy of PATH, and agent detection runs this about 25 times per scan. Please free before every return, for example with a singlefoundflag and one exit.- Please allocate through the memory core. This repo routes all allocation through
src/foundation/mem_core.h(cbm_alloc/cbm_calloc/cbm_free).scripts/lint-memory-core.pyis a ratchet that fails when a file gains rawmalloc/calloc/freesites. This PR adds 8 tosrc/cli/cli.c(173 → 181), so CI will go red. The ratchet is how we keep memory accounting and leak detection honest across the whole binary. - Please reuse the platform env helper instead of re-implementing it in
cli.c.cbm_safe_getenv(src/foundation/platform.c) already does the wide read, the UTF-8 conversion and the missing-vs-empty handling. The cleanest shape is a small allocating sibling there that returns a memory-core-owned UTF-8 copy viacbm_wide_to_utf8, called fromfind_in_path. That keeps#include <windows.h>out of the middle ofcli.cand gives both call sites one tested code path. - Please keep the existing Windows fallbacks and add the new ones.
%USERPROFILE%/.local/binand%USERPROFILE%/.cargo/binwere also probed on Windows before this change, and both are real there: pipx installs to~\.local\binby default, and cargo to~\.cargo\bin. Replacing the list would make pipx- and cargo-installed agents disappear. Please also build these paths from thehome_dirargument rather thancbm_get_home_dir(), so the function honours its contract and can be tested with a temporary home./separators, as the rest of the file uses, are fine on Windows. - Please add a test that fails without the change. We merge bug fixes with a regression test that is red on
mainand green with the fix, so the bug can't quietly return. The 4 KB PATH limit affects POSIX too, so a portable test is easy: build a PATH longer than 4096 characters whose last entry is a temp directory holding a uniquely named executable, and assertcbm_find_cliresolves it. That is also the case that covers the original #221 reporter's layout. For the npm/mise/scoop fallbacks, a Windows-only test that pointsAPPDATA,LOCALAPPDATAandUSERPROFILEat temp directories containing aname.cmdshim would be ideal.tests/repro/repro_issue221.cis a natural home for both. - Small style points. Please add braces to the one-line
if/forstatements (clang-format and our style require them), and hoist the duplicatedwin_exts[]array into one file-scope constant. - DCO sign-off. The commit has no
Signed-off-by:trailer, and CI enforces DCO on every commit.git commit --amend -sfollowed by a force-push fixes it.
Thanks again. This will make install work for a lot of Windows developers with long PATHs, and we really appreciate you taking it on. We're happy to help if any of the above is unclear.
|
Thank you so much, @wcy12378! This picks up exactly the two causes we described on #221, and the heap-sized PATH copy is the right shape. A few changes are needed before it can land:
Thanks again, and happy to help if any of this is unclear! |
…eusData#221) Two independent reasons `install` missed opencode on Windows 11: 1. find_in_path() copied PATH into a fixed 4 KB stack buffer through cbm_safe_getenv(), and that helper REFUSES a value it cannot fit instead of truncating it. On a machine whose PATH exceeds 4096 characters the whole PATH was therefore skipped before a single directory was probed. 2. The fallback list had no Windows-shaped entries, and it probed only the bare name, so npm's %APPDATA%\npm, mise's %LOCALAPPDATA%\mise\shims and scoop's %USERPROFILE%\scoop\shims could never match a .cmd shim. - Add cbm_env_dup() to platform.c: the allocating sibling of cbm_safe_getenv, memory-core owned, wide-read on Windows so a non-ASCII PATH is not mangled by the ANSI code page. cli.c no longer needs <windows.h> in the middle of the file, nor any raw allocation. - find_in_path() now exits once, so the PATH copy is freed on every path instead of leaking on each success. - Keep the existing pipx (~/.local/bin) and cargo (~/.cargo/bin) fallbacks, built from the home_dir argument rather than cbm_get_home_dir(), and add the npm/mise/scoop locations. PATHEXT is probed for every fallback directory, not only for PATH entries. - Bound the fallback loop by NUM_PATHS, not NUM_RETRIES. - Hoist the PATHEXT list into one file-scope constant and add braces to every one-line statement. Regression guards in tests/repro/repro_issue221.c: a PATH longer than 4096 characters whose LAST entry holds the fixture, and the Windows fallback shims driven through APPDATA / LOCALAPPDATA / the home_dir argument. Both are red against the previous code and green with this change. The PATH case is not Windows-specific: the same 4 KB cap hid entries on macOS and Linux. No raw allocator call site is added under src/, so the memory-core ratchet is untouched; clang-format and the no-skips policy both pass locally. Signed-off-by: Kris <2040188027@qq.com>
9d8f51d to
48f2559
Compare
|
Thanks for the detailed review — all seven points are addressed. The branch is also rebased onto today's 1. 2. Allocation through the memory core. The PATH copy is now allocated by the new 3. Reuse the platform env helper. One deliberate deviation to flag: it does not call 4. Existing Windows fallbacks kept. 5. Regression test. Both cases live in
I could not run the repo's own test binary here (no gcc/clang on this box), so I extracted the three functions verbatim, compiled them with MSVC, and ran both cases against each revision. Against the current 6. Style. Braces on every one-line 7. DCO. Single commit, One thing worth your call: I kept the tests in |
|
The failing Windows shard stops in the parallel scheduler infrastructure self-test, before the CLI suite: Evidence: https://github.com/DeusData/codebase-memory-mcp/actions/runs/36737825537/job/109990817112 (log at 2026-09-30T16:45:05Z). This PR does not modify the scheduler self-test. The latest main cache-warm run passed, but it is a different workflow, so I cannot use it as proof that this particular self-test passes on main. I attempted to rerun the failed jobs; GitHub refused because repository admin rights are required. Could a maintainer rerun this job when convenient? I will follow up on any reproducible failure in the changed CLI/platform code. |
|
Re-checking CI on the current head ( Everything that actually exercises the code is green: Could a maintainer please re-run the failed Windows shard (or the whole |
DeusData#1180) Three detection defects kept `codebase-memory-mcp install` from configuring agents people run, and made it configure one they never installed. OpenCode without a config file or a CLI on PATH (DeusData#1167, DeusData#1180). OpenCode was detected only from its global config file or directory, OPENCODE_CONFIG_DIR, or an `opencode` found on PATH. It now also counts as installed when its data directory exists: ~/.local/share/opencode on every OS, %USERPROFILE%\.local\share\opencode on Windows (opencode.ai/docs/troubleshooting, "Storage"; the same page names it as the global config location of older installs). The OpenCode CLI and the Desktop app both create it -- the Desktop's bundled opencode-cli server uses the same XDG paths (anomalyco/opencode packages/core/src/global.ts creates the config and data dirs at startup; packages/desktop/src/main/sidecar.ts only redirects XDG_STATE_HOME) -- so detection no longer depends on PATH. The install target ~/.config/opencode/opencode.json(c) -- %USERPROFILE%\.config\opencode on Windows per the same docs page -- is unchanged and right for CLI and Desktop alike. A PATH longer than 4 KB, which hides every CLI from find_in_path(), is handled separately by PR DeusData#2381. Hermes home on Windows (DeusData#1180). Native Windows Hermes -- the install.ps1 CLI, the MSIX package and the Desktop app -- defaults HERMES_HOME to %LOCALAPPDATA%\hermes and falls back to a legacy ~/.hermes only while that directory is absent (NousResearch/hermes-agent website/docs/user-guide/windows-native.md, "Data layout"; apps/desktop/electron/data-paths.mjs, resolveDesktopHermesHome). cbm probed and wrote ~/.hermes only, so a Desktop install was never detected and a Hermes found on PATH got its config.yaml and skill in a home it never reads. On Windows the home now resolves to <home>/AppData/Local/hermes unless only ~/.hermes exists, using the home-derived AppData convention of the existing Zed, goose, Kilo and VS Code probes; detection, install and uninstall all follow it. HERMES_HOME still wins, and macOS/Linux keep ~/.hermes. Claude Code from a bare ~/.claude (DeusData#1180). Any ~/.claude directory counted as a Claude Code install, so a user who only had the folder got hooks, skills and MCP entries for a client they never installed. Detection now needs what Claude Code itself leaves behind: settings.json in the config dir, .claude.json in the home (in CLAUDE_CONFIG_DIR when set), or the claude CLI. Proof on macOS against synthetic HOME/cache/runtime dirs with a minimal PATH (`install --dry-run --skip-binary`, then a config-only install): bare ~/.claude main: Claude-Code fix: none ~/.local/share/opencode only main: none fix: OpenCode In the OpenCode case the fixed install writes the codebase-memory-mcp entry to ~/.config/opencode/opencode.json; main writes nothing. Controls (a launched Desktop layout, a real Claude user) are detected by both. The Windows Hermes home is covered by a platform-parameterised resolver test that runs on every host plus a _WIN32-bound end-to-end detection and plan test. Tests (cli suite, 335 passed): seven new tests; five fail on main three times out of three (the _WIN32-bound Hermes test and the look-alike control are green on macOS by design). Reverting the Claude+Hermes half and the OpenCode data-dir probe separately turns exactly their own tests red. Nine existing Claude fixtures that used a bare ~/.claude as the install marker now write .claude.json; two Hermes tests and smoke-test 8x expect %LOCALAPPDATA%\hermes on Windows. Refs DeusData#1167 Fixes DeusData#1180 Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
|
The requested changes are present in head 48f2559: ind_in_path owns/frees its PATH copy through the memory core and has one cleanup exit; PATH and fallback lookups share the Windows extension list; existing pipx/cargo locations are retained; Windows npm/mise/scoop paths and test fixtures use the documented env/home seams; the long-PATH regression and style changes are included. The commit also has the required Signed-off-by: Kris 2040188027@qq.com trailer. The remaining red CI is infrastructure-only: every Windows shard task passed, but the Windows CLANG64 2/2 runner then failed to prove process-tree cleanup for hang_after_summary ( askkill could not prove process-tree cleanup), so it emitted no shard manifest and shard-completeness failed downstream. I attempted gh run rerun ... --failed, but GitHub denied it because rerunning requires repository admin rights. Could a maintainer rerun the failed Windows job when convenient? No source change appears warranted by this log. |
|
Thanks for the detailed response to the review and the repeated Windows-runner evidence. I have read the request for a maintainer rerun and the question about gating the regression cases. Those remain on our side; this sweep has not rerun CI or independently attributed the cleanup failure. No new source change is requested here. |
Resolve the src/foundation/platform.h conflict by keeping both blocks: main's settings environment resolver declarations and this branch's cbm_env_dup declaration, which sit next to each other after cbm_safe_getenv. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…sData#221) Since this branch was written, main routes cbm_safe_getenv through a startup settings resolver before it reads the process environment. cbm_env_dup, its allocating sibling, read only the process environment, so after the merge the two helpers could give different answers for the same name. Consult the resolver first, exactly as cbm_safe_getenv does: a handled value is copied through the memory core, and a handled NULL masks the variable. The resolver serves CBM_* settings today, so PATH lookups behave as before; this keeps both helpers one view of the environment by construction. platform_env_dup_honours_the_settings_resolver pins the three cases: resolved, masked, and falling through to the process environment. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…s in the cli suite The two regressions sat in tests/repro/repro_issue221.c, which builds only into the non-gating bug-repro runner, so CI could not stop the fix from regressing. The Windows-only case also skipped on macOS and Linux, and scripts/repro.sh reports any skipped case as an incomplete board. Move both into tests/test_cli.c next to the other cbm_find_cli tests, unchanged apart from their names: the cli suite runs on every CI leg, and SKIP_PLATFORM is how that suite already marks Windows-only cases. tests/repro/repro_issue221.c is back to its content on main. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
|
Thank you so much, @wcy12378, and sorry for the long wait on our side. Your second round answered every point of our review, and it was done with real care: the single-exit Since
On your other two questions:
The red Windows shard you reported was not caused by your change, and CI runs fresh on the new head. Thanks again for sticking with this through several rounds. It will make |
|
Hi @DeusData maintainers — following up on the 7 CHANGES_REQUESTED items from the review. All points were addressed and the branch was rebased onto the current |
|
Maintainers — reporting on the red CI on the current head The failing shards fail in repo-wide documentation contract checks, not in the CLI-detection code this PR touches:
So both the unix-shard and windows-shard reds on this head reflect the same repo-wide docs-contract drift on |
|
Branch updated onto current The previous failures were not from this diff. Every failing lane ( None of those five paths is in this PR, which touches only On the new base the earlier blockers are already green: On the seven review items from 2026-09-27, all are addressed in Could you re-review when the new run settles? Happy to split or reshape anything that is still awkward. |
|
The lanes that were re-running when I last reported have now settled on head No new commits were needed for this round; the head is unchanged at
Could you re-review when convenient? Happy to split or reshape anything that is still awkward. |
|
Thank you for the detailed October 25 update and the reported green runs on 7d01cae. The earlier review items and gating-test placement have been addressed according to the thread; the requested re-review is now on us. Sorry for the delay—I’ll follow up soon. |
|
Merged - thank you so much, @wcy12378! This fixes a long-standing Windows install problem, and you carried it through every round with real care: the PATH copy sized to the real value, the single-exit find_in_path that can no longer leak, cbm_env_dup allocating through the memory core, the pipx and cargo fallbacks kept and built from the home_dir argument, and a long-PATH test that puts the fixture in the last entry so any truncation hides exactly the directory under test. Your finding that the fallback directories needed the PATHEXT probe too was a genuinely good catch, and your careful CI write-ups saved us real time. Both regressions now gate in the cli suite on every CI leg, Windows included. Thanks again for sticking with this - it will make install work for a lot of Windows developers. |
- Non-ASCII paths: drop the NTFS junction example; the workaround is ASCII-only paths for the two variables, or an upgrade. - Update entry: name the real command (update, not upgrade) and mark DeusData#1168 as closed, fixed in v0.10.0. - Index worker: from v0.12.0 a worker that exits without returning a result is no longer counted as a success, and its log is kept; ask for logs when indexing still fails on v0.11.0 or newer. - Antigravity: state the affected range (all releases through v0.12.1 when neither detection signal is present) and which signal each version checks; scope the duplicate binary to v0.9.x and earlier. - OpenCode: list the detection signals per version (PATH, config, and from v0.12.0 the data folder), the 4 KB PATH and npm/mise/scoop shim gaps fixed after v0.12.1 (DeusData#2381), and a workaround per version. The page structure and the original entries were first drafted by Tamer in DeusData#2262. Refs DeusData#1170 Co-authored-by: Tamer <tamer.elbakkali@gmail.com> Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Why
Issue #221 (
installcannot wire up opencode on Windows 11) was reopened after thePATHEXT fix because two further root causes remain (maintainer diagnosis, 2026-09-26):
%PATH%into a fixed 4 KB stack buffer(
char path_copy[CLI_BUF_4K]infind_in_path). On Windows dev machines whoseprocess PATH is >= 4096 characters,
cbm_safe_getenvcannot fit the value and thesearch skips the whole PATH, so opencode (present via mise/npm/scoop) is invisible.
cbm_find_clihome-directory fallbacks were POSIX-only(
/usr/local/bin,~/.npm/bin,~/.local/bin,~/.cargo/bin,/opt/homebrew/bin).None of these exist on Windows; the Windows-shaped locations
(
%APPDATA%\npm,%LOCALAPPDATA%\mise\shims,%USERPROFILE%\scoop\shims) were never probed.Summary
find_in_pathnow duplicates PATH into a heap buffer sized to the real value(
cbm_dup_env_path), so long PATHs are searched in full instead of being truncated.cbm_find_clibuilds a platform-aware fallback list. On_WIN32it probes%APPDATA%\npm,%LOCALAPPDATA%\mise\shimsand%USERPROFILE%\scoop\shims, andalso tries the PATHEXT variants (
.exe/.cmd/.bat/.ps1) for those fallback locationsso the extension-bearing shims resolve. POSIX behaviour is unchanged.
How to Test
Build on Windows and run the CLI suite (the existing
repro_issue221_opencode_pathext_lookupregression guard must stay green; a long-PATH (>4096 char) + npm/mise/scoop shim case is the
additional scenario this addresses).
cbm_find_cli("opencode", home)should now resolve ashim that lives on a long PATH or under one of the Windows install dirs.
Closes #221