diff --git a/AGENTS.md b/AGENTS.md
index 09fbde0..e5b7a10 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -31,7 +31,7 @@ cargo test --manifest-path src-tauri/Cargo.toml
or an agent in Boite). It never reads Boite's files beyond `core.json`.
- Tests and manual runs use a throwaway core on a temporary data folder, never
the data of a Boite someone uses.
-- Native commands check which webview calls them (`only_bots`,
- `only_companion`), and every command is listed in
+- Native commands check which webview calls them (`only_companion`: the
+ companion's window is Bots's only page), and every command is listed in
`src-tauri/permissions/bots.toml` and covered by `src-tauri/src/acl.rs`.
- Quit exits with code 0; any other exit tells Boite to start Bots again.
diff --git a/README.md b/README.md
index 1c85f08..8957dbd 100644
--- a/README.md
+++ b/README.md
@@ -132,10 +132,10 @@ A pomodoro or a timer sits beside it.
### Settings
-Everything else is in **Settings**, from the tray icon: where the robots sit and on which screen, the shortcut, what the pill shows, the mascot and the agents on screen, quotas, pomodoro, missions, sounds and reminders. In English and French.
+Everything else is in **Settings**, a panel that grows out of the open island under its bar, from the bar's gear or the tray icon: where the robots sit and on which screen, the shortcut, what the pill shows, the mascot and the agents on screen, quotas, pomodoro, missions, sounds and reminders. In English and French.
-
+
## Install
@@ -173,7 +173,7 @@ cd src-tauri && cargo test && cargo clippy --all-targets -- -D warnings
The demo runs the robots on Boite's in-memory fake core: no Boite needed.
-- In a browser: `bun run dev`, then open `http://localhost:5174/?fake=1` (add `&hud=1` for busy agents and quotas, or open `?view=settings&fake=1` for the settings).
+- In a browser: `bun run dev`, then open `http://localhost:5174/?fake=1` (add `&hud=1` for busy agents and quotas, or `&pose=settings§ion=crew` for the settings panel on a section).
- In the desktop window: `BOTS_DEMO=1 bun run tauri dev` (`BOTS_DEMO=hud` for the busy version). Development builds only.
In the browser, a few more parameters set a scene for captures: `pose=collapsed|peek|open|deck|desktop|away`, `tab=threads|today|chat|stats|music|apps|clipboard|wallpaper|system`, `calm=1` to answer the starting requests, `music=playing&lyrics=1`, `rest=live|quota|music|timer|robot`, `timer=1`, `todo=1`, `mission=ask|list`, `source=engine|recent|folder` for the wallpapers, `bar=custom` and `edit=1` for the bar, and more. [`src/lib/island/pose.ts`](src/lib/island/pose.ts) lists them all. The pictures of this README were taken that way, with the English interface.
diff --git a/docs/media/settings.png b/docs/media/settings.png
index 156d269..2223e6d 100644
Binary files a/docs/media/settings.png and b/docs/media/settings.png differ
diff --git a/src-tauri/capabilities/settings.json b/src-tauri/capabilities/settings.json
deleted file mode 100644
index 65c7984..0000000
--- a/src-tauri/capabilities/settings.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "$schema": "../gen/schemas/desktop-schema.json",
- "identifier": "settings",
- "description": "The settings window may connect to the core and list the screens. Remote origins receive nothing.",
- "webviews": ["settings"],
- "permissions": ["allow-settings-ui", "core:event:default"]
-}
diff --git a/src-tauri/permissions/bots.toml b/src-tauri/permissions/bots.toml
index 0293698..9de4658 100644
--- a/src-tauri/permissions/bots.toml
+++ b/src-tauri/permissions/bots.toml
@@ -1,6 +1,6 @@
[[permission]]
identifier = "allow-companion-ui"
-description = "Allows the companion to connect to the core, place its window on the desktop or as the island, take clicks where it draws, read the music playing, register its shortcut, see the screen when asked, take the keyboard when files are dropped on it, open its settings and name the tray; and, for the deck's computer tabs, read the system's numbers, close a process, lock, sleep, restart or shut down the computer, list and open the Start menu's apps, keep a clipboard history in memory and copy an entry back, list and set wallpapers, and drive Wallpaper Engine; and, for the island's bar, open a web link the user added there."
+description = "Allows the companion to connect to the core, place its window on the desktop or as the island, take clicks where it draws, read the music playing, register its shortcut, see the screen when asked, take the keyboard when files are dropped on it, open its settings panel and name the tray; and, for the deck's computer tabs, read the system's numbers, close a process, lock, sleep, restart or shut down the computer, list and open the Start menu's apps, keep a clipboard history in memory and copy an entry back, list and set wallpapers, and drive Wallpaper Engine; and, for the island's bar, open a web link the user added there."
commands.allow = [
"core_endpoint",
"companion_monitors",
@@ -42,7 +42,3 @@ commands.allow = [
"computer_engine_control",
]
-[[permission]]
-identifier = "allow-settings-ui"
-description = "Allows the settings window to connect to the core and list the screens the companion can sit on."
-commands.allow = ["core_endpoint", "companion_monitors"]
diff --git a/src-tauri/src/acl.rs b/src-tauri/src/acl.rs
index ed7df57..4e7bb6b 100644
--- a/src-tauri/src/acl.rs
+++ b/src-tauri/src/acl.rs
@@ -34,14 +34,11 @@ mod tests {
}
#[test]
- fn the_settings_window_connects_and_lists_screens_but_does_not_drive_the_companion() {
+ fn the_settings_live_in_the_companion_and_no_settings_webview_is_granted_anything() {
let mut context: tauri::Context = crate::bots_context();
let authority = context.runtime_authority_mut();
- for command in ["core_endpoint", "companion_monitors", "plugin:event|listen", "plugin:event|unlisten"] {
- assert!(authority.resolve_access(command, "settings", "settings", &Origin::Local).is_some(), "settings cannot invoke {command}");
- }
- for command in ["companion_place", "island_place", "companion_capture", "companion_keep", "companion_configure", "bots_tray_labels", "bots_settings"] {
- assert!(authority.resolve_access(command, "settings", "settings", &Origin::Local).is_none(), "settings can invoke {command}");
+ for command in COMPANION {
+ assert!(authority.resolve_access(command, "settings", "settings", &Origin::Local).is_none(), "a settings webview can invoke {command}");
}
}
}
diff --git a/src-tauri/src/companion_window.rs b/src-tauri/src/companion_window.rs
index 7be6ab4..86f8d40 100644
--- a/src-tauri/src/companion_window.rs
+++ b/src-tauri/src/companion_window.rs
@@ -254,7 +254,7 @@ fn place(window: &WebviewWindow, monitor: Option<&str>, anchor: A
/// The page's query: `BOTS_DEMO=1` runs a development build on the fake core,
/// `BOTS_DEMO=hud` with the HUD demo seeded too. A release build ignores it.
-pub fn demo_query() -> &'static str {
+fn demo_query() -> &'static str {
if !cfg!(debug_assertions) { return ""; }
match std::env::var("BOTS_DEMO").as_deref() {
Ok("hud") => "fake=1&hud=1",
@@ -428,12 +428,18 @@ fn watch(app: AppHandle, shared: Shared, mine: u64) {
/// The shortcut, or Bots launched again: the companion comes forward, over a
/// full-screen app too, and the page opens its question bar.
pub fn summon(app: &AppHandle) {
- let Some(window) = app.get_webview_window(LABEL) else { return };
+ if let Some(window) = bring_forward(app) { let _ = window.emit("companion://summon", ()); }
+}
+
+/// The companion's window over the others, with the keyboard, back from
+/// hiding for a full-screen app: for the shortcut and for Settings.
+pub fn bring_forward(app: &AppHandle) -> Option> {
+ let window = app.get_webview_window(LABEL)?;
app.state::().shared.hidden.store(false, Ordering::Release);
let _ = window.show();
crate::platform::keep_on_top(&window);
let _ = window.set_focus();
- let _ = window.emit("companion://summon", ());
+ Some(window)
}
/// Opens the companion, at start. It stays until Bots quits: closing it is
@@ -465,7 +471,7 @@ fn window_of(app: &AppHandle) -> Result {
/// The screens connected now, for the setting that picks one.
#[tauri::command]
pub async fn companion_monitors(app: AppHandle, webview: Webview) -> Result, String> {
- crate::only_bots(&webview)?;
+ only_companion(&webview)?;
let primary = app.primary_monitor().map_err(|error| error.to_string())?.map(|monitor| monitor_name(&monitor));
Ok(app.available_monitors().map_err(|error| error.to_string())?.into_iter().map(|monitor| {
let name = monitor_name(&monitor);
diff --git a/src-tauri/src/endpoint.rs b/src-tauri/src/endpoint.rs
index 5f5caaa..22f543d 100644
--- a/src-tauri/src/endpoint.rs
+++ b/src-tauri/src/endpoint.rs
@@ -108,11 +108,11 @@ fn find() -> Option {
listening(&endpoint.url).then_some(endpoint)
}
-/// The core to connect to, or none yet. Only Bots's own pages may ask: the
-/// answer carries the owner's token.
+/// The core to connect to, or none yet. Only the companion's page may ask:
+/// the answer carries the owner's token.
#[tauri::command]
pub async fn core_endpoint(webview: Webview) -> Result