@@ -2977,244 +2977,6 @@ fn resolve_skill_path(skill: &str) -> Result<std::path::PathBuf, String> {
29772977 commands:: resolve_skill_path ( & cwd, skill) . map_err ( |error| error. to_string ( ) )
29782978}
29792979
2980- #[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
2981- enum SkillLookupOrigin {
2982- SkillsDir ,
2983- LegacyCommandsDir ,
2984- }
2985-
2986- #[ derive( Debug , Clone , PartialEq , Eq ) ]
2987- struct SkillLookupRoot {
2988- path : std:: path:: PathBuf ,
2989- origin : SkillLookupOrigin ,
2990- }
2991-
2992- fn skill_lookup_roots ( ) -> Vec < SkillLookupRoot > {
2993- let mut roots = Vec :: new ( ) ;
2994-
2995- if let Ok ( cwd) = std:: env:: current_dir ( ) {
2996- push_project_skill_lookup_roots ( & mut roots, & cwd) ;
2997- }
2998-
2999- if let Ok ( claw_config_home) = std:: env:: var ( "CLAW_CONFIG_HOME" ) {
3000- push_prefixed_skill_lookup_roots ( & mut roots, std:: path:: Path :: new ( & claw_config_home) ) ;
3001- }
3002- if let Ok ( codex_home) = std:: env:: var ( "CODEX_HOME" ) {
3003- push_prefixed_skill_lookup_roots ( & mut roots, std:: path:: Path :: new ( & codex_home) ) ;
3004- }
3005- if let Ok ( home) = std:: env:: var ( "HOME" ) {
3006- push_home_skill_lookup_roots ( & mut roots, std:: path:: Path :: new ( & home) ) ;
3007- }
3008- if let Ok ( claude_config_dir) = std:: env:: var ( "CLAUDE_CONFIG_DIR" ) {
3009- let claude_config_dir = std:: path:: PathBuf :: from ( claude_config_dir) ;
3010- push_skill_lookup_root (
3011- & mut roots,
3012- claude_config_dir. join ( "skills" ) ,
3013- SkillLookupOrigin :: SkillsDir ,
3014- ) ;
3015- push_skill_lookup_root (
3016- & mut roots,
3017- claude_config_dir. join ( "skills" ) . join ( "omc-learned" ) ,
3018- SkillLookupOrigin :: SkillsDir ,
3019- ) ;
3020- push_skill_lookup_root (
3021- & mut roots,
3022- claude_config_dir. join ( "commands" ) ,
3023- SkillLookupOrigin :: LegacyCommandsDir ,
3024- ) ;
3025- }
3026- push_skill_lookup_root (
3027- & mut roots,
3028- std:: path:: PathBuf :: from ( "/home/bellman/.claw/skills" ) ,
3029- SkillLookupOrigin :: SkillsDir ,
3030- ) ;
3031- push_skill_lookup_root (
3032- & mut roots,
3033- std:: path:: PathBuf :: from ( "/home/bellman/.codex/skills" ) ,
3034- SkillLookupOrigin :: SkillsDir ,
3035- ) ;
3036-
3037- roots
3038- }
3039-
3040- fn push_project_skill_lookup_roots ( roots : & mut Vec < SkillLookupRoot > , cwd : & std:: path:: Path ) {
3041- for ancestor in cwd. ancestors ( ) {
3042- push_prefixed_skill_lookup_roots ( roots, & ancestor. join ( ".omc" ) ) ;
3043- push_prefixed_skill_lookup_roots ( roots, & ancestor. join ( ".agents" ) ) ;
3044- push_prefixed_skill_lookup_roots ( roots, & ancestor. join ( ".claw" ) ) ;
3045- push_prefixed_skill_lookup_roots ( roots, & ancestor. join ( ".codex" ) ) ;
3046- push_prefixed_skill_lookup_roots ( roots, & ancestor. join ( ".claude" ) ) ;
3047- }
3048- }
3049-
3050- fn push_home_skill_lookup_roots ( roots : & mut Vec < SkillLookupRoot > , home : & std:: path:: Path ) {
3051- push_prefixed_skill_lookup_roots ( roots, & home. join ( ".omc" ) ) ;
3052- push_prefixed_skill_lookup_roots ( roots, & home. join ( ".claw" ) ) ;
3053- push_prefixed_skill_lookup_roots ( roots, & home. join ( ".codex" ) ) ;
3054- push_prefixed_skill_lookup_roots ( roots, & home. join ( ".claude" ) ) ;
3055- push_skill_lookup_root (
3056- roots,
3057- home. join ( ".agents" ) . join ( "skills" ) ,
3058- SkillLookupOrigin :: SkillsDir ,
3059- ) ;
3060- push_skill_lookup_root (
3061- roots,
3062- home. join ( ".config" ) . join ( "opencode" ) . join ( "skills" ) ,
3063- SkillLookupOrigin :: SkillsDir ,
3064- ) ;
3065- push_skill_lookup_root (
3066- roots,
3067- home. join ( ".claude" ) . join ( "skills" ) . join ( "omc-learned" ) ,
3068- SkillLookupOrigin :: SkillsDir ,
3069- ) ;
3070- }
3071-
3072- fn push_prefixed_skill_lookup_roots ( roots : & mut Vec < SkillLookupRoot > , prefix : & std:: path:: Path ) {
3073- push_skill_lookup_root ( roots, prefix. join ( "skills" ) , SkillLookupOrigin :: SkillsDir ) ;
3074- push_skill_lookup_root (
3075- roots,
3076- prefix. join ( "commands" ) ,
3077- SkillLookupOrigin :: LegacyCommandsDir ,
3078- ) ;
3079- }
3080-
3081- fn push_skill_lookup_root (
3082- roots : & mut Vec < SkillLookupRoot > ,
3083- path : std:: path:: PathBuf ,
3084- origin : SkillLookupOrigin ,
3085- ) {
3086- if path. is_dir ( ) && !roots. iter ( ) . any ( |existing| existing. path == path) {
3087- roots. push ( SkillLookupRoot { path, origin } ) ;
3088- }
3089- }
3090-
3091- fn resolve_skill_path_in_root (
3092- root : & SkillLookupRoot ,
3093- requested : & str ,
3094- ) -> Option < std:: path:: PathBuf > {
3095- match root. origin {
3096- SkillLookupOrigin :: SkillsDir => resolve_skill_path_in_skills_dir ( & root. path , requested) ,
3097- SkillLookupOrigin :: LegacyCommandsDir => {
3098- resolve_skill_path_in_legacy_commands_dir ( & root. path , requested)
3099- }
3100- }
3101- }
3102-
3103- fn resolve_skill_path_in_skills_dir (
3104- root : & std:: path:: Path ,
3105- requested : & str ,
3106- ) -> Option < std:: path:: PathBuf > {
3107- let direct = root. join ( requested) . join ( "SKILL.md" ) ;
3108- if direct. is_file ( ) {
3109- return Some ( direct) ;
3110- }
3111-
3112- let entries = std:: fs:: read_dir ( root) . ok ( ) ?;
3113- for entry in entries. flatten ( ) {
3114- if !entry. path ( ) . is_dir ( ) {
3115- continue ;
3116- }
3117- let skill_path = entry. path ( ) . join ( "SKILL.md" ) ;
3118- if !skill_path. is_file ( ) {
3119- continue ;
3120- }
3121- if entry
3122- . file_name ( )
3123- . to_string_lossy ( )
3124- . eq_ignore_ascii_case ( requested)
3125- || skill_frontmatter_name_matches ( & skill_path, requested)
3126- {
3127- return Some ( skill_path) ;
3128- }
3129- }
3130-
3131- None
3132- }
3133-
3134- fn resolve_skill_path_in_legacy_commands_dir (
3135- root : & std:: path:: Path ,
3136- requested : & str ,
3137- ) -> Option < std:: path:: PathBuf > {
3138- let direct_dir = root. join ( requested) . join ( "SKILL.md" ) ;
3139- if direct_dir. is_file ( ) {
3140- return Some ( direct_dir) ;
3141- }
3142-
3143- let direct_markdown = root. join ( format ! ( "{requested}.md" ) ) ;
3144- if direct_markdown. is_file ( ) {
3145- return Some ( direct_markdown) ;
3146- }
3147-
3148- let entries = std:: fs:: read_dir ( root) . ok ( ) ?;
3149- for entry in entries. flatten ( ) {
3150- let path = entry. path ( ) ;
3151- let candidate_path = if path. is_dir ( ) {
3152- let skill_path = path. join ( "SKILL.md" ) ;
3153- if !skill_path. is_file ( ) {
3154- continue ;
3155- }
3156- skill_path
3157- } else if path
3158- . extension ( )
3159- . is_some_and ( |ext| ext. to_string_lossy ( ) . eq_ignore_ascii_case ( "md" ) )
3160- {
3161- path
3162- } else {
3163- continue ;
3164- } ;
3165-
3166- let matches_entry_name = candidate_path
3167- . file_stem ( )
3168- . is_some_and ( |stem| stem. to_string_lossy ( ) . eq_ignore_ascii_case ( requested) )
3169- || entry
3170- . file_name ( )
3171- . to_string_lossy ( )
3172- . trim_end_matches ( ".md" )
3173- . eq_ignore_ascii_case ( requested) ;
3174- if matches_entry_name || skill_frontmatter_name_matches ( & candidate_path, requested) {
3175- return Some ( candidate_path) ;
3176- }
3177- }
3178-
3179- None
3180- }
3181-
3182- fn skill_frontmatter_name_matches ( path : & std:: path:: Path , requested : & str ) -> bool {
3183- std:: fs:: read_to_string ( path)
3184- . ok ( )
3185- . and_then ( |contents| parse_skill_name ( & contents) )
3186- . is_some_and ( |name| name. eq_ignore_ascii_case ( requested) )
3187- }
3188-
3189- fn parse_skill_name ( contents : & str ) -> Option < String > {
3190- parse_skill_frontmatter_value ( contents, "name" )
3191- }
3192-
3193- fn parse_skill_frontmatter_value ( contents : & str , key : & str ) -> Option < String > {
3194- let mut lines = contents. lines ( ) ;
3195- if lines. next ( ) . map ( str:: trim) != Some ( "---" ) {
3196- return None ;
3197- }
3198-
3199- for line in lines {
3200- let trimmed = line. trim ( ) ;
3201- if trimmed == "---" {
3202- break ;
3203- }
3204- if let Some ( value) = trimmed. strip_prefix ( & format ! ( "{key}:" ) ) {
3205- let value = value
3206- . trim ( )
3207- . trim_matches ( |ch| matches ! ( ch, '"' | '\'' ) )
3208- . trim ( ) ;
3209- if !value. is_empty ( ) {
3210- return Some ( value. to_string ( ) ) ;
3211- }
3212- }
3213- }
3214-
3215- None
3216- }
3217-
32182980const DEFAULT_AGENT_MODEL : & str = "claude-opus-4-6" ;
32192981const DEFAULT_AGENT_SYSTEM_DATE : & str = "2026-03-31" ;
32202982const DEFAULT_AGENT_MAX_ITERATIONS : usize = 32 ;
0 commit comments