1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
//! Skills and `/onboard:<topic>` resolve instead of erroring (#889).
//!
//! Every recorded `slash_command` failure was one of these shapes:
//!
//! - `/servers`, `/channels` — skills on disk. `handle_user_command` consulted
//! only `commands.toml`, so no skill could ever resolve and each one reached
//! the "Unknown command" arm.
//! - `/onboard:voice` — the dispatch matched the bare `/onboard` only, so the
//! colon form people actually type fell through.
//! - `/skills` — a real TUI command this tool cannot execute, which belonged in
//! the guidance arm beside `/plan` and `/cowork`.
//!
//! None of these was a failing tool. The tool could not see what it was asked
//! about.
//!
//! Fixtures are synthetic and carry no user identifiers.
use crate::brain::skills::load_all_skills;
#[test]
fn skills_carry_the_slash_form_the_tool_matches_on() {
// Resolution compares `slash_name`, so it must be the `/name` shape or the
// lookup silently never matches.
for s in load_all_skills() {
assert!(
s.slash_name.starts_with('/'),
"skill {:?} has slash_name {:?}",
s.name,
s.slash_name
);
assert_eq!(s.slash_name, format!("/{}", s.name));
}
}
#[test]
fn a_skill_lookup_by_slash_name_succeeds() {
// The exact lookup the tool performs. Uses whichever skills exist rather
// than hard-coding one, so the test does not depend on local install state.
let skills = load_all_skills();
if let Some(first) = skills.first() {
let found = skills.iter().find(|s| s.slash_name == first.slash_name);
assert!(
found.is_some(),
"a skill could not find itself by slash_name"
);
}
}
#[test]
fn direct_setup_commands_route_to_their_step() {
// #1981: the direct commands are what users type now.
use crate::brain::tools::slash_onboard::setup_step_for;
for (cmd, step) in [
("/voice", "voice"),
("/channels", "channels"),
("/image", "image"),
("/brain", "brain"),
("/workspace", "workspace"),
("/daemon", "daemon"),
] {
assert_eq!(setup_step_for(cmd), Some(step), "{cmd}");
}
}
#[test]
fn the_legacy_onboard_colon_form_still_routes() {
// #889 made the colon form resolve; #1981 keeps it as a fallback.
use crate::brain::tools::slash_onboard::setup_step_for;
for (cmd, step) in [
("/onboard:voice", "voice"),
("/onboard:channels", "channels"),
("/onboard:image", "image"),
] {
assert_eq!(setup_step_for(cmd), Some(step), "{cmd}");
}
}
#[test]
fn unrelated_commands_are_not_setup_steps() {
use crate::brain::tools::slash_onboard::setup_step_for;
for c in [
"/onboard",
"/onboard:",
"/onboarding",
"/on",
"/board",
"/models",
"/voices",
] {
assert_eq!(setup_step_for(c), None, "wrongly captured: {c}");
}
}
#[test]
fn typed_args_reach_the_rendered_prompt() {
// #1868: handle_user_command discarded the user's args as `_args`, so
// `/servers staging` executed the skill text with no request attached
// and the agent never saw what the human actually asked for.
use crate::brain::tools::slash_command::with_user_args;
assert_eq!(with_user_args("body".into(), ""), "body");
assert_eq!(with_user_args("body".into(), " "), "body");
assert_eq!(
with_user_args("body".into(), "fix tests"),
"body\n\nUser args: fix tests"
);
}
#[test]
fn the_args_parameter_is_named_not_discarded() {
// Structural pin: the signature must thread args, never mask them with
// `_args`. Owner rule: unused code is removed or used, not underscored.
let src = include_str!("../brain/tools/slash_command.rs");
assert!(
src.contains("fn handle_user_command(&self, command: &str, args: &str)"),
"handle_user_command must take args by name (#1868)"
);
assert!(
!src.contains("_args: &str) -> Result<ToolResult>"),
"the discarded-args shape must not come back"
);
}