replace firefox with chrome (#14)

This commit is contained in:
Hari 2026-03-26 15:25:40 -04:00 committed by GitHub
parent 580ea79c27
commit ff26c57035
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 61 additions and 63 deletions

View file

@ -37,9 +37,9 @@ preferred read surface for focused state queries.
## Wait for state transitions
```sh
deskctl wait window --selector 'title=Firefox' --timeout 10
deskctl wait window --selector 'title=Chromium' --timeout 10
deskctl wait focus --selector 'id=win3' --timeout 5
deskctl --json wait window --selector 'class=firefox' --poll-ms 100
deskctl --json wait window --selector 'class=chromium' --poll-ms 100
```
Wait commands return the matched window payload on success. In `--json` mode,
@ -48,9 +48,9 @@ timeouts and selector failures expose structured `kind` values.
## Act on windows
```sh
deskctl launch firefox
deskctl launch chromium
deskctl focus @w1
deskctl focus 'title=Firefox'
deskctl focus 'title=Chromium'
deskctl click @w1
deskctl click 960,540
deskctl dblclick @w2
@ -86,8 +86,8 @@ more deterministic for automation, and easier to retry safely.
```sh
ref=w1
id=win1
title=Firefox
class=firefox
title=Chromium
class=chromium
focused
```
@ -99,7 +99,7 @@ w1
win1
```
Bare strings like `firefox` are fuzzy matches. They resolve when there is one
Bare strings like `chromium` are fuzzy matches. They resolve when there is one
match and fail with candidate windows when there are multiple matches.
## Global options

View file

@ -38,13 +38,13 @@ Prefer explicit selectors when you need deterministic targeting:
```sh
ref=w1
id=win1
title=Firefox
class=firefox
title=Chromium
class=chromium
focused
```
Legacy refs such as `@w1` still work after `snapshot` or `list-windows`. Bare
strings like `firefox` are fuzzy matches and now fail on ambiguity.
strings like `chromium` are fuzzy matches and now fail on ambiguity.
## 4. Wait, act, verify
@ -55,16 +55,16 @@ The core loop is:
deskctl snapshot --annotate
# wait
deskctl wait window --selector 'title=Firefox' --timeout 10
deskctl wait window --selector 'title=Chromium' --timeout 10
# act
deskctl focus 'title=Firefox'
deskctl focus 'title=Chromium'
deskctl hotkey ctrl l
deskctl type "https://example.com"
deskctl press enter
# verify
deskctl wait focus --selector 'title=Firefox' --timeout 5
deskctl wait focus --selector 'title=Chromium' --timeout 5
deskctl snapshot
```
@ -84,8 +84,8 @@ Every command supports `--json` and uses the same top-level envelope:
{
"ref_id": "w1",
"window_id": "win1",
"title": "Firefox",
"app_name": "firefox",
"title": "Chromium",
"app_name": "chromium",
"x": 0,
"y": 0,
"width": 1920,

View file

@ -30,8 +30,8 @@ Every desktop interaction follows: **observe -> wait -> act -> verify**.
```bash
deskctl snapshot --annotate # observe
deskctl wait window --selector 'title=Firefox' --timeout 10 # wait
deskctl click 'title=Firefox' # act
deskctl wait window --selector 'title=Chromium' --timeout 10 # wait
deskctl click 'title=Chromium' # act
deskctl snapshot # verify
```
@ -42,12 +42,12 @@ See [workflows/observe-act.sh](workflows/observe-act.sh) for a reusable script.
```bash
ref=w1 # snapshot ref (short-lived)
id=win1 # stable window ID (session-scoped)
title=Firefox # match by title
class=firefox # match by WM class
title=Chromium # match by title
class=chromium # match by WM class
focused # currently focused window
```
Bare strings like `firefox` do fuzzy matching but fail on ambiguity. Prefer explicit selectors.
Bare strings like `chromium` do fuzzy matching but fail on ambiguity. Prefer explicit selectors.
## References

View file

@ -23,8 +23,8 @@ deskctl get-mouse-position
## Wait
```bash
deskctl wait window --selector 'title=Firefox' --timeout 10
deskctl wait focus --selector 'class=firefox' --timeout 5
deskctl wait window --selector 'title=Chromium' --timeout 10
deskctl wait focus --selector 'class=chromium' --timeout 5
```
Returns the matched window payload on success. Failures include structured
@ -35,8 +35,8 @@ Returns the matched window payload on success. Failures include structured
```bash
ref=w1
id=win1
title=Firefox
class=firefox
title=Chromium
class=chromium
focused
```
@ -46,7 +46,7 @@ on ambiguity.
## Act
```bash
deskctl focus 'class=firefox'
deskctl focus 'class=chromium'
deskctl click @w1
deskctl dblclick @w2
deskctl type "hello world"
@ -59,7 +59,7 @@ deskctl mouse drag 100 100 500 500
deskctl move-window @w1 100 120
deskctl resize-window @w1 1280 720
deskctl close @w3
deskctl launch firefox
deskctl launch chromium
```
The daemon starts automatically on first command. In normal usage you should

View file

@ -1,7 +1,7 @@
#!/usr/bin/env bash
# observe-act.sh - main desktop interaction loop
# usage: ./observe-act.sh <selector> [action] [action-args...]
# example: ./observe-act.sh 'title=Firefox' click
# example: ./observe-act.sh 'title=Chromium' click
# example: ./observe-act.sh 'class=terminal' type "ls -la"
set -euo pipefail

View file

@ -48,13 +48,13 @@ pub enum Command {
/// Click a window ref or coordinates
#[command(after_help = CLICK_EXAMPLES)]
Click {
/// Selector (ref=w1, id=win1, title=Firefox, class=firefox, focused) or x,y coordinates
/// Selector (ref=w1, id=win1, title=Chromium, class=chromium, focused) or x,y coordinates
selector: String,
},
/// Double-click a window ref or coordinates
#[command(after_help = DBLCLICK_EXAMPLES)]
Dblclick {
/// Selector (ref=w1, id=win1, title=Firefox, class=firefox, focused) or x,y coordinates
/// Selector (ref=w1, id=win1, title=Chromium, class=chromium, focused) or x,y coordinates
selector: String,
},
/// Type text into the focused window
@ -81,19 +81,19 @@ pub enum Command {
/// Focus a window by ref or name
#[command(after_help = FOCUS_EXAMPLES)]
Focus {
/// Selector: ref=w1, id=win1, title=Firefox, class=firefox, focused, or a fuzzy substring
/// Selector: ref=w1, id=win1, title=Chromium, class=chromium, focused, or a fuzzy substring
selector: String,
},
/// Close a window by ref or name
#[command(after_help = CLOSE_EXAMPLES)]
Close {
/// Selector: ref=w1, id=win1, title=Firefox, class=firefox, focused, or a fuzzy substring
/// Selector: ref=w1, id=win1, title=Chromium, class=chromium, focused, or a fuzzy substring
selector: String,
},
/// Move a window
#[command(after_help = MOVE_WINDOW_EXAMPLES)]
MoveWindow {
/// Selector: ref=w1, id=win1, title=Firefox, class=firefox, focused, or a fuzzy substring
/// Selector: ref=w1, id=win1, title=Chromium, class=chromium, focused, or a fuzzy substring
selector: String,
/// X position
x: i32,
@ -103,7 +103,7 @@ pub enum Command {
/// Resize a window
#[command(after_help = RESIZE_WINDOW_EXAMPLES)]
ResizeWindow {
/// Selector: ref=w1, id=win1, title=Firefox, class=firefox, focused, or a fuzzy substring
/// Selector: ref=w1, id=win1, title=Chromium, class=chromium, focused, or a fuzzy substring
selector: String,
/// Width
w: u32,
@ -210,19 +210,19 @@ const SNAPSHOT_EXAMPLES: &str =
const LIST_WINDOWS_EXAMPLES: &str =
"Examples:\n deskctl list-windows\n deskctl --json list-windows";
const CLICK_EXAMPLES: &str =
"Examples:\n deskctl click @w1\n deskctl click 'title=Firefox'\n deskctl click 500,300";
"Examples:\n deskctl click @w1\n deskctl click 'title=Chromium'\n deskctl click 500,300";
const DBLCLICK_EXAMPLES: &str =
"Examples:\n deskctl dblclick @w2\n deskctl dblclick 'class=firefox'\n deskctl dblclick 500,300";
"Examples:\n deskctl dblclick @w2\n deskctl dblclick 'class=chromium'\n deskctl dblclick 500,300";
const TYPE_EXAMPLES: &str =
"Examples:\n deskctl type \"hello world\"\n deskctl type \"https://example.com\"";
const PRESS_EXAMPLES: &str = "Examples:\n deskctl press enter\n deskctl press escape";
const HOTKEY_EXAMPLES: &str = "Examples:\n deskctl hotkey ctrl l\n deskctl hotkey ctrl shift t";
const FOCUS_EXAMPLES: &str =
"Examples:\n deskctl focus @w1\n deskctl focus 'title=Firefox'\n deskctl focus focused";
"Examples:\n deskctl focus @w1\n deskctl focus 'title=Chromium'\n deskctl focus focused";
const CLOSE_EXAMPLES: &str =
"Examples:\n deskctl close @w3\n deskctl close 'id=win2'\n deskctl close 'class=firefox'";
"Examples:\n deskctl close @w3\n deskctl close 'id=win2'\n deskctl close 'class=chromium'";
const MOVE_WINDOW_EXAMPLES: &str =
"Examples:\n deskctl move-window @w1 100 200\n deskctl move-window 'title=Firefox' 0 0";
"Examples:\n deskctl move-window @w1 100 200\n deskctl move-window 'title=Chromium' 0 0";
const RESIZE_WINDOW_EXAMPLES: &str =
"Examples:\n deskctl resize-window @w1 1280 720\n deskctl resize-window 'id=win2' 800 600";
const GET_MONITORS_EXAMPLES: &str =
@ -237,12 +237,12 @@ const GET_MOUSE_POSITION_EXAMPLES: &str =
const DOCTOR_EXAMPLES: &str = "Examples:\n deskctl doctor\n deskctl --json doctor";
const UPGRADE_EXAMPLES: &str =
"Examples:\n deskctl upgrade\n deskctl upgrade --yes\n deskctl --json upgrade --yes";
const WAIT_WINDOW_EXAMPLES: &str = "Examples:\n deskctl wait window --selector 'title=Firefox' --timeout 10\n deskctl --json wait window --selector 'class=firefox' --poll-ms 100";
const WAIT_WINDOW_EXAMPLES: &str = "Examples:\n deskctl wait window --selector 'title=Chromium' --timeout 10\n deskctl --json wait window --selector 'class=chromium' --poll-ms 100";
const WAIT_FOCUS_EXAMPLES: &str = "Examples:\n deskctl wait focus --selector 'id=win3' --timeout 5\n deskctl wait focus --selector focused --poll-ms 200";
const SCREENSHOT_EXAMPLES: &str =
"Examples:\n deskctl screenshot\n deskctl screenshot /tmp/screen.png\n deskctl screenshot --annotate";
const LAUNCH_EXAMPLES: &str =
"Examples:\n deskctl launch firefox\n deskctl launch code -- --new-window";
"Examples:\n deskctl launch chromium\n deskctl launch code -- --new-window";
const MOUSE_MOVE_EXAMPLES: &str =
"Examples:\n deskctl mouse move 500 300\n deskctl mouse move 0 0";
const MOUSE_SCROLL_EXAMPLES: &str =
@ -277,7 +277,7 @@ pub enum WaitCmd {
#[derive(Args)]
pub struct WaitSelectorOpts {
/// Selector: ref=w1, id=win1, title=Firefox, class=firefox, focused, or a fuzzy substring
/// Selector: ref=w1, id=win1, title=Chromium, class=chromium, focused, or a fuzzy substring
#[arg(long)]
pub selector: String,
@ -1103,8 +1103,8 @@ mod tests {
"windows": [{
"ref_id": "w1",
"window_id": "win1",
"title": "Firefox",
"app_name": "firefox",
"title": "Chromium",
"app_name": "chromium",
"x": 0,
"y": 0,
"width": 1280,
@ -1125,37 +1125,37 @@ mod tests {
fn action_text_includes_target_identity() {
let lines = render_success_lines(
&Command::Focus {
selector: "title=Firefox".to_string(),
selector: "title=Chromium".to_string(),
},
Some(&json!({
"action": "focus",
"window": "Firefox",
"title": "Firefox",
"window": "Chromium",
"title": "Chromium",
"ref_id": "w2",
"window_id": "win7"
})),
)
.unwrap();
assert_eq!(lines, vec!["Focused @w2 [win7] \"Firefox\""]);
assert_eq!(lines, vec!["Focused @w2 [win7] \"Chromium\""]);
}
#[test]
fn timeout_errors_render_last_observation() {
let lines = render_error_lines(&Response::err_with_data(
"Timed out waiting for focus to match selector: title=Firefox",
"Timed out waiting for focus to match selector: title=Chromium",
json!({
"kind": "timeout",
"wait": "focus",
"selector": "title=Firefox",
"selector": "title=Chromium",
"timeout_ms": 1000,
"last_observation": {
"kind": "window_not_focused",
"window": {
"ref_id": "w1",
"window_id": "win1",
"title": "Firefox",
"app_name": "firefox",
"title": "Chromium",
"app_name": "chromium",
"x": 0,
"y": 0,
"width": 1280,
@ -1167,10 +1167,8 @@ mod tests {
}),
));
assert!(lines
.iter()
.any(|line| line
.contains("Timed out after 1000ms waiting for focus selector title=Firefox")));
assert!(lines.iter().any(|line| line
.contains("Timed out after 1000ms waiting for focus selector title=Chromium")));
assert!(lines
.iter()
.any(|line| line.contains("matching window exists but is not focused yet")));
@ -1190,9 +1188,9 @@ mod tests {
let summary = target_summary(&json!({
"ref_id": "w1",
"window_id": "win1",
"title": "Firefox"
"title": "Chromium"
}));
assert_eq!(summary.as_deref(), Some("@w1 [win1] \"Firefox\""));
assert_eq!(summary.as_deref(), Some("@w1 [win1] \"Chromium\""));
}
#[test]

View file

@ -412,8 +412,8 @@ mod tests {
SelectorQuery::WindowId("win4".to_string())
);
assert_eq!(
SelectorQuery::parse("title=Firefox"),
SelectorQuery::Title("Firefox".to_string())
SelectorQuery::parse("title=Chromium"),
SelectorQuery::Title("Chromium".to_string())
);
assert_eq!(
SelectorQuery::parse("class=Navigator"),
@ -458,11 +458,11 @@ mod tests {
fn fuzzy_resolution_fails_with_candidates_when_ambiguous() {
let mut refs = RefMap::new();
refs.rebuild(&[
sample_window(1, "Firefox"),
sample_window(1, "Chromium"),
BackendWindow {
native_id: 2,
title: "Firefox Settings".to_string(),
app_name: "Firefox".to_string(),
title: "Chromium Settings".to_string(),
app_name: "Chromium".to_string(),
x: 0,
y: 0,
width: 10,
@ -472,7 +472,7 @@ mod tests {
},
]);
match refs.resolve("firefox") {
match refs.resolve("chromium") {
ResolveResult::Ambiguous {
mode, candidates, ..
} => {