@@ -1518,7 +1518,7 @@ TEST(cli_install_recovers_markerless_stale_rendezvous) {
15181518 snprintf(runtime_parent, sizeof(runtime_parent), "%s/runtime", tmpdir);
15191519 snprintf(cache_dir, sizeof(cache_dir), "%s/cache", tmpdir);
15201520 snprintf(install_dir, sizeof(install_dir), "%s/custom/bin", tmpdir);
1521- snprintf(target_path, sizeof(target_path), "%s/codebase-memory-mcp ", install_dir);
1521+ snprintf(target_path, sizeof(target_path), "%s/codebase-memory-cli ", install_dir);
15221522 snprintf(activation_log, sizeof(activation_log), "%s/logs/activation-events.ndjson", cache_dir);
15231523 if (test_mkdirp(runtime_parent) != 0) {
15241524 test_rmdir_r(tmpdir);
@@ -2024,7 +2024,7 @@ TEST(cli_install_binary_into_foreign_home_never_drains_host_cohort) {
20242024 char activation_log[704];
20252025 cli_scope_foreign_paths(&fixture, foreign_home, foreign_cache, foreign_bin, activation_log);
20262026 char target_path[704];
2027- snprintf(target_path, sizeof(target_path), "%s/codebase-memory-mcp ", foreign_bin);
2027+ snprintf(target_path, sizeof(target_path), "%s/codebase-memory-cli ", foreign_bin);
20282028 bool prepared = ready && cbm_mkdir_p(foreign_home, 0700);
20292029 int install_rc =
20302030 prepared ? cli_scope_install(&fixture, foreign_home, foreign_cache, foreign_bin, false)
@@ -3006,7 +3006,7 @@ TEST(cli_uninstall_quiesces_active_cohort_before_removing_binary_and_index) {
30063006 PASS();
30073007}
30083008
3009- TEST(cli_uninstall_reports_foreign_cache_without_mutating ) {
3009+ TEST(cli_uninstall_leaves_foreign_cache_running_while_removing_cli_files ) {
30103010 char tmpdir[256];
30113011 snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-foreign-cache-XXXXXX");
30123012 ASSERT_NOT_NULL(cbm_mkdtemp(tmpdir));
@@ -3068,10 +3068,9 @@ TEST(cli_uninstall_reports_foreign_cache_without_mutating) {
30683068 (void)fread(output, 1, sizeof(output) - 1, capture);
30693069 fclose(capture);
30703070 }
3071- bool binary_preserved =
3072- read_test_file(binary) && strcmp(read_test_file(binary), "preserved binary") == 0;
3073- bool index_preserved =
3074- read_test_file(index) && strcmp(read_test_file(index), "preserved index") == 0;
3071+ struct stat removed_status;
3072+ bool binary_removed = lstat(binary, &removed_status) != 0 && errno == ENOENT;
3073+ bool index_removed = lstat(index, &removed_status) != 0 && errno == ENOENT;
30753074 if (lease)
30763075 (void)cbm_version_cohort_lease_release(&lease);
30773076 if (owner)
@@ -3081,11 +3080,9 @@ TEST(cli_uninstall_reports_foreign_cache_without_mutating) {
30813080 test_rmdir_r(tmpdir);
30823081 ASSERT_TRUE(owned);
30833082 ASSERT_TRUE(capturing);
3084- ASSERT_NEQ(rc, 0);
3085- ASSERT_NOT_NULL(strstr(output, "different cache"));
3086- ASSERT_NOT_NULL(strstr(output, "left running"));
3087- ASSERT_TRUE(binary_preserved);
3088- ASSERT_TRUE(index_preserved);
3083+ ASSERT_EQ(rc, 0);
3084+ ASSERT_TRUE(binary_removed);
3085+ ASSERT_TRUE(index_removed);
30893086 PASS();
30903087}
30913088
@@ -3182,19 +3179,15 @@ TEST(cli_uninstall_removes_binary_and_index_when_agent_config_cleanup_fails) {
31823179 char bin_target[640];
31833180 snprintf(bin_dir, sizeof(bin_dir), "%s/.local/bin", tmpdir);
31843181 test_mkdirp(bin_dir);
3185- snprintf(bin_target, sizeof(bin_target), "%s/codebase-memory-mcp ", bin_dir);
3182+ snprintf(bin_target, sizeof(bin_target), "%s/codebase-memory-cli ", bin_dir);
31863183 write_test_file(bin_target, "binary must go even when a config cannot be cleaned");
31873184
3188- char cursor_dir[512];
3189- char cursor_config[640];
3190- char dangling_target[640];
3191- snprintf(cursor_dir, sizeof(cursor_dir), "%s/.cursor", tmpdir);
3192- test_mkdirp(cursor_dir);
3193- snprintf(cursor_config, sizeof(cursor_config), "%s/mcp.json", cursor_dir);
3194- snprintf(dangling_target, sizeof(dangling_target), "%s/.dotfiles/cursor/mcp.json", tmpdir);
3195- if (symlink(dangling_target, cursor_config) != 0) {
3196- FAIL("symlink failed");
3197- }
3185+ char claude_dir[512];
3186+ char settings_path[640];
3187+ snprintf(claude_dir, sizeof(claude_dir), "%s/.claude", tmpdir);
3188+ snprintf(settings_path, sizeof(settings_path), "%s/settings.json", claude_dir);
3189+ test_mkdirp(claude_dir);
3190+ write_test_file(settings_path, "{ malformed CLI-owned hook settings");
31983191
31993192 cli_activation_fake_t fake = {.mutation_reserve_result = 1};
32003193 cbm_cli_activation_ops_t ops = cli_activation_fake_ops(&fake);
@@ -3213,8 +3206,10 @@ TEST(cli_uninstall_removes_binary_and_index_when_agent_config_cleanup_fails) {
32133206 struct stat state;
32143207 bool binary_gone = lstat(bin_target, &state) != 0 && errno == ENOENT;
32153208 bool index_gone = lstat(index_path, &state) != 0 && errno == ENOENT;
3216- bool link_untouched = lstat(cursor_config, &state) == 0 && S_ISLNK(state.st_mode);
3217- bool failure_named = err_text && strstr(err_text, cursor_config) != NULL;
3209+ bool config_untouched =
3210+ read_test_file(settings_path) &&
3211+ strcmp(read_test_file(settings_path), "{ malformed CLI-owned hook settings") == 0;
3212+ bool failure_named = err_text && strstr(err_text, settings_path) != NULL;
32183213
32193214 cli_activation_restore_env(old_home, old_cache);
32203215 restore_test_env("PATH", old_path);
@@ -3225,15 +3220,13 @@ TEST(cli_uninstall_removes_binary_and_index_when_agent_config_cleanup_fails) {
32253220 ASSERT(rc != 0);
32263221 ASSERT_TRUE(binary_gone);
32273222 ASSERT_TRUE(index_gone);
3228- ASSERT_TRUE(link_untouched );
3223+ ASSERT_TRUE(config_untouched );
32293224 ASSERT_TRUE(failure_named);
32303225 PASS();
32313226}
32323227
3233- /* #1954 end to end: ~/.cursor/mcp.json is a user-owned symlink into a
3234- * dotfiles checkout. The uninstall command opts in to following it, removes
3235- * our entry THROUGH the link, leaves the link pointing where it did, and
3236- * exits 0 with the binary and the index gone. */
3228+ /* A user-owned OpenHands MCP config is preserved while the CLI binary and
3229+ * index are removed. */
32373230TEST(cli_uninstall_cleans_user_owned_symlinked_config) {
32383231 char tmpdir[256];
32393232 snprintf(tmpdir, sizeof(tmpdir), "/tmp/cli-uninstall-symlinked-XXXXXX");
@@ -3259,7 +3252,7 @@ TEST(cli_uninstall_cleans_user_owned_symlinked_config) {
32593252 char bin_target[640];
32603253 snprintf(bin_dir, sizeof(bin_dir), "%s/.local/bin", tmpdir);
32613254 test_mkdirp(bin_dir);
3262- snprintf(bin_target, sizeof(bin_target), "%s/codebase-memory-mcp ", bin_dir);
3255+ snprintf(bin_target, sizeof(bin_target), "%s/codebase-memory-cli ", bin_dir);
32633256 write_test_file(bin_target, "binary goes with the uninstall");
32643257
32653258 char cursor_dir[512];
@@ -3305,8 +3298,8 @@ TEST(cli_uninstall_cleans_user_owned_symlinked_config) {
33053298 ssize_t link_length = readlink(cursor_config, link_value, sizeof(link_value) - 1U);
33063299 bool link_same = link_length > 0 && strcmp(link_value, dotfiles_config) == 0;
33073300 char *after = read_test_file_alloc(dotfiles_config);
3308- bool entry_removed =
3309- after && ! strstr(after, "codebase-memory-mcp") && strstr(after, "\"keep\"");
3301+ bool entry_preserved =
3302+ after && strstr(after, "codebase-memory-mcp") && strstr(after, "\"keep\"");
33103303 bool no_error = err_text && !strstr(err_text, "error:");
33113304
33123305 cli_activation_restore_env(old_home, old_cache);
@@ -3321,7 +3314,7 @@ TEST(cli_uninstall_cleans_user_owned_symlinked_config) {
33213314 ASSERT_TRUE(index_gone);
33223315 ASSERT_TRUE(link_intact);
33233316 ASSERT_TRUE(link_same);
3324- ASSERT_TRUE(entry_removed );
3317+ ASSERT_TRUE(entry_preserved );
33253318 ASSERT_TRUE(no_error);
33263319 PASS();
33273320}
@@ -4171,9 +4164,9 @@ static bool openhands_fixture_open(openhands_fixture_t *fx, bool with_profiles)
41714164 }
41724165 snprintf(fx->settings, sizeof(fx->settings), "%s/.openhands/settings.json", fx->home);
41734166#ifdef _WIN32
4174- snprintf(fx->binary, sizeof(fx->binary), "%s/.local/bin/codebase-memory-mcp .exe", fx->home);
4167+ snprintf(fx->binary, sizeof(fx->binary), "%s/.local/bin/codebase-memory-cli .exe", fx->home);
41754168#else
4176- snprintf(fx->binary, sizeof(fx->binary), "%s/.local/bin/codebase-memory-mcp ", fx->home);
4169+ snprintf(fx->binary, sizeof(fx->binary), "%s/.local/bin/codebase-memory-cli ", fx->home);
41774170#endif
41784171 snprintf(fx->mcp, sizeof(fx->mcp), "%s/.openhands/mcp.json", fx->home);
41794172 snprintf(fx->profiles_dir, sizeof(fx->profiles_dir), "%s/.openhands/agent-profiles", fx->home);
@@ -4277,10 +4270,8 @@ static const char openhands_custom_profile_before[] =
42774270 "{\"name\": \"custom\", \"mcp_server_refs\": [\"other-mcp\"]}\n";
42784271static const char openhands_note_before[] = "not a profile\n";
42794272
4280- /* Foreign settings keys and a foreign mcp_config sibling survive verbatim;
4281- * a null profile ref list becomes ours, an existing list is appended once;
4282- * a second install is byte-idempotent; uninstall restores the foreign files
4283- * byte-for-byte and removes only our ref. */
4273+ /* This CLI fork does not register MCP. OpenHands settings, profiles, and MCP
4274+ * configuration stay untouched by install and uninstall. */
42844275TEST(cli_openhands_registers_settings_mcp_config_and_profile_refs_issue1826) {
42854276 openhands_fixture_t fx;
42864277 if (!openhands_fixture_open(&fx, true))
@@ -4292,23 +4283,22 @@ TEST(cli_openhands_registers_settings_mcp_config_and_profile_refs_issue1826) {
42924283
42934284 cbm_install_agent_configs(fx.home, fx.binary, false, false);
42944285
4295- const char *const only_ours[] = {"codebase-memory-mcp"};
4296- const char *const appended[] = {"other-mcp" , "codebase-memory-mcp"};
4297- bool ours_ok = openhands_settings_entry_ok(fx.settings, "codebase-memory-mcp", fx.binary);
4286+ bool no_registration =
4287+ openhands_settings_entry_absent(fx.settings , "codebase-memory-mcp") &&
4288+ ! openhands_settings_entry_ok(fx.settings, "codebase-memory-mcp", fx.binary);
42984289 char *settings_after = read_test_file_alloc(fx.settings);
42994290 bool foreign_ok =
43004291 settings_after && strstr(settings_after, "\"language\": \"en\"") &&
43014292 strstr(settings_after, "\"llm_model\": \"gpt-x\"") &&
43024293 strstr(settings_after, "\"other-mcp\": {\"transport\": \"stdio\", \"command\": "
43034294 "\"/opt/other\", \"enabled\": false}");
4304- bool default_ok = openhands_profile_refs_equal(fx.default_profile, only_ours, 1U);
4305- bool custom_ok = openhands_profile_refs_equal(fx.custom_profile, appended, 2U );
4295+ bool custom_untouched =
4296+ openhands_profile_refs_equal(fx.custom_profile, (const char *const[]){"other-mcp"}, 1U );
43064297 char *default_after = read_test_file_alloc(fx.default_profile);
43074298 bool default_foreign_ok = default_after && strstr(default_after, "\"name\": \"default\"") &&
43084299 strstr(default_after, "\"tools\": [\"bash\"]");
43094300 bool note_ok = openhands_file_equals(fx.note, openhands_note_before);
4310- const char *const standard_json[] = {"mcpServers", "codebase-memory-mcp", fx.binary};
4311- bool mcp_json_ok = test_file_contains_all(fx.mcp, standard_json, 3);
4301+ bool mcp_json_absent = access(fx.mcp, F_OK) != 0;
43124302 char *custom_after = read_test_file_alloc(fx.custom_profile);
43134303
43144304 /* Second install: byte-idempotent on every touched file. */
@@ -4325,63 +4315,59 @@ TEST(cli_openhands_registers_settings_mcp_config_and_profile_refs_issue1826) {
43254315 bool settings_restored = openhands_file_equals(fx.settings, openhands_settings_before);
43264316 bool custom_restored =
43274317 openhands_file_equals(fx.custom_profile, openhands_custom_profile_before);
4328- /* null → ["codebase-memory-mcp"] → [] : the ref is gone; an empty list is
4329- * the minimal edit (the editor cannot know the list was null before). */
4330- bool default_cleared = openhands_profile_refs_equal(fx.default_profile, only_ours, 0U);
4318+ bool default_restored =
4319+ openhands_file_equals(fx.default_profile, openhands_default_profile_before);
43314320 bool note_restored = openhands_file_equals(fx.note, openhands_note_before);
43324321 openhands_fixture_close(&fx);
43334322
4334- if (!ours_ok )
4335- FAIL("settings.json must register mcp_config. codebase-memory-mcp {stdio, binary, enabled} ");
4323+ if (!no_registration )
4324+ FAIL("OpenHands settings must not receive a codebase-memory-mcp registration ");
43364325 if (!foreign_ok)
43374326 FAIL("settings.json foreign keys and the foreign mcp_config sibling must survive verbatim");
4338- if (!default_ok)
4339- FAIL("a null mcp_server_refs must become [\"codebase-memory-mcp\"]");
4340- if (!custom_ok)
4341- FAIL("an existing mcp_server_refs list must gain codebase-memory-mcp exactly once");
4327+ if (!custom_untouched)
4328+ FAIL("OpenHands profile MCP refs must remain unchanged");
43424329 if (!default_foreign_ok)
43434330 FAIL("profile keys around mcp_server_refs must survive verbatim");
43444331 if (!note_ok)
43454332 FAIL("non-JSON files under agent-profiles must not be touched");
4346- if (!mcp_json_ok )
4347- FAIL("the existing ~/.openhands/mcp.json registration must be kept ");
4333+ if (!mcp_json_absent )
4334+ FAIL("install must not create ~/.openhands/mcp.json");
43484335 if (!idempotent)
43494336 FAIL("a second install must be byte-idempotent");
43504337 if (rc != 0 || !settings_restored)
43514338 FAIL("uninstall must restore settings.json byte-for-byte");
43524339 if (!custom_restored)
43534340 FAIL("uninstall must restore a profile with foreign refs byte-for-byte");
4354- if (!default_cleared )
4355- FAIL("uninstall must remove our ref from the null-origin profile");
4341+ if (!default_restored )
4342+ FAIL("uninstall must leave the default profile untouched ");
43564343 if (!note_restored)
43574344 FAIL("uninstall must not touch non-JSON files under agent-profiles");
43584345 PASS();
43594346}
43604347
4361- /* Fresh ~/.openhands without settings.json or agent-profiles: settings.json is
4362- * created with only our entry, no profile directory is invented, and uninstall
4363- * removes the entry again. */
4348+ /* Fresh ~/.openhands without settings.json or agent-profiles: CLI install
4349+ * creates neither MCP settings nor an agent-profiles directory. */
43644350TEST(cli_openhands_creates_settings_and_skips_missing_profiles_issue1826) {
43654351 openhands_fixture_t fx;
43664352 if (!openhands_fixture_open(&fx, false))
43674353 FAIL("cbm_mkdtemp failed");
43684354
43694355 cbm_install_agent_configs(fx.home, fx.binary, false, false);
4370- bool ours_ok = openhands_settings_entry_ok (fx.settings, "codebase-memory-mcp", fx.binary) ;
4356+ bool no_settings = access (fx.settings, F_OK) != 0 ;
43714357 struct stat st;
43724358 bool no_profiles_invented = stat(fx.profiles_dir, &st) != 0;
43734359
43744360 char *argv[] = {"uninstall", "--yes"};
43754361 int rc = cli_test_cmd_uninstall(2, argv);
4376- bool removed = openhands_settings_entry_absent (fx.settings, "codebase-memory-mcp") ;
4362+ bool still_absent = access (fx.settings, F_OK) != 0 ;
43774363 openhands_fixture_close(&fx);
43784364
4379- if (!ours_ok )
4380- FAIL("a missing settings.json must be created with mcp_config.codebase-memory-mcp ");
4365+ if (!no_settings || !still_absent )
4366+ FAIL("install must not create an OpenHands MCP settings.json ");
43814367 if (!no_profiles_invented)
43824368 FAIL("install must never create ~/.openhands/agent-profiles");
4383- if (rc != 0 || !removed )
4384- FAIL("uninstall must remove mcp_config.codebase-memory-mcp from settings.json ");
4369+ if (rc != 0)
4370+ FAIL("uninstall must complete without touching OpenHands MCP configuration ");
43854371 PASS();
43864372}
43874373
@@ -11513,7 +11499,7 @@ TEST(cli_claude_hooks_use_exec_form_across_shells_issue1733) {
1151311499 char *saved_path = save_test_env("PATH");
1151411500 char *saved_config = save_test_env("CLAUDE_CONFIG_DIR");
1151511501 const char *const matchers[] = {"startup", "resume", "clear", "compact"};
11516- const char *binary_path = "C:/Program Files/CBM & Tools/codebase-memory-mcp .exe";
11502+ const char *binary_path = "C:/Program Files/CBM & Tools/codebase-memory-cli .exe";
1151711503 bool all_valid = true;
1151811504
1151911505 for (int custom = 0; custom < 2; custom++) {
@@ -11540,7 +11526,7 @@ TEST(cli_claude_hooks_use_exec_form_across_shells_issue1733) {
1154011526 "{\"hooks\":{\"SessionStart\":[{\"matcher\":\"resume\",\"hooks\":[{"
1154111527 "\"type\":\"command\",\"command\":\"foreign-hook\",\"args\":[\"keep\"]}]}]}}";
1154211528 if (write_test_file(settings_path, foreign) != 0 ||
11543- cbm_install_agent_configs (tmpdir, binary_path, false, false) != 0) {
11529+ cbm_install_agent_hooks_for_testing (tmpdir, binary_path, false, false) != 0) {
1154411530 all_valid = false;
1154511531 test_rmdir_r(tmpdir);
1154611532 break;
@@ -11594,9 +11580,9 @@ TEST(cli_claude_exec_hooks_custom_dir_uninstall_issue1733) {
1159411580 snprintf(settings_path, sizeof(settings_path), "%s/settings.json", config_dir);
1159511581 snprintf(install_dir, sizeof(install_dir), "%s/custom CBM & bin", tmpdir);
1159611582#ifdef _WIN32
11597- snprintf(binary_path, sizeof(binary_path), "%s/codebase-memory-mcp .exe", install_dir);
11583+ snprintf(binary_path, sizeof(binary_path), "%s/codebase-memory-cli .exe", install_dir);
1159811584#else
11599- snprintf(binary_path, sizeof(binary_path), "%s/codebase-memory-mcp ", install_dir);
11585+ snprintf(binary_path, sizeof(binary_path), "%s/codebase-memory-cli ", install_dir);
1160011586#endif
1160111587 test_mkdirp(config_dir);
1160211588 test_mkdirp(install_dir);
@@ -11608,7 +11594,7 @@ TEST(cli_claude_exec_hooks_custom_dir_uninstall_issue1733) {
1160811594 cbm_setenv("PATH", tmpdir, 1);
1160911595 cbm_unsetenv("CLAUDE_CONFIG_DIR");
1161011596
11611- int install_rc = cbm_install_agent_configs (tmpdir, binary_path, false, false);
11597+ int install_rc = cbm_install_agent_hooks_for_testing (tmpdir, binary_path, false, false);
1161211598 char *installed = read_test_file_alloc(settings_path);
1161311599 yyjson_doc *installed_doc = installed ? yyjson_read(installed, strlen(installed), 0) : NULL;
1161411600 yyjson_val *installed_root = installed_doc ? yyjson_doc_get_root(installed_doc) : NULL;
@@ -13309,8 +13295,8 @@ TEST(cli_cp78_explicit_claude_hooks_preserve_mcp_hook_assets) {
1330913295 char *cli_gate = read_test_file_alloc(cli_gate_path);
1331013296
1331113297 bool ok = rc == 0 && after_script && strcmp(after_script, mcp_gate) == 0 && after_settings &&
13312- strstr(after_settings, mcp_command) &&
13313- strstr(after_settings, "codebase-memory-cli-discovery-gate") && cli_gate;
13298+ strstr(after_settings, mcp_command) && strstr(after_settings, "hook-augment") &&
13299+ cli_gate;
1331413300
1331513301 free(after_script);
1331613302 free(after_settings);
@@ -13333,7 +13319,7 @@ SUITE(cli) {
1333313319 cbm_cli_set_activation_runtime_parent_for_test(g_cli_suite_runtime_parent);
1333413320
1333513321 RUN_TEST(cli_suite_uses_private_activation_runtime);
13336- RUN_TEST(cli_uninstall_reports_foreign_cache_without_mutating );
13322+ RUN_TEST(cli_uninstall_leaves_foreign_cache_running_while_removing_cli_files );
1333713323 RUN_TEST(cli_update_only_names_an_installer_that_exists_issue1632);
1333813324#ifndef _WIN32
1333913325 RUN_TEST(cli_hook_deadline_ignores_an_unreadable_value);
0 commit comments