| 1405 | /* ── Skill management ─────────────────────────────────────────── */ |
| 1406 | |
| 1407 | int cbm_install_skills(const char *skills_dir, bool force, bool dry_run) { |
| 1408 | if (!skills_dir) { |
| 1409 | return 0; |
| 1410 | } |
| 1411 | int count = 0; |
| 1412 | |
| 1413 | /* Clean up only empty old directories. Historical files may have been |
| 1414 | * customized, and their old content is not an ownership proof. */ |
| 1415 | for (int i = 0; i < OLD_SKILL_COUNT; i++) { |
| 1416 | char old_path[CLI_BUF_1K]; |
| 1417 | snprintf(old_path, sizeof(old_path), "%s/%s", skills_dir, old_skill_names[i]); |
| 1418 | (void)cbm_remove_empty_directory(old_path, dry_run); |
| 1419 | } |
| 1420 | |
| 1421 | for (int i = 0; i < CBM_SKILL_COUNT; i++) { |
| 1422 | char skill_path[CLI_BUF_1K]; |
| 1423 | snprintf(skill_path, sizeof(skill_path), "%s/%s", skills_dir, skills[i].name); |
| 1424 | char file_path[CLI_BUF_1K]; |
| 1425 | snprintf(file_path, sizeof(file_path), "%s/SKILL.md", skill_path); |
| 1426 | |
| 1427 | struct stat skill_state; |
| 1428 | #ifndef _WIN32 |
| 1429 | if (lstat(skill_path, &skill_state) == 0 && !S_ISDIR(skill_state.st_mode)) { |
| 1430 | continue; |
| 1431 | } |
| 1432 | #else |
| 1433 | if (stat(skill_path, &skill_state) == 0 && !S_ISDIR(skill_state.st_mode)) { |
| 1434 | continue; |
| 1435 | } |
| 1436 | #endif |
| 1437 | |
| 1438 | /* Check if already exists */ |
| 1439 | if (!force) { |
| 1440 | struct stat st; |
| 1441 | if (stat(file_path, &st) == 0) { |
| 1442 | continue; |
| 1443 | } |
| 1444 | } |
| 1445 | |
| 1446 | if (dry_run) { |
| 1447 | count++; |
| 1448 | continue; |
| 1449 | } |
| 1450 | |
| 1451 | if (mkdirp(skill_path, DIR_PERMS) != 0) { |
| 1452 | continue; |
| 1453 | } |
| 1454 | |
| 1455 | if (cbm_text_write_owned_document(file_path, skills[i].content) == 0) { |
| 1456 | count++; |
| 1457 | } |
| 1458 | } |
| 1459 | return count; |
| 1460 | } |
| 1461 | |
| 1462 | int cbm_remove_skills(const char *skills_dir, bool dry_run) { |
| 1463 | if (!skills_dir) { |
no test coverage detected