diff --git a/src/cli/cli.c b/src/cli/cli.c index 0bc327586..dce0531da 100644 --- a/src/cli/cli.c +++ b/src/cli/cli.c @@ -4070,11 +4070,14 @@ char *cbm_build_install_plan_json(const char *home, const char *binary_path) { yyjson_mut_val *configs = yyjson_mut_arr(doc); yyjson_mut_val *instrs = yyjson_mut_arr(doc); + yyjson_mut_val *skill_dirs = yyjson_mut_arr(doc); yyjson_mut_val *hooks = yyjson_mut_arr(doc); for (int i = 0; i < plan.count; i++) { cbm_plan_entry_t *e = &plan.items[i]; if (strcmp(e->kind, "mcp_config") == 0) { yyjson_mut_arr_add_strcpy(doc, configs, e->path); + } else if (strcmp(e->kind, "skills") == 0) { + yyjson_mut_arr_add_strcpy(doc, skill_dirs, e->path); } else if (strcmp(e->kind, "hook") == 0) { yyjson_mut_val *h = yyjson_mut_obj(doc); yyjson_mut_obj_add_strcpy(doc, h, "agent", e->agent); @@ -4086,6 +4089,7 @@ char *cbm_build_install_plan_json(const char *home, const char *binary_path) { } yyjson_mut_obj_add_val(doc, root, "config_files_planned", configs); yyjson_mut_obj_add_val(doc, root, "instruction_files_planned", instrs); + yyjson_mut_obj_add_val(doc, root, "skill_dirs_planned", skill_dirs); yyjson_mut_obj_add_val(doc, root, "hooks_planned", hooks); yyjson_mut_obj_add_bool(doc, root, "writes_started", false); yyjson_mut_obj_add_bool(doc, root, "network_after_install", false); diff --git a/tests/test_cli.c b/tests/test_cli.c index ed312e4f7..5630c0eee 100644 --- a/tests/test_cli.c +++ b/tests/test_cli.c @@ -1679,8 +1679,10 @@ TEST(cli_install_plan_receipt_no_mutation_issue388) { if (!cbm_mkdtemp(tmpdir)) FAIL("cbm_mkdtemp failed"); - /* Make Cursor + Codex "detected". */ + /* Make Claude Code + Cursor + Codex "detected". */ char dir[512]; + snprintf(dir, sizeof(dir), "%s/.claude", tmpdir); + test_mkdirp(dir); snprintf(dir, sizeof(dir), "%s/.cursor", tmpdir); test_mkdirp(dir); snprintf(dir, sizeof(dir), "%s/.codex", tmpdir); @@ -1692,8 +1694,17 @@ TEST(cli_install_plan_receipt_no_mutation_issue388) { ASSERT(strstr(json, "writes_started") != NULL); ASSERT(strstr(json, "next_safe_command") != NULL); ASSERT(strstr(json, "cursor") != NULL); + ASSERT(strstr(json, "skill_dirs_planned") != NULL); + ASSERT(strstr(json, ".claude/skills") != NULL); ASSERT(strstr(json, ".cursor/mcp.json") != NULL); ASSERT(strstr(json, ".codex/config.toml") != NULL); + const char *instrs = strstr(json, "\"instruction_files_planned\""); + ASSERT_NOT_NULL(instrs); + const char *skill_dirs = strstr(json, "\"skill_dirs_planned\""); + ASSERT_NOT_NULL(skill_dirs); + ASSERT(instrs < skill_dirs); + const char *misclassified = strstr(instrs, ".claude/skills"); + ASSERT(misclassified == NULL || misclassified > skill_dirs); free(json); /* Critical: building the plan must NOT have created any config file. */