diff --git a/desktop/src-tauri/Cargo.lock b/desktop/src-tauri/Cargo.lock index 45bbcf71f..995d6b790 100644 --- a/desktop/src-tauri/Cargo.lock +++ b/desktop/src-tauri/Cargo.lock @@ -1028,6 +1028,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix", + "windows-link 0.2.1", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -1160,6 +1170,24 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +[[package]] +name = "global-hotkey" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9247516746aa8e53411a0db9b62b0e24efbcf6a76e0ba73e5a91b512ddabed7" +dependencies = [ + "crossbeam-channel", + "keyboard-types", + "objc2", + "objc2-app-kit", + "once_cell", + "serde", + "thiserror 2.0.18", + "windows-sys 0.59.0", + "x11rb", + "xkeysym", +] + [[package]] name = "gobject-sys" version = "0.18.0" @@ -1749,6 +1777,12 @@ dependencies = [ "libc", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "litemap" version = "0.8.1" @@ -2769,6 +2803,19 @@ dependencies = [ "semver", ] +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + [[package]] name = "rustversion" version = "1.0.22" @@ -3227,6 +3274,7 @@ dependencies = [ "serde_json", "tauri", "tauri-build", + "tauri-plugin-global-shortcut", "tauri-plugin-shell", "tracing", "tracing-subscriber", @@ -3545,6 +3593,21 @@ dependencies = [ "walkdir", ] +[[package]] +name = "tauri-plugin-global-shortcut" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "424af23c7e88d05e4a1a6fc2c7be077912f8c76bd7900fd50aa2b7cbf5a2c405" +dependencies = [ + "global-hotkey", + "log", + "serde", + "serde_json", + "tauri", + "tauri-plugin", + "thiserror 2.0.18", +] + [[package]] name = "tauri-plugin-shell" version = "2.3.5" @@ -5060,6 +5123,29 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "gethostname", + "rustix", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + [[package]] name = "yoke" version = "0.8.1" diff --git a/desktop/src-tauri/Cargo.toml b/desktop/src-tauri/Cargo.toml index 9c5943e05..477d4c2b2 100644 --- a/desktop/src-tauri/Cargo.toml +++ b/desktop/src-tauri/Cargo.toml @@ -9,6 +9,7 @@ path = "src/main.rs" [dependencies] tauri = { version = "2", features = ["macos-private-api"] } +tauri-plugin-global-shortcut = "2" tauri-plugin-shell = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" diff --git a/desktop/src-tauri/gen/schemas/acl-manifests.json b/desktop/src-tauri/gen/schemas/acl-manifests.json index 86cdb1f5f..96d86d645 100644 --- a/desktop/src-tauri/gen/schemas/acl-manifests.json +++ b/desktop/src-tauri/gen/schemas/acl-manifests.json @@ -1 +1 @@ -{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"shell":{"default_permission":{"identifier":"default","description":"This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n","permissions":["allow-open"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"allow-kill":{"identifier":"allow-kill","description":"Enables the kill command without any pre-configured scope.","commands":{"allow":["kill"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-spawn":{"identifier":"allow-spawn","description":"Enables the spawn command without any pre-configured scope.","commands":{"allow":["spawn"],"deny":[]}},"allow-stdin-write":{"identifier":"allow-stdin-write","description":"Enables the stdin_write command without any pre-configured scope.","commands":{"allow":["stdin_write"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}},"deny-kill":{"identifier":"deny-kill","description":"Denies the kill command without any pre-configured scope.","commands":{"allow":[],"deny":["kill"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-spawn":{"identifier":"deny-spawn","description":"Denies the spawn command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn"]}},"deny-stdin-write":{"identifier":"deny-stdin-write","description":"Denies the stdin_write command without any pre-configured scope.","commands":{"allow":[],"deny":["stdin_write"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}}} \ No newline at end of file +{"core":{"default_permission":{"identifier":"default","description":"Default core plugins set.","permissions":["core:path:default","core:event:default","core:window:default","core:webview:default","core:app:default","core:image:default","core:resources:default","core:menu:default","core:tray:default"]},"permissions":{},"permission_sets":{},"global_scope_schema":null},"core:app":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-version","allow-name","allow-tauri-version","allow-identifier","allow-bundle-type","allow-register-listener","allow-remove-listener"]},"permissions":{"allow-app-hide":{"identifier":"allow-app-hide","description":"Enables the app_hide command without any pre-configured scope.","commands":{"allow":["app_hide"],"deny":[]}},"allow-app-show":{"identifier":"allow-app-show","description":"Enables the app_show command without any pre-configured scope.","commands":{"allow":["app_show"],"deny":[]}},"allow-bundle-type":{"identifier":"allow-bundle-type","description":"Enables the bundle_type command without any pre-configured scope.","commands":{"allow":["bundle_type"],"deny":[]}},"allow-default-window-icon":{"identifier":"allow-default-window-icon","description":"Enables the default_window_icon command without any pre-configured scope.","commands":{"allow":["default_window_icon"],"deny":[]}},"allow-fetch-data-store-identifiers":{"identifier":"allow-fetch-data-store-identifiers","description":"Enables the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":["fetch_data_store_identifiers"],"deny":[]}},"allow-identifier":{"identifier":"allow-identifier","description":"Enables the identifier command without any pre-configured scope.","commands":{"allow":["identifier"],"deny":[]}},"allow-name":{"identifier":"allow-name","description":"Enables the name command without any pre-configured scope.","commands":{"allow":["name"],"deny":[]}},"allow-register-listener":{"identifier":"allow-register-listener","description":"Enables the register_listener command without any pre-configured scope.","commands":{"allow":["register_listener"],"deny":[]}},"allow-remove-data-store":{"identifier":"allow-remove-data-store","description":"Enables the remove_data_store command without any pre-configured scope.","commands":{"allow":["remove_data_store"],"deny":[]}},"allow-remove-listener":{"identifier":"allow-remove-listener","description":"Enables the remove_listener command without any pre-configured scope.","commands":{"allow":["remove_listener"],"deny":[]}},"allow-set-app-theme":{"identifier":"allow-set-app-theme","description":"Enables the set_app_theme command without any pre-configured scope.","commands":{"allow":["set_app_theme"],"deny":[]}},"allow-set-dock-visibility":{"identifier":"allow-set-dock-visibility","description":"Enables the set_dock_visibility command without any pre-configured scope.","commands":{"allow":["set_dock_visibility"],"deny":[]}},"allow-tauri-version":{"identifier":"allow-tauri-version","description":"Enables the tauri_version command without any pre-configured scope.","commands":{"allow":["tauri_version"],"deny":[]}},"allow-version":{"identifier":"allow-version","description":"Enables the version command without any pre-configured scope.","commands":{"allow":["version"],"deny":[]}},"deny-app-hide":{"identifier":"deny-app-hide","description":"Denies the app_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["app_hide"]}},"deny-app-show":{"identifier":"deny-app-show","description":"Denies the app_show command without any pre-configured scope.","commands":{"allow":[],"deny":["app_show"]}},"deny-bundle-type":{"identifier":"deny-bundle-type","description":"Denies the bundle_type command without any pre-configured scope.","commands":{"allow":[],"deny":["bundle_type"]}},"deny-default-window-icon":{"identifier":"deny-default-window-icon","description":"Denies the default_window_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["default_window_icon"]}},"deny-fetch-data-store-identifiers":{"identifier":"deny-fetch-data-store-identifiers","description":"Denies the fetch_data_store_identifiers command without any pre-configured scope.","commands":{"allow":[],"deny":["fetch_data_store_identifiers"]}},"deny-identifier":{"identifier":"deny-identifier","description":"Denies the identifier command without any pre-configured scope.","commands":{"allow":[],"deny":["identifier"]}},"deny-name":{"identifier":"deny-name","description":"Denies the name command without any pre-configured scope.","commands":{"allow":[],"deny":["name"]}},"deny-register-listener":{"identifier":"deny-register-listener","description":"Denies the register_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["register_listener"]}},"deny-remove-data-store":{"identifier":"deny-remove-data-store","description":"Denies the remove_data_store command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_data_store"]}},"deny-remove-listener":{"identifier":"deny-remove-listener","description":"Denies the remove_listener command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_listener"]}},"deny-set-app-theme":{"identifier":"deny-set-app-theme","description":"Denies the set_app_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_app_theme"]}},"deny-set-dock-visibility":{"identifier":"deny-set-dock-visibility","description":"Denies the set_dock_visibility command without any pre-configured scope.","commands":{"allow":[],"deny":["set_dock_visibility"]}},"deny-tauri-version":{"identifier":"deny-tauri-version","description":"Denies the tauri_version command without any pre-configured scope.","commands":{"allow":[],"deny":["tauri_version"]}},"deny-version":{"identifier":"deny-version","description":"Denies the version command without any pre-configured scope.","commands":{"allow":[],"deny":["version"]}}},"permission_sets":{},"global_scope_schema":null},"core:event":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-listen","allow-unlisten","allow-emit","allow-emit-to"]},"permissions":{"allow-emit":{"identifier":"allow-emit","description":"Enables the emit command without any pre-configured scope.","commands":{"allow":["emit"],"deny":[]}},"allow-emit-to":{"identifier":"allow-emit-to","description":"Enables the emit_to command without any pre-configured scope.","commands":{"allow":["emit_to"],"deny":[]}},"allow-listen":{"identifier":"allow-listen","description":"Enables the listen command without any pre-configured scope.","commands":{"allow":["listen"],"deny":[]}},"allow-unlisten":{"identifier":"allow-unlisten","description":"Enables the unlisten command without any pre-configured scope.","commands":{"allow":["unlisten"],"deny":[]}},"deny-emit":{"identifier":"deny-emit","description":"Denies the emit command without any pre-configured scope.","commands":{"allow":[],"deny":["emit"]}},"deny-emit-to":{"identifier":"deny-emit-to","description":"Denies the emit_to command without any pre-configured scope.","commands":{"allow":[],"deny":["emit_to"]}},"deny-listen":{"identifier":"deny-listen","description":"Denies the listen command without any pre-configured scope.","commands":{"allow":[],"deny":["listen"]}},"deny-unlisten":{"identifier":"deny-unlisten","description":"Denies the unlisten command without any pre-configured scope.","commands":{"allow":[],"deny":["unlisten"]}}},"permission_sets":{},"global_scope_schema":null},"core:image":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-from-bytes","allow-from-path","allow-rgba","allow-size"]},"permissions":{"allow-from-bytes":{"identifier":"allow-from-bytes","description":"Enables the from_bytes command without any pre-configured scope.","commands":{"allow":["from_bytes"],"deny":[]}},"allow-from-path":{"identifier":"allow-from-path","description":"Enables the from_path command without any pre-configured scope.","commands":{"allow":["from_path"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-rgba":{"identifier":"allow-rgba","description":"Enables the rgba command without any pre-configured scope.","commands":{"allow":["rgba"],"deny":[]}},"allow-size":{"identifier":"allow-size","description":"Enables the size command without any pre-configured scope.","commands":{"allow":["size"],"deny":[]}},"deny-from-bytes":{"identifier":"deny-from-bytes","description":"Denies the from_bytes command without any pre-configured scope.","commands":{"allow":[],"deny":["from_bytes"]}},"deny-from-path":{"identifier":"deny-from-path","description":"Denies the from_path command without any pre-configured scope.","commands":{"allow":[],"deny":["from_path"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-rgba":{"identifier":"deny-rgba","description":"Denies the rgba command without any pre-configured scope.","commands":{"allow":[],"deny":["rgba"]}},"deny-size":{"identifier":"deny-size","description":"Denies the size command without any pre-configured scope.","commands":{"allow":[],"deny":["size"]}}},"permission_sets":{},"global_scope_schema":null},"core:menu":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-append","allow-prepend","allow-insert","allow-remove","allow-remove-at","allow-items","allow-get","allow-popup","allow-create-default","allow-set-as-app-menu","allow-set-as-window-menu","allow-text","allow-set-text","allow-is-enabled","allow-set-enabled","allow-set-accelerator","allow-set-as-windows-menu-for-nsapp","allow-set-as-help-menu-for-nsapp","allow-is-checked","allow-set-checked","allow-set-icon"]},"permissions":{"allow-append":{"identifier":"allow-append","description":"Enables the append command without any pre-configured scope.","commands":{"allow":["append"],"deny":[]}},"allow-create-default":{"identifier":"allow-create-default","description":"Enables the create_default command without any pre-configured scope.","commands":{"allow":["create_default"],"deny":[]}},"allow-get":{"identifier":"allow-get","description":"Enables the get command without any pre-configured scope.","commands":{"allow":["get"],"deny":[]}},"allow-insert":{"identifier":"allow-insert","description":"Enables the insert command without any pre-configured scope.","commands":{"allow":["insert"],"deny":[]}},"allow-is-checked":{"identifier":"allow-is-checked","description":"Enables the is_checked command without any pre-configured scope.","commands":{"allow":["is_checked"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-items":{"identifier":"allow-items","description":"Enables the items command without any pre-configured scope.","commands":{"allow":["items"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-popup":{"identifier":"allow-popup","description":"Enables the popup command without any pre-configured scope.","commands":{"allow":["popup"],"deny":[]}},"allow-prepend":{"identifier":"allow-prepend","description":"Enables the prepend command without any pre-configured scope.","commands":{"allow":["prepend"],"deny":[]}},"allow-remove":{"identifier":"allow-remove","description":"Enables the remove command without any pre-configured scope.","commands":{"allow":["remove"],"deny":[]}},"allow-remove-at":{"identifier":"allow-remove-at","description":"Enables the remove_at command without any pre-configured scope.","commands":{"allow":["remove_at"],"deny":[]}},"allow-set-accelerator":{"identifier":"allow-set-accelerator","description":"Enables the set_accelerator command without any pre-configured scope.","commands":{"allow":["set_accelerator"],"deny":[]}},"allow-set-as-app-menu":{"identifier":"allow-set-as-app-menu","description":"Enables the set_as_app_menu command without any pre-configured scope.","commands":{"allow":["set_as_app_menu"],"deny":[]}},"allow-set-as-help-menu-for-nsapp":{"identifier":"allow-set-as-help-menu-for-nsapp","description":"Enables the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_help_menu_for_nsapp"],"deny":[]}},"allow-set-as-window-menu":{"identifier":"allow-set-as-window-menu","description":"Enables the set_as_window_menu command without any pre-configured scope.","commands":{"allow":["set_as_window_menu"],"deny":[]}},"allow-set-as-windows-menu-for-nsapp":{"identifier":"allow-set-as-windows-menu-for-nsapp","description":"Enables the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":["set_as_windows_menu_for_nsapp"],"deny":[]}},"allow-set-checked":{"identifier":"allow-set-checked","description":"Enables the set_checked command without any pre-configured scope.","commands":{"allow":["set_checked"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-text":{"identifier":"allow-set-text","description":"Enables the set_text command without any pre-configured scope.","commands":{"allow":["set_text"],"deny":[]}},"allow-text":{"identifier":"allow-text","description":"Enables the text command without any pre-configured scope.","commands":{"allow":["text"],"deny":[]}},"deny-append":{"identifier":"deny-append","description":"Denies the append command without any pre-configured scope.","commands":{"allow":[],"deny":["append"]}},"deny-create-default":{"identifier":"deny-create-default","description":"Denies the create_default command without any pre-configured scope.","commands":{"allow":[],"deny":["create_default"]}},"deny-get":{"identifier":"deny-get","description":"Denies the get command without any pre-configured scope.","commands":{"allow":[],"deny":["get"]}},"deny-insert":{"identifier":"deny-insert","description":"Denies the insert command without any pre-configured scope.","commands":{"allow":[],"deny":["insert"]}},"deny-is-checked":{"identifier":"deny-is-checked","description":"Denies the is_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["is_checked"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-items":{"identifier":"deny-items","description":"Denies the items command without any pre-configured scope.","commands":{"allow":[],"deny":["items"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-popup":{"identifier":"deny-popup","description":"Denies the popup command without any pre-configured scope.","commands":{"allow":[],"deny":["popup"]}},"deny-prepend":{"identifier":"deny-prepend","description":"Denies the prepend command without any pre-configured scope.","commands":{"allow":[],"deny":["prepend"]}},"deny-remove":{"identifier":"deny-remove","description":"Denies the remove command without any pre-configured scope.","commands":{"allow":[],"deny":["remove"]}},"deny-remove-at":{"identifier":"deny-remove-at","description":"Denies the remove_at command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_at"]}},"deny-set-accelerator":{"identifier":"deny-set-accelerator","description":"Denies the set_accelerator command without any pre-configured scope.","commands":{"allow":[],"deny":["set_accelerator"]}},"deny-set-as-app-menu":{"identifier":"deny-set-as-app-menu","description":"Denies the set_as_app_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_app_menu"]}},"deny-set-as-help-menu-for-nsapp":{"identifier":"deny-set-as-help-menu-for-nsapp","description":"Denies the set_as_help_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_help_menu_for_nsapp"]}},"deny-set-as-window-menu":{"identifier":"deny-set-as-window-menu","description":"Denies the set_as_window_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_window_menu"]}},"deny-set-as-windows-menu-for-nsapp":{"identifier":"deny-set-as-windows-menu-for-nsapp","description":"Denies the set_as_windows_menu_for_nsapp command without any pre-configured scope.","commands":{"allow":[],"deny":["set_as_windows_menu_for_nsapp"]}},"deny-set-checked":{"identifier":"deny-set-checked","description":"Denies the set_checked command without any pre-configured scope.","commands":{"allow":[],"deny":["set_checked"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-text":{"identifier":"deny-set-text","description":"Denies the set_text command without any pre-configured scope.","commands":{"allow":[],"deny":["set_text"]}},"deny-text":{"identifier":"deny-text","description":"Denies the text command without any pre-configured scope.","commands":{"allow":[],"deny":["text"]}}},"permission_sets":{},"global_scope_schema":null},"core:path":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-resolve-directory","allow-resolve","allow-normalize","allow-join","allow-dirname","allow-extname","allow-basename","allow-is-absolute"]},"permissions":{"allow-basename":{"identifier":"allow-basename","description":"Enables the basename command without any pre-configured scope.","commands":{"allow":["basename"],"deny":[]}},"allow-dirname":{"identifier":"allow-dirname","description":"Enables the dirname command without any pre-configured scope.","commands":{"allow":["dirname"],"deny":[]}},"allow-extname":{"identifier":"allow-extname","description":"Enables the extname command without any pre-configured scope.","commands":{"allow":["extname"],"deny":[]}},"allow-is-absolute":{"identifier":"allow-is-absolute","description":"Enables the is_absolute command without any pre-configured scope.","commands":{"allow":["is_absolute"],"deny":[]}},"allow-join":{"identifier":"allow-join","description":"Enables the join command without any pre-configured scope.","commands":{"allow":["join"],"deny":[]}},"allow-normalize":{"identifier":"allow-normalize","description":"Enables the normalize command without any pre-configured scope.","commands":{"allow":["normalize"],"deny":[]}},"allow-resolve":{"identifier":"allow-resolve","description":"Enables the resolve command without any pre-configured scope.","commands":{"allow":["resolve"],"deny":[]}},"allow-resolve-directory":{"identifier":"allow-resolve-directory","description":"Enables the resolve_directory command without any pre-configured scope.","commands":{"allow":["resolve_directory"],"deny":[]}},"deny-basename":{"identifier":"deny-basename","description":"Denies the basename command without any pre-configured scope.","commands":{"allow":[],"deny":["basename"]}},"deny-dirname":{"identifier":"deny-dirname","description":"Denies the dirname command without any pre-configured scope.","commands":{"allow":[],"deny":["dirname"]}},"deny-extname":{"identifier":"deny-extname","description":"Denies the extname command without any pre-configured scope.","commands":{"allow":[],"deny":["extname"]}},"deny-is-absolute":{"identifier":"deny-is-absolute","description":"Denies the is_absolute command without any pre-configured scope.","commands":{"allow":[],"deny":["is_absolute"]}},"deny-join":{"identifier":"deny-join","description":"Denies the join command without any pre-configured scope.","commands":{"allow":[],"deny":["join"]}},"deny-normalize":{"identifier":"deny-normalize","description":"Denies the normalize command without any pre-configured scope.","commands":{"allow":[],"deny":["normalize"]}},"deny-resolve":{"identifier":"deny-resolve","description":"Denies the resolve command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve"]}},"deny-resolve-directory":{"identifier":"deny-resolve-directory","description":"Denies the resolve_directory command without any pre-configured scope.","commands":{"allow":[],"deny":["resolve_directory"]}}},"permission_sets":{},"global_scope_schema":null},"core:resources":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-close"]},"permissions":{"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}}},"permission_sets":{},"global_scope_schema":null},"core:tray":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin, which enables all commands.","permissions":["allow-new","allow-get-by-id","allow-remove-by-id","allow-set-icon","allow-set-menu","allow-set-tooltip","allow-set-title","allow-set-visible","allow-set-temp-dir-path","allow-set-icon-as-template","allow-set-show-menu-on-left-click"]},"permissions":{"allow-get-by-id":{"identifier":"allow-get-by-id","description":"Enables the get_by_id command without any pre-configured scope.","commands":{"allow":["get_by_id"],"deny":[]}},"allow-new":{"identifier":"allow-new","description":"Enables the new command without any pre-configured scope.","commands":{"allow":["new"],"deny":[]}},"allow-remove-by-id":{"identifier":"allow-remove-by-id","description":"Enables the remove_by_id command without any pre-configured scope.","commands":{"allow":["remove_by_id"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-icon-as-template":{"identifier":"allow-set-icon-as-template","description":"Enables the set_icon_as_template command without any pre-configured scope.","commands":{"allow":["set_icon_as_template"],"deny":[]}},"allow-set-menu":{"identifier":"allow-set-menu","description":"Enables the set_menu command without any pre-configured scope.","commands":{"allow":["set_menu"],"deny":[]}},"allow-set-show-menu-on-left-click":{"identifier":"allow-set-show-menu-on-left-click","description":"Enables the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":["set_show_menu_on_left_click"],"deny":[]}},"allow-set-temp-dir-path":{"identifier":"allow-set-temp-dir-path","description":"Enables the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":["set_temp_dir_path"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-tooltip":{"identifier":"allow-set-tooltip","description":"Enables the set_tooltip command without any pre-configured scope.","commands":{"allow":["set_tooltip"],"deny":[]}},"allow-set-visible":{"identifier":"allow-set-visible","description":"Enables the set_visible command without any pre-configured scope.","commands":{"allow":["set_visible"],"deny":[]}},"deny-get-by-id":{"identifier":"deny-get-by-id","description":"Denies the get_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["get_by_id"]}},"deny-new":{"identifier":"deny-new","description":"Denies the new command without any pre-configured scope.","commands":{"allow":[],"deny":["new"]}},"deny-remove-by-id":{"identifier":"deny-remove-by-id","description":"Denies the remove_by_id command without any pre-configured scope.","commands":{"allow":[],"deny":["remove_by_id"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-icon-as-template":{"identifier":"deny-set-icon-as-template","description":"Denies the set_icon_as_template command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon_as_template"]}},"deny-set-menu":{"identifier":"deny-set-menu","description":"Denies the set_menu command without any pre-configured scope.","commands":{"allow":[],"deny":["set_menu"]}},"deny-set-show-menu-on-left-click":{"identifier":"deny-set-show-menu-on-left-click","description":"Denies the set_show_menu_on_left_click command without any pre-configured scope.","commands":{"allow":[],"deny":["set_show_menu_on_left_click"]}},"deny-set-temp-dir-path":{"identifier":"deny-set-temp-dir-path","description":"Denies the set_temp_dir_path command without any pre-configured scope.","commands":{"allow":[],"deny":["set_temp_dir_path"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-tooltip":{"identifier":"deny-set-tooltip","description":"Denies the set_tooltip command without any pre-configured scope.","commands":{"allow":[],"deny":["set_tooltip"]}},"deny-set-visible":{"identifier":"deny-set-visible","description":"Denies the set_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible"]}}},"permission_sets":{},"global_scope_schema":null},"core:webview":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-webviews","allow-webview-position","allow-webview-size","allow-internal-toggle-devtools"]},"permissions":{"allow-clear-all-browsing-data":{"identifier":"allow-clear-all-browsing-data","description":"Enables the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":["clear_all_browsing_data"],"deny":[]}},"allow-create-webview":{"identifier":"allow-create-webview","description":"Enables the create_webview command without any pre-configured scope.","commands":{"allow":["create_webview"],"deny":[]}},"allow-create-webview-window":{"identifier":"allow-create-webview-window","description":"Enables the create_webview_window command without any pre-configured scope.","commands":{"allow":["create_webview_window"],"deny":[]}},"allow-get-all-webviews":{"identifier":"allow-get-all-webviews","description":"Enables the get_all_webviews command without any pre-configured scope.","commands":{"allow":["get_all_webviews"],"deny":[]}},"allow-internal-toggle-devtools":{"identifier":"allow-internal-toggle-devtools","description":"Enables the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":["internal_toggle_devtools"],"deny":[]}},"allow-print":{"identifier":"allow-print","description":"Enables the print command without any pre-configured scope.","commands":{"allow":["print"],"deny":[]}},"allow-reparent":{"identifier":"allow-reparent","description":"Enables the reparent command without any pre-configured scope.","commands":{"allow":["reparent"],"deny":[]}},"allow-set-webview-auto-resize":{"identifier":"allow-set-webview-auto-resize","description":"Enables the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":["set_webview_auto_resize"],"deny":[]}},"allow-set-webview-background-color":{"identifier":"allow-set-webview-background-color","description":"Enables the set_webview_background_color command without any pre-configured scope.","commands":{"allow":["set_webview_background_color"],"deny":[]}},"allow-set-webview-focus":{"identifier":"allow-set-webview-focus","description":"Enables the set_webview_focus command without any pre-configured scope.","commands":{"allow":["set_webview_focus"],"deny":[]}},"allow-set-webview-position":{"identifier":"allow-set-webview-position","description":"Enables the set_webview_position command without any pre-configured scope.","commands":{"allow":["set_webview_position"],"deny":[]}},"allow-set-webview-size":{"identifier":"allow-set-webview-size","description":"Enables the set_webview_size command without any pre-configured scope.","commands":{"allow":["set_webview_size"],"deny":[]}},"allow-set-webview-zoom":{"identifier":"allow-set-webview-zoom","description":"Enables the set_webview_zoom command without any pre-configured scope.","commands":{"allow":["set_webview_zoom"],"deny":[]}},"allow-webview-close":{"identifier":"allow-webview-close","description":"Enables the webview_close command without any pre-configured scope.","commands":{"allow":["webview_close"],"deny":[]}},"allow-webview-hide":{"identifier":"allow-webview-hide","description":"Enables the webview_hide command without any pre-configured scope.","commands":{"allow":["webview_hide"],"deny":[]}},"allow-webview-position":{"identifier":"allow-webview-position","description":"Enables the webview_position command without any pre-configured scope.","commands":{"allow":["webview_position"],"deny":[]}},"allow-webview-show":{"identifier":"allow-webview-show","description":"Enables the webview_show command without any pre-configured scope.","commands":{"allow":["webview_show"],"deny":[]}},"allow-webview-size":{"identifier":"allow-webview-size","description":"Enables the webview_size command without any pre-configured scope.","commands":{"allow":["webview_size"],"deny":[]}},"deny-clear-all-browsing-data":{"identifier":"deny-clear-all-browsing-data","description":"Denies the clear_all_browsing_data command without any pre-configured scope.","commands":{"allow":[],"deny":["clear_all_browsing_data"]}},"deny-create-webview":{"identifier":"deny-create-webview","description":"Denies the create_webview command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview"]}},"deny-create-webview-window":{"identifier":"deny-create-webview-window","description":"Denies the create_webview_window command without any pre-configured scope.","commands":{"allow":[],"deny":["create_webview_window"]}},"deny-get-all-webviews":{"identifier":"deny-get-all-webviews","description":"Denies the get_all_webviews command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_webviews"]}},"deny-internal-toggle-devtools":{"identifier":"deny-internal-toggle-devtools","description":"Denies the internal_toggle_devtools command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_devtools"]}},"deny-print":{"identifier":"deny-print","description":"Denies the print command without any pre-configured scope.","commands":{"allow":[],"deny":["print"]}},"deny-reparent":{"identifier":"deny-reparent","description":"Denies the reparent command without any pre-configured scope.","commands":{"allow":[],"deny":["reparent"]}},"deny-set-webview-auto-resize":{"identifier":"deny-set-webview-auto-resize","description":"Denies the set_webview_auto_resize command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_auto_resize"]}},"deny-set-webview-background-color":{"identifier":"deny-set-webview-background-color","description":"Denies the set_webview_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_background_color"]}},"deny-set-webview-focus":{"identifier":"deny-set-webview-focus","description":"Denies the set_webview_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_focus"]}},"deny-set-webview-position":{"identifier":"deny-set-webview-position","description":"Denies the set_webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_position"]}},"deny-set-webview-size":{"identifier":"deny-set-webview-size","description":"Denies the set_webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_size"]}},"deny-set-webview-zoom":{"identifier":"deny-set-webview-zoom","description":"Denies the set_webview_zoom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_webview_zoom"]}},"deny-webview-close":{"identifier":"deny-webview-close","description":"Denies the webview_close command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_close"]}},"deny-webview-hide":{"identifier":"deny-webview-hide","description":"Denies the webview_hide command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_hide"]}},"deny-webview-position":{"identifier":"deny-webview-position","description":"Denies the webview_position command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_position"]}},"deny-webview-show":{"identifier":"deny-webview-show","description":"Denies the webview_show command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_show"]}},"deny-webview-size":{"identifier":"deny-webview-size","description":"Denies the webview_size command without any pre-configured scope.","commands":{"allow":[],"deny":["webview_size"]}}},"permission_sets":{},"global_scope_schema":null},"core:window":{"default_permission":{"identifier":"default","description":"Default permissions for the plugin.","permissions":["allow-get-all-windows","allow-scale-factor","allow-inner-position","allow-outer-position","allow-inner-size","allow-outer-size","allow-is-fullscreen","allow-is-minimized","allow-is-maximized","allow-is-focused","allow-is-decorated","allow-is-resizable","allow-is-maximizable","allow-is-minimizable","allow-is-closable","allow-is-visible","allow-is-enabled","allow-title","allow-current-monitor","allow-primary-monitor","allow-monitor-from-point","allow-available-monitors","allow-cursor-position","allow-theme","allow-is-always-on-top","allow-internal-toggle-maximize"]},"permissions":{"allow-available-monitors":{"identifier":"allow-available-monitors","description":"Enables the available_monitors command without any pre-configured scope.","commands":{"allow":["available_monitors"],"deny":[]}},"allow-center":{"identifier":"allow-center","description":"Enables the center command without any pre-configured scope.","commands":{"allow":["center"],"deny":[]}},"allow-close":{"identifier":"allow-close","description":"Enables the close command without any pre-configured scope.","commands":{"allow":["close"],"deny":[]}},"allow-create":{"identifier":"allow-create","description":"Enables the create command without any pre-configured scope.","commands":{"allow":["create"],"deny":[]}},"allow-current-monitor":{"identifier":"allow-current-monitor","description":"Enables the current_monitor command without any pre-configured scope.","commands":{"allow":["current_monitor"],"deny":[]}},"allow-cursor-position":{"identifier":"allow-cursor-position","description":"Enables the cursor_position command without any pre-configured scope.","commands":{"allow":["cursor_position"],"deny":[]}},"allow-destroy":{"identifier":"allow-destroy","description":"Enables the destroy command without any pre-configured scope.","commands":{"allow":["destroy"],"deny":[]}},"allow-get-all-windows":{"identifier":"allow-get-all-windows","description":"Enables the get_all_windows command without any pre-configured scope.","commands":{"allow":["get_all_windows"],"deny":[]}},"allow-hide":{"identifier":"allow-hide","description":"Enables the hide command without any pre-configured scope.","commands":{"allow":["hide"],"deny":[]}},"allow-inner-position":{"identifier":"allow-inner-position","description":"Enables the inner_position command without any pre-configured scope.","commands":{"allow":["inner_position"],"deny":[]}},"allow-inner-size":{"identifier":"allow-inner-size","description":"Enables the inner_size command without any pre-configured scope.","commands":{"allow":["inner_size"],"deny":[]}},"allow-internal-toggle-maximize":{"identifier":"allow-internal-toggle-maximize","description":"Enables the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":["internal_toggle_maximize"],"deny":[]}},"allow-is-always-on-top":{"identifier":"allow-is-always-on-top","description":"Enables the is_always_on_top command without any pre-configured scope.","commands":{"allow":["is_always_on_top"],"deny":[]}},"allow-is-closable":{"identifier":"allow-is-closable","description":"Enables the is_closable command without any pre-configured scope.","commands":{"allow":["is_closable"],"deny":[]}},"allow-is-decorated":{"identifier":"allow-is-decorated","description":"Enables the is_decorated command without any pre-configured scope.","commands":{"allow":["is_decorated"],"deny":[]}},"allow-is-enabled":{"identifier":"allow-is-enabled","description":"Enables the is_enabled command without any pre-configured scope.","commands":{"allow":["is_enabled"],"deny":[]}},"allow-is-focused":{"identifier":"allow-is-focused","description":"Enables the is_focused command without any pre-configured scope.","commands":{"allow":["is_focused"],"deny":[]}},"allow-is-fullscreen":{"identifier":"allow-is-fullscreen","description":"Enables the is_fullscreen command without any pre-configured scope.","commands":{"allow":["is_fullscreen"],"deny":[]}},"allow-is-maximizable":{"identifier":"allow-is-maximizable","description":"Enables the is_maximizable command without any pre-configured scope.","commands":{"allow":["is_maximizable"],"deny":[]}},"allow-is-maximized":{"identifier":"allow-is-maximized","description":"Enables the is_maximized command without any pre-configured scope.","commands":{"allow":["is_maximized"],"deny":[]}},"allow-is-minimizable":{"identifier":"allow-is-minimizable","description":"Enables the is_minimizable command without any pre-configured scope.","commands":{"allow":["is_minimizable"],"deny":[]}},"allow-is-minimized":{"identifier":"allow-is-minimized","description":"Enables the is_minimized command without any pre-configured scope.","commands":{"allow":["is_minimized"],"deny":[]}},"allow-is-resizable":{"identifier":"allow-is-resizable","description":"Enables the is_resizable command without any pre-configured scope.","commands":{"allow":["is_resizable"],"deny":[]}},"allow-is-visible":{"identifier":"allow-is-visible","description":"Enables the is_visible command without any pre-configured scope.","commands":{"allow":["is_visible"],"deny":[]}},"allow-maximize":{"identifier":"allow-maximize","description":"Enables the maximize command without any pre-configured scope.","commands":{"allow":["maximize"],"deny":[]}},"allow-minimize":{"identifier":"allow-minimize","description":"Enables the minimize command without any pre-configured scope.","commands":{"allow":["minimize"],"deny":[]}},"allow-monitor-from-point":{"identifier":"allow-monitor-from-point","description":"Enables the monitor_from_point command without any pre-configured scope.","commands":{"allow":["monitor_from_point"],"deny":[]}},"allow-outer-position":{"identifier":"allow-outer-position","description":"Enables the outer_position command without any pre-configured scope.","commands":{"allow":["outer_position"],"deny":[]}},"allow-outer-size":{"identifier":"allow-outer-size","description":"Enables the outer_size command without any pre-configured scope.","commands":{"allow":["outer_size"],"deny":[]}},"allow-primary-monitor":{"identifier":"allow-primary-monitor","description":"Enables the primary_monitor command without any pre-configured scope.","commands":{"allow":["primary_monitor"],"deny":[]}},"allow-request-user-attention":{"identifier":"allow-request-user-attention","description":"Enables the request_user_attention command without any pre-configured scope.","commands":{"allow":["request_user_attention"],"deny":[]}},"allow-scale-factor":{"identifier":"allow-scale-factor","description":"Enables the scale_factor command without any pre-configured scope.","commands":{"allow":["scale_factor"],"deny":[]}},"allow-set-always-on-bottom":{"identifier":"allow-set-always-on-bottom","description":"Enables the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":["set_always_on_bottom"],"deny":[]}},"allow-set-always-on-top":{"identifier":"allow-set-always-on-top","description":"Enables the set_always_on_top command without any pre-configured scope.","commands":{"allow":["set_always_on_top"],"deny":[]}},"allow-set-background-color":{"identifier":"allow-set-background-color","description":"Enables the set_background_color command without any pre-configured scope.","commands":{"allow":["set_background_color"],"deny":[]}},"allow-set-badge-count":{"identifier":"allow-set-badge-count","description":"Enables the set_badge_count command without any pre-configured scope.","commands":{"allow":["set_badge_count"],"deny":[]}},"allow-set-badge-label":{"identifier":"allow-set-badge-label","description":"Enables the set_badge_label command without any pre-configured scope.","commands":{"allow":["set_badge_label"],"deny":[]}},"allow-set-closable":{"identifier":"allow-set-closable","description":"Enables the set_closable command without any pre-configured scope.","commands":{"allow":["set_closable"],"deny":[]}},"allow-set-content-protected":{"identifier":"allow-set-content-protected","description":"Enables the set_content_protected command without any pre-configured scope.","commands":{"allow":["set_content_protected"],"deny":[]}},"allow-set-cursor-grab":{"identifier":"allow-set-cursor-grab","description":"Enables the set_cursor_grab command without any pre-configured scope.","commands":{"allow":["set_cursor_grab"],"deny":[]}},"allow-set-cursor-icon":{"identifier":"allow-set-cursor-icon","description":"Enables the set_cursor_icon command without any pre-configured scope.","commands":{"allow":["set_cursor_icon"],"deny":[]}},"allow-set-cursor-position":{"identifier":"allow-set-cursor-position","description":"Enables the set_cursor_position command without any pre-configured scope.","commands":{"allow":["set_cursor_position"],"deny":[]}},"allow-set-cursor-visible":{"identifier":"allow-set-cursor-visible","description":"Enables the set_cursor_visible command without any pre-configured scope.","commands":{"allow":["set_cursor_visible"],"deny":[]}},"allow-set-decorations":{"identifier":"allow-set-decorations","description":"Enables the set_decorations command without any pre-configured scope.","commands":{"allow":["set_decorations"],"deny":[]}},"allow-set-effects":{"identifier":"allow-set-effects","description":"Enables the set_effects command without any pre-configured scope.","commands":{"allow":["set_effects"],"deny":[]}},"allow-set-enabled":{"identifier":"allow-set-enabled","description":"Enables the set_enabled command without any pre-configured scope.","commands":{"allow":["set_enabled"],"deny":[]}},"allow-set-focus":{"identifier":"allow-set-focus","description":"Enables the set_focus command without any pre-configured scope.","commands":{"allow":["set_focus"],"deny":[]}},"allow-set-focusable":{"identifier":"allow-set-focusable","description":"Enables the set_focusable command without any pre-configured scope.","commands":{"allow":["set_focusable"],"deny":[]}},"allow-set-fullscreen":{"identifier":"allow-set-fullscreen","description":"Enables the set_fullscreen command without any pre-configured scope.","commands":{"allow":["set_fullscreen"],"deny":[]}},"allow-set-icon":{"identifier":"allow-set-icon","description":"Enables the set_icon command without any pre-configured scope.","commands":{"allow":["set_icon"],"deny":[]}},"allow-set-ignore-cursor-events":{"identifier":"allow-set-ignore-cursor-events","description":"Enables the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":["set_ignore_cursor_events"],"deny":[]}},"allow-set-max-size":{"identifier":"allow-set-max-size","description":"Enables the set_max_size command without any pre-configured scope.","commands":{"allow":["set_max_size"],"deny":[]}},"allow-set-maximizable":{"identifier":"allow-set-maximizable","description":"Enables the set_maximizable command without any pre-configured scope.","commands":{"allow":["set_maximizable"],"deny":[]}},"allow-set-min-size":{"identifier":"allow-set-min-size","description":"Enables the set_min_size command without any pre-configured scope.","commands":{"allow":["set_min_size"],"deny":[]}},"allow-set-minimizable":{"identifier":"allow-set-minimizable","description":"Enables the set_minimizable command without any pre-configured scope.","commands":{"allow":["set_minimizable"],"deny":[]}},"allow-set-overlay-icon":{"identifier":"allow-set-overlay-icon","description":"Enables the set_overlay_icon command without any pre-configured scope.","commands":{"allow":["set_overlay_icon"],"deny":[]}},"allow-set-position":{"identifier":"allow-set-position","description":"Enables the set_position command without any pre-configured scope.","commands":{"allow":["set_position"],"deny":[]}},"allow-set-progress-bar":{"identifier":"allow-set-progress-bar","description":"Enables the set_progress_bar command without any pre-configured scope.","commands":{"allow":["set_progress_bar"],"deny":[]}},"allow-set-resizable":{"identifier":"allow-set-resizable","description":"Enables the set_resizable command without any pre-configured scope.","commands":{"allow":["set_resizable"],"deny":[]}},"allow-set-shadow":{"identifier":"allow-set-shadow","description":"Enables the set_shadow command without any pre-configured scope.","commands":{"allow":["set_shadow"],"deny":[]}},"allow-set-simple-fullscreen":{"identifier":"allow-set-simple-fullscreen","description":"Enables the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":["set_simple_fullscreen"],"deny":[]}},"allow-set-size":{"identifier":"allow-set-size","description":"Enables the set_size command without any pre-configured scope.","commands":{"allow":["set_size"],"deny":[]}},"allow-set-size-constraints":{"identifier":"allow-set-size-constraints","description":"Enables the set_size_constraints command without any pre-configured scope.","commands":{"allow":["set_size_constraints"],"deny":[]}},"allow-set-skip-taskbar":{"identifier":"allow-set-skip-taskbar","description":"Enables the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":["set_skip_taskbar"],"deny":[]}},"allow-set-theme":{"identifier":"allow-set-theme","description":"Enables the set_theme command without any pre-configured scope.","commands":{"allow":["set_theme"],"deny":[]}},"allow-set-title":{"identifier":"allow-set-title","description":"Enables the set_title command without any pre-configured scope.","commands":{"allow":["set_title"],"deny":[]}},"allow-set-title-bar-style":{"identifier":"allow-set-title-bar-style","description":"Enables the set_title_bar_style command without any pre-configured scope.","commands":{"allow":["set_title_bar_style"],"deny":[]}},"allow-set-visible-on-all-workspaces":{"identifier":"allow-set-visible-on-all-workspaces","description":"Enables the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":["set_visible_on_all_workspaces"],"deny":[]}},"allow-show":{"identifier":"allow-show","description":"Enables the show command without any pre-configured scope.","commands":{"allow":["show"],"deny":[]}},"allow-start-dragging":{"identifier":"allow-start-dragging","description":"Enables the start_dragging command without any pre-configured scope.","commands":{"allow":["start_dragging"],"deny":[]}},"allow-start-resize-dragging":{"identifier":"allow-start-resize-dragging","description":"Enables the start_resize_dragging command without any pre-configured scope.","commands":{"allow":["start_resize_dragging"],"deny":[]}},"allow-theme":{"identifier":"allow-theme","description":"Enables the theme command without any pre-configured scope.","commands":{"allow":["theme"],"deny":[]}},"allow-title":{"identifier":"allow-title","description":"Enables the title command without any pre-configured scope.","commands":{"allow":["title"],"deny":[]}},"allow-toggle-maximize":{"identifier":"allow-toggle-maximize","description":"Enables the toggle_maximize command without any pre-configured scope.","commands":{"allow":["toggle_maximize"],"deny":[]}},"allow-unmaximize":{"identifier":"allow-unmaximize","description":"Enables the unmaximize command without any pre-configured scope.","commands":{"allow":["unmaximize"],"deny":[]}},"allow-unminimize":{"identifier":"allow-unminimize","description":"Enables the unminimize command without any pre-configured scope.","commands":{"allow":["unminimize"],"deny":[]}},"deny-available-monitors":{"identifier":"deny-available-monitors","description":"Denies the available_monitors command without any pre-configured scope.","commands":{"allow":[],"deny":["available_monitors"]}},"deny-center":{"identifier":"deny-center","description":"Denies the center command without any pre-configured scope.","commands":{"allow":[],"deny":["center"]}},"deny-close":{"identifier":"deny-close","description":"Denies the close command without any pre-configured scope.","commands":{"allow":[],"deny":["close"]}},"deny-create":{"identifier":"deny-create","description":"Denies the create command without any pre-configured scope.","commands":{"allow":[],"deny":["create"]}},"deny-current-monitor":{"identifier":"deny-current-monitor","description":"Denies the current_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["current_monitor"]}},"deny-cursor-position":{"identifier":"deny-cursor-position","description":"Denies the cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["cursor_position"]}},"deny-destroy":{"identifier":"deny-destroy","description":"Denies the destroy command without any pre-configured scope.","commands":{"allow":[],"deny":["destroy"]}},"deny-get-all-windows":{"identifier":"deny-get-all-windows","description":"Denies the get_all_windows command without any pre-configured scope.","commands":{"allow":[],"deny":["get_all_windows"]}},"deny-hide":{"identifier":"deny-hide","description":"Denies the hide command without any pre-configured scope.","commands":{"allow":[],"deny":["hide"]}},"deny-inner-position":{"identifier":"deny-inner-position","description":"Denies the inner_position command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_position"]}},"deny-inner-size":{"identifier":"deny-inner-size","description":"Denies the inner_size command without any pre-configured scope.","commands":{"allow":[],"deny":["inner_size"]}},"deny-internal-toggle-maximize":{"identifier":"deny-internal-toggle-maximize","description":"Denies the internal_toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["internal_toggle_maximize"]}},"deny-is-always-on-top":{"identifier":"deny-is-always-on-top","description":"Denies the is_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["is_always_on_top"]}},"deny-is-closable":{"identifier":"deny-is-closable","description":"Denies the is_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_closable"]}},"deny-is-decorated":{"identifier":"deny-is-decorated","description":"Denies the is_decorated command without any pre-configured scope.","commands":{"allow":[],"deny":["is_decorated"]}},"deny-is-enabled":{"identifier":"deny-is-enabled","description":"Denies the is_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["is_enabled"]}},"deny-is-focused":{"identifier":"deny-is-focused","description":"Denies the is_focused command without any pre-configured scope.","commands":{"allow":[],"deny":["is_focused"]}},"deny-is-fullscreen":{"identifier":"deny-is-fullscreen","description":"Denies the is_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["is_fullscreen"]}},"deny-is-maximizable":{"identifier":"deny-is-maximizable","description":"Denies the is_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximizable"]}},"deny-is-maximized":{"identifier":"deny-is-maximized","description":"Denies the is_maximized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_maximized"]}},"deny-is-minimizable":{"identifier":"deny-is-minimizable","description":"Denies the is_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimizable"]}},"deny-is-minimized":{"identifier":"deny-is-minimized","description":"Denies the is_minimized command without any pre-configured scope.","commands":{"allow":[],"deny":["is_minimized"]}},"deny-is-resizable":{"identifier":"deny-is-resizable","description":"Denies the is_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["is_resizable"]}},"deny-is-visible":{"identifier":"deny-is-visible","description":"Denies the is_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["is_visible"]}},"deny-maximize":{"identifier":"deny-maximize","description":"Denies the maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["maximize"]}},"deny-minimize":{"identifier":"deny-minimize","description":"Denies the minimize command without any pre-configured scope.","commands":{"allow":[],"deny":["minimize"]}},"deny-monitor-from-point":{"identifier":"deny-monitor-from-point","description":"Denies the monitor_from_point command without any pre-configured scope.","commands":{"allow":[],"deny":["monitor_from_point"]}},"deny-outer-position":{"identifier":"deny-outer-position","description":"Denies the outer_position command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_position"]}},"deny-outer-size":{"identifier":"deny-outer-size","description":"Denies the outer_size command without any pre-configured scope.","commands":{"allow":[],"deny":["outer_size"]}},"deny-primary-monitor":{"identifier":"deny-primary-monitor","description":"Denies the primary_monitor command without any pre-configured scope.","commands":{"allow":[],"deny":["primary_monitor"]}},"deny-request-user-attention":{"identifier":"deny-request-user-attention","description":"Denies the request_user_attention command without any pre-configured scope.","commands":{"allow":[],"deny":["request_user_attention"]}},"deny-scale-factor":{"identifier":"deny-scale-factor","description":"Denies the scale_factor command without any pre-configured scope.","commands":{"allow":[],"deny":["scale_factor"]}},"deny-set-always-on-bottom":{"identifier":"deny-set-always-on-bottom","description":"Denies the set_always_on_bottom command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_bottom"]}},"deny-set-always-on-top":{"identifier":"deny-set-always-on-top","description":"Denies the set_always_on_top command without any pre-configured scope.","commands":{"allow":[],"deny":["set_always_on_top"]}},"deny-set-background-color":{"identifier":"deny-set-background-color","description":"Denies the set_background_color command without any pre-configured scope.","commands":{"allow":[],"deny":["set_background_color"]}},"deny-set-badge-count":{"identifier":"deny-set-badge-count","description":"Denies the set_badge_count command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_count"]}},"deny-set-badge-label":{"identifier":"deny-set-badge-label","description":"Denies the set_badge_label command without any pre-configured scope.","commands":{"allow":[],"deny":["set_badge_label"]}},"deny-set-closable":{"identifier":"deny-set-closable","description":"Denies the set_closable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_closable"]}},"deny-set-content-protected":{"identifier":"deny-set-content-protected","description":"Denies the set_content_protected command without any pre-configured scope.","commands":{"allow":[],"deny":["set_content_protected"]}},"deny-set-cursor-grab":{"identifier":"deny-set-cursor-grab","description":"Denies the set_cursor_grab command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_grab"]}},"deny-set-cursor-icon":{"identifier":"deny-set-cursor-icon","description":"Denies the set_cursor_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_icon"]}},"deny-set-cursor-position":{"identifier":"deny-set-cursor-position","description":"Denies the set_cursor_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_position"]}},"deny-set-cursor-visible":{"identifier":"deny-set-cursor-visible","description":"Denies the set_cursor_visible command without any pre-configured scope.","commands":{"allow":[],"deny":["set_cursor_visible"]}},"deny-set-decorations":{"identifier":"deny-set-decorations","description":"Denies the set_decorations command without any pre-configured scope.","commands":{"allow":[],"deny":["set_decorations"]}},"deny-set-effects":{"identifier":"deny-set-effects","description":"Denies the set_effects command without any pre-configured scope.","commands":{"allow":[],"deny":["set_effects"]}},"deny-set-enabled":{"identifier":"deny-set-enabled","description":"Denies the set_enabled command without any pre-configured scope.","commands":{"allow":[],"deny":["set_enabled"]}},"deny-set-focus":{"identifier":"deny-set-focus","description":"Denies the set_focus command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focus"]}},"deny-set-focusable":{"identifier":"deny-set-focusable","description":"Denies the set_focusable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_focusable"]}},"deny-set-fullscreen":{"identifier":"deny-set-fullscreen","description":"Denies the set_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_fullscreen"]}},"deny-set-icon":{"identifier":"deny-set-icon","description":"Denies the set_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_icon"]}},"deny-set-ignore-cursor-events":{"identifier":"deny-set-ignore-cursor-events","description":"Denies the set_ignore_cursor_events command without any pre-configured scope.","commands":{"allow":[],"deny":["set_ignore_cursor_events"]}},"deny-set-max-size":{"identifier":"deny-set-max-size","description":"Denies the set_max_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_max_size"]}},"deny-set-maximizable":{"identifier":"deny-set-maximizable","description":"Denies the set_maximizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_maximizable"]}},"deny-set-min-size":{"identifier":"deny-set-min-size","description":"Denies the set_min_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_min_size"]}},"deny-set-minimizable":{"identifier":"deny-set-minimizable","description":"Denies the set_minimizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_minimizable"]}},"deny-set-overlay-icon":{"identifier":"deny-set-overlay-icon","description":"Denies the set_overlay_icon command without any pre-configured scope.","commands":{"allow":[],"deny":["set_overlay_icon"]}},"deny-set-position":{"identifier":"deny-set-position","description":"Denies the set_position command without any pre-configured scope.","commands":{"allow":[],"deny":["set_position"]}},"deny-set-progress-bar":{"identifier":"deny-set-progress-bar","description":"Denies the set_progress_bar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_progress_bar"]}},"deny-set-resizable":{"identifier":"deny-set-resizable","description":"Denies the set_resizable command without any pre-configured scope.","commands":{"allow":[],"deny":["set_resizable"]}},"deny-set-shadow":{"identifier":"deny-set-shadow","description":"Denies the set_shadow command without any pre-configured scope.","commands":{"allow":[],"deny":["set_shadow"]}},"deny-set-simple-fullscreen":{"identifier":"deny-set-simple-fullscreen","description":"Denies the set_simple_fullscreen command without any pre-configured scope.","commands":{"allow":[],"deny":["set_simple_fullscreen"]}},"deny-set-size":{"identifier":"deny-set-size","description":"Denies the set_size command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size"]}},"deny-set-size-constraints":{"identifier":"deny-set-size-constraints","description":"Denies the set_size_constraints command without any pre-configured scope.","commands":{"allow":[],"deny":["set_size_constraints"]}},"deny-set-skip-taskbar":{"identifier":"deny-set-skip-taskbar","description":"Denies the set_skip_taskbar command without any pre-configured scope.","commands":{"allow":[],"deny":["set_skip_taskbar"]}},"deny-set-theme":{"identifier":"deny-set-theme","description":"Denies the set_theme command without any pre-configured scope.","commands":{"allow":[],"deny":["set_theme"]}},"deny-set-title":{"identifier":"deny-set-title","description":"Denies the set_title command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title"]}},"deny-set-title-bar-style":{"identifier":"deny-set-title-bar-style","description":"Denies the set_title_bar_style command without any pre-configured scope.","commands":{"allow":[],"deny":["set_title_bar_style"]}},"deny-set-visible-on-all-workspaces":{"identifier":"deny-set-visible-on-all-workspaces","description":"Denies the set_visible_on_all_workspaces command without any pre-configured scope.","commands":{"allow":[],"deny":["set_visible_on_all_workspaces"]}},"deny-show":{"identifier":"deny-show","description":"Denies the show command without any pre-configured scope.","commands":{"allow":[],"deny":["show"]}},"deny-start-dragging":{"identifier":"deny-start-dragging","description":"Denies the start_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_dragging"]}},"deny-start-resize-dragging":{"identifier":"deny-start-resize-dragging","description":"Denies the start_resize_dragging command without any pre-configured scope.","commands":{"allow":[],"deny":["start_resize_dragging"]}},"deny-theme":{"identifier":"deny-theme","description":"Denies the theme command without any pre-configured scope.","commands":{"allow":[],"deny":["theme"]}},"deny-title":{"identifier":"deny-title","description":"Denies the title command without any pre-configured scope.","commands":{"allow":[],"deny":["title"]}},"deny-toggle-maximize":{"identifier":"deny-toggle-maximize","description":"Denies the toggle_maximize command without any pre-configured scope.","commands":{"allow":[],"deny":["toggle_maximize"]}},"deny-unmaximize":{"identifier":"deny-unmaximize","description":"Denies the unmaximize command without any pre-configured scope.","commands":{"allow":[],"deny":["unmaximize"]}},"deny-unminimize":{"identifier":"deny-unminimize","description":"Denies the unminimize command without any pre-configured scope.","commands":{"allow":[],"deny":["unminimize"]}}},"permission_sets":{},"global_scope_schema":null},"global-shortcut":{"default_permission":{"identifier":"default","description":"No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n","permissions":[]},"permissions":{"allow-is-registered":{"identifier":"allow-is-registered","description":"Enables the is_registered command without any pre-configured scope.","commands":{"allow":["is_registered"],"deny":[]}},"allow-register":{"identifier":"allow-register","description":"Enables the register command without any pre-configured scope.","commands":{"allow":["register"],"deny":[]}},"allow-register-all":{"identifier":"allow-register-all","description":"Enables the register_all command without any pre-configured scope.","commands":{"allow":["register_all"],"deny":[]}},"allow-unregister":{"identifier":"allow-unregister","description":"Enables the unregister command without any pre-configured scope.","commands":{"allow":["unregister"],"deny":[]}},"allow-unregister-all":{"identifier":"allow-unregister-all","description":"Enables the unregister_all command without any pre-configured scope.","commands":{"allow":["unregister_all"],"deny":[]}},"deny-is-registered":{"identifier":"deny-is-registered","description":"Denies the is_registered command without any pre-configured scope.","commands":{"allow":[],"deny":["is_registered"]}},"deny-register":{"identifier":"deny-register","description":"Denies the register command without any pre-configured scope.","commands":{"allow":[],"deny":["register"]}},"deny-register-all":{"identifier":"deny-register-all","description":"Denies the register_all command without any pre-configured scope.","commands":{"allow":[],"deny":["register_all"]}},"deny-unregister":{"identifier":"deny-unregister","description":"Denies the unregister command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister"]}},"deny-unregister-all":{"identifier":"deny-unregister-all","description":"Denies the unregister_all command without any pre-configured scope.","commands":{"allow":[],"deny":["unregister_all"]}}},"permission_sets":{},"global_scope_schema":null},"shell":{"default_permission":{"identifier":"default","description":"This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n","permissions":["allow-open"]},"permissions":{"allow-execute":{"identifier":"allow-execute","description":"Enables the execute command without any pre-configured scope.","commands":{"allow":["execute"],"deny":[]}},"allow-kill":{"identifier":"allow-kill","description":"Enables the kill command without any pre-configured scope.","commands":{"allow":["kill"],"deny":[]}},"allow-open":{"identifier":"allow-open","description":"Enables the open command without any pre-configured scope.","commands":{"allow":["open"],"deny":[]}},"allow-spawn":{"identifier":"allow-spawn","description":"Enables the spawn command without any pre-configured scope.","commands":{"allow":["spawn"],"deny":[]}},"allow-stdin-write":{"identifier":"allow-stdin-write","description":"Enables the stdin_write command without any pre-configured scope.","commands":{"allow":["stdin_write"],"deny":[]}},"deny-execute":{"identifier":"deny-execute","description":"Denies the execute command without any pre-configured scope.","commands":{"allow":[],"deny":["execute"]}},"deny-kill":{"identifier":"deny-kill","description":"Denies the kill command without any pre-configured scope.","commands":{"allow":[],"deny":["kill"]}},"deny-open":{"identifier":"deny-open","description":"Denies the open command without any pre-configured scope.","commands":{"allow":[],"deny":["open"]}},"deny-spawn":{"identifier":"deny-spawn","description":"Denies the spawn command without any pre-configured scope.","commands":{"allow":[],"deny":["spawn"]}},"deny-stdin-write":{"identifier":"deny-stdin-write","description":"Denies the stdin_write command without any pre-configured scope.","commands":{"allow":[],"deny":["stdin_write"]}}},"permission_sets":{},"global_scope_schema":{"$schema":"http://json-schema.org/draft-07/schema#","anyOf":[{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"cmd":{"description":"The command name. It can start with a variable that resolves to a system base directory. The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.","type":"string"},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"}},"required":["cmd","name"],"type":"object"},{"additionalProperties":false,"properties":{"args":{"allOf":[{"$ref":"#/definitions/ShellScopeEntryAllowedArgs"}],"description":"The allowed arguments for the command execution."},"name":{"description":"The name for this allowed shell command configuration.\n\nThis name will be used inside of the webview API to call this command along with any specified arguments.","type":"string"},"sidecar":{"description":"If this command is a sidecar command.","type":"boolean"}},"required":["name","sidecar"],"type":"object"}],"definitions":{"ShellScopeEntryAllowedArg":{"anyOf":[{"description":"A non-configurable argument that is passed to the command in the order it was specified.","type":"string"},{"additionalProperties":false,"description":"A variable that is set while calling the command from the webview API.","properties":{"raw":{"default":false,"description":"Marks the validator as a raw regex, meaning the plugin should not make any modification at runtime.\n\nThis means the regex will not match on the entire string by default, which might be exploited if your regex allow unexpected input to be considered valid. When using this option, make sure your regex is correct.","type":"boolean"},"validator":{"description":"[regex] validator to require passed values to conform to an expected input.\n\nThis will require the argument value passed to this variable to match the `validator` regex before it will be executed.\n\nThe regex string is by default surrounded by `^...$` to match the full string. For example the `https?://\\w+` regex would be registered as `^https?://\\w+$`.\n\n[regex]: ","type":"string"}},"required":["validator"],"type":"object"}],"description":"A command argument allowed to be executed by the webview API."},"ShellScopeEntryAllowedArgs":{"anyOf":[{"description":"Use a simple boolean to allow all or disable all arguments to this command configuration.","type":"boolean"},{"description":"A specific set of [`ShellScopeEntryAllowedArg`] that are valid to call for the command configuration.","items":{"$ref":"#/definitions/ShellScopeEntryAllowedArg"},"type":"array"}],"description":"A set of command arguments allowed to be executed by the webview API.\n\nA value of `true` will allow any arguments to be passed to the command. `false` will disable all arguments. A list of [`ShellScopeEntryAllowedArg`] will set those arguments as the only valid arguments to be passed to the attached command configuration."}},"description":"Shell scope entry.","title":"ShellScopeEntry"}}} \ No newline at end of file diff --git a/desktop/src-tauri/gen/schemas/desktop-schema.json b/desktop/src-tauri/gen/schemas/desktop-schema.json index f827fe175..2cb2c2a88 100644 --- a/desktop/src-tauri/gen/schemas/desktop-schema.json +++ b/desktop/src-tauri/gen/schemas/desktop-schema.json @@ -2354,6 +2354,72 @@ "const": "core:window:deny-unminimize", "markdownDescription": "Denies the unminimize command without any pre-configured scope." }, + { + "description": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n", + "type": "string", + "const": "global-shortcut:default", + "markdownDescription": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n" + }, + { + "description": "Enables the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-is-registered", + "markdownDescription": "Enables the is_registered command without any pre-configured scope." + }, + { + "description": "Enables the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register", + "markdownDescription": "Enables the register command without any pre-configured scope." + }, + { + "description": "Enables the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register-all", + "markdownDescription": "Enables the register_all command without any pre-configured scope." + }, + { + "description": "Enables the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister", + "markdownDescription": "Enables the unregister command without any pre-configured scope." + }, + { + "description": "Enables the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister-all", + "markdownDescription": "Enables the unregister_all command without any pre-configured scope." + }, + { + "description": "Denies the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-is-registered", + "markdownDescription": "Denies the is_registered command without any pre-configured scope." + }, + { + "description": "Denies the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register", + "markdownDescription": "Denies the register command without any pre-configured scope." + }, + { + "description": "Denies the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register-all", + "markdownDescription": "Denies the register_all command without any pre-configured scope." + }, + { + "description": "Denies the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister", + "markdownDescription": "Denies the unregister command without any pre-configured scope." + }, + { + "description": "Denies the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister-all", + "markdownDescription": "Denies the unregister_all command without any pre-configured scope." + }, { "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n\n#### This default permission set includes:\n\n- `allow-open`", "type": "string", diff --git a/desktop/src-tauri/gen/schemas/macOS-schema.json b/desktop/src-tauri/gen/schemas/macOS-schema.json index f827fe175..2cb2c2a88 100644 --- a/desktop/src-tauri/gen/schemas/macOS-schema.json +++ b/desktop/src-tauri/gen/schemas/macOS-schema.json @@ -2354,6 +2354,72 @@ "const": "core:window:deny-unminimize", "markdownDescription": "Denies the unminimize command without any pre-configured scope." }, + { + "description": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n", + "type": "string", + "const": "global-shortcut:default", + "markdownDescription": "No features are enabled by default, as we believe\nthe shortcuts can be inherently dangerous and it is\napplication specific if specific shortcuts should be\nregistered or unregistered.\n" + }, + { + "description": "Enables the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-is-registered", + "markdownDescription": "Enables the is_registered command without any pre-configured scope." + }, + { + "description": "Enables the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register", + "markdownDescription": "Enables the register command without any pre-configured scope." + }, + { + "description": "Enables the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-register-all", + "markdownDescription": "Enables the register_all command without any pre-configured scope." + }, + { + "description": "Enables the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister", + "markdownDescription": "Enables the unregister command without any pre-configured scope." + }, + { + "description": "Enables the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:allow-unregister-all", + "markdownDescription": "Enables the unregister_all command without any pre-configured scope." + }, + { + "description": "Denies the is_registered command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-is-registered", + "markdownDescription": "Denies the is_registered command without any pre-configured scope." + }, + { + "description": "Denies the register command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register", + "markdownDescription": "Denies the register command without any pre-configured scope." + }, + { + "description": "Denies the register_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-register-all", + "markdownDescription": "Denies the register_all command without any pre-configured scope." + }, + { + "description": "Denies the unregister command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister", + "markdownDescription": "Denies the unregister command without any pre-configured scope." + }, + { + "description": "Denies the unregister_all command without any pre-configured scope.", + "type": "string", + "const": "global-shortcut:deny-unregister-all", + "markdownDescription": "Denies the unregister_all command without any pre-configured scope." + }, { "description": "This permission set configures which\nshell functionality is exposed by default.\n\n#### Granted Permissions\n\nIt allows to use the `open` functionality with a reasonable\nscope pre-configured. It will allow opening `http(s)://`,\n`tel:` and `mailto:` links.\n\n#### This default permission set includes:\n\n- `allow-open`", "type": "string", diff --git a/docs/design-docs/api-client-package-followup.md b/docs/design-docs/api-client-package-followup.md new file mode 100644 index 000000000..7cc141be8 --- /dev/null +++ b/docs/design-docs/api-client-package-followup.md @@ -0,0 +1,30 @@ +# API Client Package Follow-up + +The first extraction of `@spacebot/api-client` is intentionally light. + +It creates a reusable package boundary for Spacedrive and other consumers, but it still re-exports generated types from `interface/src/api/`. + +## Follow-up Work + +### 1. Make `spacebot/interface` consume `@spacebot/api-client` + +The Spacebot interface should stop importing from its local `src/api/*` modules directly and instead consume the shared package. + +That will make the package the single source of truth for: + +- OpenAPI client setup +- generated schema types +- friendly exported types +- manual SSE event types + +### 2. Move OpenAPI generation output into the package + +The long-term target is for `schema.d.ts` to be generated directly into `packages/api-client/` instead of `interface/src/api/`. + +That will let the shared package fully own the generated contract and avoid the current re-export bridge. + +## Why Deferred + +These steps are worth doing, but they are not required for the first Spacedrive integration slice. + +For now, the package boundary exists, and Spacedrive can start consuming it immediately. diff --git a/docs/design-docs/channel-settings-unification.md b/docs/design-docs/channel-settings-unification.md new file mode 100644 index 000000000..fa23dbf54 --- /dev/null +++ b/docs/design-docs/channel-settings-unification.md @@ -0,0 +1,314 @@ +# Channel Settings Unification — Response Modes, Per-Channel Overrides, and Binding Defaults + +**Status:** Draft +**Date:** 2026-03-28 +**Context:** Conversation settings (model, memory, delegation, worker context) are implemented for portal conversations. Platform channels (Discord, Slack, Telegram, etc.) have no equivalent — their behavior is controlled by a fragmented mix of binding-level `require_mention`, agent-global `listen_only_mode`, per-channel key-value overrides in SettingsStore, and runtime slash commands (`/quiet`, `/active`). This doc proposes unifying all of it under ConversationSettings with a new `response_mode` field. + +--- + +## Problem + +### 1. Three systems, one concept + +There are three independent mechanisms that all control "should the bot respond to this message": + +| Mechanism | Where configured | Scope | What it does | +| -------------------- | -------------------------------------------------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------- | +| `require_mention` | `[[bindings]]` in TOML | Per-binding pattern | Drops messages at routing layer — channel never sees them | +| `listen_only_mode` | `[defaults.channel]` or `[agents.channel]` in TOML | Agent-global | Channel receives message, records history, runs memory persistence, but suppresses LLM response | +| `/quiet` / `/active` | Slash command in chat | Per-channel (persisted to SettingsStore) | Toggles listen_only at runtime for one channel | + +Users encounter these in different places with different terminology and no explanation of how they interact. The global `listen_only_mode` toggle in the config UI is particularly confusing — it forces all channels into quiet mode with no per-channel escape (explicit config overrides per-channel DB values). + +### 2. Platform channels have no ConversationSettings + +Portal conversations got `ConversationSettings` (model, memory, delegation, worker context, model overrides) with a settings panel and persistence. Platform channels have none of this. You can't say "this Discord channel uses Haiku" or "this Slack channel doesn't need memory." The only per-channel state is `listen_only_mode` in the key-value SettingsStore. + +### 3. Bindings are routing, not configuration + +Bindings exist to route messages to agents. But `require_mention` is a behavioral setting masquerading as a routing field. It happens to be on bindings because channels are created lazily — you can't configure a channel that doesn't exist yet. Bindings are the only place where you can say "for messages matching this pattern, apply this behavior." + +--- + +## What Exists Today + +### Response suppression flow + +``` +Message arrives + | + v +resolve_agent_for_message() + |-- binding.matches_route() --> no match --> next binding / default agent + |-- binding.passes_require_mention() --> FAIL --> message DROPPED (never seen) + | + v +Channel created or reused + |-- Channel.listen_only_mode checked + | |-- if quiet AND not (@mention | reply | command) --> message RECORDED but no LLM response + | |-- if active --> normal processing + | + v +LLM processes message, generates response +``` + +### listen_only resolution priority (current) + +``` +1. Session override (ephemeral, from /quiet or /active if persistence failed) +2. Explicit agent config ([agents.channel].listen_only_mode in TOML — LOCKS, blocks per-channel overrides) +3. Per-channel SettingsStore value (keyed by conversation_id) +4. Agent default from [defaults.channel] +``` + +Problem: Level 2 acts as a hard lock. If the agent config explicitly sets `listen_only_mode`, per-channel values are ignored. This is probably a bug, not a feature. + +### ConversationSettings (portal only, current) + +```rust +pub struct ConversationSettings { + pub model: Option, + pub model_overrides: ModelOverrides, + pub memory: MemoryMode, // Full | Ambient | Off + pub delegation: DelegationMode, // Standard | Direct + pub worker_context: WorkerContextMode, +} +``` + +Stored as JSON in `portal_conversations.settings` column. Loaded at channel creation for portal conversations. Not available for platform channels. + +--- + +## Proposed Design + +### Core idea: Response Mode + +Replace `require_mention` (binding) and `listen_only_mode` (channel) with a single `response_mode` field on `ConversationSettings`: + +```rust +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)] +#[serde(rename_all = "snake_case")] +pub enum ResponseMode { + /// Respond to all messages normally. + #[default] + Active, + /// Observe and learn (history + memory persistence) but only respond + /// to @mentions, replies-to-bot, and slash commands. + Quiet, + /// Ignore messages entirely unless @mentioned or replied to. + /// Messages that don't pass the mention check are still recorded in + /// history but receive no processing (no memory persistence, no LLM). + MentionOnly, +} +``` + +**Behavior comparison:** + +| Mode | Message recorded in history? | Memory persistence? | LLM response? | Trigger to respond | +| ----------- | ---------------------------- | ------------------- | ------------- | ------------------------ | +| Active | Yes | Yes | Yes | Any message | +| Quiet | Yes | Yes | No | @mention, reply, command | +| MentionOnly | Yes (lightweight) | No | No | @mention, reply | + +**Key decision:** `MentionOnly` keeps the routing-level drop. See "Why require_mention stays on bindings" below for the rationale. + +### Updated ConversationSettings + +```rust +pub struct ConversationSettings { + pub model: Option, + pub model_overrides: ModelOverrides, + pub memory: MemoryMode, + pub delegation: DelegationMode, + pub response_mode: ResponseMode, // NEW + pub worker_context: WorkerContextMode, +} +``` + +### Settings on bindings (TOML) + +Bindings gain an optional `[bindings.settings]` table that provides **defaults** for any channel matched by that binding: + +```toml +[[bindings]] +agent_id = "ops" +channel = "discord" +guild_id = "123456" +channel_ids = ["789"] + +[bindings.settings] +response_mode = "quiet" +model = "anthropic/claude-haiku-4.5" +memory = "ambient" +``` + +Backwards compatibility: `require_mention = true` on a binding is equivalent to `settings.response_mode = "mention_only"`. If both are set, `settings.response_mode` takes priority. + +### Why require_mention stays on bindings + +There are three levels of "should the bot respond?" and they operate at different layers: + +| Level | Setting | Where it lives | Why it lives there | +|-------|---------|---------------|-------------------| +| **Routing** | `require_mention` | Binding | Must be decided **before a channel exists**. Drops messages at the router — the channel is never created, no resources allocated, no history recorded. This is the right place for noisy servers where creating a channel per Discord channel would be wasteful. | +| **Binding defaults** | `[bindings.settings]` | Binding | Sets the **default behavior** for any channel that IS created by this binding. A policy applied to a pattern of channels. | +| **Per-channel override** | ConversationSettings | DB (per conversation_id) | Runtime overrides set by `/quiet`, `/active`, or the settings UI. An exception to the binding policy. | + +The key insight: **bindings are policies, channels are exceptions.** + +A binding like `channel = "discord", guild_id = "123456", require_mention = true` says: "For every channel in this server, don't even create a channel unless the bot is mentioned." That's a routing decision about resource allocation, not a channel behavior setting. + +Once the bot IS mentioned and a channel is created, that channel gets `response_mode = MentionOnly` as its default from the binding. The user can then `/active` it — that per-channel override persists and the binding default no longer applies to that specific channel. But the binding still controls whether NEW channels are created for other Discord channels in the same server. + +`listen_only` (Quiet mode) does NOT need to be on bindings as a routing gate because it doesn't affect channel creation — the channel is created either way, messages flow through, the bot just doesn't respond. It lives entirely in ConversationSettings: +- Set as a binding default via `[bindings.settings].response_mode = "quiet"` +- Toggled at runtime via `/quiet` and `/active` +- Visible in the settings panel + +``` +Message arrives + │ + ▼ +resolve_agent_for_message() + ├── binding.matches_route() ──→ no match → next binding / default agent + ├── binding.require_mention? ──→ not mentioned → MESSAGE DROPPED (routing gate) + │ + ▼ +Channel created or reused + ├── Load ConversationSettings: + │ per-channel DB > binding defaults > agent defaults > system defaults + ├── response_mode == Active? → normal processing + ├── response_mode == Quiet? → record + memory, suppress LLM unless @mention/reply/command + ├── response_mode == MentionOnly? → record only, suppress everything unless @mention/reply + │ + ▼ +LLM processes message (if not suppressed) +``` + +### Resolution order + +For any channel (portal or platform): + +``` +1. Per-channel ConversationSettings (persisted in DB, set via API/commands) +2. Binding defaults (from [bindings.settings] in TOML, matched at message routing time) +3. Agent defaults (from agent config) +4. System defaults (Active, Full memory, Standard delegation, etc.) +``` + +The current "explicit config locks everything" behavior for `listen_only_mode` goes away. Per-channel overrides always win. + +### Where per-channel settings are stored + +**Portal conversations:** Already in `portal_conversations.settings` (JSON column). No change. + +**Platform channels:** New `channel_settings` SQLite table (see "Decisions made" #5). Same JSON-in-TEXT pattern as `portal_conversations`. The existing per-channel `listen_only_mode` keys in SettingsStore (redb) are migrated out and removed in Phase 3. + +### Slash command changes + +- `/quiet` → sets `response_mode = Quiet` on the current channel's ConversationSettings +- `/active` → sets `response_mode = Active` +- `/mention-only` → sets `response_mode = MentionOnly` (new) +- `/status` → shows current response mode alongside other settings + +### How binding settings flow to channels + +When a message arrives and matches a binding, the binding's `settings` block provides defaults. The binding does NOT need to know about per-channel overrides — it just provides the baseline: + +``` +1. Message arrives, matches binding +2. require_mention gate passes (or message is dropped) +3. Channel created or reused +4. Load per-channel ConversationSettings from DB +5. If found → use per-channel settings (override) +6. If not found → use binding.settings as defaults +7. Resolve against agent defaults and system defaults +``` + +The binding's settings are NOT persisted to the DB automatically — they're just defaults. If a user runs `/quiet` on a channel that was `Active` via binding defaults, the per-channel override (`Quiet`) is persisted and takes priority from then on. The binding default still applies to any other channel matched by the same binding that hasn't been overridden. + +--- + +## Migration path + +### Phase 1: Add ResponseMode to ConversationSettings + +- Add `response_mode: ResponseMode` field (default: Active) +- Keep existing `listen_only_mode` working in parallel +- `/quiet` and `/active` write to both old and new systems + +### Phase 2: Add settings to bindings + +- Parse `[bindings.settings]` from TOML +- Store parsed `ConversationSettings` on `Binding` struct +- Pass binding settings through to channel creation + +### Phase 3: Unify listen_only into response_mode + +- Channel's `listen_only_mode` field replaced by `resolved_settings.response_mode` +- Remove `listen_only_mode` from `ChannelConfig` +- Remove per-channel listen_only keys from SettingsStore +- `require_mention` on bindings becomes sugar for `settings.response_mode = "mention_only"` + +### Phase 4: Platform channel settings persistence + +- New `channel_settings` table (or reuse SettingsStore — TBD) +- Load per-channel settings at channel creation for all channel types +- API endpoints for get/set channel settings + +--- + +## Decisions made + +1. **MentionOnly drops at routing.** `require_mention` stays on bindings as a routing gate. No channel created, no resources wasted. Once mentioned, the channel is created with `response_mode = MentionOnly` as its default. + +2. **require_mention stays on bindings, not in ConversationSettings.** It's a routing decision, not a channel behavior. See "Why require_mention stays on bindings" above. + +3. **Bindings provide setting defaults via `[bindings.settings]`.** These are policies applied to a pattern of channels. Per-channel overrides (via commands or UI) are exceptions that always win. + +4. **The global `listen_only_mode` agent config becomes a default, not a lock.** Per-channel overrides always take priority. + +5. **Platform channel settings stored in a new SQLite table.** SettingsStore (redb) is a simple KV store for scalar runtime toggles — not the right place for structured JSON settings. A `channel_settings` table in SQLite matches the existing `portal_conversations` pattern, is queryable for the Channels UI, and keeps everything in one database. The per-channel `listen_only_mode` keys in redb migrate out as part of the cleanup. + +```sql +CREATE TABLE channel_settings ( + agent_id TEXT NOT NULL, + conversation_id TEXT NOT NULL, + settings TEXT NOT NULL DEFAULT '{}', + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + PRIMARY KEY (agent_id, conversation_id) +); +``` + +6. **`listen_only_mode` in agent config becomes `response_mode`.** Boolean `listen_only_mode = true/false` replaced by `response_mode = "active" | "quiet" | "mention_only"` in `[defaults.channel]` and `[agents.channel]`. Backwards compat: `listen_only_mode = true` accepted as alias for `response_mode = "quiet"` with a deprecation warning. + +```toml +# Before +[defaults.channel] +listen_only_mode = true + +# After +[defaults.channel] +response_mode = "quiet" +``` + +7. **Platform channel settings in the UI.** The Channels page gets a gear icon per channel row that opens the existing `ConversationSettingsPanel` as a popover — same component used for portal conversations. Wired to `GET/PUT /channel-settings/{conversation_id}` API endpoints backed by the new `channel_settings` table. + +8. **`save_attachments` moves into ConversationSettings.** It's a per-channel behavior toggle, same as response_mode or memory. Added as a boolean field on `ConversationSettings` and a toggle in the settings panel. + +## Future: `/new` command for platform channels + +Portal conversations support creating new conversations (new session ID, fresh history). Platform channels are tied to a fixed `conversation_id` (e.g., `discord:guild:channel`) — you can't create a new Discord channel from a slash command. + +For platform channels, `/new` means **"clear context and start fresh"**: + +1. Flush the channel's in-memory history vec +2. Insert a marker message in `conversation_messages` so the DB history shows where the reset happened +3. The channel continues with the same `conversation_id` — no new rows in `channel_settings` or `portal_conversations` +4. Old messages stay in the DB for reference, but the LLM starts with a clean slate + +This is simpler than portal's new-conversation flow — no new metadata rows, no session ID changes. Just a context reset. + +**Implementation:** Add `/new` to the channel's built-in command handler (alongside `/quiet`, `/active`, `/status`). Clear `self.state.history`, optionally reset `self.message_count` and `self.last_persistence_at`, log a system marker. + +**Separate from the settings unification work** — this is a standalone feature that can be built independently. diff --git a/docs/design-docs/conversation-settings.md b/docs/design-docs/conversation-settings.md new file mode 100644 index 000000000..4eba5f71e --- /dev/null +++ b/docs/design-docs/conversation-settings.md @@ -0,0 +1,1056 @@ +# Conversation & Channel Settings — Unifying Configuration and Sunsetting Cortex Chat + +**Status:** Draft +**Date:** 2026-03-25 +**Context:** The Spacedrive Spacebot interface is gaining multi-conversation support. The existing split between channels (no tools, has personality) and cortex chat (all tools, no personality) creates UX confusion. This doc proposes a unified per-conversation settings model that absorbs cortex chat's capabilities into normal conversations. It also defines worker context settings and renames "webchat" to "portal" throughout the codebase. + +--- + +## Problem + +There are four problems converging: + +### 1. Cortex Chat is a UX Dead End + +Cortex chat exists because channels deliberately lack tools — they delegate to branches and workers. When a user wants to configure something, query memories, or run shell commands directly, they go to cortex chat. But from a user's perspective, "cortex" is an unexplained internal concept. Why is there a separate chat? Why does it behave differently? Why can't I just tell my agent to do this in our normal conversation? + +Cortex chat is one session per agent. It has no personality. It gets a different system prompt. It persists to a separate table (`cortex_chat_messages`). None of this is visible or meaningful to the user — it's implementation leaking into product. + +### 2. No Per-Conversation Configuration + +The portal conversation feature just landed. Users can now create multiple conversations. But every conversation behaves identically — same model, same tools, same memory injection. There is no way to say "this conversation uses Opus" or "this conversation doesn't need memory context" or "let me use tools directly here." + +The model selector in the Spacedrive UI is decorative — Spacebot ignores it because models are configured per process type in TOML, not per conversation. + +### 3. Channel Configuration is Agent-Global + +Channels (Discord, Slack, etc.) have `require_mention` on bindings and `listen_only_mode` in config. But the model, memory injection, and tool access are all agent-level. You can't say "this Discord channel uses Haiku" or "this Slack channel doesn't need working memory." All channels for an agent share the same routing config. + +### 4. Workers Are Context-Starved + +Workers receive only a task description and a static system prompt. No conversation history, no knowledge synthesis, no working memory. The channel must pack everything the worker needs into the task string. This is limiting — a worker can't understand the broader conversation context, can't leverage memory the agent has built up, and can't see what led to the task being created. + +Branches, by contrast, get the full channel history clone plus memory tools. The gap between branch context richness and worker context poverty is entirely hardcoded. There's no way to say "this worker should get conversation history" or "this worker should get the agent's memory context." + +--- + +## What Exists Today + +### Configuration Hierarchy (Current) + +``` +Agent Config (TOML) +├── routing: { channel, branch, worker, compactor, cortex } +│ ├── task_overrides: { "coding" → model } +│ └── fallbacks: { model → [fallback_models] } +├── memory_persistence: { enabled, message_interval } +├── working_memory: { enabled, context_token_budget, ... } +├── cortex: { knowledge_synthesis (change-driven), maintenance, ... } +├── channel_config: { listen_only_mode, save_attachments } +└── bindings[]: { channel, require_mention, ... } +``` + +### Tool Access (Current) + +| Context | Memory Tools | Execution Tools | Delegation Tools | Platform Tools | +|---------|-------------|-----------------|------------------|----------------| +| Channel | No | No | Yes (branch, spawn_worker, route) | Yes (reply, react, skip) | +| Branch | Yes (recall, save, delete) | No | Yes (spawn_worker) | No | +| Worker | No | Yes (shell, file_*, browser) | No | No | +| Cortex Chat | Yes | Yes | Yes (spawn_worker) | No | + +Cortex chat is the only context that combines memory tools + execution tools + worker spawning. That's why it exists — it's the "power mode." + +### Memory Injection (Current) + +The memory system has three layers that get injected into prompts: + +1. **Knowledge Synthesis** (replaced the old "bulletin") — LLM-curated briefing synthesized from the memory graph (decisions, preferences, goals, high-importance facts, active tasks). Change-driven regeneration via dirty-flag + debounce. Primary memory context. +2. **Working Memory** — Temporal event log. Today's events in detail, yesterday compressed to summary, earlier this week as a paragraph. Real-time, rendered on every prompt. +3. **Channel Activity Map** — Cross-channel visibility. What's happening in other channels. Real-time. + +The old bulletin is kept only as a startup fallback if knowledge synthesis fails. The prompt template prefers `knowledge_synthesis`, falls back to `memory_bulletin`, and renders `working_memory` separately. + +| Context | Knowledge Synthesis | Working Memory (Temporal) | Channel Activity Map | Tool-Based Recall | +|---------|-------------------|--------------------------|---------------------|-------------------| +| Channel | Yes | Yes (if enabled) | Yes (if enabled) | No (delegates to branch) | +| Branch | Yes | No | No | Yes | +| Worker | No | No | No | No | +| Cortex Chat | Yes | No | No | Yes | + +### Worker Context (Current) + +When a worker is spawned today: + +1. **System prompt** — Rendered from `worker.md.j2` with filesystem paths, sandbox config, tool secrets, available skills. No memory, no conversation context. +2. **Task description** — The only user-facing input. Becomes the first prompt. Channel must front-load all necessary context into this string. +3. **Skills** — Available skills listed with suggested skills flagged by the channel. +4. **Tools** — shell, file_read/write/edit/list, set_status, read_skill, task_update, optionally browser/web_search/MCP. +5. **No history** — Fire-and-forget workers start with empty history. Interactive workers only get history from prior turns in their own session. +6. **No memory** — No knowledge synthesis, no working memory, no memory tools. + +Compare to branches, which get a **full clone of the channel history** plus memory tools (recall, save, delete) and knowledge synthesis via system prompt. + +--- + +## Proposed Design + +### Core Idea: Conversation Modes + +Every conversation (portal or platform channel) gets a **mode** that determines its behavior. The mode is a small set of flags. Agent config provides defaults. Per-channel and per-conversation overrides are optional. + +### The Settings + +``` +ConversationSettings { + model: Option, // LLM override for this conversation's channel process + memory: MemoryMode, // How memory is used + delegation: DelegationMode, // How tools work + worker_context: WorkerContextMode, // What context workers receive +} +``` + +#### `model: Option` + +When set, overrides `routing.channel` for the channel process in this conversation. Branches and workers spawned from this conversation also inherit the override (overriding `routing.branch` and `routing.worker` respectively). + +When `None`, falls through to agent-level routing config as today. + +This replaces the non-functional model selector in the UI with something that actually works. + +**Implementation:** `routing.resolve()` gains an optional `override_model` parameter. When present, it returns the override instead of the process-type default. Task-type overrides (`task_overrides`) still take priority over per-conversation overrides for workers/branches, because task-type routing is a quality-of-output concern, not a user preference. + +#### `memory: MemoryMode` + +```rust +enum MemoryMode { + Full, // Knowledge synthesis + working memory + channel activity map + auto-persistence (current default) + Ambient, // All memory context injected, but no auto-persistence and no memory tools + Off, // No memory context injected, no memory tools, no persistence +} +``` + +- **Full** — The agent knows everything it normally knows. All three memory layers injected (knowledge synthesis, working memory, channel activity map). Memory persistence branches fire. This is today's default. +- **Ambient** — The agent gets all memory context (knowledge synthesis, working memory, channel activity map) but doesn't write new memories from this conversation. No auto-persistence branches. Useful for throwaway chats or sensitive topics. +- **Off** — Raw mode. No memory context injected — no knowledge synthesis, no working memory, no channel activity map. The conversation is stateless relative to the agent's memory. System prompt still includes identity/personality. This is the spirit of what cortex chat provides today. + +#### `delegation: DelegationMode` + +```rust +enum DelegationMode { + Standard, // Current channel behavior: must delegate via branch/worker + Direct, // Channel gets all tools: memory, shell, file, browser, + delegation tools +} +``` + +- **Standard** — The channel has `reply`, `branch`, `spawn_worker`, `route`, `cancel`, `skip`, `react`. It delegates heavy work. It stays responsive. This is today's default and the right mode for ongoing async conversations. +- **Direct** — The channel gets the full tool set: memory tools, shell, file operations, browser, web search, **plus** delegation tools. The agent can choose to do things directly or spawn workers. This is what cortex chat provides today — the "power user" mode. + +**Why not just "tools on/off"?** Because turning tools "off" for a channel is meaningless — it already barely has tools. The meaningful toggle is whether the channel can act directly or must delegate. "Direct" mode is strictly additive. + +#### `worker_context: WorkerContextMode` + +```rust +struct WorkerContextMode { + history: WorkerHistoryMode, // What conversation context the worker sees + memory: WorkerMemoryMode, // What memory context the worker gets +} + +enum WorkerHistoryMode { + None, // No conversation history (current default) + Summary, // LLM-generated summary of recent conversation context + Recent(u32), // Last N messages from the parent conversation, injected into system prompt + Full, // Full conversation history clone (branch-style) +} + +enum WorkerMemoryMode { + None, // No memory context (current default) + Ambient, // Knowledge synthesis + working memory injected into system prompt (read-only) + Tools, // Ambient context + memory_recall tool (can search but not write) + Full, // Ambient context + full memory tools (recall, save, delete) — branch-level access +} +``` + +This is the most important new axis. Today, the gap between "worker" and "branch" is a cliff — branches see everything, workers see nothing. Worker context settings turn this into a spectrum. + +**`WorkerHistoryMode` options:** + +- **None** — Current behavior. Worker sees only the task description. Channel must front-load all context into the task string. Cheapest, most isolated, fastest to start. +- **Summary** — Before spawning the worker, the channel generates a brief summary of the relevant conversation context and prepends it to the worker's system prompt. Cost: one extra LLM call at spawn time (can use a cheap model). Benefit: worker understands why the task exists without seeing the full transcript. +- **Recent(N)** — Last N conversation messages injected into the worker's system prompt as context (similar to how cortex chat injects channel context). No extra LLM call. Worker sees recent exchanges but not the full history. Good middle ground. +- **Full** — Worker receives a clone of the full channel history, same as a branch. Most expensive in tokens, but gives the worker complete conversational context. + +**`WorkerMemoryMode` options:** + +- **None** — Current behavior. No memory context, no memory tools. Worker is a pure executor. +- **Ambient** — Knowledge synthesis + working memory injected into the worker's system prompt. Worker has ambient awareness of what the agent knows — identity, facts, preferences, decisions, recent activity — but can't search or write. Read-only, no extra tools, minimal cost. +- **Tools** — Ambient context + `memory_recall` tool. Worker can actively search the agent's memory when it needs context. Cannot save new memories (that's still a branch concern). This is the "informed executor" mode. +- **Full** — Ambient context + full memory tools (recall, save, delete). Worker operates at branch-level memory access. Use sparingly — this blurs the worker/branch boundary. + +**Why this matters for the Spacedrive interface:** When a user starts a "Hands-on" conversation in Spacedrive (Direct delegation, memory off), the workers spawned from that conversation should probably get more context than workers spawned from a Discord channel with 50 participants. The user is sitting right there, interacting directly — the workers are extensions of that focused session. + +**Implementation:** Worker context settings are resolved at spawn time in `spawn_worker_from_state()`: + +```rust +fn spawn_worker_with_context( + state: &ChannelState, + task: &str, + settings: &ResolvedConversationSettings, +) { + let mut system_prompt = render_worker_prompt(...); + + // Inject memory context + match settings.worker_context.memory { + WorkerMemoryMode::None => { /* current behavior */ } + WorkerMemoryMode::Ambient | WorkerMemoryMode::Tools | WorkerMemoryMode::Full => { + // Inject knowledge synthesis (primary memory context) + let knowledge = state.deps.runtime_config.knowledge_synthesis(); + system_prompt.push_str(&format!("\n\n## Knowledge Context\n{knowledge}")); + // Inject working memory (temporal context) + if let Some(wm) = render_working_memory(&state.deps.working_memory_store, &config).await { + system_prompt.push_str(&format!("\n\n{wm}")); + } + } + } + + // Build history + let history = match settings.worker_context.history { + WorkerHistoryMode::None => vec![], + WorkerHistoryMode::Summary => { + let summary = generate_context_summary(state, task).await; + // Inject as a system message at the start + vec![Message::system(format!("[Conversation context]: {summary}"))] + } + WorkerHistoryMode::Recent(n) => { + let h = state.history.read().await; + h.iter().rev().take(n as usize).rev().cloned().collect() + } + WorkerHistoryMode::Full => { + let h = state.history.read().await; + h.clone() + } + }; + + // Build tool server + let mut tool_server = create_worker_tool_server(...); + match settings.worker_context.memory { + WorkerMemoryMode::Tools => { + tool_server.add(MemoryRecallTool::new(...)); + } + WorkerMemoryMode::Full => { + tool_server.add(MemoryRecallTool::new(...)); + tool_server.add(MemorySaveTool::new(...)); + tool_server.add(MemoryDeleteTool::new(...)); + } + _ => {} + } + + Worker::new(..., task, system_prompt, history, tool_server) +} +``` + +### Configuration Hierarchy (Proposed) + +``` +Agent Config (TOML) — defaults for all conversations +├── defaults.conversation_settings: +│ ├── model: None (use routing config) +│ ├── memory: Full +│ ├── delegation: Standard +│ └── worker_context: { history: None, memory: None } +│ +├── Per-Channel Override (TOML or runtime API) +│ └── channels["discord:guild:channel"].settings: +│ ├── model: "anthropic/claude-haiku-4.5" +│ ├── memory: Ambient +│ ├── delegation: Standard +│ └── worker_context: { history: None, memory: Ambient } +│ +└── Per-Conversation Override (runtime, stored in DB) + └── portal_conversations.settings: + ├── model: "anthropic/claude-opus-4" + ├── memory: Off + ├── delegation: Direct + └── worker_context: { history: Recent(20), memory: Tools } +``` + +**Resolution order:** Per-conversation > Per-channel > Agent default > System default + +For portal conversations, "per-channel" doesn't apply (there's no binding). For platform channels, "per-conversation" doesn't apply (Discord threads aren't separate conversations in this model — they share the channel's settings). + +### Sunsetting Cortex Chat + +With these settings, cortex chat becomes a conversation preset, not a separate system: + +**"Cortex mode" conversation** = `{ model: None, memory: Off, delegation: Direct, worker_context: { history: Recent(20), memory: Tools } }` + +The user starts a new conversation, toggles delegation to Direct, turns memory off, and they have cortex chat. No separate concept, no separate table, no separate API. + +**Migration path:** + +1. Add `ConversationSettings` to `portal_conversations` table (JSON column). +2. Add `ConversationSettings` to channel config (TOML + runtime). +3. Wire settings into channel creation — read settings when spawning a channel process. +4. In `Direct` mode, use `create_cortex_chat_tool_server()` (or a new unified factory) instead of `add_channel_tools()`. +5. In `Off` memory mode, skip knowledge synthesis, working memory, and channel activity map injection in the system prompt. +6. Deprecate `/api/cortex-chat/*` endpoints. Keep them working but add a sunset header. +7. Remove cortex chat from the UI. Replace with conversation presets. + +**What about cortex chat's channel context injection?** Today, opening cortex chat on a channel page injects the last 50 messages from that channel. This is useful. In the new model, a "Direct" conversation can have a `channel_context` field — "I'm looking at Discord #general" — and the system prompt injects that context. This is an optional enhancement, not a blocker. + +**What about cortex chat's admin-only access?** Cortex chat is implicitly admin-only because it's in the dashboard. In the portal/Spacedrive context, all users are the owner. If multi-user access control becomes needed, it should be a separate authorization layer, not a property of conversation mode. + +--- + +## Schema Changes + +### `portal_conversations` table (renamed from `webchat_conversations`) + +Add a `settings` JSON column: + +```sql +ALTER TABLE portal_conversations ADD COLUMN settings TEXT; +-- JSON: {"model": "...", "memory": "full|ambient|off", "delegation": "standard|direct", +-- "worker_context": {"history": "none|summary|recent:20|full", "memory": "none|ambient|tools|full"}} +-- NULL means "use defaults" +``` + +### `channels` table + +Add a `settings` JSON column: + +```sql +ALTER TABLE channels ADD COLUMN settings TEXT; +-- Same schema as above. NULL means "use agent defaults" +``` + +### Config TOML + +```toml +[defaults.conversation_settings] +memory = "full" # "full", "ambient", "off" +delegation = "standard" # "standard", "direct" +# model omitted = use routing config + +[defaults.conversation_settings.worker_context] +history = "none" # "none", "summary", "recent:20", "full" +memory = "none" # "none", "ambient", "tools", "full" +``` + +Per-channel overrides in bindings: + +```toml +[[bindings]] +agent_id = "star" +channel = "discord" +guild_id = "123456" +channel_ids = ["789"] + +[bindings.settings] +model = "anthropic/claude-haiku-4.5" +memory = "ambient" +delegation = "standard" + +[bindings.settings.worker_context] +history = "none" +memory = "ambient" +``` + +--- + +## API Changes + +### Portal Endpoints (renamed from `/webchat/*`) + +**POST /portal/conversations** — Add optional `settings` field: + +```json +{ + "agent_id": "star", + "title": "Quick coding help", + "settings": { + "model": "anthropic/claude-opus-4", + "memory": "off", + "delegation": "direct", + "worker_context": { + "history": "recent:20", + "memory": "tools" + } + } +} +``` + +**PUT /portal/conversations/{id}** — Allow updating `settings`: + +```json +{ + "agent_id": "star", + "settings": { + "memory": "ambient" + } +} +``` + +Settings changes take effect on the **next message** in the conversation. In-flight channel processes are not interrupted. + +**GET /portal/conversations** — Return `settings` in response (null = defaults). + +**Full endpoint rename:** + +| Old | New | +|-----|-----| +| `POST /webchat/send` | `POST /portal/send` | +| `GET /webchat/history` | `GET /portal/history` | +| `GET /webchat/conversations` | `GET /portal/conversations` | +| `POST /webchat/conversations` | `POST /portal/conversations` | +| `PUT /webchat/conversations/{id}` | `PUT /portal/conversations/{id}` | +| `DELETE /webchat/conversations/{id}` | `DELETE /portal/conversations/{id}` | + +### New Endpoint: GET /api/conversation-defaults + +Returns the resolved default settings for new conversations: + +```json +{ + "model": "anthropic/claude-sonnet-4", + "memory": "full", + "delegation": "standard", + "worker_context": { + "history": "none", + "memory": "none" + }, + "available_models": ["anthropic/claude-sonnet-4", "anthropic/claude-opus-4", "anthropic/claude-haiku-4.5"], + "memory_modes": ["full", "ambient", "off"], + "delegation_modes": ["standard", "direct"], + "worker_history_modes": ["none", "summary", "recent", "full"], + "worker_memory_modes": ["none", "ambient", "tools", "full"] +} +``` + +This replaces the hardcoded model list in the Spacedrive UI. + +### Channel Settings Endpoint + +**PUT /api/channels/{id}/settings** — Update per-channel settings: + +```json +{ + "agent_id": "star", + "settings": { + "model": "anthropic/claude-haiku-4.5", + "memory": "ambient", + "worker_context": { + "memory": "ambient" + } + } +} +``` + +**GET /api/channels/{id}** — Return `settings` in channel info. + +--- + +## Implementation in the Channel Process + +### Channel Creation Changes + +When a channel is created (`main.rs` routing logic), resolve settings: + +```rust +fn resolve_conversation_settings( + agent_config: &AgentConfig, + channel_settings: Option<&ConversationSettings>, + conversation_settings: Option<&ConversationSettings>, +) -> ResolvedConversationSettings { + let defaults = &agent_config.conversation_settings; + + // Per-conversation > Per-channel > Agent default + ResolvedConversationSettings { + model: conversation_settings.and_then(|s| s.model.clone()) + .or_else(|| channel_settings.and_then(|s| s.model.clone())) + .or_else(|| defaults.model.clone()), + memory: conversation_settings.map(|s| s.memory) + .or_else(|| channel_settings.map(|s| s.memory)) + .unwrap_or(defaults.memory), + delegation: conversation_settings.map(|s| s.delegation) + .or_else(|| channel_settings.map(|s| s.delegation)) + .unwrap_or(defaults.delegation), + worker_context: conversation_settings.and_then(|s| s.worker_context.clone()) + .or_else(|| channel_settings.and_then(|s| s.worker_context.clone())) + .unwrap_or_else(|| defaults.worker_context.clone()), + } +} +``` + +### Tool Server Selection + +In `run_agent_turn()`, check delegation mode: + +```rust +match self.resolved_settings.delegation { + DelegationMode::Standard => { + // Current behavior: add_channel_tools() + self.tool_server.add_channel_tools(...); + } + DelegationMode::Direct => { + // Full tool access: memory + execution + delegation + // Use a new factory or merge channel + cortex tool sets + self.tool_server.add_direct_mode_tools(...); + } +} +``` + +### Memory Injection + +In `build_system_prompt()`, check memory mode: + +```rust +match self.resolved_settings.memory { + MemoryMode::Full => { + // Inject all memory layers + enable persistence branches + prompt.set("knowledge_synthesis", &knowledge_synthesis); + prompt.set("working_memory", &working_memory_context); + prompt.set("channel_activity_map", &channel_activity_map); + } + MemoryMode::Ambient => { + // Inject all memory layers, but no persistence + prompt.set("knowledge_synthesis", &knowledge_synthesis); + prompt.set("working_memory", &working_memory_context); + prompt.set("channel_activity_map", &channel_activity_map); + // Skip scheduling persistence branches + } + MemoryMode::Off => { + // No memory context at all + prompt.set("knowledge_synthesis", ""); + prompt.set("working_memory", ""); + prompt.set("channel_activity_map", ""); + } +} +``` + +### Model Override + +In the LLM call, check for model override: + +```rust +let model_name = match &self.resolved_settings.model { + Some(override_model) => override_model.clone(), + None => routing.resolve(ProcessType::Channel, None).to_string(), +}; +``` + +For spawned workers and branches, propagate the override: + +```rust +// In spawn_worker +let worker_model = match &self.resolved_settings.model { + Some(override_model) => override_model.clone(), + None => routing.resolve(ProcessType::Worker, task_type).to_string(), +}; +``` + +--- + +## Interface Changes — Separation of Concerns + +There are three interface surfaces that interact with this feature. The critical constraint is: **do not break the legacy Spacebot dashboard while building the Spacedrive experience.** + +### The Three Surfaces + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ Spacebot Server (Rust) │ +│ ├── /api/portal/* — portal conversation endpoints │ +│ ├── /api/channels/* — channel endpoints │ +│ ├── /api/conversation-defaults — new settings metadata │ +│ └── /api/cortex-chat/* — cortex chat (deprecated later) │ +├─────────────────────────────────────────────────────────────────┤ +│ @spacebot/api-client (shared TS package) │ +│ ├── portalSend(), portalHistory(), etc. │ +│ ├── createPortalConversation({ settings? }) ← new field │ +│ ├── updatePortalConversation({ settings? }) ← new field │ +│ ├── getConversationDefaults() ← new method │ +│ └── All existing methods remain unchanged │ +├──────────────────────┬──────────────────────────────────────────┤ +│ Spacebot Dashboard │ Spacedrive Interface │ +│ (spacebot/interface)│ (spacedrive/.../Spacebot/) │ +│ │ │ +│ ✗ NO changes needed │ ✓ All new settings UI goes here │ +│ - AgentConfig keeps │ - SpacebotContext gets settings state │ +│ its model routing │ - ChatComposer gets settings controls │ +│ - CortexChatPanel │ - ConversationScreen shows active mode │ +│ keeps working │ - New conversation gets settings picker │ +│ - ChannelDetail │ - Presets for common configurations │ +│ unchanged │ │ +│ - Settings page │ │ +│ unchanged │ │ +└──────────────────────┴──────────────────────────────────────────┘ +``` + +### Why the Dashboard Doesn't Change + +The Spacebot dashboard (`spacebot/interface/`) is a developer-facing admin control plane. It already has: + +- **Agent-level model routing** in `AgentConfig.tsx` — 6 model slots (channel, branch, worker, compactor, cortex, voice) with `ModelSelect` component and adaptive thinking controls. These are agent-wide defaults. They keep working. The new per-conversation settings are *overrides* on top of these defaults. +- **Cortex chat** in `CortexChatPanel.tsx` — used in the Cortex route and Channel Detail views. This keeps working until Phase 4 sunset. No dashboard changes needed for deprecation — we just stop rendering it later. +- **Channel management** in `ChannelDetail.tsx` — read-only channel timeline with cortex panel. No per-channel settings UI exists today. Adding per-channel settings to the dashboard is a *future* enhancement, not a blocker. +- **Global settings** in `Settings.tsx` (3000+ lines) — provider credentials, channel bindings, server config. None of this changes. + +The dashboard consumes the same `@spacebot/api-client` package, but it never calls `createPortalConversation()` with settings because its `WebChatPanel` component creates conversations without settings (defaulting to `null`). The new `settings` field is optional — `null` means "use agent defaults." Existing code that doesn't pass settings continues working identically. + +### What Changes in @spacebot/api-client + +All changes are **additive**. No breaking changes to existing methods. + +**Renamed methods (Phase 0 — portal rename):** + +```typescript +// Old (removed after rename) // New +apiClient.webchatSend(...) → apiClient.portalSend(...) +apiClient.webchatHistory(...) → apiClient.portalHistory(...) +apiClient.listWebchatConversations() → apiClient.listPortalConversations() +apiClient.createWebchatConversation()→ apiClient.createPortalConversation() +apiClient.updateWebchatConversation()→ apiClient.updatePortalConversation() +apiClient.deleteWebchatConversation()→ apiClient.deletePortalConversation() +``` + +The rename touches both surfaces simultaneously — the Spacebot dashboard's `WebChatPanel` and `AgentChat.tsx` import from api-client too. This is a coordinated rename across both consumers. It's mechanical but must be done in one pass. + +**New methods (Phase 1):** + +```typescript +// Fetch resolved defaults + available options for settings UI +apiClient.getConversationDefaults(agentId: string): Promise + +// Types +interface ConversationDefaultsResponse { + model: string; // Current default model name + memory: MemoryMode; // Current default memory mode + delegation: DelegationMode; // Current default delegation mode + worker_context: WorkerContextMode; // Current default worker context + available_models: ModelOption[]; // All available models with metadata + memory_modes: MemoryMode[]; + delegation_modes: DelegationMode[]; + worker_history_modes: string[]; + worker_memory_modes: string[]; +} + +interface ModelOption { + id: string; // e.g. "anthropic/claude-sonnet-4" + name: string; // e.g. "Claude Sonnet 4" + provider: string; // e.g. "anthropic" + context_window: number; + supports_tools: boolean; + supports_thinking: boolean; +} + +type MemoryMode = 'full' | 'ambient' | 'off'; +type DelegationMode = 'standard' | 'direct'; + +interface WorkerContextMode { + history: string; // "none" | "summary" | "recent:N" | "full" + memory: string; // "none" | "ambient" | "tools" | "full" +} + +interface ConversationSettings { + model?: string | null; + memory?: MemoryMode; + delegation?: DelegationMode; + worker_context?: WorkerContextMode; +} +``` + +**Updated method signatures (additive):** + +```typescript +// createPortalConversation gains optional settings +apiClient.createPortalConversation(input: { + agentId: string; + title?: string | null; + settings?: ConversationSettings | null; // ← new, optional +}): Promise + +// updatePortalConversation gains optional settings +apiClient.updatePortalConversation(input: { + agentId: string; + sessionId: string; + title?: string | null; + archived?: boolean; + settings?: ConversationSettings | null; // ← new, optional +}): Promise + +// PortalConversationResponse and PortalConversationSummary gain settings field +interface PortalConversationResponse { + // ...existing fields... + settings: ConversationSettings | null; // ← new, nullable +} + +interface PortalConversationSummary { + // ...existing fields... + settings: ConversationSettings | null; // ← new, nullable +} +``` + +**Dashboard impact:** The dashboard's `WebChatPanel` calls `createWebchatConversation({ agentId, title })` (soon `createPortalConversation`). After the type update, `settings` is optional, so this call continues to work — settings defaults to `null`, which means "use agent defaults." The dashboard never needs to pass settings unless it wants to. The `settings` field appears in the response type but the dashboard's list rendering doesn't use it — it only shows title, preview, and timestamp. + +### What Changes in Spacedrive Interface + +All new settings UI lives in `spacedrive/packages/interface/src/Spacebot/`. Here's the file-by-file breakdown. + +#### `SpacebotContext.tsx` — State & Data + +**Remove hardcoded data:** +```typescript +// DELETE these static arrays +export const modelOptions = ['Claude 3.7 Sonnet', 'GPT-5', 'Qwen 2.5 72B']; +export const projectOptions = ['Spacedrive v3', 'Spacebot Runtime', 'Hosted Platform']; +``` + +**Add settings state:** +```typescript +// New state in SpacebotContext +conversationDefaults: ConversationDefaultsResponse | null; // from API +conversationSettings: ConversationSettings; // current selection +setConversationSettings: (s: Partial) => void; +``` + +**Add defaults query:** +```typescript +// New TanStack Query — fetches available models, modes, defaults +const defaultsQuery = useQuery({ + queryKey: ['spacebot', 'conversation-defaults', selectedAgent], + queryFn: () => apiClient.getConversationDefaults(selectedAgent), + staleTime: 60_000, // Defaults don't change often +}); +``` + +**Update conversation creation:** +```typescript +// handleSendMessage — when creating a new conversation, pass settings +const conversation = await apiClient.createPortalConversation({ + agentId: selectedAgent, + title: null, + settings: hasNonDefaultSettings(conversationSettings) + ? conversationSettings + : null, // Don't store if all defaults +}); +``` + +**Add settings from conversation response:** +```typescript +// When loading a conversation, read its settings +const activeConversationSettings: ConversationSettings | null = + activeConversation?.settings ?? null; + +// Resolved settings: conversation-specific if set, else defaults +const resolvedSettings: ConversationSettings = { + model: activeConversationSettings?.model ?? conversationDefaults?.model ?? null, + memory: activeConversationSettings?.memory ?? conversationDefaults?.memory ?? 'full', + delegation: activeConversationSettings?.delegation ?? conversationDefaults?.delegation ?? 'standard', + worker_context: activeConversationSettings?.worker_context ?? conversationDefaults?.worker_context ?? { history: 'none', memory: 'none' }, +}; +``` + +**Expose through context:** +```typescript +// Added to SpacebotContextType +conversationDefaults: ConversationDefaultsResponse | null; +resolvedSettings: ConversationSettings; +updateConversationSettings: (patch: Partial) => Promise; +``` + +The `updateConversationSettings` mutation calls `apiClient.updatePortalConversation()` with the new settings and invalidates the conversation query. + +#### `ChatComposer.tsx` — Settings Controls + +The composer currently has project and model selector popovers that are non-functional. Replace them with real settings controls. + +**Replace model selector:** +``` +Before: Static dropdown cycling through ['Claude 3.7 Sonnet', 'GPT-5', 'Qwen 2.5 72B'] +After: Real model dropdown populated from conversationDefaults.available_models + Selecting a model calls updateConversationSettings({ model: selectedId }) +``` + +**Replace project selector with memory/delegation toggles:** +``` +Before: Static dropdown cycling through project names (unused) +After: Two compact selectors: + Memory: [On ▾] / [Context Only ▾] / [Off ▾] + Mode: [Standard ▾] / [Direct ▾] +``` + +The composer bottom bar becomes: + +``` +┌──────────────────────────────────────────────────────┐ +│ [textarea input area] │ +│ │ +│ [Model: Sonnet 4 ▾] [Memory: On ▾] [Mode ▾] [⎈] │ +└──────────────────────────────────────────────────────┘ + ^ + settings gear → opens + full settings panel + with worker context +``` + +The `[⎈]` gear icon opens a popover/panel for advanced settings (worker context, presets). The three inline selectors cover the most common toggles without requiring the panel. + +**New component: `ConversationSettingsPanel.tsx`** + +``` +spacedrive/packages/interface/src/Spacebot/ConversationSettingsPanel.tsx +``` + +A panel (popover or slide-out) with: + +``` +Model +[Sonnet 4 ▾] — searchable dropdown from available_models + +Memory +( ) On — Full memory context, auto-persistence +( ) Context Only — Memory context visible, no writes +( ) Off — No memory context + +Mode +( ) Standard — Delegates to workers and branches +( ) Direct — Full tool access (shell, files, memory) + +Worker Context (collapsed by default) + History: [None ▾] — None / Summary / Recent (20) / Full + Memory: [None ▾] — None / Ambient / Tools / Full + +Presets +[Chat] [Focus] [Hands-on] [Quick] [Deep Work] +``` + +Presets are pill buttons that set all fields at once. Selecting one updates the form. User can then tweak individual fields. + +#### `ConversationScreen.tsx` — Active Settings Display + +Show the active settings inline below the conversation header: + +``` +Conversation Title +Sonnet 4 · Memory On · Standard [⎈] +───────────────────────────────────────────────────── +[messages...] +``` + +This is a single line of muted text showing the resolved settings. Clicking `[⎈]` opens the settings panel for editing. If all settings are defaults, this line can be hidden or show just the model name. + +When settings are `Direct` delegation, show a visual indicator (e.g., a subtle border color change or badge) so the user knows the conversation has tool access. + +#### `EmptyChatHero.tsx` — Preset Selection + +The empty chat hero currently says "Let's get to work, James." Update it to: + +1. Replace "James" with the actual user name (from library context or platform). +2. Show preset cards below the greeting: + +``` +Let's get to work, Jamie + +How would you like to work? + +[💬 Chat] [🔧 Hands-on] [⚡ Quick] +Normal Direct tools Fast & cheap +conversation replaces cortex throwaway +``` + +Selecting a preset sets `conversationSettings` in context and focuses the composer. The user's first message creates the conversation with those settings. + +#### `SpacebotLayout.tsx` — No Structural Changes + +The layout (sidebar + topbar + content area) doesn't change structurally. The sidebar conversation list could optionally show a small icon or badge indicating non-default settings (e.g., a wrench icon for Direct mode conversations), but this is polish, not required. + +#### New File: `ConversationSettingsPanel.tsx` + +``` +spacedrive/packages/interface/src/Spacebot/ConversationSettingsPanel.tsx +``` + +This is the only new file. It's a self-contained panel component that: +- Reads `conversationDefaults` and `resolvedSettings` from context +- Renders model dropdown, memory radio group, delegation radio group, worker context dropdowns +- Renders preset buttons +- Calls `updateConversationSettings()` on change +- Uses @sd/ui primitives (DropdownMenu, RadioGroup, Button) and semantic colors + +#### Routes — No New Routes + +No new routes needed. Settings are accessed from within existing conversation views via the settings panel, not from a separate page. The stub routes (Tasks, Memories, Autonomy, Schedule) are unrelated and don't change. + +### Conversation Presets + +Common configurations get named presets: + +| Preset | Model | Memory | Delegation | Worker History | Worker Memory | Use Case | +|--------|-------|--------|------------|----------------|---------------|----------| +| Chat | Default | On | Standard | None | None | Normal conversation | +| Focus | Default | Context Only | Standard | None | None | Sensitive topic, no memory writes | +| Hands-on | Default | Off | Direct | Recent(20) | Tools | Direct tool use, replaces cortex | +| Quick | Haiku | Off | Standard | None | None | Fast, cheap, throwaway | +| Deep Work | Opus | On | Standard | Summary | Ambient | Long-running complex tasks with rich worker context | + +Presets are UI sugar — they set the fields. Users can customize after selecting a preset. Presets are defined client-side in the Spacedrive interface, not stored on the server. + +### Channel Settings (Spacebot Dashboard — Future) + +For platform channels (Discord, Slack), per-channel settings can eventually be added to the Spacebot dashboard's `ChannelDetail.tsx`. This is **not part of the initial implementation** — it requires changes to the dashboard, which we're avoiding. The backend API (`PUT /api/channels/{id}/settings`) supports it, but the dashboard UI can be added later when the feature is proven in the Spacedrive interface. + +``` +Future: #general (Discord) +├── Model: [Sonnet 4 ▾] (override / use default) +├── Memory: [On ▾] +├── Mode: [Standard ▾] +├── Mention Only: [Yes/No] +└── [Advanced: Worker Settings] + ├── History: [None ▾] + └── Memory: [None ▾] +``` + +--- + +## Webchat → Portal Rename + +### Motivation + +"Webchat" and "portal" have been two names for the same thing since the beginning. The conversation ID format already uses `portal:chat:{agent_id}:{uuid}`. The adapter registers as `"webchat"` but the platform is extracted as `"portal"`. This inconsistency has been called out in `multi-agent-communication-graph.md` as needing resolution. + +The name **"portal"** wins because: +- It's already the canonical ID prefix +- It's product-facing (webchat is implementation) +- It describes what it is — a portal into the agent, usable from any surface (browser, Spacedrive, mobile) +- "Webchat" implies a web-only chat widget, which undersells what this is + +### Scope + +This rename touches: + +**Rust source (30 files):** +- 3 module files: `src/api/webchat.rs` → `src/api/portal.rs`, `src/messaging/webchat.rs` → `src/messaging/portal.rs`, `src/conversation/webchat.rs` → `src/conversation/portal.rs` +- 18 struct/type names: `WebChat*` → `Portal*` (e.g., `WebChatConversation` → `PortalConversation`, `WebChatAdapter` → `PortalAdapter`) +- 24 function names: `webchat_*` → `portal_*` +- 8 string literals: `"webchat"` → `"portal"` (adapter name, message source) +- Module declarations in `src/api.rs`, `src/conversation.rs`, `src/messaging.rs` +- References in `src/main.rs`, `src/api/state.rs`, `src/api/server.rs`, `src/tools.rs`, `src/config/types.rs` + +**SQL migration:** +- New migration: `ALTER TABLE webchat_conversations RENAME TO portal_conversations` +- Rename index: `idx_webchat_conversations_agent_updated` → `idx_portal_conversations_agent_updated` + +**TypeScript/React:** +- `interface/src/components/WebChatPanel.tsx` → `PortalChatPanel.tsx` +- `interface/src/hooks/useWebChat.ts` → `usePortal.ts` +- `packages/api-client/src/client.ts`: all `webchat*` methods → `portal*` +- Generated types in `interface/src/api/schema.d.ts` and `types.ts` +- Import references in `interface/src/routes/AgentChat.tsx` + +**API endpoints:** +- `/webchat/send` → `/portal/send` +- `/webchat/history` → `/portal/history` +- `/webchat/conversations` → `/portal/conversations` (CRUD) + +**OpenAPI tags:** `"webchat"` → `"portal"` + +**Documentation:** References in 7 design docs and README. + +### Migration Strategy + +1. **Rename Rust modules and types** — Mechanical rename. `WebChat` → `Portal` everywhere. +2. **Rename SQL table** — Single migration: `ALTER TABLE webchat_conversations RENAME TO portal_conversations`. SQLite supports this natively. +3. **Rename API routes** — Update route registration in `server.rs`. Add temporary redirects from old paths for any external consumers. +4. **Rename adapter** — `PortalAdapter::name()` returns `"portal"`. Update source literals. Remove the `"portal" => "webchat:{id}"` remapping hack in `tools.rs` since the names now match. +5. **Rename TypeScript** — Rename files, update imports, regenerate OpenAPI types. +6. **Conversation ID prefix stays `portal:chat:`** — Already correct. No data migration needed. +7. **Update design docs** — Search-and-replace in markdown files. + +This rename is safe to do in a single commit. The "webchat" name is internal — no external API consumers depend on it (the Spacedrive interface uses the `@spacebot/api-client` package which abstracts the endpoints). + +--- + +## What This Replaces + +| Today | After | +|-------|-------| +| Cortex chat (separate system) | "Direct" mode conversation | +| Cortex chat API (`/api/cortex-chat/*`) | Deprecated, then removed | +| `cortex_chat_messages` table | No longer written to | +| `CortexChatSession` struct | Removed | +| Hardcoded model selector (non-functional) | Per-conversation model override (functional) | +| Agent-global memory settings | Per-conversation memory mode | +| Agent-global tool access | Per-conversation delegation mode | +| Context-starved workers | Configurable worker context (history + memory) | +| "webchat" naming confusion | Unified "portal" naming | +| `webchat_conversations` table | `portal_conversations` table | + +--- + +## Migration + +### Phase 0 — Portal Rename + +Rename webchat → portal throughout the codebase. This is a prerequisite because it's purely mechanical and removes naming confusion before the settings work begins. + +1. Rename Rust modules, structs, functions, string literals. +2. Add SQL migration to rename table and index. +3. Rename TypeScript files, components, hooks, API methods. +4. Update API route paths. +5. Remove `portal → webchat` remapping hack in tools.rs. +6. Update documentation. + +### Phase 1 — Add Settings Infrastructure + +1. Add `settings` column to `portal_conversations` and `channels` tables. +2. Add `ConversationSettings` struct to config types (with `WorkerContextMode`). +3. Add `conversation_settings` defaults to agent config. +4. Add `resolve_conversation_settings()` function. +5. Wire settings into conversation create/update API. +6. Add `/api/conversation-defaults` endpoint. + +### Phase 2 — Wire Into Channel Process + +1. Pass resolved settings into `Channel::new()`. +2. Branch tool server selection on `delegation` mode. +3. Branch memory injection on `memory` mode. +4. Branch model resolution on `model` override. +5. Wire worker context settings into `spawn_worker_from_state()`. +6. Add knowledge synthesis + working memory injection and history cloning to worker creation based on settings. +7. Add memory tools to worker tool server when `worker_context.memory` is `Tools` or `Full`. + +### Phase 3 — Wire Into UI + +1. Add settings controls to new conversation dialog in Spacedrive. +2. Add settings display/edit to conversation header. +3. Add presets. +4. Replace non-functional model selector. +5. Add advanced worker context settings (collapsed by default). + +### Phase 4 — Sunset Cortex Chat + +1. Stop showing cortex chat in dashboard UI. +2. Add deprecation notice to cortex chat API endpoints. +3. Offer migration: convert existing cortex chat threads to portal conversations with `Direct` mode. +4. Eventually remove `CortexChatSession`, cortex chat API routes, and `cortex_chat_messages` table. + +--- + +## Open Questions + +1. **Should model override propagate to workers unconditionally?** If a user picks Opus for a conversation and the agent spawns 5 workers, that's expensive. Option: override only applies to the channel process, workers still use routing defaults. Or: show estimated cost in the UI. + +2. **Should "Direct" mode keep personality?** Cortex chat strips personality. But a "Direct" conversation might feel better with personality intact — you're still talking to your agent, just with more power. Proposal: keep personality, add a "technical mode" flag separately if needed. + +3. **Per-channel settings for Discord threads?** Discord threads inherit their parent channel's settings. Should a user be able to override per-thread? Probably not in v1 — threads are ephemeral. + +4. **Settings changes mid-conversation?** Proposed: take effect on next message. But what if the user switches from Standard to Direct mid-conversation — does the history context change? The channel process would need to reload its tool server. This is doable (tools are per-turn already) but needs care. + +5. **Should `Ambient` mode still allow explicit memory tool use in Direct mode?** If delegation is Direct and memory is Ambient, the agent has memory tools but we said "no writes." Option: Ambient removes `memory_save` tool but keeps `memory_recall`. Off removes both. + +6. **Channel-level settings via TOML vs API?** TOML is static and requires restart. API is runtime. Proposal: support both. TOML provides initial defaults, API allows runtime changes that persist to DB. DB overrides TOML. + +7. **Worker context cost guardrails?** `WorkerHistoryMode::Full` with a long conversation could inject thousands of tokens into every worker. Should there be a token budget cap? A max message count even in Full mode? Or is that the user's problem — they opted in. + +8. **Summary mode implementation?** `WorkerHistoryMode::Summary` requires an extra LLM call at spawn time. Which model? The compactor model (cheap, fast)? The conversation's override model? A hardcoded summarizer? This adds latency to worker spawning. diff --git a/interface/bun.lock b/interface/bun.lock index 4fc28204e..0b5178050 100644 --- a/interface/bun.lock +++ b/interface/bun.lock @@ -33,6 +33,8 @@ "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", "@react-sigma/core": "^5.0.6", + "@spaceui/primitives": "file:../../spaceui/packages/primitives", + "@spaceui/tokens": "file:../../spaceui/packages/tokens", "@tanstack/react-query": "^5.62.0", "@tanstack/react-query-devtools": "^5.91.3", "@tanstack/react-router": "^1.159.5", @@ -212,8 +214,58 @@ "@emotion/weak-memoize": ["@emotion/weak-memoize@0.4.0", "", {}, "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg=="], + "@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.4", "", { "os": "aix", "cpu": "ppc64" }, "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q=="], + + "@esbuild/android-arm": ["@esbuild/android-arm@0.27.4", "", { "os": "android", "cpu": "arm" }, "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ=="], + + "@esbuild/android-arm64": ["@esbuild/android-arm64@0.27.4", "", { "os": "android", "cpu": "arm64" }, "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw=="], + + "@esbuild/android-x64": ["@esbuild/android-x64@0.27.4", "", { "os": "android", "cpu": "x64" }, "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw=="], + "@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.12", "", { "os": "darwin", "cpu": "arm64" }, ""], + "@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.27.4", "", { "os": "darwin", "cpu": "x64" }, "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw=="], + + "@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.27.4", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw=="], + + "@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.27.4", "", { "os": "freebsd", "cpu": "x64" }, "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ=="], + + "@esbuild/linux-arm": ["@esbuild/linux-arm@0.27.4", "", { "os": "linux", "cpu": "arm" }, "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg=="], + + "@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.27.4", "", { "os": "linux", "cpu": "arm64" }, "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA=="], + + "@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.27.4", "", { "os": "linux", "cpu": "ia32" }, "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA=="], + + "@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA=="], + + "@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw=="], + + "@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.27.4", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA=="], + + "@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.27.4", "", { "os": "linux", "cpu": "none" }, "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw=="], + + "@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.27.4", "", { "os": "linux", "cpu": "s390x" }, "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA=="], + + "@esbuild/linux-x64": ["@esbuild/linux-x64@0.27.4", "", { "os": "linux", "cpu": "x64" }, "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA=="], + + "@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q=="], + + "@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.27.4", "", { "os": "none", "cpu": "x64" }, "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg=="], + + "@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.27.4", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow=="], + + "@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.27.4", "", { "os": "openbsd", "cpu": "x64" }, "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ=="], + + "@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.27.4", "", { "os": "none", "cpu": "arm64" }, "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg=="], + + "@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.27.4", "", { "os": "sunos", "cpu": "x64" }, "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g=="], + + "@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.27.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg=="], + + "@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.27.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw=="], + + "@esbuild/win32-x64": ["@esbuild/win32-x64@0.27.4", "", { "os": "win32", "cpu": "x64" }, "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg=="], + "@floating-ui/core": ["@floating-ui/core@1.7.4", "", { "dependencies": { "@floating-ui/utils": "^0.2.10" } }, "sha512-C3HlIdsBxszvm5McXlB8PeOEWfBhcGBTZGkGlWc2U0KFY5IwG5OQEuQ8rq52DZmcHDlPLd+YFBK+cZcytwIFWg=="], "@floating-ui/dom": ["@floating-ui/dom@1.7.5", "", { "dependencies": { "@floating-ui/core": "^1.7.4", "@floating-ui/utils": "^0.2.10" } }, "sha512-N0bD2kIPInNHUHehXhMke1rBGs1dwqvC9O9KYMyyjK7iXt7GAhnro7UlcuYcGdS/yYOlq0MAVgrow8IbWJwyqg=="], @@ -238,6 +290,8 @@ "@giscus/react": ["@giscus/react@3.1.0", "", { "dependencies": { "giscus": "^1.6.0" }, "peerDependencies": { "react": "^16 || ^17 || ^18 || ^19", "react-dom": "^16 || ^17 || ^18 || ^19" } }, "sha512-0TCO2TvL43+oOdyVVGHDItwxD1UMKP2ZYpT6gXmhFOqfAJtZxTzJ9hkn34iAF/b6YzyJ4Um89QIt9z/ajmAEeg=="], + "@headlessui/react": ["@headlessui/react@1.7.19", "", { "dependencies": { "@tanstack/react-virtual": "^3.0.0-beta.60", "client-only": "^0.0.1" }, "peerDependencies": { "react": "^16 || ^17 || ^18", "react-dom": "^16 || ^17 || ^18" } }, "sha512-Ll+8q3OlMJfJbAKM/+/Y2q6PPYbryqNTXDbryx7SXLIDamkF6iQFbriYHga0dY44PvDhvvBWCx1Xj4U5+G4hOw=="], + "@hookform/resolvers": ["@hookform/resolvers@5.2.2", "", { "dependencies": { "@standard-schema/utils": "^0.3.0" }, "peerDependencies": { "react-hook-form": "^7.55.0" } }, "sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA=="], "@hugeicons/core-free-icons": ["@hugeicons/core-free-icons@3.1.1", "", {}, "sha512-UpS2lUQFi5sKyJSWwM6rO+BnPLvVz1gsyCpPHeZyVuZqi89YH8ksliza4cwaODqKOZyeXmG8juo1ty4QtQofkg=="], @@ -294,6 +348,8 @@ "@parcel/watcher-darwin-arm64": ["@parcel/watcher-darwin-arm64@2.5.6", "", { "os": "darwin", "cpu": "arm64" }, ""], + "@phosphor-icons/react": ["@phosphor-icons/react@2.1.10", "", { "peerDependencies": { "react": ">= 16.8", "react-dom": ">= 16.8" } }, "sha512-vt8Tvq8GLjheAZZYa+YG/pW7HDbov8El/MANW8pOAz4eGxrwhnbfrQZq0Cp4q8zBEu8NIhHdnr+r8thnfRSNYA=="], + "@pierre/diffs": ["@pierre/diffs@1.0.11", "", { "dependencies": { "@shikijs/core": "^3.0.0", "@shikijs/engine-javascript": "^3.0.0", "@shikijs/transformers": "^3.0.0", "diff": "8.0.3", "hast-util-to-html": "9.0.5", "lru_map": "0.4.1", "shiki": "^3.0.0" }, "peerDependencies": { "react": "^18.3.1 || ^19.0.0", "react-dom": "^18.3.1 || ^19.0.0" } }, "sha512-j6zIEoyImQy1HfcJqbrDwP0O5I7V2VNXAaw53FqQ+SykRfaNwABeZHs9uibXO4supaXPmTx6LEH9Lffr03e1Tw=="], "@primer/octicons": ["@primer/octicons@19.22.0", "", { "dependencies": { "object-assign": "^4.1.1" } }, "sha512-nWoh9PlE6u7xbiZF3KcUm3ktLpN2rQPt11trwp/t4EsKuYRNVWVbBp1LkCBsvZq7ScckNKUURLigIU0wS1FQdw=="], @@ -312,6 +368,8 @@ "@radix-ui/react-context": ["@radix-ui/react-context@1.1.2", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA=="], + "@radix-ui/react-context-menu": ["@radix-ui/react-context-menu@2.2.16", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww=="], + "@radix-ui/react-dialog": ["@radix-ui/react-dialog@1.1.15", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", "@radix-ui/react-focus-guards": "1.1.3", "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", "aria-hidden": "^1.2.4", "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw=="], "@radix-ui/react-direction": ["@radix-ui/react-direction@1.1.1", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw=="], @@ -338,6 +396,8 @@ "@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.3", "", { "dependencies": { "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ=="], + "@radix-ui/react-progress": ["@radix-ui/react-progress@1.1.8", "", { "dependencies": { "@radix-ui/react-context": "1.1.3", "@radix-ui/react-primitive": "2.1.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-+gISHcSPUJ7ktBy9RnTqbdKW78bcGke3t6taawyZ71pio1JewwGSJizycs7rLhGTvMJYCQB1DBK4KQsxs7U8dA=="], + "@radix-ui/react-radio-group": ["@radix-ui/react-radio-group@1.3.8", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-roving-focus": "1.1.11", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", "@radix-ui/react-use-size": "1.1.1" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ=="], "@radix-ui/react-roving-focus": ["@radix-ui/react-roving-focus@1.1.11", "", { "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" } }, "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA=="], @@ -462,6 +522,18 @@ "@react-sigma/core": ["@react-sigma/core@5.0.6", "", { "peerDependencies": { "graphology": "^0.26.0", "react": "^18.0.0 || ^19.0.0", "sigma": "^3.0.2" } }, "sha512-Xu2qXyvDZIhmvGC1n8d7Kcxm5Ntcz4HbPIM7CPDD2e4h3s/oxVpVPX7wtsNreJRRPj9mK+3oqB6SWXNI4mTqVg=="], + "@react-spring/animated": ["@react-spring/animated@9.7.5", "", { "dependencies": { "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-Tqrwz7pIlsSDITzxoLS3n/v/YCUHQdOIKtOJf4yL6kYVSDTSmVK1LI1Q3M/uu2Sx4X3pIWF3xLUhlsA6SPNTNg=="], + + "@react-spring/core": ["@react-spring/core@9.7.5", "", { "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-rmEqcxRcu7dWh7MnCcMXLvrf6/SDlSokLaLTxiPlAYi11nN3B5oiCUAblO72o+9z/87j2uzxa2Inm8UbLjXA+w=="], + + "@react-spring/rafz": ["@react-spring/rafz@9.7.5", "", {}, "sha512-5ZenDQMC48wjUzPAm1EtwQ5Ot3bLIAwwqP2w2owG5KoNdNHpEJV263nGhCeKKmuA3vG2zLLOdu3or6kuDjA6Aw=="], + + "@react-spring/shared": ["@react-spring/shared@9.7.5", "", { "dependencies": { "@react-spring/rafz": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-wdtoJrhUeeyD/PP/zo+np2s1Z820Ohr/BbuVYv+3dVLW7WctoiN7std8rISoYoHpUXtbkpesSKuPIw/6U1w1Pw=="], + + "@react-spring/types": ["@react-spring/types@9.7.5", "", {}, "sha512-HVj7LrZ4ReHWBimBvu2SKND3cDVUPWKLqRTmWe/fNY6o1owGOX0cAHbdPDTMelgBlVbrTKrre6lFkhqGZErK/g=="], + + "@react-spring/web": ["@react-spring/web@9.7.5", "", { "dependencies": { "@react-spring/animated": "~9.7.5", "@react-spring/core": "~9.7.5", "@react-spring/shared": "~9.7.5", "@react-spring/types": "~9.7.5" }, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0", "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0" } }, "sha512-lmvqGwpe+CSttsWNZVr+Dg62adtKhauGwLyGE/RRyZ8AAMLgb9x3NDMA5RMElXo+IMyTkPp7nxTB8ZQlmhb6JQ=="], + "@redocly/ajv": ["@redocly/ajv@8.11.2", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2", "uri-js-replace": "^1.0.1" } }, "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg=="], "@redocly/config": ["@redocly/config@0.22.0", "", {}, "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ=="], @@ -490,6 +562,10 @@ "@shikijs/vscode-textmate": ["@shikijs/vscode-textmate@10.0.2", "", {}, "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg=="], + "@spaceui/primitives": ["@spaceui/primitives@file:../../spaceui/packages/primitives", { "dependencies": { "@headlessui/react": "^1.7.0", "@phosphor-icons/react": "^2.1.0", "@radix-ui/react-checkbox": "^1.1.0", "@radix-ui/react-context-menu": "^2.2.0", "@radix-ui/react-dialog": "^1.1.0", "@radix-ui/react-dropdown-menu": "^2.1.0", "@radix-ui/react-popover": "^1.1.0", "@radix-ui/react-progress": "^1.1.0", "@radix-ui/react-radio-group": "^1.2.0", "@radix-ui/react-select": "^2.1.0", "@radix-ui/react-slider": "^1.2.0", "@radix-ui/react-switch": "^1.1.0", "@radix-ui/react-tabs": "^1.1.0", "@radix-ui/react-tooltip": "^1.1.0", "@react-spring/web": "^9.7.0", "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "framer-motion": "^11.0.0", "react-hook-form": "^7.50.0", "react-loading-icons": "^1.1.0", "react-resizable-layout": "^0.7.0", "sonner": "^1.4.0", "zod": "^3.22.0" }, "devDependencies": { "@types/react": "^19.0.0", "@types/react-dom": "^19.0.0", "tailwindcss": "^4.1.0", "tsup": "^8.0.0", "typescript": "^5.4.0" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0", "tailwindcss": "^4.1.0" } }], + + "@spaceui/tokens": ["@spaceui/tokens@file:../../spaceui/packages/tokens", {}], + "@splinetool/runtime": ["@splinetool/runtime@0.9.526", "", { "dependencies": { "on-change": "^4.0.0", "semver-compare": "^1.0.0" } }, "sha512-qznHbXA5aKwDbCgESAothCNm1IeEZcmNWG145p5aXj4w5uoqR1TZ9qkTHTKLTsUbHeitCwdhzmRqan1kxboLgQ=="], "@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, ""], @@ -692,6 +768,10 @@ "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": "cli.js" }, ""], + "bundle-require": ["bundle-require@5.1.0", "", { "dependencies": { "load-tsconfig": "^0.2.3" }, "peerDependencies": { "esbuild": ">=0.18" } }, "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA=="], + + "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], + "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "camelcase-css": ["camelcase-css@2.0.1", "", {}, ""], @@ -724,6 +804,8 @@ "classnames": ["classnames@2.5.1", "", {}, "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="], + "client-only": ["client-only@0.0.1", "", {}, "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="], + "clsx": ["clsx@2.1.1", "", {}, ""], "codemirror": ["codemirror@6.0.2", "", { "dependencies": { "@codemirror/autocomplete": "^6.0.0", "@codemirror/commands": "^6.0.0", "@codemirror/language": "^6.0.0", "@codemirror/lint": "^6.0.0", "@codemirror/search": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.0.0" } }, "sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw=="], @@ -742,6 +824,8 @@ "confbox": ["confbox@0.1.8", "", {}, "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w=="], + "consola": ["consola@3.4.2", "", {}, "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA=="], + "convert-source-map": ["convert-source-map@2.0.0", "", {}, ""], "cookie-es": ["cookie-es@2.0.0", "", {}, ""], @@ -916,6 +1000,8 @@ "find-root": ["find-root@1.1.0", "", {}, "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng=="], + "fix-dts-default-cjs-exports": ["fix-dts-default-cjs-exports@1.0.1", "", { "dependencies": { "magic-string": "^0.30.17", "mlly": "^1.7.4", "rollup": "^4.34.8" } }, "sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg=="], + "for-in": ["for-in@1.0.2", "", {}, "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ=="], "fraction.js": ["fraction.js@5.3.4", "", {}, ""], @@ -1038,6 +1124,8 @@ "jiti": ["jiti@1.21.7", "", { "bin": "bin/jiti.js" }, ""], + "joycon": ["joycon@3.1.1", "", {}, "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw=="], + "js-cookie": ["js-cookie@3.0.5", "", {}, "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw=="], "js-levenshtein": ["js-levenshtein@1.1.6", "", {}, "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g=="], @@ -1076,6 +1164,8 @@ "lit-html": ["lit-html@3.3.2", "", { "dependencies": { "@types/trusted-types": "^2.0.2" } }, "sha512-Qy9hU88zcmaxBXcc10ZpdK7cOLXvXpRoBxERdtqV9QOrfpMZZ6pSYP91LhpPtap3sFMUiL7Tw2RImbe0Al2/kw=="], + "load-tsconfig": ["load-tsconfig@0.2.5", "", {}, "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg=="], + "lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="], "lodash-es": ["lodash-es@4.17.23", "", {}, "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg=="], @@ -1090,6 +1180,8 @@ "lucide-react": ["lucide-react@0.469.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-28vvUnnKQ/dBwiCQtwJw7QauYnE7yd2Cyp4tTTJpvglX4EMpbflcdBgrgToX2j71B3YvugK/NH3BGUk+E/p/Fw=="], + "magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="], + "markdown-extensions": ["markdown-extensions@2.0.0", "", {}, "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q=="], "markdown-table": ["markdown-table@3.0.4", "", {}, ""], @@ -1364,6 +1456,8 @@ "react-is": ["react-is@19.2.4", "", {}, ""], + "react-loading-icons": ["react-loading-icons@1.1.0", "", {}, "sha512-Y9eZ6HAufmUd8DIQd6rFrx5Bt/oDlTM9Nsjvf8YpajTa3dI8cLNU8jUN5z7KTANU+Yd6/KJuBjxVlrU2dMw33g=="], + "react-markdown": ["react-markdown@10.1.0", "", { "dependencies": { "@types/hast": "^3.0.0", "@types/mdast": "^4.0.0", "devlop": "^1.0.0", "hast-util-to-jsx-runtime": "^2.0.0", "html-url-attributes": "^3.0.0", "mdast-util-to-hast": "^13.0.0", "remark-parse": "^11.0.0", "remark-rehype": "^11.0.0", "unified": "^11.0.0", "unist-util-visit": "^5.0.0", "vfile": "^6.0.0" }, "peerDependencies": { "@types/react": ">=18", "react": ">=18" } }, ""], "react-merge-refs": ["react-merge-refs@3.0.2", "", { "peerDependencies": { "react": ">=16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "optionalPeers": ["react"] }, "sha512-MSZAfwFfdbEvwkKWP5EI5chuLYnNUxNS7vyS0i1Jp+wtd8J4Ga2ddzhaE68aMol2Z4vCnRM/oGOo1a3V75UPlw=="], @@ -1376,6 +1470,8 @@ "react-remove-scroll-bar": ["react-remove-scroll-bar@2.3.8", "", { "dependencies": { "react-style-singleton": "^2.2.2", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q=="], + "react-resizable-layout": ["react-resizable-layout@0.7.3", "", { "peerDependencies": { "react": ">=17.0.0", "react-dom": ">=17.0.0" } }, "sha512-bQBZ/u5gbn3ijm258KSb5OM2RaqWdDvTppe2ykji6RcSqgEdYui1p7px3MU/1rPMp4o3KPnKQ4Od5UOX4sLe8g=="], + "react-rnd": ["react-rnd@10.5.2", "", { "dependencies": { "re-resizable": "6.11.2", "react-draggable": "4.4.6", "tslib": "2.6.2" }, "peerDependencies": { "react": ">=16.3.0", "react-dom": ">=16.3.0" } }, "sha512-0Tm4x7k7pfHf2snewJA8x7Nwgt3LV+58MVEWOVsFjk51eYruFEa6Wy7BNdxt4/lH0wIRsu7Gm3KjSXY2w7YaNw=="], "react-style-singleton": ["react-style-singleton@2.2.3", "", { "dependencies": { "get-nonce": "^1.0.0", "tslib": "^2.0.0" }, "peerDependencies": { "@types/react": "*", "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ=="], @@ -1442,7 +1538,7 @@ "resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": "bin/resolve" }, ""], - "resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "resolve-from": ["resolve-from@5.0.0", "", {}, "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="], "reusify": ["reusify@1.1.0", "", {}, ""], @@ -1532,7 +1628,7 @@ "tiny-warning": ["tiny-warning@1.0.3", "", {}, ""], - "tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, ""], @@ -1540,6 +1636,8 @@ "to-vfile": ["to-vfile@8.0.0", "", { "dependencies": { "vfile": "^6.0.0" } }, "sha512-IcmH1xB5576MJc9qcfEC/m/nQCFt3fzMHz45sSlgJyTWjRbKW1HAkJpuf3DgE57YzIlZcwcBZA5ENQbBo4aLkg=="], + "tree-kill": ["tree-kill@1.2.2", "", { "bin": { "tree-kill": "cli.js" } }, "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="], + "trim-lines": ["trim-lines@3.0.1", "", {}, ""], "trough": ["trough@2.2.0", "", {}, ""], @@ -1552,6 +1650,8 @@ "tslib": ["tslib@2.8.1", "", {}, ""], + "tsup": ["tsup@8.5.1", "", { "dependencies": { "bundle-require": "^5.1.0", "cac": "^6.7.14", "chokidar": "^4.0.3", "consola": "^3.4.0", "debug": "^4.4.0", "esbuild": "^0.27.0", "fix-dts-default-cjs-exports": "^1.0.0", "joycon": "^3.1.1", "picocolors": "^1.1.1", "postcss-load-config": "^6.0.1", "resolve-from": "^5.0.0", "rollup": "^4.34.8", "source-map": "^0.7.6", "sucrase": "^3.35.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.11", "tree-kill": "^1.2.2" }, "peerDependencies": { "@microsoft/api-extractor": "^7.36.0", "@swc/core": "^1", "postcss": "^8.4.12", "typescript": ">=4.5.0" }, "optionalPeers": ["@microsoft/api-extractor", "@swc/core", "postcss", "typescript"], "bin": { "tsup": "dist/cli-default.js", "tsup-node": "dist/cli-node.js" } }, "sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing=="], + "type-fest": ["type-fest@4.41.0", "", {}, "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, ""], @@ -1638,6 +1738,8 @@ "zwitch": ["zwitch@2.0.4", "", {}, ""], + "@antfu/install-pkg/tinyexec": ["tinyexec@1.0.2", "", {}, "sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg=="], + "@chevrotain/cst-dts-gen/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], "@chevrotain/gast/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], @@ -1664,6 +1766,10 @@ "@lobehub/ui/lucide-react": ["lucide-react@0.563.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-8dXPB2GI4dI8jV4MgUDGBeLdGk8ekfqVZ0BdLcrRzocGgG75ltNEmWS+gE7uokKF/0oSUuczNDT+g9hFJ23FkA=="], + "@radix-ui/react-progress/@radix-ui/react-context": ["@radix-ui/react-context@1.1.3", "", { "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw=="], + + "@radix-ui/react-progress/@radix-ui/react-primitive": ["@radix-ui/react-primitive@2.1.4", "", { "dependencies": { "@radix-ui/react-slot": "1.2.4" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react", "@types/react-dom"] }, "sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg=="], + "@rc-component/dialog/@rc-component/portal": ["@rc-component/portal@2.2.0", "", { "dependencies": { "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ=="], "@rc-component/drawer/@rc-component/portal": ["@rc-component/portal@2.2.0", "", { "dependencies": { "@rc-component/util": "^1.2.1", "clsx": "^2.1.1" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-oc6FlA+uXCMiwArHsJyHcIkX4q6uKyndrPol2eWX8YPkAnztHOPsFIRtmWG4BMlGE5h7YIRE3NiaJ5VS8Lb1QQ=="], @@ -1678,6 +1784,14 @@ "@reduxjs/toolkit/immer": ["immer@11.1.4", "", {}, ""], + "@spaceui/primitives/framer-motion": ["framer-motion@11.18.2", "", { "dependencies": { "motion-dom": "^11.18.1", "motion-utils": "^11.18.1", "tslib": "^2.4.0" }, "peerDependencies": { "@emotion/is-prop-valid": "*", "react": "^18.0.0 || ^19.0.0", "react-dom": "^18.0.0 || ^19.0.0" }, "optionalPeers": ["@emotion/is-prop-valid", "react", "react-dom"] }, "sha512-5F5Och7wrvtLVElIpclDT0CBzMVg3dL22B64aZwHtsIY8RB4mXICLrkajK4G9R+ieSAGcgrLeae2SeUTg2pr6w=="], + + "@spaceui/primitives/sonner": ["sonner@1.7.4", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw=="], + + "@spaceui/primitives/tailwindcss": ["tailwindcss@4.2.2", "", {}, "sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q=="], + + "@spaceui/primitives/zod": ["zod@3.25.76", "", {}, "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ=="], + "anymatch/picomatch": ["picomatch@2.3.1", "", {}, ""], "chevrotain/lodash-es": ["lodash-es@4.17.21", "", {}, "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="], @@ -1698,6 +1812,8 @@ "hoist-non-react-statics/react-is": ["react-is@16.13.1", "", {}, "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="], + "import-fresh/resolve-from": ["resolve-from@4.0.0", "", {}, "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="], + "katex/commander": ["commander@8.3.0", "", {}, "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="], "leva/zustand": ["zustand@3.7.2", "", { "peerDependencies": { "react": ">=16.8" }, "optionalPeers": ["react"] }, "sha512-PIJDIZKtokhof+9+60cpockVOq05sJzHCriyvaLBmEJixseQ1a5Kdov6fWZfWOu5SK9c+FhH1jU0tntLxRJYMA=="], @@ -1728,6 +1844,14 @@ "tailwindcss/chokidar": ["chokidar@3.6.0", "", { "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, ""], + "tsup/esbuild": ["esbuild@0.27.4", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.4", "@esbuild/android-arm": "0.27.4", "@esbuild/android-arm64": "0.27.4", "@esbuild/android-x64": "0.27.4", "@esbuild/darwin-arm64": "0.27.4", "@esbuild/darwin-x64": "0.27.4", "@esbuild/freebsd-arm64": "0.27.4", "@esbuild/freebsd-x64": "0.27.4", "@esbuild/linux-arm": "0.27.4", "@esbuild/linux-arm64": "0.27.4", "@esbuild/linux-ia32": "0.27.4", "@esbuild/linux-loong64": "0.27.4", "@esbuild/linux-mips64el": "0.27.4", "@esbuild/linux-ppc64": "0.27.4", "@esbuild/linux-riscv64": "0.27.4", "@esbuild/linux-s390x": "0.27.4", "@esbuild/linux-x64": "0.27.4", "@esbuild/netbsd-arm64": "0.27.4", "@esbuild/netbsd-x64": "0.27.4", "@esbuild/openbsd-arm64": "0.27.4", "@esbuild/openbsd-x64": "0.27.4", "@esbuild/openharmony-arm64": "0.27.4", "@esbuild/sunos-x64": "0.27.4", "@esbuild/win32-arm64": "0.27.4", "@esbuild/win32-ia32": "0.27.4", "@esbuild/win32-x64": "0.27.4" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ=="], + + "@radix-ui/react-progress/@radix-ui/react-primitive/@radix-ui/react-slot": ["@radix-ui/react-slot@1.2.4", "", { "dependencies": { "@radix-ui/react-compose-refs": "1.1.2" }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "optionalPeers": ["@types/react"] }, "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA=="], + + "@spaceui/primitives/framer-motion/motion-dom": ["motion-dom@11.18.1", "", { "dependencies": { "motion-utils": "^11.18.1" } }, "sha512-g76KvA001z+atjfxczdRtw/RXOM3OMSdd1f4DL77qCTF/+avrRJiawSG4yDibEQ215sr9kpinSlX2pCTJ9zbhw=="], + + "@spaceui/primitives/framer-motion/motion-utils": ["motion-utils@11.18.1", "", {}, "sha512-49Kt+HKjtbJKLtgO/LKj9Ld+6vw9BjH5d9sc40R/kVyH8GLAXgT42M2NnuPcJNuA3s9ZfZBUcwIgpmZWGEE+hA=="], + "cytoscape-fcose/cose-base/layout-base": ["layout-base@2.0.1", "", {}, "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg=="], "d3-sankey/d3-array/internmap": ["internmap@1.0.1", "", {}, "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw=="], @@ -1738,6 +1862,8 @@ "tailwindcss/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, ""], + "tsup/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.27.4", "", { "os": "darwin", "cpu": "arm64" }, "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ=="], + "tailwindcss/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, ""], } } diff --git a/interface/package.json b/interface/package.json index 80cb3661f..2b598a11b 100644 --- a/interface/package.json +++ b/interface/package.json @@ -36,6 +36,8 @@ "@radix-ui/react-switch": "^1.2.6", "@radix-ui/react-tabs": "^1.1.13", "@radix-ui/react-tooltip": "^1.2.8", + "@spaceui/primitives": "file:../../spaceui/packages/primitives", + "@spaceui/tokens": "file:../../spaceui/packages/tokens", "@react-sigma/core": "^5.0.6", "@tanstack/react-query": "^5.62.0", "@tanstack/react-query-devtools": "^5.91.3", diff --git a/interface/src/api/client.ts b/interface/src/api/client.ts index 28ea9c64c..6390f6ba3 100644 --- a/interface/src/api/client.ts +++ b/interface/src/api/client.ts @@ -93,7 +93,8 @@ import type { export type { TopologyAgent, TopologyLink, TopologyGroup, TopologyHuman, TopologyResponse }; -// Aliases for backward compatibility +// Conversation-related types +export type { ConversationSettings, ConversationDefaultsResponse } from "./types"; export type ChannelInfo = Types.ChannelResponse; export type WorkerRunInfo = Types.WorkerListItem; export type AssociationItem = Types.Association; @@ -2013,9 +2014,9 @@ export const api = { } }, - // Web Chat API - webChatSend: (agentId: string, sessionId: string, message: string, senderName?: string) => - fetch(`${getApiBase()}/webchat/send`, { + // Portal API (renamed from webchat) + portalSend: (agentId: string, sessionId: string, message: string, senderName?: string) => + fetch(`${getApiBase()}/portal/send`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ @@ -2026,8 +2027,46 @@ export const api = { }), }), - webChatHistory: (agentId: string, sessionId: string, limit = 100) => - fetch(`${getApiBase()}/webchat/history?agent_id=${encodeURIComponent(agentId)}&session_id=${encodeURIComponent(sessionId)}&limit=${limit}`), + portalHistory: (agentId: string, sessionId: string, limit = 100) => + fetch(`${getApiBase()}/portal/history?agent_id=${encodeURIComponent(agentId)}&session_id=${encodeURIComponent(sessionId)}&limit=${limit}`), + + listPortalConversations: (agentId: string, includeArchived = false, limit = 100) => + fetch(`${getApiBase()}/portal/conversations?agent_id=${encodeURIComponent(agentId)}&include_archived=${includeArchived}&limit=${limit}`), + + createPortalConversation: (agentId: string, title?: string, settings?: import("./types").ConversationSettings) => + fetch(`${getApiBase()}/portal/conversations`, { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ agent_id: agentId, title, settings }), + }), + + updatePortalConversation: (agentId: string, sessionId: string, title?: string, archived?: boolean, settings?: import("./types").ConversationSettings) => + fetch(`${getApiBase()}/portal/conversations/${encodeURIComponent(sessionId)}`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ agent_id: agentId, title, archived, settings }), + }), + + deletePortalConversation: (agentId: string, sessionId: string) => + fetch(`${getApiBase()}/portal/conversations/${encodeURIComponent(sessionId)}?agent_id=${encodeURIComponent(agentId)}`, { + method: "DELETE", + }), + + getConversationDefaults: (agentId: string) => + fetchJson(`/conversation-defaults?agent_id=${encodeURIComponent(agentId)}`), + + // Channel settings API + getChannelSettings: (channelId: string, agentId: string) => + fetchJson<{ conversation_id: string; settings: Types.ConversationSettings }>( + `/channels/${encodeURIComponent(channelId)}/settings?agent_id=${encodeURIComponent(agentId)}` + ), + + updateChannelSettings: (channelId: string, agentId: string, settings: Types.ConversationSettings) => + fetch(`${getApiBase()}/channels/${encodeURIComponent(channelId)}/settings`, { + method: "PUT", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ agent_id: agentId, settings }), + }), // Tasks API listTasks: (params?: { agent_id?: string; owner_agent_id?: string; assigned_agent_id?: string; status?: TaskStatus; priority?: TaskPriority; created_by?: string; limit?: number }) => { @@ -2266,9 +2305,9 @@ export const api = { return []; }, - webChatSendAudio: async (agentId: string, _sessionId: string, _blob: Blob): Promise => { + portalSendAudio: async (agentId: string, _sessionId: string, _blob: Blob): Promise => { // TODO: Implement actual audio sending endpoint - console.warn("webChatSendAudio not implemented", agentId); + console.warn("portalSendAudio not implemented", agentId); return new Response(null, { status: 501 }); }, diff --git a/interface/src/api/schema.d.ts b/interface/src/api/schema.d.ts index e5f92ef66..f738c27ff 100644 --- a/interface/src/api/schema.d.ts +++ b/interface/src/api/schema.d.ts @@ -591,6 +591,40 @@ export interface paths { patch?: never; trace?: never; }; + "/agents/workers": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List worker runs for an agent, with live status merged from StatusBlocks. */ + get: operations["list_workers"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; + "/agents/workers/detail": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** Get full detail for a single worker run, including decompressed transcript. */ + get: operations["worker_detail"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/bindings": { parameters: { query?: never; @@ -790,7 +824,7 @@ export interface paths { patch?: never; trace?: never; }; - "/cortex/chat/messages": { + "/cortex-chat/messages": { parameters: { query?: never; header?: never; @@ -811,7 +845,7 @@ export interface paths { patch?: never; trace?: never; }; - "/cortex/chat/send": { + "/cortex-chat/send": { parameters: { query?: never; header?: never; @@ -836,15 +870,14 @@ export interface paths { patch?: never; trace?: never; }; - "/cortex/chat/threads": { + "/cortex-chat/thread": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** List all cortex chat threads for an agent, newest first. */ - get: operations["cortex_chat_threads"]; + get?: never; put?: never; post?: never; /** Delete a cortex chat thread and all its messages. */ @@ -854,6 +887,23 @@ export interface paths { patch?: never; trace?: never; }; + "/cortex-chat/threads": { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + /** List all cortex chat threads for an agent, newest first. */ + get: operations["cortex_chat_threads"]; + put?: never; + post?: never; + delete?: never; + options?: never; + head?: never; + patch?: never; + trace?: never; + }; "/cortex/events": { parameters: { query?: never; @@ -1887,23 +1937,23 @@ export interface paths { patch?: never; trace?: never; }; - "/webchat/history": { + "/webchat/conversations": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - get: operations["webchat_history"]; + get: operations["list_webchat_conversations"]; put?: never; - post?: never; + post: operations["create_webchat_conversation"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; - "/webchat/send": { + "/webchat/conversations/{session_id}": { parameters: { query?: never; header?: never; @@ -1911,27 +1961,22 @@ export interface paths { cookie?: never; }; get?: never; - put?: never; - /** - * Fire-and-forget message injection. The response arrives via the global SSE - * event bus (`/api/events`), same as every other channel. - */ - post: operations["webchat_send"]; - delete?: never; + put: operations["update_webchat_conversation"]; + post?: never; + delete: operations["delete_webchat_conversation"]; options?: never; head?: never; patch?: never; trace?: never; }; - "/workers": { + "/webchat/history": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** List worker runs for an agent, with live status merged from StatusBlocks. */ - get: operations["list_workers"]; + get: operations["webchat_history"]; put?: never; post?: never; delete?: never; @@ -1940,17 +1985,20 @@ export interface paths { patch?: never; trace?: never; }; - "/workers/detail": { + "/webchat/send": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; - /** Get full detail for a single worker run, including decompressed transcript. */ - get: operations["worker_detail"]; + get?: never; put?: never; - post?: never; + /** + * Fire-and-forget message injection. The response arrives via the global SSE + * event bus (`/api/events`), same as every other channel. + */ + post: operations["webchat_send"]; delete?: never; options?: never; head?: never; @@ -2433,6 +2481,10 @@ export interface components { subtasks?: components["schemas"]["TaskSubtask"][]; title: string; }; + CreateWebChatConversationRequest: { + agent_id: string; + title?: string | null; + }; CreateWorktreeRequest: { agent_id: string; branch: string; @@ -3481,6 +3533,11 @@ export interface components { title?: string | null; worker_id?: string | null; }; + UpdateWebChatConversationRequest: { + agent_id: string; + archived?: boolean | null; + title?: string | null; + }; UploadSkillResponse: { installed: string[]; }; @@ -3531,6 +3588,40 @@ export interface components { /** Format: int64 */ startup_delay_secs?: number | null; }; + WebChatConversation: { + agent_id: string; + archived: boolean; + /** Format: date-time */ + created_at: string; + id: string; + title: string; + title_source: string; + /** Format: date-time */ + updated_at: string; + }; + WebChatConversationResponse: { + conversation: components["schemas"]["WebChatConversation"]; + }; + WebChatConversationSummary: { + agent_id: string; + archived: boolean; + /** Format: date-time */ + created_at: string; + id: string; + /** Format: date-time */ + last_message_at?: string | null; + last_message_preview?: string | null; + last_message_role?: string | null; + /** Format: int64 */ + message_count: number; + title: string; + title_source: string; + /** Format: date-time */ + updated_at: string; + }; + WebChatConversationsResponse: { + conversations: components["schemas"]["WebChatConversationSummary"][]; + }; WebChatHistoryMessage: { content: string; id: string; @@ -5272,6 +5363,86 @@ export interface operations { }; }; }; + list_workers: { + parameters: { + query: { + /** @description Agent ID */ + agent_id: string; + /** @description Maximum number of results to return */ + limit: number; + /** @description Number of results to skip */ + offset: number; + /** @description Filter by worker status */ + status?: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WorkerListResponse"]; + }; + }; + /** @description Agent not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + worker_detail: { + parameters: { + query: { + /** @description Agent ID */ + agent_id: string; + /** @description Worker ID */ + worker_id: string; + }; + header?: never; + path?: never; + cookie?: never; + }; + requestBody?: never; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WorkerDetailResponse"]; + }; + }; + /** @description Agent or worker not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; list_bindings: { parameters: { query?: { @@ -5867,27 +6038,27 @@ export interface operations { }; }; }; - cortex_chat_threads: { + cortex_chat_delete_thread: { parameters: { - query: { - /** @description Agent ID */ - agent_id: string; - }; + query?: never; header?: never; path?: never; cookie?: never; }; - requestBody?: never; + requestBody: { + content: { + "application/json": components["schemas"]["CortexChatDeleteThreadRequest"]; + }; + }; responses: { - 200: { + /** @description Thread deleted successfully */ + 204: { headers: { [name: string]: unknown; }; - content: { - "application/json": components["schemas"]["CortexChatThreadsResponse"]; - }; + content?: never; }; - /** @description Agent not found */ + /** @description Agent or thread not found */ 404: { headers: { [name: string]: unknown; @@ -5903,27 +6074,27 @@ export interface operations { }; }; }; - cortex_chat_delete_thread: { + cortex_chat_threads: { parameters: { - query?: never; + query: { + /** @description Agent ID */ + agent_id: string; + }; header?: never; path?: never; cookie?: never; }; - requestBody: { - content: { - "application/json": components["schemas"]["CortexChatDeleteThreadRequest"]; - }; - }; + requestBody?: never; responses: { - /** @description Thread deleted successfully */ - 204: { + 200: { headers: { [name: string]: unknown; }; - content?: never; + content: { + "application/json": components["schemas"]["CortexChatThreadsResponse"]; + }; }; - /** @description Agent or thread not found */ + /** @description Agent not found */ 404: { headers: { [name: string]: unknown; @@ -8272,14 +8443,14 @@ export interface operations { }; }; }; - webchat_history: { + list_webchat_conversations: { parameters: { query: { /** @description Agent ID */ agent_id: string; - /** @description Session ID */ - session_id: string; - /** @description Maximum number of messages to return (default: 100, max: 200) */ + /** @description Include archived conversations */ + include_archived: boolean; + /** @description Maximum number of conversations to return (default: 100, max: 500) */ limit: number; }; header?: never; @@ -8293,7 +8464,7 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["WebChatHistoryMessage"][]; + "application/json": components["schemas"]["WebChatConversationsResponse"]; }; }; /** @description Agent not found */ @@ -8312,7 +8483,7 @@ export interface operations { }; }; }; - webchat_send: { + create_webchat_conversation: { parameters: { query?: never; header?: never; @@ -8321,7 +8492,7 @@ export interface operations { }; requestBody: { content: { - "application/json": components["schemas"]["WebChatSendRequest"]; + "application/json": components["schemas"]["CreateWebChatConversationRequest"]; }; }; responses: { @@ -8330,18 +8501,18 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["WebChatSendResponse"]; + "application/json": components["schemas"]["WebChatConversationResponse"]; }; }; - /** @description Invalid request */ - 400: { + /** @description Agent not found */ + 404: { headers: { [name: string]: unknown; }; content?: never; }; - /** @description Messaging manager not available */ - 503: { + /** @description Internal server error */ + 500: { headers: { [name: string]: unknown; }; @@ -8349,20 +8520,57 @@ export interface operations { }; }; }; - list_workers: { + update_webchat_conversation: { + parameters: { + query?: never; + header?: never; + path: { + /** @description Conversation session ID */ + session_id: string; + }; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["UpdateWebChatConversationRequest"]; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WebChatConversationResponse"]; + }; + }; + /** @description Conversation not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Internal server error */ + 500: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; + delete_webchat_conversation: { parameters: { query: { /** @description Agent ID */ agent_id: string; - /** @description Maximum number of results to return */ - limit: number; - /** @description Number of results to skip */ - offset: number; - /** @description Filter by worker status */ - status?: string; }; header?: never; - path?: never; + path: { + /** @description Conversation session ID */ + session_id: string; + }; cookie?: never; }; requestBody?: never; @@ -8372,10 +8580,10 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["WorkerListResponse"]; + "application/json": components["schemas"]["WebChatSendResponse"]; }; }; - /** @description Agent not found */ + /** @description Conversation not found */ 404: { headers: { [name: string]: unknown; @@ -8391,13 +8599,15 @@ export interface operations { }; }; }; - worker_detail: { + webchat_history: { parameters: { query: { /** @description Agent ID */ agent_id: string; - /** @description Worker ID */ - worker_id: string; + /** @description Session ID */ + session_id: string; + /** @description Maximum number of messages to return (default: 100, max: 200) */ + limit: number; }; header?: never; path?: never; @@ -8410,10 +8620,10 @@ export interface operations { [name: string]: unknown; }; content: { - "application/json": components["schemas"]["WorkerDetailResponse"]; + "application/json": components["schemas"]["WebChatHistoryMessage"][]; }; }; - /** @description Agent or worker not found */ + /** @description Agent not found */ 404: { headers: { [name: string]: unknown; @@ -8429,4 +8639,48 @@ export interface operations { }; }; }; + webchat_send: { + parameters: { + query?: never; + header?: never; + path?: never; + cookie?: never; + }; + requestBody: { + content: { + "application/json": components["schemas"]["WebChatSendRequest"]; + }; + }; + responses: { + 200: { + headers: { + [name: string]: unknown; + }; + content: { + "application/json": components["schemas"]["WebChatSendResponse"]; + }; + }; + /** @description Invalid request */ + 400: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Agent not found */ + 404: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + /** @description Messaging manager not available */ + 503: { + headers: { + [name: string]: unknown; + }; + content?: never; + }; + }; + }; } diff --git a/interface/src/api/types.ts b/interface/src/api/types.ts index 116e8cc05..7fdf7e898 100644 --- a/interface/src/api/types.ts +++ b/interface/src/api/types.ts @@ -8,7 +8,8 @@ import type { components } from "./schema"; export type StatusResponse = components["schemas"]["StatusResponse"]; export type IdleResponse = components["schemas"]["IdleResponse"]; export type HealthResponse = components["schemas"]["HealthResponse"]; -export type InstanceOverviewResponse = components["schemas"]["InstanceOverviewResponse"]; +export type InstanceOverviewResponse = + components["schemas"]["InstanceOverviewResponse"]; // ============================================================================= // Event/SSE Types @@ -41,20 +42,26 @@ export type InstanceOverviewResponse = components["schemas"]["InstanceOverviewRe // Channel Types // ============================================================================= -export type ChannelResponse = components["schemas"]["ChannelResponse"]; +export type ChannelResponse = components["schemas"]["ChannelResponse"] & { + response_mode?: string | null; + model?: string | null; +}; export type ChannelsResponse = components["schemas"]["ChannelsResponse"]; export type MessagesResponse = components["schemas"]["MessagesResponse"]; export type TimelineItem = components["schemas"]["TimelineItem"]; // Status-related -export type CancelProcessRequest = components["schemas"]["CancelProcessRequest"]; -export type CancelProcessResponse = components["schemas"]["CancelProcessResponse"]; +export type CancelProcessRequest = + components["schemas"]["CancelProcessRequest"]; +export type CancelProcessResponse = + components["schemas"]["CancelProcessResponse"]; // Prompt inspection export type PromptCaptureBody = components["schemas"]["PromptCaptureBody"]; // Archive -export type SetChannelArchiveRequest = components["schemas"]["SetChannelArchiveRequest"]; +export type SetChannelArchiveRequest = + components["schemas"]["SetChannelArchiveRequest"]; // ============================================================================= // Worker Types @@ -62,7 +69,8 @@ export type SetChannelArchiveRequest = components["schemas"]["SetChannelArchiveR export type WorkerListItem = components["schemas"]["WorkerListItem"]; export type WorkerListResponse = components["schemas"]["WorkerListResponse"]; -export type WorkerDetailResponse = components["schemas"]["WorkerDetailResponse"]; +export type WorkerDetailResponse = + components["schemas"]["WorkerDetailResponse"]; // Transcript export type ActionContent = components["schemas"]["ActionContent"]; @@ -75,9 +83,11 @@ export type TranscriptStep = components["schemas"]["TranscriptStep"]; export type AgentInfo = components["schemas"]["AgentInfo"]; export type AgentsResponse = components["schemas"]["AgentsResponse"]; export type AgentSummary = components["schemas"]["AgentSummary"]; -export type AgentOverviewResponse = components["schemas"]["AgentOverviewResponse"]; +export type AgentOverviewResponse = + components["schemas"]["AgentOverviewResponse"]; export type AgentProfile = components["schemas"]["AgentProfile"]; -export type AgentProfileResponse = components["schemas"]["AgentProfileResponse"]; +export type AgentProfileResponse = + components["schemas"]["AgentProfileResponse"]; // CRUD export type CreateAgentRequest = components["schemas"]["CreateAgentRequest"]; @@ -88,10 +98,91 @@ export type WarmupSection = components["schemas"]["WarmupSection"]; export type WarmupUpdate = components["schemas"]["WarmupUpdate"]; export type WarmupStatus = components["schemas"]["WarmupStatus"]; export type WarmupStatusEntry = components["schemas"]["WarmupStatusEntry"]; -export type WarmupStatusResponse = components["schemas"]["WarmupStatusResponse"]; +export type WarmupStatusResponse = + components["schemas"]["WarmupStatusResponse"]; export type WarmupState = components["schemas"]["WarmupState"]; -export type WarmupTriggerRequest = components["schemas"]["WarmupTriggerRequest"]; -export type WarmupTriggerResponse = components["schemas"]["WarmupTriggerResponse"]; +export type WarmupTriggerRequest = + components["schemas"]["WarmupTriggerRequest"]; +export type WarmupTriggerResponse = + components["schemas"]["WarmupTriggerResponse"]; + +// Webchat conversations +export type WebChatConversation = components["schemas"]["WebChatConversation"]; +export type WebChatConversationSummary = + components["schemas"]["WebChatConversationSummary"]; +export type WebChatConversationsResponse = + components["schemas"]["WebChatConversationsResponse"]; +export type WebChatConversationResponse = + components["schemas"]["WebChatConversationResponse"]; +export type CreateWebChatConversationRequest = + components["schemas"]["CreateWebChatConversationRequest"]; +export type UpdateWebChatConversationRequest = + components["schemas"]["UpdateWebChatConversationRequest"]; +export type WebChatHistoryMessage = + components["schemas"]["WebChatHistoryMessage"]; + +// Conversation Settings +export type ModelOverrides = { + channel?: string | null; + branch?: string | null; + worker?: string | null; + compactor?: string | null; +}; + +export type ConversationSettings = { + model?: string | null; + model_overrides?: ModelOverrides; + memory?: "full" | "ambient" | "off"; + delegation?: "standard" | "direct"; + response_mode?: "active" | "quiet" | "mention_only"; + save_attachments?: boolean; + worker_context?: { + history?: "none" | "summary" | "recent" | "full"; + memory?: "none" | "ambient" | "tools" | "full"; + }; +}; + +export type ConversationDefaultsResponse = { + model: string; + memory: "full" | "ambient" | "off"; + delegation: "standard" | "direct"; + worker_context: { + history: "none" | "summary" | "recent" | "full"; + memory: "none" | "ambient" | "tools" | "full"; + }; + available_models: Array<{ + id: string; + name: string; + provider: string; + context_window: number; + supports_tools: boolean; + supports_thinking: boolean; + }>; + memory_modes: string[]; + delegation_modes: string[]; + worker_history_modes: string[]; + worker_memory_modes: string[]; +}; + +// Portal conversations (renamed from webchat) +export type PortalConversation = components["schemas"]["WebChatConversation"]; +export type PortalConversationSummary = components["schemas"]["WebChatConversationSummary"]; +export type PortalConversationsResponse = components["schemas"]["WebChatConversationsResponse"]; +export type PortalConversationResponse = components["schemas"]["WebChatConversationResponse"]; +export type CreatePortalConversationRequest = { + agent_id: string; + title?: string | null; + settings?: ConversationSettings | null; +}; +export type UpdatePortalConversationRequest = { + agent_id: string; + title?: string | null; + archived?: boolean | null; + settings?: ConversationSettings | null; +}; +export type PortalHistoryMessage = components["schemas"]["WebChatHistoryMessage"]; +export type PortalSendRequest = components["schemas"]["WebChatSendRequest"]; +export type PortalSendResponse = components["schemas"]["WebChatSendResponse"]; // Activity export type ActivityDayCount = components["schemas"]["ActivityDayCount"]; @@ -104,40 +195,49 @@ export type HeatmapCell = components["schemas"]["HeatmapCell"]; export type Memory = components["schemas"]["Memory"]; export type MemoryType = components["schemas"]["MemoryType"]; -export type MemoriesListResponse = components["schemas"]["MemoriesListResponse"]; +export type MemoriesListResponse = + components["schemas"]["MemoriesListResponse"]; // Search export type MemorySearchResult = components["schemas"]["MemorySearchResult"]; -export type MemoriesSearchResponse = components["schemas"]["MemoriesSearchResponse"]; +export type MemoriesSearchResponse = + components["schemas"]["MemoriesSearchResponse"]; // Graph export type Association = components["schemas"]["Association"]; export type RelationType = components["schemas"]["RelationType"]; export type MemoryGraphResponse = components["schemas"]["MemoryGraphResponse"]; -export type MemoryGraphNeighborsResponse = components["schemas"]["MemoryGraphNeighborsResponse"]; +export type MemoryGraphNeighborsResponse = + components["schemas"]["MemoryGraphNeighborsResponse"]; // ============================================================================= // Cortex Types // ============================================================================= export type CortexEvent = components["schemas"]["CortexEvent"]; -export type CortexEventsResponse = components["schemas"]["CortexEventsResponse"]; +export type CortexEventsResponse = + components["schemas"]["CortexEventsResponse"]; // Chat export type CortexChatMessage = components["schemas"]["CortexChatMessage"]; -export type CortexChatMessagesResponse = components["schemas"]["CortexChatMessagesResponse"]; +export type CortexChatMessagesResponse = + components["schemas"]["CortexChatMessagesResponse"]; export type CortexChatThread = components["schemas"]["CortexChatThread"]; -export type CortexChatThreadsResponse = components["schemas"]["CortexChatThreadsResponse"]; +export type CortexChatThreadsResponse = + components["schemas"]["CortexChatThreadsResponse"]; export type CortexChatToolCall = components["schemas"]["CortexChatToolCall"]; -export type CortexChatSendRequest = components["schemas"]["CortexChatSendRequest"]; -export type CortexChatDeleteThreadRequest = components["schemas"]["CortexChatDeleteThreadRequest"]; +export type CortexChatSendRequest = + components["schemas"]["CortexChatSendRequest"]; +export type CortexChatDeleteThreadRequest = + components["schemas"]["CortexChatDeleteThreadRequest"]; // ============================================================================= // Config Types // ============================================================================= export type AgentConfigResponse = components["schemas"]["AgentConfigResponse"]; -export type AgentConfigUpdateRequest = components["schemas"]["AgentConfigUpdateRequest"]; +export type AgentConfigUpdateRequest = + components["schemas"]["AgentConfigUpdateRequest"]; // Sections export type RoutingSection = components["schemas"]["RoutingSection"]; @@ -145,7 +245,8 @@ export type TuningSection = components["schemas"]["TuningSection"]; export type CompactionSection = components["schemas"]["CompactionSection"]; export type CortexSection = components["schemas"]["CortexSection"]; export type CoalesceSection = components["schemas"]["CoalesceSection"]; -export type MemoryPersistenceSection = components["schemas"]["MemoryPersistenceSection"]; +export type MemoryPersistenceSection = + components["schemas"]["MemoryPersistenceSection"]; export type BrowserSection = components["schemas"]["BrowserSection"]; export type ChannelSection = components["schemas"]["ChannelSection"]; export type SandboxSection = components["schemas"]["SandboxSection"]; @@ -158,7 +259,8 @@ export type TuningUpdate = components["schemas"]["TuningUpdate"]; export type CompactionUpdate = components["schemas"]["CompactionUpdate"]; export type CortexUpdate = components["schemas"]["CortexUpdate"]; export type CoalesceUpdate = components["schemas"]["CoalesceUpdate"]; -export type MemoryPersistenceUpdate = components["schemas"]["MemoryPersistenceUpdate"]; +export type MemoryPersistenceUpdate = + components["schemas"]["MemoryPersistenceUpdate"]; export type BrowserUpdate = components["schemas"]["BrowserUpdate"]; export type ChannelUpdate = components["schemas"]["ChannelUpdate"]; export type SandboxUpdate = components["schemas"]["SandboxUpdate"]; @@ -169,20 +271,29 @@ export type DiscordUpdate = components["schemas"]["DiscordUpdate"]; export type ClosePolicy = components["schemas"]["ClosePolicy"]; // Global settings -export type GlobalSettingsResponse = components["schemas"]["GlobalSettingsResponse"]; -export type GlobalSettingsUpdate = components["schemas"]["GlobalSettingsUpdate"]; -export type GlobalSettingsUpdateResponse = components["schemas"]["GlobalSettingsUpdateResponse"]; +export type GlobalSettingsResponse = + components["schemas"]["GlobalSettingsResponse"]; +export type GlobalSettingsUpdate = + components["schemas"]["GlobalSettingsUpdate"]; +export type GlobalSettingsUpdateResponse = + components["schemas"]["GlobalSettingsUpdateResponse"]; // OpenCode (within global settings) -export type OpenCodeSettingsResponse = components["schemas"]["OpenCodeSettingsResponse"]; -export type OpenCodeSettingsUpdate = components["schemas"]["OpenCodeSettingsUpdate"]; -export type OpenCodePermissionsResponse = components["schemas"]["OpenCodePermissionsResponse"]; -export type OpenCodePermissionsUpdate = components["schemas"]["OpenCodePermissionsUpdate"]; +export type OpenCodeSettingsResponse = + components["schemas"]["OpenCodeSettingsResponse"]; +export type OpenCodeSettingsUpdate = + components["schemas"]["OpenCodeSettingsUpdate"]; +export type OpenCodePermissionsResponse = + components["schemas"]["OpenCodePermissionsResponse"]; +export type OpenCodePermissionsUpdate = + components["schemas"]["OpenCodePermissionsUpdate"]; // Raw config export type RawConfigResponse = components["schemas"]["RawConfigResponse"]; -export type RawConfigUpdateRequest = components["schemas"]["RawConfigUpdateRequest"]; -export type RawConfigUpdateResponse = components["schemas"]["RawConfigUpdateResponse"]; +export type RawConfigUpdateRequest = + components["schemas"]["RawConfigUpdateRequest"]; +export type RawConfigUpdateResponse = + components["schemas"]["RawConfigUpdateResponse"]; // ============================================================================= // Cron Types @@ -192,7 +303,8 @@ export type CronJobInfo = components["schemas"]["CronJobInfo"]; export type CronJobWithStats = components["schemas"]["CronJobWithStats"]; export type CronListResponse = components["schemas"]["CronListResponse"]; export type CronExecutionEntry = components["schemas"]["CronExecutionEntry"]; -export type CronExecutionsResponse = components["schemas"]["CronExecutionsResponse"]; +export type CronExecutionsResponse = + components["schemas"]["CronExecutionsResponse"]; export type CronActionResponse = components["schemas"]["CronActionResponse"]; // Requests @@ -206,17 +318,24 @@ export type TriggerCronRequest = components["schemas"]["TriggerCronRequest"]; export type ProviderStatus = components["schemas"]["ProviderStatus"]; export type ProvidersResponse = components["schemas"]["ProvidersResponse"]; -export type ProviderUpdateRequest = components["schemas"]["ProviderUpdateRequest"]; -export type ProviderUpdateResponse = components["schemas"]["ProviderUpdateResponse"]; +export type ProviderUpdateRequest = + components["schemas"]["ProviderUpdateRequest"]; +export type ProviderUpdateResponse = + components["schemas"]["ProviderUpdateResponse"]; // Model testing -export type ProviderModelTestRequest = components["schemas"]["ProviderModelTestRequest"]; -export type ProviderModelTestResponse = components["schemas"]["ProviderModelTestResponse"]; +export type ProviderModelTestRequest = + components["schemas"]["ProviderModelTestRequest"]; +export type ProviderModelTestResponse = + components["schemas"]["ProviderModelTestResponse"]; // OAuth -export type OpenAiOAuthBrowserStartRequest = components["schemas"]["OpenAiOAuthBrowserStartRequest"]; -export type OpenAiOAuthBrowserStartResponse = components["schemas"]["OpenAiOAuthBrowserStartResponse"]; -export type OpenAiOAuthBrowserStatusResponse = components["schemas"]["OpenAiOAuthBrowserStatusResponse"]; +export type OpenAiOAuthBrowserStartRequest = + components["schemas"]["OpenAiOAuthBrowserStartRequest"]; +export type OpenAiOAuthBrowserStartResponse = + components["schemas"]["OpenAiOAuthBrowserStartResponse"]; +export type OpenAiOAuthBrowserStatusResponse = + components["schemas"]["OpenAiOAuthBrowserStatusResponse"]; // Models export type ModelInfo = components["schemas"]["ModelInfo"]; @@ -228,8 +347,10 @@ export type ModelsResponse = components["schemas"]["ModelsResponse"]; export type IngestFileInfo = components["schemas"]["IngestFileInfo"]; export type IngestFilesResponse = components["schemas"]["IngestFilesResponse"]; -export type IngestUploadResponse = components["schemas"]["IngestUploadResponse"]; -export type IngestDeleteResponse = components["schemas"]["IngestDeleteResponse"]; +export type IngestUploadResponse = + components["schemas"]["IngestUploadResponse"]; +export type IngestDeleteResponse = + components["schemas"]["IngestDeleteResponse"]; // ============================================================================= // Skills Types @@ -237,20 +358,25 @@ export type IngestDeleteResponse = components["schemas"]["IngestDeleteResponse"] export type SkillInfo = components["schemas"]["SkillInfo"]; export type SkillsListResponse = components["schemas"]["SkillsListResponse"]; -export type SkillContentResponse = components["schemas"]["SkillContentResponse"]; +export type SkillContentResponse = + components["schemas"]["SkillContentResponse"]; // Install/Remove export type InstallSkillRequest = components["schemas"]["InstallSkillRequest"]; -export type InstallSkillResponse = components["schemas"]["InstallSkillResponse"]; +export type InstallSkillResponse = + components["schemas"]["InstallSkillResponse"]; export type RemoveSkillRequest = components["schemas"]["RemoveSkillRequest"]; export type RemoveSkillResponse = components["schemas"]["RemoveSkillResponse"]; export type UploadSkillResponse = components["schemas"]["UploadSkillResponse"]; // Registry export type RegistrySkill = components["schemas"]["RegistrySkill"]; -export type RegistryBrowseResponse = components["schemas"]["RegistryBrowseResponse"]; -export type RegistrySearchResponse = components["schemas"]["RegistrySearchResponse"]; -export type RegistrySkillContentResponse = components["schemas"]["RegistrySkillContentResponse"]; +export type RegistryBrowseResponse = + components["schemas"]["RegistryBrowseResponse"]; +export type RegistrySearchResponse = + components["schemas"]["RegistrySearchResponse"]; +export type RegistrySkillContentResponse = + components["schemas"]["RegistrySkillContentResponse"]; // ============================================================================= // Tasks Types @@ -275,34 +401,47 @@ export type AssignRequest = components["schemas"]["AssignRequest"]; // ============================================================================= export type PlatformStatus = components["schemas"]["PlatformStatus"]; -export type AdapterInstanceStatus = components["schemas"]["AdapterInstanceStatus"]; -export type MessagingStatusResponse = components["schemas"]["MessagingStatusResponse"]; -export type MessagingInstanceActionResponse = components["schemas"]["MessagingInstanceActionResponse"]; +export type AdapterInstanceStatus = + components["schemas"]["AdapterInstanceStatus"]; +export type MessagingStatusResponse = + components["schemas"]["MessagingStatusResponse"]; +export type MessagingInstanceActionResponse = + components["schemas"]["MessagingInstanceActionResponse"]; // Instances -export type CreateMessagingInstanceRequest = components["schemas"]["CreateMessagingInstanceRequest"]; -export type DeleteMessagingInstanceRequest = components["schemas"]["DeleteMessagingInstanceRequest"]; +export type CreateMessagingInstanceRequest = + components["schemas"]["CreateMessagingInstanceRequest"]; +export type DeleteMessagingInstanceRequest = + components["schemas"]["DeleteMessagingInstanceRequest"]; export type InstanceCredentials = components["schemas"]["InstanceCredentials"]; // Bindings export type BindingResponse = components["schemas"]["BindingResponse"]; -export type BindingsListResponse = components["schemas"]["BindingsListResponse"]; -export type CreateBindingRequest = components["schemas"]["CreateBindingRequest"]; -export type CreateBindingResponse = components["schemas"]["CreateBindingResponse"]; -export type UpdateBindingRequest = components["schemas"]["UpdateBindingRequest"]; -export type UpdateBindingResponse = components["schemas"]["UpdateBindingResponse"]; -export type DeleteBindingRequest = components["schemas"]["DeleteBindingRequest"]; -export type DeleteBindingResponse = components["schemas"]["DeleteBindingResponse"]; +export type BindingsListResponse = + components["schemas"]["BindingsListResponse"]; +export type CreateBindingRequest = + components["schemas"]["CreateBindingRequest"]; +export type CreateBindingResponse = + components["schemas"]["CreateBindingResponse"]; +export type UpdateBindingRequest = + components["schemas"]["UpdateBindingRequest"]; +export type UpdateBindingResponse = + components["schemas"]["UpdateBindingResponse"]; +export type DeleteBindingRequest = + components["schemas"]["DeleteBindingRequest"]; +export type DeleteBindingResponse = + components["schemas"]["DeleteBindingResponse"]; export type PlatformCredentials = components["schemas"]["PlatformCredentials"]; // Toggles -export type TogglePlatformRequest = components["schemas"]["TogglePlatformRequest"]; -export type DisconnectPlatformRequest = components["schemas"]["DisconnectPlatformRequest"]; +export type TogglePlatformRequest = + components["schemas"]["TogglePlatformRequest"]; +export type DisconnectPlatformRequest = + components["schemas"]["DisconnectPlatformRequest"]; // Web chat export type WebChatSendRequest = components["schemas"]["WebChatSendRequest"]; export type WebChatSendResponse = components["schemas"]["WebChatSendResponse"]; -export type WebChatHistoryMessage = components["schemas"]["WebChatHistoryMessage"]; // ============================================================================= // Links Types @@ -334,8 +473,10 @@ export type Project = components["schemas"]["Project"]; export type ProjectStatus = components["schemas"]["ProjectStatus"]; export type ProjectRepo = components["schemas"]["ProjectRepo"]; export type ProjectWorktree = components["schemas"]["ProjectWorktree"]; -export type ProjectWorktreeWithRepo = components["schemas"]["ProjectWorktreeWithRepo"]; -export type ProjectWithRelations = components["schemas"]["ProjectWithRelations"]; +export type ProjectWorktreeWithRepo = + components["schemas"]["ProjectWorktreeWithRepo"]; +export type ProjectWithRelations = + components["schemas"]["ProjectWithRelations"]; export type ProjectListResponse = components["schemas"]["ProjectListResponse"]; export type ProjectResponse = components["schemas"]["ProjectResponse"]; @@ -344,10 +485,13 @@ export type DiskUsageEntry = components["schemas"]["DiskUsageEntry"]; export type DiskUsageResponse = components["schemas"]["DiskUsageResponse"]; // CRUD -export type CreateProjectRequest = components["schemas"]["CreateProjectRequest"]; -export type UpdateProjectRequest = components["schemas"]["UpdateProjectRequest"]; +export type CreateProjectRequest = + components["schemas"]["CreateProjectRequest"]; +export type UpdateProjectRequest = + components["schemas"]["UpdateProjectRequest"]; export type CreateRepoRequest = components["schemas"]["CreateRepoRequest"]; -export type CreateWorktreeRequest = components["schemas"]["CreateWorktreeRequest"]; +export type CreateWorktreeRequest = + components["schemas"]["CreateWorktreeRequest"]; // Responses export type RepoResponse = components["schemas"]["RepoResponse"]; @@ -366,7 +510,8 @@ export type SecretInfoResponse = components["schemas"]["SecretInfoResponse"]; // CRUD export type PutSecretBody = components["schemas"]["PutSecretBody"]; export type PutSecretResponse = components["schemas"]["PutSecretResponse"]; -export type DeleteSecretResponse = components["schemas"]["DeleteSecretResponse"]; +export type DeleteSecretResponse = + components["schemas"]["DeleteSecretResponse"]; // Encryption export type EncryptResponse = components["schemas"]["EncryptResponse"]; diff --git a/interface/src/components/ChannelCard.tsx b/interface/src/components/ChannelCard.tsx index 0945b7fdb..0105b4591 100644 --- a/interface/src/components/ChannelCard.tsx +++ b/interface/src/components/ChannelCard.tsx @@ -1,10 +1,14 @@ +import { useEffect, useState } from "react"; import { Link } from "@tanstack/react-router"; import { AnimatePresence, motion } from "framer-motion"; -import { useMutation, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { api } from "@/api/client"; import type { ChannelInfo } from "@/api/client"; +import type { ConversationSettings, ConversationDefaultsResponse } from "@/api/types"; import { isOpenCodeWorker, type ActiveBranch, type ActiveWorker, type ChannelLiveState } from "@/hooks/useChannelLiveState"; import { LiveDuration } from "@/components/LiveDuration"; +import { ConversationSettingsPanel } from "@/components/ConversationSettingsPanel"; +import { Popover, PopoverTrigger, PopoverContent } from "@/ui/Popover"; import { formatTimeAgo, formatTimestamp, platformIcon, platformColor } from "@/lib/format"; const VISIBLE_MESSAGES = 6; @@ -87,11 +91,44 @@ export function ChannelCard({ const visible = messages.slice(-VISIBLE_MESSAGES); const hasActivity = workers.length > 0 || branches.length > 0; + const [showSettings, setShowSettings] = useState(false); + const [settings, setSettings] = useState({}); + + const { data: defaults } = useQuery({ + queryKey: ["conversation-defaults", channel.agent_id], + queryFn: () => api.getConversationDefaults(channel.agent_id), + enabled: showSettings, + }); + + const { data: channelSettingsData } = useQuery({ + queryKey: ["channel-settings", channel.id, channel.agent_id], + queryFn: () => api.getChannelSettings(channel.id, channel.agent_id), + enabled: showSettings, + }); + + useEffect(() => { + if (showSettings) { + setSettings(channelSettingsData?.settings ?? {}); + } + }, [channelSettingsData, showSettings]); + const deleteChannel = useMutation({ mutationFn: () => api.deleteChannel(channel.agent_id, channel.id), onSuccess: () => queryClient.invalidateQueries({ queryKey: ["channels"] }), }); + const saveSettingsMutation = useMutation({ + mutationFn: async () => { + const response = await api.updateChannelSettings(channel.id, channel.agent_id, settings); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["channel-settings", channel.id] }); + queryClient.invalidateQueries({ queryKey: ["channels"] }); + setShowSettings(false); + }, + }); + return ( {formatTimeAgo(channel.last_activity_at)} + {channel.response_mode === "quiet" && ( + + Quiet + + )} + {channel.response_mode === "mention_only" && ( + + Mention Only + + )} {hasActivity && ( {workers.length > 0 && `${workers.length}w`} @@ -133,6 +180,38 @@ export function ChannelCard({
+ + + + + e.preventDefault()}> + {defaults && channelSettingsData ? ( + saveSettingsMutation.mutate()} + onCancel={() => setShowSettings(false)} + saving={saveSettingsMutation.isPending} + /> + ) : ( +
Loading...
+ )} +
+
+ ))} +
+ + {/* Core settings */} +
+ + + + + + + + + + + + + + + +
+ + {/* Advanced toggle */} + + + {showAdvanced && ( +
+ {/* Per-process model overrides */} + +
+ + {(["channel", "branch", "worker"] as const).map( + (process) => ( + + + + ), + )} + + +
+ + + + + + + + +
+ )} + + {/* Actions */} +
+ {onCancel && ( + + )} + +
+
+ ); +} diff --git a/interface/src/components/ConversationsSidebar.tsx b/interface/src/components/ConversationsSidebar.tsx new file mode 100644 index 000000000..637542c0e --- /dev/null +++ b/interface/src/components/ConversationsSidebar.tsx @@ -0,0 +1,244 @@ +import { useState } from "react"; +import { Button } from "@/ui/Button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, + DialogFooter, +} from "@/ui/Dialog"; +import { Input } from "@/ui/Input"; +import type { PortalConversationSummary } from "@/api/types"; + +interface ConversationsSidebarProps { + conversations: PortalConversationSummary[]; + activeConversationId: string | null; + onSelectConversation: (id: string) => void; + onCreateConversation: () => void; + onDeleteConversation: (id: string) => void; + onRenameConversation: (id: string, title: string) => void; + onArchiveConversation: (id: string, archived: boolean) => void; + isLoading: boolean; +} + +export function ConversationsSidebar({ + conversations, + activeConversationId, + onSelectConversation, + onCreateConversation, + onDeleteConversation, + onRenameConversation, + onArchiveConversation, + isLoading, +}: ConversationsSidebarProps) { + const [renameDialogOpen, setRenameDialogOpen] = useState(false); + const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + const [selectedConversation, setSelectedConversation] = useState(null); + const [newTitle, setNewTitle] = useState(""); + + const activeConversations = conversations.filter((c) => !c.archived); + const archivedConversations = conversations.filter((c) => c.archived); + + const handleRename = (conv: PortalConversationSummary) => { + setSelectedConversation(conv); + setNewTitle(conv.title); + setRenameDialogOpen(true); + }; + + const handleDelete = (conv: PortalConversationSummary) => { + setSelectedConversation(conv); + setDeleteDialogOpen(true); + }; + + const confirmRename = () => { + if (selectedConversation && newTitle.trim()) { + onRenameConversation(selectedConversation.id, newTitle.trim()); + setRenameDialogOpen(false); + setSelectedConversation(null); + } + }; + + const confirmDelete = () => { + if (selectedConversation) { + onDeleteConversation(selectedConversation.id); + setDeleteDialogOpen(false); + setSelectedConversation(null); + } + }; + + const formatDate = (dateStr: string) => { + const date = new Date(dateStr); + const now = new Date(); + const diffDays = Math.floor((now.getTime() - date.getTime()) / (1000 * 60 * 60 * 24)); + + if (diffDays === 0) { + return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); + } else if (diffDays === 1) { + return "Yesterday"; + } else if (diffDays < 7) { + return date.toLocaleDateString([], { weekday: 'short' }); + } else { + return date.toLocaleDateString([], { month: 'short', day: 'numeric' }); + } + }; + + return ( +
+ {/* New conversation button */} +
+ +
+ + {/* Conversations List */} +
+ {isLoading ? ( +
Loading...
+ ) : activeConversations.length === 0 ? ( +
+ No conversations yet +
+ ) : ( +
+ {activeConversations.map((conv) => ( +
onSelectConversation(conv.id)} + > +
+
{conv.title}
+
+ + {formatDate(conv.updated_at)} + +
+ + + +
+
+ ))} +
+ )} + + {/* Archived Section */} + {archivedConversations.length > 0 && ( +
+
+ Archived +
+
+ {archivedConversations.map((conv) => ( +
onSelectConversation(conv.id)} + > +
+
{conv.title}
+
+ +
+ ))} +
+
+ )} +
+ + {/* Rename Dialog */} + + + + Rename Conversation + + setNewTitle(e.target.value)} + placeholder="Conversation title" + onKeyDown={(e) => { + if (e.key === "Enter") confirmRename(); + }} + /> + + + + + + + + {/* Delete Dialog */} + + + + Delete Conversation + +

+ Are you sure you want to delete "{selectedConversation?.title}"? This cannot be undone. +

+ + + + +
+
+
+ ); +} diff --git a/interface/src/components/WebChatPanel.tsx b/interface/src/components/WebChatPanel.tsx index f3361907b..a0239f074 100644 --- a/interface/src/components/WebChatPanel.tsx +++ b/interface/src/components/WebChatPanel.tsx @@ -1,9 +1,17 @@ import {useEffect, useRef, useState} from "react"; import {Link} from "@tanstack/react-router"; -import {useWebChat} from "@/hooks/useWebChat"; +import {usePortal, getPortalSessionId} from "@/hooks/usePortal"; import {isOpenCodeWorker, type ActiveWorker} from "@/hooks/useChannelLiveState"; import {useLiveContext} from "@/hooks/useLiveContext"; import {Markdown} from "@/components/Markdown"; +import {ConversationSettingsPanel} from "@/components/ConversationSettingsPanel"; +import {ConversationsSidebar} from "@/components/ConversationsSidebar"; +import {Button} from "@/ui/Button"; +import {Popover, PopoverTrigger, PopoverContent} from "@/ui/Popover"; +import {api, type ConversationDefaultsResponse, type ConversationSettings} from "@/api/client"; +import {useQuery, useMutation, useQueryClient} from "@tanstack/react-query"; +import {Settings02Icon} from "@hugeicons/core-free-icons"; +import {HugeiconsIcon} from "@hugeicons/react"; interface WebChatPanelProps { agentId: string; @@ -176,21 +184,98 @@ function FloatingChatInput({ } export function WebChatPanel({agentId}: WebChatPanelProps) { - const {sessionId, isSending, error, sendMessage} = useWebChat(agentId); + const queryClient = useQueryClient(); + const [activeConversationId, setActiveConversationId] = useState(getPortalSessionId(agentId)); + const {isSending, error, sendMessage} = usePortal(agentId, activeConversationId); const {liveStates} = useLiveContext(); const [input, setInput] = useState(""); const scrollRef = useRef(null); + const [showSettings, setShowSettings] = useState(false); + const [settings, setSettings] = useState({}); - const liveState = liveStates[sessionId]; + // Fetch conversations list + const { data: conversationsData, isLoading: conversationsLoading } = useQuery({ + queryKey: ["portal-conversations", agentId], + queryFn: async () => { + const response = await api.listPortalConversations(agentId); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }, + }); + + const conversations = conversationsData?.conversations ?? []; + + // Reset settings when switching conversations, hydrating from cached data if available + useEffect(() => { + const activeConv = conversations.find( + (c: any) => c.id === activeConversationId + ); + setSettings(activeConv?.settings ?? {}); + setShowSettings(false); + }, [activeConversationId, agentId, conversationsData]); + + // Fetch conversation defaults + const {data: defaults, isLoading: defaultsLoading, error: defaultsError} = useQuery({ + queryKey: ["conversation-defaults", agentId], + queryFn: () => api.getConversationDefaults(agentId), + }); + + const liveState = liveStates[activeConversationId]; const timeline = liveState?.timeline ?? []; const isTyping = liveState?.isTyping ?? false; const activeWorkers = Object.values(liveState?.workers ?? {}); const hasActiveWorkers = activeWorkers.length > 0; + // Mutations + const createConversationMutation = useMutation({ + mutationFn: async () => { + const response = await api.createPortalConversation(agentId); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }, + onSuccess: (data) => { + setActiveConversationId(data.conversation.id); + queryClient.invalidateQueries({ queryKey: ["portal-conversations", agentId] }); + }, + }); + + const deleteConversationMutation = useMutation({ + mutationFn: async (id: string) => { + const response = await api.deletePortalConversation(agentId, id); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }, + onSuccess: (_, deletedId) => { + if (activeConversationId === deletedId) { + setActiveConversationId(getPortalSessionId(agentId)); + } + queryClient.invalidateQueries({ queryKey: ["portal-conversations", agentId] }); + }, + }); + + const renameConversationMutation = useMutation({ + mutationFn: async ({ id, title }: { id: string; title: string }) => { + const response = await api.updatePortalConversation(agentId, id, title); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["portal-conversations", agentId] }); + }, + }); + + const archiveConversationMutation = useMutation({ + mutationFn: async ({ id, archived }: { id: string; archived: boolean }) => { + const response = await api.updatePortalConversation(agentId, id, undefined, archived); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["portal-conversations", agentId] }); + }, + }); + // Auto-scroll on new messages or typing state changes. - // Use direct scrollTo on the container instead of scrollIntoView, - // which can propagate scroll to ancestor overflow-hidden containers - // and shift the entire layout (hiding the top navbar). useEffect(() => { const el = scrollRef.current; if (el) { @@ -205,65 +290,141 @@ export function WebChatPanel({agentId}: WebChatPanelProps) { sendMessage(trimmed); }; + const saveSettingsMutation = useMutation({ + mutationFn: async () => { + if (!activeConversationId) return; + const response = await api.updatePortalConversation(agentId, activeConversationId, undefined, undefined, settings); + if (!response.ok) throw new Error(`HTTP ${response.status}`); + return response.json(); + }, + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ["portal-conversations", agentId] }); + setShowSettings(false); + }, + }); + return ( -
- {/* Messages */} -
-
- {hasActiveWorkers && ( -
- -
- )} - - {timeline.length === 0 && !isTyping && ( -
-

- Start a conversation with {agentId} -

-
- )} - - {timeline.map((item) => { - if (item.type !== "message") return null; - return ( -
- {item.role === "user" ? ( -
-
-

- {item.content} -

-
-
- ) : ( -
- {item.content} -
- )} +
+ {/* Sidebar */} + createConversationMutation.mutate()} + onDeleteConversation={(id) => deleteConversationMutation.mutate(id)} + onRenameConversation={(id, title) => renameConversationMutation.mutate({ id, title })} + onArchiveConversation={(id, archived) => archiveConversationMutation.mutate({ id, archived })} + isLoading={conversationsLoading} + /> + + {/* Main Chat Area */} +
+ {/* Header */} +
+
+

{agentId}

+ {defaults && ( + + {defaults.available_models.find((m) => m.id === (settings.model || defaults.model))?.name + ?? settings.model ?? defaults.model} + + )} + {settings.response_mode === "quiet" && ( + + Quiet + + )} + {settings.response_mode === "mention_only" && ( + + Mention Only + + )} +
+ + + + + + {defaultsLoading ? ( +
Loading...
+ ) : defaults ? ( + saveSettingsMutation.mutate()} + onCancel={() => setShowSettings(false)} + saving={saveSettingsMutation.isPending} + /> + ) : ( +
+ {defaultsError instanceof Error ? defaultsError.message : "Failed to load settings"} +
+ )} +
+
+
+ + {/* Messages */} +
+
+ {hasActiveWorkers && ( +
+
- ); - })} + )} - {/* Typing indicator */} - {isTyping && } + {timeline.length === 0 && !isTyping && ( +
+

+ Start a conversation with {agentId} +

+
+ )} - {error && ( -
- {error} -
- )} + {timeline.map((item) => { + if (item.type !== "message") return null; + return ( +
+ {item.role === "user" ? ( +
+
+

+ {item.content} +

+
+
+ ) : ( +
+ {item.content} +
+ )} +
+ ); + })} + + {/* Typing indicator */} + {isTyping && } + + {error && ( +
+ {error} +
+ )} +
-
- {/* Floating input */} - + {/* Floating input */} + +
); } diff --git a/interface/src/hooks/useWebChat.ts b/interface/src/hooks/usePortal.ts similarity index 60% rename from interface/src/hooks/useWebChat.ts rename to interface/src/hooks/usePortal.ts index 95168480e..a5b75b880 100644 --- a/interface/src/hooks/useWebChat.ts +++ b/interface/src/hooks/usePortal.ts @@ -1,16 +1,16 @@ import { useCallback, useState } from "react"; import { api } from "@/api/client"; -export function getPortalChatSessionId(agentId: string) { +export function getPortalSessionId(agentId: string) { return `portal:chat:${agentId}`; } /** - * Sends messages to the webchat endpoint. The response arrives via the global + * Sends messages to the portal endpoint. The response arrives via the global * SSE event bus (same timeline used by regular channels) — no per-request SSE. */ -export function useWebChat(agentId: string) { - const sessionId = getPortalChatSessionId(agentId); +export function usePortal(agentId: string, sessionId?: string) { + const resolvedSessionId = sessionId || getPortalSessionId(agentId); const [isSending, setIsSending] = useState(false); const [error, setError] = useState(null); @@ -22,7 +22,7 @@ export function useWebChat(agentId: string) { setIsSending(true); try { - const response = await api.webChatSend(agentId, sessionId, text); + const response = await api.portalSend(agentId, resolvedSessionId, text); if (!response.ok) { throw new Error(`HTTP ${response.status}`); } @@ -34,8 +34,8 @@ export function useWebChat(agentId: string) { setIsSending(false); } }, - [agentId, sessionId, isSending], + [agentId, resolvedSessionId, isSending], ); - return { sessionId, isSending, error, sendMessage }; + return { sessionId: resolvedSessionId, isSending, error, sendMessage }; } diff --git a/interface/src/hooks/useTheme.ts b/interface/src/hooks/useTheme.ts index 797b76456..7fe73c528 100644 --- a/interface/src/hooks/useTheme.ts +++ b/interface/src/hooks/useTheme.ts @@ -13,25 +13,25 @@ export const THEMES: ThemeOption[] = [ { id: "default", name: "Default", - description: "Dark theme with purple accent", + description: "SpaceUI dark theme with blue accent", className: "", }, { id: "vanilla", name: "Vanilla", - description: "Light theme with blue accent", + description: "SpaceUI light theme", className: "vanilla-theme", }, { id: "midnight", name: "Midnight", - description: "Deep blue dark theme", + description: "SpaceUI midnight dark theme", className: "midnight-theme", }, { id: "noir", name: "Noir", - description: "Pure black and white theme", + description: "SpaceUI high-contrast noir theme", className: "noir-theme", }, ]; diff --git a/interface/src/routes/Overlay.tsx b/interface/src/routes/Overlay.tsx index 0735764e4..b152e28fa 100644 --- a/interface/src/routes/Overlay.tsx +++ b/interface/src/routes/Overlay.tsx @@ -3,7 +3,7 @@ import {useQuery} from "@tanstack/react-query"; import {api} from "@/api/client"; import {useAudioRecorder} from "@/hooks/useAudioRecorder"; import {useTtsPlayback} from "@/hooks/useTtsPlayback"; -import {getPortalChatSessionId} from "@/hooks/useWebChat"; +import {getPortalSessionId} from "@/hooks/usePortal"; import {useEventSource} from "@/hooks/useEventSource"; import {cx} from "@/ui/utils"; import {IS_TAURI, resizeWindow, listen as platformListen} from "@/platform"; @@ -36,7 +36,7 @@ export function Overlay() { const [transcript, setTranscript] = useState>([]); const containerRef = useRef(null); - const sessionId = getPortalChatSessionId(agentId); + const sessionId = getPortalSessionId(agentId); const { state: recorderState, startRecording, @@ -188,7 +188,7 @@ export function Overlay() { setTranscript((prev) => [...prev, {role: "user", text: "[voice message]"}]); try { - const response = await api.webChatSendAudio(agentId, sessionId, blob); + const response = await api.portalSendAudio(agentId, sessionId, blob); if (!response.ok) throw new Error(`HTTP ${response.status}`); // Now waiting for SSE events (typing_state, outbound_message, spoken_response) } catch (error) { diff --git a/interface/src/routes/Settings.tsx b/interface/src/routes/Settings.tsx index b7e834190..313c9c62e 100644 --- a/interface/src/routes/Settings.tsx +++ b/interface/src/routes/Settings.tsx @@ -862,9 +862,9 @@ function AppearanceSection() { function ThemePreview({ themeId }: { themeId: ThemeId }) { const colors = { - default: { bg: "#0d0d0f", sidebar: "#0a0a0b", accent: "#a855f7" }, + default: { bg: "#1b1d2b", sidebar: "#10111a", accent: "#2490ff" }, vanilla: { bg: "#ffffff", sidebar: "#f5f5f6", accent: "#3b82f6" }, - midnight: { bg: "#14162b", sidebar: "#0c0e1a", accent: "#3b82f6" }, + midnight: { bg: "#14162b", sidebar: "#0a0b13", accent: "#3b82f6" }, noir: { bg: "#080808", sidebar: "#000000", accent: "#3b82f6" }, }; const c = colors[themeId]; diff --git a/interface/src/ui/Badge.tsx b/interface/src/ui/Badge.tsx index eb5879e17..813aea04a 100644 --- a/interface/src/ui/Badge.tsx +++ b/interface/src/ui/Badge.tsx @@ -1,80 +1,65 @@ import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; -import { cx } from "./utils"; +import {Badge as SpaceUIBadge} from "@spaceui/primitives"; +import {cva, type VariantProps} from "class-variance-authority"; +import {cx} from "./utils"; -export const badgeStyles = cva( - [ - "inline-flex items-center rounded-full border font-medium transition-colors", - "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", - ], - { - variants: { - variant: { - default: [ - "border-transparent bg-app-button text-ink-dull", - "hover:bg-app-hover hover:text-ink", - ], - accent: [ - "border-transparent bg-accent/15 text-accent", - "hover:bg-accent/25", - ], - amber: [ - "border-transparent bg-amber-500/15 text-amber-500", - "hover:bg-amber-500/25", - ], - violet: [ - "border-transparent bg-violet-500/15 text-violet-500", - "hover:bg-violet-500/25", - ], - blue: [ - "border-transparent bg-blue-500/15 text-blue-500", - "hover:bg-blue-500/25", - ], - red: [ - "border-transparent bg-red-500/15 text-red-500", - "hover:bg-red-500/25", - ], - green: [ - "border-transparent bg-emerald-500/15 text-emerald-500", - "hover:bg-emerald-500/25", - ], - outline: [ - "border-app-line text-ink-dull", - "hover:border-ink-faint hover:text-ink", - ], - }, - size: { - sm: "h-5 px-2 text-tiny gap-1", - md: "h-6 px-2.5 text-xs gap-1.5", - }, - }, - defaultVariants: { - variant: "default", - size: "sm", - }, - } -); +export const badgeStyles = cva("inline-flex items-center rounded-full border font-medium transition-colors", { + variants: { + variant: { + default: "border-transparent bg-app-button text-ink-dull hover:bg-app-hover hover:text-ink", + accent: "border-transparent bg-accent/15 text-accent hover:bg-accent/25", + amber: "border-transparent bg-amber-500/15 text-amber-500 hover:bg-amber-500/25", + violet: "border-transparent bg-violet-500/15 text-violet-500 hover:bg-violet-500/25", + blue: "border-transparent bg-blue-500/15 text-blue-500 hover:bg-blue-500/25", + red: "border-transparent bg-red-500/15 text-red-500 hover:bg-red-500/25", + green: "border-transparent bg-emerald-500/15 text-emerald-500 hover:bg-emerald-500/25", + outline: "border-app-line text-ink-dull hover:border-ink-faint hover:text-ink", + }, + size: { + sm: "h-5 px-2 text-tiny gap-1", + md: "h-6 px-2.5 text-xs gap-1.5", + }, + }, + defaultVariants: { + variant: "default", + size: "sm", + }, +}); export type BadgeBaseProps = VariantProps; export interface BadgeProps - extends React.HTMLAttributes, - BadgeBaseProps { - children?: React.ReactNode; + extends React.HTMLAttributes, + BadgeBaseProps { + children?: React.ReactNode; } export const Badge = React.forwardRef( - ({ className, variant, size, children, ...props }, ref) => { - return ( -
- {children} -
- ); - } + ({className, variant, size, children, ...props}, ref) => { + void ref; + const spaceUiVariant = + variant === "outline" + ? "outline" + : variant === "red" + ? "destructive" + : variant === "green" + ? "success" + : variant === "amber" + ? "warning" + : "secondary"; + + return ( + + {children} + + ); + }, ); Badge.displayName = "Badge"; +const SpaceUIBadgeCompat = SpaceUIBadge as unknown as React.ComponentType; diff --git a/interface/src/ui/Banner.tsx b/interface/src/ui/Banner.tsx index 2a21bee3a..62e58eed9 100644 --- a/interface/src/ui/Banner.tsx +++ b/interface/src/ui/Banner.tsx @@ -1,63 +1,42 @@ import * as React from "react"; -import { cx } from "./utils"; +import {Banner as SpaceUIBanner} from "@spaceui/primitives"; +import {cx} from "./utils"; export type BannerVariant = "info" | "warning" | "error" | "success" | "cyan"; interface BannerProps extends React.HTMLAttributes { - variant?: BannerVariant; - dot?: "pulse" | "static" | "none"; - children: React.ReactNode; + variant?: BannerVariant; + dot?: "pulse" | "static" | "none"; + children: React.ReactNode; } -const variantStyles: Record = { - info: "bg-blue-500/10 text-blue-400 border-blue-500/20", - warning: "bg-amber-500/10 text-amber-400 border-amber-500/20", - error: "bg-red-500/10 text-red-400 border-red-500/20", - success: "bg-green-500/10 text-green-400 border-green-500/20", - cyan: "bg-cyan-500/10 text-cyan-400 border-cyan-500/20", -}; - export function Banner({ - variant = "info", - dot = "static", - className, - children, - ...props + variant = "info", + dot = "static", + className, + children, + ...props }: BannerProps) { - return ( -
-
- {dot !== "none" && ( -
- )} - {children} -
-
- ); + const mappedVariant = variant === "cyan" ? "info" : variant; + + return ( + span:first-child]:animate-pulse", className)} + {...props} + > + {children} + + ); } export function BannerActions({ - children, - className, + children, + className, }: { - children: React.ReactNode; - className?: string; + children: React.ReactNode; + className?: string; }) { - return ( -
- {children} -
- ); + return
{children}
; } diff --git a/interface/src/ui/Button.tsx b/interface/src/ui/Button.tsx index 411f6236b..d2d890d76 100644 --- a/interface/src/ui/Button.tsx +++ b/interface/src/ui/Button.tsx @@ -1,46 +1,30 @@ import * as React from "react"; import {cva, type VariantProps} from "class-variance-authority"; +import {Button as SpaceUIButton, Loader} from "@spaceui/primitives"; import {cx} from "./utils"; -import {Loader} from "./Loader"; -export const buttonStyles = cva( - [ - "inline-flex items-center justify-center rounded-lg font-medium transition-colors", - "disabled:pointer-events-none disabled:opacity-50", - "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2", - ], - { - variants: { - size: { - default: "h-9 px-4 py-2 text-sm", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8 text-sm", - icon: "h-8 w-8 rounded-md p-0", - }, - variant: { - default: ["bg-accent text-white shadow", "hover:bg-accent/90"], - destructive: [ - "border border-app-line bg-transparent text-ink-dull", - "hover:bg-red-600 hover:text-white hover:border-red-600", - ], - outline: [ - "border border-app-line bg-transparent", - "hover:bg-app-hover/40 hover:text-ink", - ], - secondary: [ - "bg-app-darkBox text-ink-dull", - "hover:bg-app-lightBox hover:text-ink", - ], - ghost: ["hover:bg-app-darkBox hover:text-ink-dull", "text-ink-faint"], - link: ["text-accent underline-offset-4", "hover:underline"], - }, +export const buttonStyles = cva("", { + variants: { + size: { + default: "", + sm: "", + lg: "", + icon: "", }, - defaultVariants: { - variant: "default", - size: "default", + variant: { + default: "", + destructive: "", + outline: "", + secondary: "", + ghost: "", + link: "", }, }, -); + defaultVariants: { + variant: "default", + size: "default", + }, +}); export type ButtonBaseProps = VariantProps; @@ -52,28 +36,64 @@ export interface ButtonProps children?: React.ReactNode; } +const sizeMap: Record, "icon" | "sm" | "md" | "lg"> = { + default: "md", + sm: "sm", + lg: "lg", + icon: "icon", +}; + +const variantMap: Record, "accent" | "gray" | "default" | "bare"> = { + default: "accent", + destructive: "gray", + outline: "default", + secondary: "gray", + ghost: "bare", + link: "bare", +}; + +const variantClassMap: Record, string> = { + default: "", + destructive: + "text-ink-dull hover:border-red-600 hover:bg-red-600 hover:text-white", + outline: "", + secondary: "", + ghost: "text-ink-faint hover:bg-app-darkBox hover:text-ink-dull", + link: "h-auto border-none p-0 text-accent underline-offset-4 hover:underline", +}; + export const Button = React.forwardRef( ( { className, - variant, - size, + variant: variantProp = "default", + size: sizeProp = "default", loading, leftIcon, rightIcon, children, disabled, + type = "button", ...props }, ref, ) => { + const variant = variantProp ?? "default"; + const size = sizeProp ?? "default"; const isDisabled = disabled || loading; return ( - + ); }, ); diff --git a/interface/src/ui/Card.tsx b/interface/src/ui/Card.tsx index 320d4c351..4da206195 100644 --- a/interface/src/ui/Card.tsx +++ b/interface/src/ui/Card.tsx @@ -1,110 +1,115 @@ import * as React from "react"; -import { cva, type VariantProps } from "class-variance-authority"; -import { cx } from "./utils"; - -export const cardStyles = cva( - [ - "rounded-xl border transition-colors", - ], - { - variants: { - variant: { - default: [ - "border-app-line bg-app-darkBox", - ], - darker: [ - "border-app-line bg-app-darkerBox", - ], - ghost: [ - "border-transparent bg-transparent", - ], - }, - padding: { - none: "", - sm: "p-3", - md: "p-5", - lg: "p-6", - }, - }, - defaultVariants: { - variant: "default", - padding: "md", - }, - } -); +import { + Card as SpaceUICard, + CardContent as SpaceUICardContent, + CardDescription as SpaceUICardDescription, + CardFooter as SpaceUICardFooter, + CardHeader as SpaceUICardHeader, + CardTitle as SpaceUICardTitle, +} from "@spaceui/primitives"; +import {cva, type VariantProps} from "class-variance-authority"; +import {cx} from "./utils"; + +const SpaceUICardCompat = SpaceUICard as unknown as React.ComponentType; +const SpaceUICardHeaderCompat = SpaceUICardHeader as unknown as React.ComponentType; +const SpaceUICardTitleCompat = SpaceUICardTitle as unknown as React.ComponentType; +const SpaceUICardDescriptionCompat = SpaceUICardDescription as unknown as React.ComponentType; +const SpaceUICardContentCompat = SpaceUICardContent as unknown as React.ComponentType; +const SpaceUICardFooterCompat = SpaceUICardFooter as unknown as React.ComponentType; + +export const cardStyles = cva("", { + variants: { + variant: { + default: "bg-app-darkBox", + darker: "bg-app-darkerBox", + ghost: "border-transparent bg-transparent shadow-none", + }, + padding: { + none: "", + sm: "p-3", + md: "p-5", + lg: "p-6", + }, + }, + defaultVariants: { + variant: "default", + padding: "md", + }, +}); export type CardBaseProps = VariantProps; export interface CardProps - extends React.HTMLAttributes, - CardBaseProps {} + extends React.HTMLAttributes, + CardBaseProps {} export const Card = React.forwardRef( - ({ className, variant, padding, ...props }, ref) => { - return ( -
- ); - } + ({className, variant, padding, ...props}, ref) => { + void ref; + const paddingClass = padding === "none" ? "p-0" : undefined; + + return ( + + ); + }, ); Card.displayName = "Card"; export const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => { + void ref; + return ; +}); + CardHeader.displayName = "CardHeader"; export const CardTitle = React.forwardRef< - HTMLHeadingElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)); + HTMLHeadingElement, + React.HTMLAttributes +>(({className, ...props}, ref) => { + void ref; + return ( + + ); +}); + CardTitle.displayName = "CardTitle"; export const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)); + HTMLParagraphElement, + React.HTMLAttributes +>(({className, ...props}, ref) => { + void ref; + return ; +}); + CardDescription.displayName = "CardDescription"; export const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)); + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => { + void ref; + return ; +}); + CardContent.displayName = "CardContent"; export const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)); + HTMLDivElement, + React.HTMLAttributes +>(({className, ...props}, ref) => { + void ref; + return ; +}); + CardFooter.displayName = "CardFooter"; diff --git a/interface/src/ui/Checkbox.tsx b/interface/src/ui/Checkbox.tsx index 709382451..fa3da3459 100644 --- a/interface/src/ui/Checkbox.tsx +++ b/interface/src/ui/Checkbox.tsx @@ -1,110 +1,101 @@ "use client"; import * as React from "react"; -import * as CheckboxPrimitive from "@radix-ui/react-checkbox"; -import { Tick02Icon, MinusSignIcon } from "@hugeicons/core-free-icons"; -import { HugeiconsIcon } from "@hugeicons/react"; -import { cva, type VariantProps } from "class-variance-authority"; -import { cx } from "./utils"; +import {Check, Minus} from "@phosphor-icons/react"; +import {CheckboxIndicator, CheckboxRoot} from "@spaceui/primitives"; +import {cva, type VariantProps} from "class-variance-authority"; +import {cx} from "./utils"; -const checkboxStyles = cva( - [ - "peer h-4 w-4 shrink-0 rounded border border-app-line", - "ring-offset-app-box focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2", - "disabled:cursor-not-allowed disabled:opacity-50", - "data-[state=checked]:bg-accent data-[state=checked]:border-accent", - "data-[state=indeterminate]:bg-accent data-[state=indeterminate]:border-accent", - ] -); +const CheckboxRootCompat = CheckboxRoot as unknown as React.ComponentType; +const CheckboxIndicatorCompat = CheckboxIndicator as unknown as React.ComponentType; -const indicatorStyles = cva( - "flex items-center justify-center text-current" -); +const checkboxStyles = cva([ + "peer h-4 w-4 shrink-0 rounded border border-app-line", + "ring-offset-app-box focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent focus-visible:ring-offset-2", + "disabled:cursor-not-allowed disabled:opacity-50", + "data-[state=checked]:bg-accent data-[state=checked]:border-accent", + "data-[state=indeterminate]:bg-accent data-[state=indeterminate]:border-accent", +]); + +const indicatorStyles = cva("flex items-center justify-center text-current"); export interface CheckboxProps - extends React.ComponentPropsWithoutRef, - VariantProps { - indeterminate?: boolean; + extends React.ComponentPropsWithoutRef, + VariantProps { + indeterminate?: boolean; } -export const Checkbox = React.forwardRef< - React.ElementRef, - CheckboxProps ->(({ className, indeterminate, checked, ...props }, ref) => ( - - - {indeterminate ? ( - - ) : ( - - )} - - -)); +export const Checkbox = React.forwardRef( + ({className, indeterminate, checked, ...props}, ref) => ( + + + {indeterminate ? ( + + ) : ( + + )} + + + ), +); -Checkbox.displayName = CheckboxPrimitive.Root.displayName; +Checkbox.displayName = "Checkbox"; export interface CheckboxLabelProps { - children: React.ReactNode; - disabled?: boolean; - className?: string; + children: React.ReactNode; + disabled?: boolean; + className?: string; } export const CheckboxLabel: React.FC = ({ - children, - disabled, - className, + children, + disabled, + className, }) => ( - - {children} - + + {children} + ); export interface CheckboxFieldProps { - label: React.ReactNode; - description?: string; - disabled?: boolean; - className?: string; - checkboxProps?: Omit; + label: React.ReactNode; + description?: string; + disabled?: boolean; + className?: string; + checkboxProps?: Omit; } export const CheckboxField: React.FC = ({ - label, - description, - disabled, - className, - checkboxProps, + label, + description, + disabled, + className, + checkboxProps, }) => ( - + ); diff --git a/interface/src/ui/Dialog.tsx b/interface/src/ui/Dialog.tsx index 5e6ebcf33..fcbf97450 100644 --- a/interface/src/ui/Dialog.tsx +++ b/interface/src/ui/Dialog.tsx @@ -1,117 +1,12 @@ -import * as React from "react"; -import * as DialogPrimitive from "@radix-ui/react-dialog"; -import { cx } from "./utils"; -import { Cancel01Icon } from "@hugeicons/core-free-icons"; -import { HugeiconsIcon } from "@hugeicons/react"; - -const Dialog = DialogPrimitive.Root; -const DialogTrigger = DialogPrimitive.Trigger; -const DialogPortal = DialogPrimitive.Portal; -const DialogClose = DialogPrimitive.Close; - -const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; - -const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)); -DialogContent.displayName = DialogPrimitive.Content.displayName; - -const DialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-); -DialogHeader.displayName = "DialogHeader"; - -const DialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-); -DialogFooter.displayName = "DialogFooter"; - -const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogTitle.displayName = DialogPrimitive.Title.displayName; - -const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)); -DialogDescription.displayName = DialogPrimitive.Description.displayName; - export { - Dialog, - DialogPortal, - DialogOverlay, - DialogClose, - DialogTrigger, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, - DialogDescription, -}; + DialogRoot as Dialog, + DialogPortal, + DialogOverlay, + DialogClose, + DialogTrigger, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +} from "@spaceui/primitives"; diff --git a/interface/src/ui/FilterButton.tsx b/interface/src/ui/FilterButton.tsx index 14c8a8a96..ccb42664c 100644 --- a/interface/src/ui/FilterButton.tsx +++ b/interface/src/ui/FilterButton.tsx @@ -1,5 +1,5 @@ import * as React from "react"; -import { cx } from "./utils"; +import {FilterButton as SpaceUIFilterButton} from "@spaceui/primitives"; export interface FilterButtonProps extends React.ButtonHTMLAttributes { @@ -11,20 +11,16 @@ export interface FilterButtonProps export const FilterButton = React.forwardRef< HTMLButtonElement, FilterButtonProps ->(({ active, colorClass, className, children, ...props }, ref) => ( - + {typeof children === "string" ? undefined : children} + )); FilterButton.displayName = "FilterButton"; diff --git a/interface/src/ui/Input.tsx b/interface/src/ui/Input.tsx index 87946252d..f01157e80 100644 --- a/interface/src/ui/Input.tsx +++ b/interface/src/ui/Input.tsx @@ -1,95 +1,65 @@ import * as React from "react"; -import {cva, type VariantProps} from "class-variance-authority"; +import { + Input as SpaceUIInput, + PasswordInput as SpaceUIPasswordInput, + SearchInput as SpaceUISearchInput, + TextArea as SpaceUITextArea, +} from "@spaceui/primitives"; import {cx} from "./utils"; -import {Search01Icon} from "@hugeicons/core-free-icons"; -import {HugeiconsIcon} from "@hugeicons/react"; + +const SpaceUIInputCompat = SpaceUIInput as unknown as React.ComponentType; +const SpaceUITextAreaCompat = SpaceUITextArea as unknown as React.ComponentType; +const SpaceUISearchInputCompat = SpaceUISearchInput as unknown as React.ComponentType; +const SpaceUIPasswordInputCompat = SpaceUIPasswordInput as unknown as React.ComponentType; export const inputSizes = { - sm: "h-8 text-sm px-3 py-1.5", - md: "h-9 text-sm px-3", - lg: "h-10 text-base px-3.5", + sm: "sm", + md: "md", + lg: "lg", } as const; -export const inputStyles = cva( - [ - "rounded-md border text-sm leading-4", - "outline-none transition-colors", - "text-ink", - ], - { - variants: { - variant: { - default: ["border-app-line bg-app-darkBox", "focus-within:border-accent/50"], - transparent: [ - "border-transparent bg-app-box", - "focus-within:border-app-line", - ], - }, - error: { - true: "border-red-500/50 focus-within:border-red-500", - }, - size: inputSizes, - }, - defaultVariants: { - variant: "default", - size: "sm", - }, - }, -); - -type InputVariants = VariantProps; +type LocalSize = keyof typeof inputSizes; export interface InputProps - extends - Omit, "size">, - InputVariants { + extends Omit, "size"> { + size?: LocalSize; + error?: boolean; icon?: React.ReactNode; right?: React.ReactNode; + variant?: "default" | "transparent"; + inputElementClassName?: string; } export const Input = React.forwardRef( - ({className, variant, size, error, icon, right, ...props}, ref) => { - return ( -
- {icon && {icon}} - - {right && {right}} -
- ); - }, + ({className, size = "sm", variant = "default", ...props}, ref) => ( + + ), ); Input.displayName = "Input"; export interface TextAreaProps - extends - React.TextareaHTMLAttributes, - Pick {} + extends React.TextareaHTMLAttributes { + variant?: "default" | "transparent"; + error?: boolean; +} export const TextArea = React.forwardRef( - ({className, variant = "default", error, ...props}, ref) => { - return ( -