list_projects: scan cache directory for .db files. * Each project is a single .db file — no central registry needed. */
| 2559 | /* list_projects: scan cache directory for .db files. |
| 2560 | * Each project is a single .db file — no central registry needed. */ |
| 2561 | static char *handle_list_projects(cbm_mcp_server_t *srv, const char *args) { |
| 2562 | (void)srv; |
| 2563 | bool metadata_only = false; |
| 2564 | yyjson_doc *args_doc = args ? yyjson_read(args, strlen(args), 0) : NULL; |
| 2565 | yyjson_val *args_root = args_doc ? yyjson_doc_get_root(args_doc) : NULL; |
| 2566 | yyjson_val *metadata_value = |
| 2567 | args_root && yyjson_is_obj(args_root) ? yyjson_obj_get(args_root, "metadata_only") : NULL; |
| 2568 | metadata_only = metadata_value && yyjson_is_true(metadata_value); |
| 2569 | if (args_doc) { |
| 2570 | yyjson_doc_free(args_doc); |
| 2571 | } |
| 2572 | |
| 2573 | char dir_path[CBM_SZ_1K]; |
| 2574 | cache_dir(dir_path, sizeof(dir_path)); |
| 2575 | |
| 2576 | cbm_dir_t *d = cbm_opendir(dir_path); |
| 2577 | |
| 2578 | yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL); |
| 2579 | yyjson_mut_val *root = yyjson_mut_obj(doc); |
| 2580 | yyjson_mut_doc_set_root(doc, root); |
| 2581 | yyjson_mut_val *arr = yyjson_mut_arr(doc); |
| 2582 | |
| 2583 | if (!d) { |
| 2584 | char msg[CBM_SZ_1K]; |
| 2585 | snprintf(msg, sizeof(msg), |
| 2586 | "{\"error\":\"cannot read cache directory: %s\",\"hint\":" |
| 2587 | "\"Check directory permissions or run index_repository first.\"}", |
| 2588 | dir_path); |
| 2589 | yyjson_mut_doc_free(doc); |
| 2590 | return cbm_mcp_text_result(msg, true); |
| 2591 | } |
| 2592 | |
| 2593 | cbm_dirent_t *entry; |
| 2594 | while ((entry = cbm_readdir(d)) != NULL) { |
| 2595 | const char *name = entry->name; |
| 2596 | size_t len = strlen(name); |
| 2597 | if (!is_project_db_file(name, len)) { |
| 2598 | continue; |
| 2599 | } |
| 2600 | char full_path[CBM_SZ_2K]; |
| 2601 | snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, name); |
| 2602 | int64_t size_bytes = cbm_file_size(full_path); |
| 2603 | if (size_bytes < 0) { |
| 2604 | continue; |
| 2605 | } |
| 2606 | build_project_json_entry(doc, arr, dir_path, name, len, size_bytes, metadata_only); |
| 2607 | } |
| 2608 | cbm_closedir(d); |
| 2609 | |
| 2610 | yyjson_mut_obj_add_val(doc, root, "projects", arr); |
| 2611 | |
| 2612 | /* Guide user when no projects are indexed */ |
| 2613 | if (yyjson_mut_arr_size(arr) == 0) { |
| 2614 | yyjson_mut_obj_add_str(doc, root, "hint", |
| 2615 | "No projects indexed. Call index_repository(repo_path=...) first."); |
| 2616 | } |
| 2617 | |
| 2618 | char *json = yy_doc_to_str(doc); |
no test coverage detected