Skip to content

Commit f9cb42f

Browse files
committed
Resolve claw-code main merge conflicts
1 parent 01b263c commit f9cb42f

5 files changed

Lines changed: 939 additions & 22 deletions

File tree

rust/crates/commands/src/lib.rs

Lines changed: 183 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ const SLASH_COMMAND_SPECS: &[SlashCommandSpec] = &[
243243
},
244244
SlashCommandSpec {
245245
name: "skills",
246-
aliases: &[],
246+
aliases: &["skill"],
247247
summary: "List, install, or invoke available skills",
248248
argument_hint: Some("[list|install <path>|help|<skill> [args]]"),
249249
resume_supported: true,
@@ -1312,7 +1312,7 @@ pub fn validate_slash_command_input(
13121312
"agents" => SlashCommand::Agents {
13131313
args: parse_list_or_help_args(command, remainder)?,
13141314
},
1315-
"skills" => SlashCommand::Skills {
1315+
"skills" | "skill" => SlashCommand::Skills {
13161316
args: parse_skills_args(remainder.as_deref())?,
13171317
},
13181318
"doctor" => {
@@ -1975,9 +1975,9 @@ enum DefinitionScope {
19751975
impl DefinitionScope {
19761976
fn label(self) -> &'static str {
19771977
match self {
1978-
Self::Project => "Project (.claw)",
1979-
Self::UserConfigHome => "User ($CLAW_CONFIG_HOME)",
1980-
Self::UserHome => "User (~/.claw)",
1978+
Self::Project => "Project roots",
1979+
Self::UserConfigHome => "User config roots",
1980+
Self::UserHome => "User home roots",
19811981
}
19821982
}
19831983
}
@@ -2548,6 +2548,14 @@ fn discover_definition_roots(cwd: &Path, leaf: &str) -> Vec<(DefinitionSource, P
25482548
);
25492549
}
25502550

2551+
if let Ok(claude_config_dir) = env::var("CLAUDE_CONFIG_DIR") {
2552+
push_unique_root(
2553+
&mut roots,
2554+
DefinitionSource::UserClaude,
2555+
PathBuf::from(claude_config_dir).join(leaf),
2556+
);
2557+
}
2558+
25512559
if let Some(home) = env::var_os("HOME") {
25522560
let home = PathBuf::from(home);
25532561
push_unique_root(
@@ -2581,6 +2589,18 @@ fn discover_skill_roots(cwd: &Path) -> Vec<SkillRoot> {
25812589
ancestor.join(".claw").join("skills"),
25822590
SkillOrigin::SkillsDir,
25832591
);
2592+
push_unique_skill_root(
2593+
&mut roots,
2594+
DefinitionSource::ProjectClaw,
2595+
ancestor.join(".omc").join("skills"),
2596+
SkillOrigin::SkillsDir,
2597+
);
2598+
push_unique_skill_root(
2599+
&mut roots,
2600+
DefinitionSource::ProjectClaw,
2601+
ancestor.join(".agents").join("skills"),
2602+
SkillOrigin::SkillsDir,
2603+
);
25842604
push_unique_skill_root(
25852605
&mut roots,
25862606
DefinitionSource::ProjectCodex,
@@ -2653,6 +2673,12 @@ fn discover_skill_roots(cwd: &Path) -> Vec<SkillRoot> {
26532673
home.join(".claw").join("skills"),
26542674
SkillOrigin::SkillsDir,
26552675
);
2676+
push_unique_skill_root(
2677+
&mut roots,
2678+
DefinitionSource::UserClaw,
2679+
home.join(".omc").join("skills"),
2680+
SkillOrigin::SkillsDir,
2681+
);
26562682
push_unique_skill_root(
26572683
&mut roots,
26582684
DefinitionSource::UserClaw,
@@ -2677,6 +2703,12 @@ fn discover_skill_roots(cwd: &Path) -> Vec<SkillRoot> {
26772703
home.join(".claude").join("skills"),
26782704
SkillOrigin::SkillsDir,
26792705
);
2706+
push_unique_skill_root(
2707+
&mut roots,
2708+
DefinitionSource::UserClaude,
2709+
home.join(".claude").join("skills").join("omc-learned"),
2710+
SkillOrigin::SkillsDir,
2711+
);
26802712
push_unique_skill_root(
26812713
&mut roots,
26822714
DefinitionSource::UserClaude,
@@ -2685,6 +2717,29 @@ fn discover_skill_roots(cwd: &Path) -> Vec<SkillRoot> {
26852717
);
26862718
}
26872719

2720+
if let Ok(claude_config_dir) = env::var("CLAUDE_CONFIG_DIR") {
2721+
let claude_config_dir = PathBuf::from(claude_config_dir);
2722+
let skills_dir = claude_config_dir.join("skills");
2723+
push_unique_skill_root(
2724+
&mut roots,
2725+
DefinitionSource::UserClaude,
2726+
skills_dir.clone(),
2727+
SkillOrigin::SkillsDir,
2728+
);
2729+
push_unique_skill_root(
2730+
&mut roots,
2731+
DefinitionSource::UserClaude,
2732+
skills_dir.join("omc-learned"),
2733+
SkillOrigin::SkillsDir,
2734+
);
2735+
push_unique_skill_root(
2736+
&mut roots,
2737+
DefinitionSource::UserClaude,
2738+
claude_config_dir.join("commands"),
2739+
SkillOrigin::LegacyCommandsDir,
2740+
);
2741+
}
2742+
26882743
roots
26892744
}
26902745

@@ -3467,10 +3522,11 @@ fn render_skills_usage(unexpected: Option<&str>) -> String {
34673522
let mut lines = vec![
34683523
"Skills".to_string(),
34693524
" Usage /skills [list|install <path>|help|<skill> [args]]".to_string(),
3525+
" Alias /skill".to_string(),
34703526
" Direct CLI claw skills [list|install <path>|help|<skill> [args]]".to_string(),
34713527
" Invoke /skills help overview -> $help overview".to_string(),
34723528
" Install root $CLAW_CONFIG_HOME/skills or ~/.claw/skills".to_string(),
3473-
" Sources .claw/skills, ~/.claw/skills, legacy /commands".to_string(),
3529+
" Sources .claw/skills, .omc/skills, .agents/skills, .codex/skills, .claude/skills, ~/.claw/skills, ~/.omc/skills, ~/.claude/skills/omc-learned, ~/.codex/skills, ~/.claude/skills, legacy /commands".to_string(),
34743530
];
34753531
if let Some(args) = unexpected {
34763532
lines.push(format!(" Unexpected {args}"));
@@ -3484,10 +3540,24 @@ fn render_skills_usage_json(unexpected: Option<&str>) -> Value {
34843540
"action": "help",
34853541
"usage": {
34863542
"slash_command": "/skills [list|install <path>|help|<skill> [args]]",
3543+
"aliases": ["/skill"],
34873544
"direct_cli": "claw skills [list|install <path>|help|<skill> [args]]",
34883545
"invoke": "/skills help overview -> $help overview",
34893546
"install_root": "$CLAW_CONFIG_HOME/skills or ~/.claw/skills",
3490-
"sources": [".claw/skills", "legacy /commands", "legacy fallback dirs still load automatically"],
3547+
"sources": [
3548+
".claw/skills",
3549+
".omc/skills",
3550+
".agents/skills",
3551+
".codex/skills",
3552+
".claude/skills",
3553+
"~/.claw/skills",
3554+
"~/.omc/skills",
3555+
"~/.claude/skills/omc-learned",
3556+
"~/.codex/skills",
3557+
"~/.claude/skills",
3558+
"legacy /commands",
3559+
"legacy fallback dirs still load automatically"
3560+
],
34913561
},
34923562
"unexpected": unexpected,
34933563
})
@@ -3849,8 +3919,10 @@ mod tests {
38493919
use runtime::{
38503920
CompactionConfig, ConfigLoader, ContentBlock, ConversationMessage, MessageRole, Session,
38513921
};
3922+
use std::ffi::OsString;
38523923
use std::fs;
38533924
use std::path::{Path, PathBuf};
3925+
use std::sync::{Mutex, OnceLock};
38543926
use std::time::{SystemTime, UNIX_EPOCH};
38553927

38563928
fn temp_dir(label: &str) -> PathBuf {
@@ -3861,6 +3933,18 @@ mod tests {
38613933
std::env::temp_dir().join(format!("commands-plugin-{label}-{nanos}"))
38623934
}
38633935

3936+
fn env_lock() -> &'static Mutex<()> {
3937+
static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
3938+
LOCK.get_or_init(|| Mutex::new(()))
3939+
}
3940+
3941+
fn restore_env_var(key: &str, original: Option<OsString>) {
3942+
match original {
3943+
Some(value) => std::env::set_var(key, value),
3944+
None => std::env::remove_var(key),
3945+
}
3946+
}
3947+
38643948
fn write_external_plugin(root: &Path, name: &str, version: &str) {
38653949
fs::create_dir_all(root.join(".claude-plugin")).expect("manifest dir");
38663950
fs::write(
@@ -4275,6 +4359,7 @@ mod tests {
42754359
assert!(help.contains("aliases: /plugins, /marketplace"));
42764360
assert!(help.contains("/agents [list|help]"));
42774361
assert!(help.contains("/skills [list|install <path>|help|<skill> [args]]"));
4362+
assert!(help.contains("aliases: /skill"));
42784363
assert_eq!(slash_command_specs().len(), 141);
42794364
assert!(resume_supported_slash_commands().len() >= 39);
42804365
}
@@ -4517,10 +4602,10 @@ mod tests {
45174602

45184603
assert!(report.contains("Agents"));
45194604
assert!(report.contains("2 active agents"));
4520-
assert!(report.contains("Project (.claw):"));
4605+
assert!(report.contains("Project roots:"));
45214606
assert!(report.contains("planner · Project planner · gpt-5.4 · medium"));
4522-
assert!(report.contains("User (~/.claw):"));
4523-
assert!(report.contains("(shadowed by Project (.claw)) planner · User planner"));
4607+
assert!(report.contains("User home roots:"));
4608+
assert!(report.contains("(shadowed by Project roots) planner · User planner"));
45244609
assert!(report.contains("verifier · Verification agent · gpt-5.4-mini · high"));
45254610

45264611
let _ = fs::remove_dir_all(workspace);
@@ -4628,11 +4713,11 @@ mod tests {
46284713

46294714
assert!(report.contains("Skills"));
46304715
assert!(report.contains("3 available skills"));
4631-
assert!(report.contains("Project (.claw):"));
4716+
assert!(report.contains("Project roots:"));
46324717
assert!(report.contains("plan · Project planning guidance"));
46334718
assert!(report.contains("deploy · Legacy deployment guidance · legacy /commands"));
4634-
assert!(report.contains("User (~/.claw):"));
4635-
assert!(report.contains("(shadowed by Project (.claw)) plan · User planning guidance"));
4719+
assert!(report.contains("User home roots:"));
4720+
assert!(report.contains("(shadowed by Project roots) plan · User planning guidance"));
46364721
assert!(report.contains("help · Help guidance"));
46374722

46384723
let _ = fs::remove_dir_all(workspace);
@@ -4704,6 +4789,7 @@ mod tests {
47044789
let help = handle_skills_slash_command_json(Some("help"), &workspace).expect("skills help");
47054790
assert_eq!(help["kind"], "skills");
47064791
assert_eq!(help["action"], "help");
4792+
assert_eq!(help["usage"]["aliases"][0], "/skill");
47074793
assert_eq!(
47084794
help["usage"]["direct_cli"],
47094795
"claw skills [list|install <path>|help|<skill> [args]]"
@@ -4732,8 +4818,12 @@ mod tests {
47324818
super::handle_skills_slash_command(Some("--help"), &cwd).expect("skills help");
47334819
assert!(skills_help
47344820
.contains("Usage /skills [list|install <path>|help|<skill> [args]]"));
4821+
assert!(skills_help.contains("Alias /skill"));
47354822
assert!(skills_help.contains("Invoke /skills help overview -> $help overview"));
47364823
assert!(skills_help.contains("Install root $CLAW_CONFIG_HOME/skills or ~/.claw/skills"));
4824+
assert!(skills_help.contains(".omc/skills"));
4825+
assert!(skills_help.contains(".agents/skills"));
4826+
assert!(skills_help.contains("~/.claude/skills/omc-learned"));
47374827
assert!(skills_help.contains("legacy /commands"));
47384828

47394829
let skills_unexpected =
@@ -4744,6 +4834,7 @@ mod tests {
47444834
.expect("nested skills help");
47454835
assert!(skills_install_help
47464836
.contains("Usage /skills [list|install <path>|help|<skill> [args]]"));
4837+
assert!(skills_install_help.contains("Alias /skill"));
47474838
assert!(skills_install_help.contains("Unexpected install"));
47484839

47494840
let skills_unknown_help =
@@ -4752,9 +4843,87 @@ mod tests {
47524843
.contains("Usage /skills [list|install <path>|help|<skill> [args]]"));
47534844
assert!(skills_unknown_help.contains("Unexpected show"));
47544845

4846+
let skills_help_json =
4847+
super::handle_skills_slash_command_json(Some("help"), &cwd).expect("skills help json");
4848+
let sources = skills_help_json["usage"]["sources"]
4849+
.as_array()
4850+
.expect("skills help sources");
4851+
assert_eq!(skills_help_json["usage"]["aliases"][0], "/skill");
4852+
assert!(sources.iter().any(|value| value == ".omc/skills"));
4853+
assert!(sources.iter().any(|value| value == ".agents/skills"));
4854+
assert!(sources.iter().any(|value| value == "~/.omc/skills"));
4855+
assert!(sources
4856+
.iter()
4857+
.any(|value| value == "~/.claude/skills/omc-learned"));
4858+
47554859
let _ = fs::remove_dir_all(cwd);
47564860
}
47574861

4862+
#[test]
4863+
fn discovers_omc_skills_from_project_and_user_compatibility_roots() {
4864+
let _guard = env_lock().lock().expect("env lock");
4865+
let workspace = temp_dir("skills-omc-workspace");
4866+
let user_home = temp_dir("skills-omc-home");
4867+
let claude_config_dir = temp_dir("skills-omc-claude-config");
4868+
let project_omc_skills = workspace.join(".omc").join("skills");
4869+
let project_agents_skills = workspace.join(".agents").join("skills");
4870+
let user_omc_skills = user_home.join(".omc").join("skills");
4871+
let claude_config_skills = claude_config_dir.join("skills");
4872+
let claude_config_commands = claude_config_dir.join("commands");
4873+
let learned_skills = claude_config_dir.join("skills").join("omc-learned");
4874+
let original_home = std::env::var_os("HOME");
4875+
let original_claude_config_dir = std::env::var_os("CLAUDE_CONFIG_DIR");
4876+
4877+
write_skill(&project_omc_skills, "hud", "OMC HUD guidance");
4878+
write_skill(
4879+
&project_agents_skills,
4880+
"trace",
4881+
"Compatibility skill guidance",
4882+
);
4883+
write_skill(&user_omc_skills, "cancel", "OMC cancel guidance");
4884+
write_skill(
4885+
&claude_config_skills,
4886+
"statusline",
4887+
"Claude config skill guidance",
4888+
);
4889+
write_legacy_command(
4890+
&claude_config_commands,
4891+
"doctor-check",
4892+
"Claude config command guidance",
4893+
);
4894+
write_skill(&learned_skills, "learned", "Learned skill guidance");
4895+
std::env::set_var("HOME", &user_home);
4896+
std::env::set_var("CLAUDE_CONFIG_DIR", &claude_config_dir);
4897+
4898+
let report = super::handle_skills_slash_command(None, &workspace).expect("skills list");
4899+
assert!(report.contains("available skills"));
4900+
assert!(report.contains("hud · OMC HUD guidance"));
4901+
assert!(report.contains("trace · Compatibility skill guidance"));
4902+
assert!(report.contains("cancel · OMC cancel guidance"));
4903+
assert!(report.contains("statusline · Claude config skill guidance"));
4904+
assert!(report.contains("doctor-check · Claude config command guidance · legacy /commands"));
4905+
assert!(report.contains("learned · Learned skill guidance"));
4906+
4907+
let help =
4908+
super::handle_skills_slash_command_json(Some("help"), &workspace).expect("skills help");
4909+
let sources = help["usage"]["sources"]
4910+
.as_array()
4911+
.expect("skills help sources");
4912+
assert_eq!(help["usage"]["aliases"][0], "/skill");
4913+
assert!(sources.iter().any(|value| value == ".omc/skills"));
4914+
assert!(sources.iter().any(|value| value == ".agents/skills"));
4915+
assert!(sources.iter().any(|value| value == "~/.omc/skills"));
4916+
assert!(sources
4917+
.iter()
4918+
.any(|value| value == "~/.claude/skills/omc-learned"));
4919+
4920+
restore_env_var("HOME", original_home);
4921+
restore_env_var("CLAUDE_CONFIG_DIR", original_claude_config_dir);
4922+
let _ = fs::remove_dir_all(workspace);
4923+
let _ = fs::remove_dir_all(user_home);
4924+
let _ = fs::remove_dir_all(claude_config_dir);
4925+
}
4926+
47584927
#[test]
47594928
fn mcp_usage_supports_help_and_unexpected_args() {
47604929
let cwd = temp_dir("mcp-usage");
@@ -4991,7 +5160,7 @@ mod tests {
49915160
let listed = render_skills_report(
49925161
&load_skills_from_roots(&roots).expect("installed skills should load"),
49935162
);
4994-
assert!(listed.contains("User ($CLAW_CONFIG_HOME):"));
5163+
assert!(listed.contains("User config roots:"));
49955164
assert!(listed.contains("help · Helpful skill"));
49965165

49975166
let _ = fs::remove_dir_all(workspace);

0 commit comments

Comments
 (0)