| 1461 | /* ── Skill management ─────────────────────────────────────────── */ |
| 1462 | |
| 1463 | int cbm_install_skills(const char *skills_dir, bool force, bool dry_run) { |
| 1464 | if (!skills_dir) { |
| 1465 | return 0; |
| 1466 | } |
| 1467 | int count = 0; |
| 1468 | |
| 1469 | /* Clean up only empty old directories. Historical files may have been |
| 1470 | * customized, and their old content is not an ownership proof. */ |
| 1471 | for (int i = 0; i < OLD_SKILL_COUNT; i++) { |
| 1472 | char old_path[CLI_BUF_1K]; |
| 1473 | snprintf(old_path, sizeof(old_path), "%s/%s", skills_dir, old_skill_names[i]); |
| 1474 | (void)cbm_remove_empty_directory(old_path, dry_run); |
| 1475 | } |
| 1476 | |
| 1477 | for (int i = 0; i < CBM_SKILL_COUNT; i++) { |
| 1478 | char skill_path[CLI_BUF_1K]; |
| 1479 | snprintf(skill_path, sizeof(skill_path), "%s/%s", skills_dir, skills[i].name); |
| 1480 | char file_path[CLI_BUF_1K]; |
| 1481 | snprintf(file_path, sizeof(file_path), "%s/SKILL.md", skill_path); |
| 1482 | |
| 1483 | struct stat skill_state; |
| 1484 | #ifndef _WIN32 |
| 1485 | if (lstat(skill_path, &skill_state) == 0 && !S_ISDIR(skill_state.st_mode)) { |
| 1486 | continue; |
| 1487 | } |
| 1488 | #else |
| 1489 | if (stat(skill_path, &skill_state) == 0 && !S_ISDIR(skill_state.st_mode)) { |
| 1490 | continue; |
| 1491 | } |
| 1492 | #endif |
| 1493 | |
| 1494 | /* Check if already exists */ |
| 1495 | if (!force) { |
| 1496 | struct stat st; |
| 1497 | if (stat(file_path, &st) == 0) { |
| 1498 | continue; |
| 1499 | } |
| 1500 | } |
| 1501 | |
| 1502 | if (dry_run) { |
| 1503 | count++; |
| 1504 | continue; |
| 1505 | } |
| 1506 | |
| 1507 | if (mkdirp(skill_path, DIR_PERMS) != 0) { |
| 1508 | continue; |
| 1509 | } |
| 1510 | |
| 1511 | if (cbm_text_write_owned_document(file_path, skills[i].content) == 0) { |
| 1512 | count++; |
| 1513 | } |
| 1514 | } |
| 1515 | return count; |
| 1516 | } |
| 1517 | |
| 1518 | int cbm_remove_skills(const char *skills_dir, bool dry_run) { |
| 1519 | if (!skills_dir) { |
no test coverage detected