diff options
| author | Ömer Hamid Kamışlı <hamidkamisli@icloud.com> | 2026-08-27 14:30:24 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-08-27 14:30:24 +0300 |
| commit | 7b675f42af35508eab66ac42fe1598628597a893 (patch) | |
| tree | f67d4a863c11c6967df6f4538b9d455bfc105163 /src/detect/mod.rs | |
| parent | d79fd746a96ddb5642939c9727baefce642d78e6 (diff) | |
feat(detect): add muse agent with generic Pick blocked detection (#2489)
* feat(detect): add muse agent with generic Pick blocked detection
Add Muse agent manifests and runtime detection for idle/working/blocked
states. Blocked Pick is generic on footer 'Enter to select' so any
question title/message triggers, fixing missed waiting answer where
previous AND-gated rule required specific hint combos. Cover process
names muse, muse-bin, muse-code variants and YOLO footer.
refs #herdr
* fix(detect): tighten muse manifest and agent lookup
- manifests: change working_esc_interrupt and blocked_approval
from whole_recent to bottom_non_empty_lines(8) to use captured
bottom-buffer controls instead of incidental whole-pane text
- manifests: anchor idle_prompt line_regex to ^\s*⟩\s*$ so working
chrome "⟩ ..." does not match idle
- runtime: restrict muse lookup to explicit aliases
(muse|muse-bin|muse-code|muse-cli), remove starts_with("muse")
fallback that misclassified museum/muse-helper/muser; add
positive/negative identification tests
- keep website mirror identical; verified with agent_detection
manifest check --require-website
refs #2489
refs #2456
* fix(detect): address mjdouglas vendor findings for muse
- manifests: widen pick_request_blocked to bottom_non_empty_lines(8) and add
Enter to toggle for multi-select; add menu_request_blocked for user-opened
pickers (enter confirm/esc go back/esc close/space toggle); add
workspace_trust_blocked for Do you trust dialog; tighten blocked_approval
to footer chrome Allow once/Always allow/Yes proceed; split idle_prompt
into any gate for empty and typed draft and not-gate pick/menu anchors;
change idle_status_fallback from YOLO to model \u00b7 effort \u00b7 cwd shape
- runtime: replace bare muse-bin alias with muse-bin-<version> digit check
to match versioned launcher binary and avoid museum/muse-binary false
positives
- cross-checked with vendor-side captures reported on PR #2489 against
strings in shipped muse-bin binary
refs #2489
* fix(detect): handle path-qualified muse-bin versioned binary
lookup_agent now uses path_basename before matching so a launcher
exec with absolute argv0 like /usr/local/lib/muse/muse-bin-0.1.0-R708.1
is correctly identified. is_muse_versioned_binary also checks basename
so direct path-qualified names succeed without relying on the
argv0_argv fallback path. Prevents missed Muse detection when screen
state and sound overrides are not applied.
refs #2489
* fix(detect): add enter save to muse menu detection
Evidence documents /theme with enter save footer which was not
matched. Add enter save to menu_request_blocked any list and to
idle_prompt not-gate (highlighted row ⟩ <choice> shares glyph) and
keep website mirror in sync. Update evidence comment counts from
four to five.
refs #2489
* docs: add Muse to supported agents table
Muse detection (manifest, process identification, sound)
was added earlier but docs/next agents table omitted the row.
Add Muse as screen manifest / none (no integration hook,
consistent with Amp/Kiro/Maki) to en/ja/zh-cn translations.
* fix(detect): resize agent arrays for new upstream variant
Agent::ALL and SCREEN_MANIFEST_AGENTS gained an entry from master
but kept stale size annotations, breaking compilation after rebase.
refs #2489
* docs: add muse detection entry to next changelog
refs #2489
* docs: add muse sound override to config reference
refs #2489
* fix(detect): prevent false muse blocked states
refs #2489
---------
Co-authored-by: Omer Hamid Kamisli <ohkamisli@poikus.com>
Co-authored-by: Ogulcan Celik <ogulcancelik@gmail.com>
Diffstat (limited to 'src/detect/mod.rs')
| -rw-r--r-- | src/detect/mod.rs | 46 |
1 files changed, 44 insertions, 2 deletions
diff --git a/src/detect/mod.rs b/src/detect/mod.rs index def440dc..0f956ee3 100644 --- a/src/detect/mod.rs +++ b/src/detect/mod.rs @@ -63,10 +63,11 @@ pub enum Agent { Qodercli, Qwen, Maki, + Muse, } impl Agent { - pub const ALL: [Self; 22] = [ + pub const ALL: [Self; 23] = [ Self::Pi, Self::Claude, Self::Codex, @@ -89,9 +90,10 @@ impl Agent { Self::Qodercli, Self::Qwen, Self::Maki, + Self::Muse, ]; - pub const SCREEN_MANIFEST_AGENTS: [Self; 20] = [ + pub const SCREEN_MANIFEST_AGENTS: [Self; 21] = [ Self::Pi, Self::Claude, Self::Codex, @@ -112,6 +114,7 @@ impl Agent { Self::Qodercli, Self::Qwen, Self::Maki, + Self::Muse, ]; } @@ -139,6 +142,7 @@ pub fn agent_label(agent: Agent) -> &'static str { Agent::Qodercli => "qodercli", Agent::Qwen => "qwen", Agent::Maki => "maki", + Agent::Muse => "muse", } } @@ -172,6 +176,7 @@ pub fn interactive_agent_executable(agent: Agent) -> &'static str { Agent::Qodercli => "qodercli", Agent::Qwen => "qwen", Agent::Maki => "maki", + Agent::Muse => "muse", } } @@ -186,6 +191,7 @@ pub(crate) fn parse_canonical_agent_label(label: &str) -> Option<Agent> { } fn lookup_agent(name: &str) -> Option<Agent> { + let name = path_basename(name); match name { "pi" => Some(Agent::Pi), "claude" | "claude-code" => Some(Agent::Claude), @@ -209,10 +215,25 @@ fn lookup_agent(name: &str) -> Option<Agent> { "qodercli" | "qoderclicn" | "qoder" | "qodercn" => Some(Agent::Qodercli), "qwen" | "qwen-code" | "qwen code" => Some(Agent::Qwen), "maki" => Some(Agent::Maki), + "muse" | "muse-code" | "muse-cli" => Some(Agent::Muse), + _ if is_muse_versioned_binary(name) => Some(Agent::Muse), _ => None, } } +/// Muse's install-dir launcher script resolves the active release and execs +/// `muse-bin-<version>` (e.g. `muse-bin-0.1.0-R708.1`), so the running +/// process never carries a bare `muse`/`muse-bin` alias. Require a digit +/// immediately after the `muse-bin-` prefix so unrelated binaries such as +/// `muse-binary` or a bare `muse-bin` stay unmatched. +/// Accepts path-qualified `argv0` values by checking only the basename, since +/// the launcher may `exec` with an absolute install-dir path. +fn is_muse_versioned_binary(name: &str) -> bool { + path_basename(name) + .strip_prefix("muse-bin-") + .is_some_and(|rest| rest.starts_with(|c: char| c.is_ascii_digit())) +} + /// Identify which agent is running from the process name. /// Returns `None` for plain shells or unrecognized programs. pub fn identify_agent(process_name: &str) -> Option<Agent> { @@ -766,6 +787,19 @@ mod tests { assert_eq!(identify_agent("qwen"), Some(Agent::Qwen)); assert_eq!(identify_agent("Qwen Code"), Some(Agent::Qwen)); assert_eq!(identify_agent("maki"), Some(Agent::Maki)); + assert_eq!(identify_agent("muse"), Some(Agent::Muse)); + assert_eq!(identify_agent("muse-code"), Some(Agent::Muse)); + assert_eq!(identify_agent("muse-cli"), Some(Agent::Muse)); + assert_eq!(identify_agent("muse-bin-0.1.0-R708.1"), Some(Agent::Muse)); + assert_eq!(identify_agent("muse-bin-1.2.3"), Some(Agent::Muse)); + assert_eq!( + identify_agent("/home/user/.local/bin/muse-bin-0.2.1-R1215.1"), + Some(Agent::Muse) + ); + assert_eq!( + identify_agent(r"C:\Users\user\muse-bin-0.2.1-R1215.1.exe"), + Some(Agent::Muse) + ); } #[test] @@ -836,6 +870,7 @@ mod tests { (Agent::Qodercli, "qodercli"), (Agent::Qwen, "qwen"), (Agent::Maki, "maki"), + (Agent::Muse, "muse"), ]; assert_eq!(expected.len(), Agent::ALL.len()); for (agent, executable) in expected { @@ -879,6 +914,13 @@ mod tests { assert_eq!(identify_agent("zsh"), None); assert_eq!(identify_agent("vim"), None); assert_eq!(identify_agent("node"), None); + assert_eq!(identify_agent("museum"), None); + assert_eq!(identify_agent("muse-helper"), None); + assert_eq!(identify_agent("muser"), None); + assert_eq!(identify_agent("musescore"), None); + assert_eq!(identify_agent("muse-bin"), None); + assert_eq!(identify_agent("muse-bin-"), None); + assert_eq!(identify_agent("muse-binary"), None); } #[test] |
