Skip to content

Commit dfd2ab2

Browse files
committed
feat(install): add CBM_PACKAGE_MANAGED build guard, fix FreeBSD self-path
When built with -DCBM_PACKAGE_MANAGED, `install` no longer mutates the user's $HOME and wires agent configs to the real installed binary: - skips copying the running binary into ~/.local/bin (the package manager already owns it under its prefix), and - skips appending `export PATH=...` to the shell rc, and - points bin_target (hence the MCP `command` written into .claude.json, .mcp.json, etc.) at the running executable instead of the hardcoded ~/.local/bin path. Also add a FreeBSD self-path branch: cbm_detect_self_path() used readlink("/proc/self/exe"), but FreeBSD has no /proc by default, so it silently fell back to ~/.local/bin — writing that wrong path into every agent config. Use sysctl KERN_PROC_PATHNAME, which needs no /proc. The flag is off by default; source installs (scripts/build.sh) are unchanged. Non-FreeBSD self-path detection is unchanged.
1 parent 560ad40 commit dfd2ab2

1 file changed

Lines changed: 37 additions & 3 deletions

File tree

‎src/cli/cli.c‎

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ static int cbm_powershell_quote_word(const char *value, char *out, size_t out_si
9494
#ifdef __APPLE__
9595
#include <mach-o/dyld.h>
9696
#endif
97+
#ifdef __FreeBSD__
98+
#include <sys/sysctl.h> // KERN_PROC_PATHNAME — /proc-free self-path detection
99+
#include <sys/types.h>
100+
#endif
97101
#include "foundation/compat_fs.h"
98102

99103
#ifndef CBM_VERSION
@@ -8887,6 +8891,15 @@ static bool cbm_detect_self_path(char *buf, size_t buf_sz, const char *home) {
88878891
if (!exact) {
88888892
buf[0] = '\0';
88898893
}
8894+
#elif defined(__FreeBSD__)
8895+
/* FreeBSD has no /proc by default; sysctl KERN_PROC_PATHNAME returns the
8896+
* running executable's path without it. */
8897+
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
8898+
size_t sp_sz = buf_sz;
8899+
exact = sysctl(mib, 4, buf, &sp_sz, NULL, 0) == 0 && sp_sz > 0 && sp_sz <= buf_sz;
8900+
if (!exact) {
8901+
buf[0] = '\0';
8902+
}
88908903
#else
88918904
ssize_t sp_len = readlink("/proc/self/exe", buf, buf_sz - SKIP_ONE);
88928905
exact = sp_len > 0 && (size_t)sp_len < buf_sz - SKIP_ONE;
@@ -9234,12 +9247,28 @@ int cbm_cmd_install(int argc, char **argv) {
92349247
printf("codebase-memory-mcp install %s\n\n", CBM_VERSION);
92359248

92369249
char self_path[CLI_BUF_1K] = {0};
9237-
(void)cbm_detect_self_path(self_path, sizeof(self_path), home);
9250+
bool self_path_exact = cbm_detect_self_path(self_path, sizeof(self_path), home);
9251+
9252+
#ifdef CBM_PACKAGE_MANAGED
9253+
/* A package manager (FreeBSD ports, Homebrew, distro pkg) already placed the
9254+
* binary on PATH under its own prefix and owns that file. Install must not
9255+
* copy it into ~/.local/bin (a duplicate, unmanaged binary in $HOME), and
9256+
* agent configs must reference the real binary the manager installed, not
9257+
* the ~/.local/bin path. Point bin_target at the running executable. */
9258+
if (self_path_exact && self_path[0]) {
9259+
snprintf(bin_target, sizeof(bin_target), "%s", self_path);
9260+
}
9261+
#else
9262+
(void)self_path_exact;
9263+
#endif
92389264

92399265
struct stat target_status;
92409266
bool target_exists = (stat(bin_target, &target_status) == 0);
92419267
bool same_binary = cbm_same_file(self_path, bin_target);
92429268
bool do_copy = !same_binary && (!target_exists || force);
9269+
#ifdef CBM_PACKAGE_MANAGED
9270+
do_copy = false;
9271+
#endif
92439272

92449273
/* (#607) Default: preserve existing indexes. `--reset-indexes` opts into
92459274
* the old prompt-and-delete behaviour. The helper returns 0 only when the
@@ -9400,7 +9429,10 @@ int cbm_cmd_install(int argc, char **argv) {
94009429
}
94019430
}
94029431
char shell_rc[CLI_BUF_1K] = {0};
9403-
#ifndef _WIN32
9432+
#if !defined(_WIN32) && !defined(CBM_PACKAGE_MANAGED)
9433+
/* Leave shell_rc empty under CBM_PACKAGE_MANAGED: the package manager owns
9434+
* PATH via its prefix, so install must not append `export PATH=...` to the
9435+
* user's shell rc. cli_install_activate() skips the PATH step on empty rc. */
94049436
snprintf(shell_rc, sizeof(shell_rc), "%s", cbm_detect_shell_rc(home));
94059437
#endif
94069438
cli_install_activation_t activation = {
@@ -9454,7 +9486,9 @@ int cbm_cmd_install(int argc, char **argv) {
94549486
printf("\nInstall complete. Please restart your coding-agent sessions to "
94559487
"properly take this into account.\n");
94569488
#ifndef _WIN32
9457-
printf("Restart your shell or run:\n source %s\n", shell_rc);
9489+
if (shell_rc[0]) {
9490+
printf("Restart your shell or run:\n source %s\n", shell_rc);
9491+
}
94589492
#endif
94599493
if (dry_run) {
94609494
printf("\n(dry-run — no files were modified)\n");

0 commit comments

Comments
 (0)