feat: add lazy macro resolver with two-dir discovery and per-macro states
Adds src/config/macro_policy.rs: MacroPolicy::effective computes the visible macro set on demand from the discovered definition files, the four-level enabled_macros allowlists, and the built-in command names. - Discovery scans workspace (.coyote/macros/) then global macros dirs on every resolution; workspace shadows global by name, and the shadowed global entry is retained and flagged so both stay listable (plan custom-commands-design.md §5). Workspace scanning is gated on a bool parameter so the future --no-workspace-macros flag wires in one line. - Allowlist precedence is session > agent > role > global, first Some wins, no merging; None falls through, an empty list is an explicit zero, all-None enables everything (mirrors SkillPolicy). - Per-macro states per plan §6: enabled, disabled (runtime, global-level exclusions only), locked (role/agent/session exclusions, recording the owning level), missing (unknown allowlist names warn instead of bailing — deliberate divergence from skills), shadowed (built-in name collisions), and invalid (parse failures and the reserved names enable/disable). Invalid beats allowlist exclusion beats shadowing. - Adds enabled_macros() accessors on Role, Session, and Agent alongside their enabled_skills() counterparts, plus paths::workspace_macros_dir. - 37 tests: state matrix, pairwise precedence, explicit-zero pinned at every level, workspace shadowing, reserved names, builtin collisions, missing rows, invalid YAML, and env-gated discovery (#[serial]).
This commit is contained in:
@@ -368,6 +368,10 @@ impl Role {
|
||||
self.enabled_skills.as_deref()
|
||||
}
|
||||
|
||||
pub fn enabled_macros(&self) -> Option<&[String]> {
|
||||
self.enabled_macros.as_deref()
|
||||
}
|
||||
|
||||
pub fn append_to_prompt(&mut self, text: &str) {
|
||||
self.prompt.push_str(text);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user