Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ similar = "2.5"
urlencoding = "2.1"

# Tauri (desktop only)
tauri = { version = "2", features = [] }
tauri = { version = "2", features = ["unstable"] }
tauri-plugin-opener = "2"
tauri-plugin-dialog = "2.6"
tauri-plugin-fs = "2"
Expand Down
13 changes: 13 additions & 0 deletions src/apps/desktop/capabilities/browser-webview.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "browser-webview",
"description": "Minimal permissions for embedded browser webviews to emit events back to the host",
"webviews": ["embedded-browser-*"],
"local": true,
"remote": {
"urls": ["https://*", "http://*"]
},
"permissions": [
"core:event:allow-emit"
]
}
9 changes: 9 additions & 0 deletions src/apps/desktop/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,15 @@
"core:event:allow-listen",
"core:event:allow-emit",
"core:window:default",
"core:webview:default",
"core:webview:allow-create-webview",
"core:webview:allow-set-webview-position",
"core:webview:allow-set-webview-size",
"core:webview:allow-set-webview-focus",
"core:webview:allow-reparent",
"core:webview:allow-webview-show",
"core:webview:allow-webview-hide",
"core:webview:allow-webview-close",
"core:window:allow-create",
"core:window:allow-set-focus",
"core:window:allow-set-always-on-top",
Expand Down
81 changes: 81 additions & 0 deletions src/apps/desktop/src/api/browser_api.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
//! Browser API — commands for the embedded browser feature.

use serde::Deserialize;
use tauri::Manager;

#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WebviewEvalRequest {
pub label: String,
pub script: String,
}

#[tauri::command]
pub async fn browser_webview_eval(
app: tauri::AppHandle,
request: WebviewEvalRequest,
) -> Result<(), String> {
let webview = app
.get_webview(&request.label)
.ok_or_else(|| format!("Webview not found: {}", request.label))?;

webview
.eval(&request.script)
.map_err(|e| format!("eval failed: {e}"))
}

// #region agent log
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct WebviewLabelRequest {
pub label: String,
}

/// Pull debug logs from the injected inspector script.
/// The script stores logs in `window.__bitfun_debug_logs`.
/// We eval a script that writes them into URL hash, then read the URL.
#[tauri::command]
pub async fn browser_pull_debug_logs(
app: tauri::AppHandle,
request: WebviewLabelRequest,
) -> Result<String, String> {
let webview = app
.get_webview(&request.label)
.ok_or_else(|| format!("Webview not found: {}", request.label))?;

webview
.eval(
r#"(function(){
var logs = window.__bitfun_debug_logs || [];
window.__bitfun_debug_logs = [];
try {
var hash = '__BFDEBUG__' + encodeURIComponent(JSON.stringify(logs));
history.replaceState(null, '', '#' + hash);
} catch(e) {
history.replaceState(null, '', '#__BFDEBUG__ERR_' + encodeURIComponent(String(e)));
}
})()"#,
)
.map_err(|e| format!("eval failed: {e}"))?;

tokio::time::sleep(std::time::Duration::from_millis(300)).await;

let url = webview.url().map_err(|e| format!("url failed: {e}"))?;
let fragment = url.fragment().unwrap_or("");

if fragment.starts_with("__BFDEBUG__") {
let encoded = &fragment[11..];
let decoded = urlencoding::decode(encoded)
.map(|s| s.into_owned())
.unwrap_or_else(|_| format!("decode_error:{}", encoded));

webview
.eval("try { history.replaceState(null, '', location.pathname + location.search); } catch(e) {}")
.ok();

Ok(decoded)
} else {
Ok(format!("no_debug_marker_in_fragment:{}", &fragment.chars().take(100).collect::<String>()))
}
}
// #endregion
1 change: 1 addition & 0 deletions src/apps/desktop/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

pub mod agentic_api;
pub mod ai_memory_api;
pub mod browser_api;
pub mod ai_rules_api;
pub mod app_state;
pub mod btw_api;
Expand Down
3 changes: 3 additions & 0 deletions src/apps/desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,9 @@ pub async fn run() {
api::miniapp_api::miniapp_dialog_message,
api::miniapp_api::miniapp_import_from_path,
api::miniapp_api::miniapp_sync_from_fs,
// Browser API
api::browser_api::browser_webview_eval,
api::browser_api::browser_pull_debug_logs,
])
.run(tauri::generate_context!());
if let Err(e) = run_result {
Expand Down
11 changes: 6 additions & 5 deletions src/apps/relay-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter"] }

# Utilities
chrono = { workspace = true }
dashmap = { workspace = true }
rand = { workspace = true }
base64 = { workspace = true }
sha2 = { workspace = true }
uuid = { version = "1.0", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde", "clock"] }
dashmap = "5.5"
rand = "0.8"
base64 = "0.21"
sha2 = "0.10"
2 changes: 1 addition & 1 deletion src/apps/relay-server/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
container_name: bitfun-relay
restart: unless-stopped
ports:
- "9700:9700"
- "${RELAY_HOST_BIND_IP:-0.0.0.0}:9700:9700"
environment:
- RELAY_PORT=9700
- RELAY_STATIC_DIR=/app/static
Expand Down
6 changes: 4 additions & 2 deletions src/apps/relay-server/restart.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONTAINER_NAME="bitfun-relay"
RELAY_HOST_BIND_IP="127.0.0.1"

usage() {
cat <<'EOF'
Expand Down Expand Up @@ -65,13 +66,14 @@ cd "$SCRIPT_DIR"

if container_running; then
echo "Relay service is running. Restarting it..."
docker compose restart
RELAY_HOST_BIND_IP="$RELAY_HOST_BIND_IP" docker compose up -d --force-recreate
else
echo "Relay service is not running. Starting it instead..."
docker compose up -d
RELAY_HOST_BIND_IP="$RELAY_HOST_BIND_IP" docker compose up -d
fi

echo ""
echo "Relay service is ready."
echo "Relay endpoint: http://127.0.0.1:9700"
echo "Check status: docker compose ps"
echo "View logs: docker compose logs -f relay-server"
4 changes: 3 additions & 1 deletion src/apps/relay-server/start.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONTAINER_NAME="bitfun-relay"
RELAY_HOST_BIND_IP="127.0.0.1"

usage() {
cat <<'EOF'
Expand Down Expand Up @@ -77,9 +78,10 @@ else
echo "Relay service is not created yet. Creating and starting it..."
fi

docker compose up -d
RELAY_HOST_BIND_IP="$RELAY_HOST_BIND_IP" docker compose up -d

echo ""
echo "Relay service started."
echo "Relay endpoint: http://127.0.0.1:9700"
echo "Check status: docker compose ps"
echo "View logs: docker compose logs -f relay-server"
Loading
Loading