Skip to content

fix(desktop): render connection screen via custom URI scheme (closes #3052)#3056

Merged
houko merged 1 commit into
mainfrom
fix/3052-connection-blank-window
Apr 24, 2026
Merged

fix(desktop): render connection screen via custom URI scheme (closes #3052)#3056
houko merged 1 commit into
mainfrom
fix/3052-connection-blank-window

Conversation

@houko

@houko houko commented Apr 24, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #3052 — first-launch blank window on Linux desktop.

Two fixes bundled because they're both hit by the same user flow (fresh NixOS build, first launch):

1. Connection screen no longer renders (the primary bug)

crates/librefang-desktop/src/lib.rs built the first-launch connection screen by opening about:blank and injecting HTML via window.eval(\"document.open(); document.write(...); document.close();\"). On WebKitGTK 2.50 — stock NixOS 25.11 / 26.05, and the webkit bundled in the AppImage — that sequence silently no-ops. The window opens, the title says "LibreFang — Connect", and the content area stays blank. New users (no saved preference, no LIBREFANG_SERVER_URL) always take this path, so the app is dead on arrival.

Fix: register a custom URI scheme (lfconnect://) on the Tauri Builder, return the connection HTML as a normal HTTP response, and point the webview at lfconnect://localhost/ via WebviewUrl::CustomProtocol. That's a regular navigation to a regular response, so WebKit loads it the same way it loads any other page — no about:blank edge cases, no async eval race, and connect_remote / start_local still work via window.location.href = ….

2. Nix build runs but the binary panics on launch

#2974 merged the build-organisation part of a flake fix but dropped the libayatana-appindicator bits. Since tray-icon dlopens libayatana-appindicator3.so.1 at runtime (it's not a link-time dep), the resulting binary aborts on first launch on stock NixOS. This is the "build is again failing due to the dlopen not finding libayatana-appindicator" half of #3052.

Restored the two lines from commit cdad334e in the original PR branch: add the lib to desktopBuildInputs, and a postFixup that patches it into the desktop binary's RPATH.

Verification (on NixOS 25.11 + GNOME 49, WebKitGTK 2.50.5)

  • cargo check -p librefang-desktop ✅ clean
  • cargo clippy -p librefang-desktop -- -D warnings ✅ clean
  • nix build .#librefang-desktop ✅ builds and produces a runnable binary
  • Launched result/bin/librefang-desktop with no saved preference (first-run path):
    • Before: window opens, titled "LibreFang — Connect", content blank.
    • After: connection form renders (server URL input, Test/Connect/Start Local buttons, remember checkbox). Confirmed by the issue-reporter reproduction scenario at the same webkit version.

Notes / follow-ups

  • Not changing the connection HTML itself (connection.rs) — the waitForTauri() polling that was there for the old about:blank timing is harmless on the new path and I'd rather not scope-creep this PR.
  • The custom scheme's origin is lfconnect://localhost; Tauri IPC (__TAURI__.core.invoke) works from it the same as from http://127.0.0.1, so the existing test_connection / connect_remote / start_local commands don't need any changes.
  • No new dependencies, no new feature flags, no Cargo.lock churn.

The connection screen was loaded via about:blank and the HTML injected
through window.eval("document.open/write/close"). WebKitGTK 2.50 (stock
NixOS, current AppImage bundle) silently no-ops that sequence, so new
users hit a blank window on every first launch — they can't pick local
or remote, the app is dead.

Serve the HTML through a registered custom URI scheme (lfconnect://) and
point the webview at that instead. This is a normal navigation to a
normal HTTP response, so WebKit loads it like any other page.

Also restore libayatana-appindicator to desktopBuildInputs plus a
postFixup patchelf for its rpath. tray-icon dlopens the library at
runtime, not as a link dep, so without this the nix-built desktop
binary aborts on launch.
@github-actions github-actions Bot added size/S 10-49 lines changed ready-for-review PR is ready for maintainer review labels Apr 24, 2026
@houko
houko merged commit 4f0bb46 into main Apr 24, 2026
18 of 21 checks passed
@houko
houko deleted the fix/3052-connection-blank-window branch April 24, 2026 13:49
@github-actions github-actions Bot removed the ready-for-review PR is ready for maintainer review label Apr 24, 2026
houko added a commit that referenced this pull request Apr 26, 2026
PR review caught 1 stale-doc contradiction + 7 undocumented behaviour
changes from the fix-PR cohort.

- #3114 — configuration/core: 'api_key empty = unauthenticated' was
  stale; now documents the loopback-only policy (non-loopback bypass
  was closed)
- #3170 — features/observability: auto_start is opt-in; home_dir-
  scoped Docker labels; RAII cleanup
- #2989 — api/agents POST /message: per-request session_id override
- #3048 — Interrupting a Running Agent Turn: /stop cascades into
  agent_send subagents (recursive)
- #3056 + #3000 — desktop: dedicated Connection screen via custom
  URI scheme with retry / open-in-browser / uninstall
- #2952 — triggers: response routes to agent's home channel
- #2955 — triggers: task_posted assignee_match = 'self' | 'any'
- #3069 — providers/local: 60-second reprobe + manual 'Test
  connection' refresh

All sections mirrored in docs/src/app/zh/.
houko added a commit that referenced this pull request Apr 26, 2026
…pi / observability (#3189)

* docs(providers): add Novita / SearXHG / Bedrock entries

* docs(config): document [parallel_tools] section + max_history_messages

* docs(scheduler): cron multi-delivery + pre_script + silent_marker

* docs: live context.md, chat attachments, CLI slash commands

Salvages three of the six items from the (quota-killed) misc-features
agent run. Each is a focused append, no rewrite of existing content.

- agent/templates: live Live Context section explains the per-turn
  re-read of `context.md` (#3115), the .identity/ vs root path lookup,
  the 32 KB cap with stale-cache fallback, and the cache_context opt-out.
- integrations/api/agents: attachment-resolution table (image / PDF /
  text+code) covering the supported MIME / extension list and the
  200 KB truncation, plus a note about adjacent-text coalescing for
  small chat-tuned local models (#3094).
- integrations/cli/commands: 'Slash Commands in Chat' section listing
  the registry-backed CLI commands (/model /status /help /clear /kill
  /exit) and pointing at channel-side commands for the broader set
  (#3122 #3123).

* docs: tool invoke API, trajectory export, doctor audit, CLI default-pick, SDK codegen

Picks up the items the second misc-features agent didn't get to before
hitting the org quota.

- integrations/api/system: POST /api/tools/{name}/invoke (#3025) — fail-
  closed allowlist, agent_id requirement for approval-gated tools.
- integrations/api/agents: GET /sessions/{id}/trajectory (#3097) —
  json/jsonl formats, redactor pipeline, audit use case.
- operations/troubleshooting: 'Audit checks' subsection enumerating the
  three registered AuditChecks (#3082) — VaultKey, ApiListenAddr,
  ConfigTomlSchema — with what each asserts and how to extend.
- configuration/providers/tools: 'CLI logins as first-class default
  providers' section (#3061) — detection priority claude-code > codex-
  cli > gemini-cli > qwen-code, override via [default_model] in
  config.toml.
- integrations/sdk: 'Auto-generated from openapi.json' section (#3046) —
  scripts/codegen-sdks.py, pre-commit hook, openai-tag skip rule.

* docs(zh): mirror providers / config-core / cron / features-index sections

* docs(zh): mirror agent / api / cli / providers-tools / troubleshooting / sdk additions

Round 2 of the zh translation pass — picks up the seven mid-priority
files that the first commit didn't cover. All sections mirror the EN
content from #3189 but read naturally as Chinese (terms like agent /
session / fallback / NoEntry left in English where they're API
surface, prose translated to 中文).

- agent/templates: Live Context section, .identity/ vs root fallback,
  cache_context = true opt-out.
- api/agents: attachment-resolution table + trajectory export endpoint
  (#3025 / #3094 / #3097).
- api/system: POST /api/tools/{name}/invoke endpoint + fail-closed
  allowlist explanation.
- cli/commands: 'Slash Commands in Chat' section listing CLI registry
  commands and pointing at channel commands.
- providers/tools: 'CLI logins as first-class default providers'
  detection priority and override.
- troubleshooting: 'Audit checks' subsection + table.
- sdk: 'Auto-generated from openapi.json' section.

* docs: refresh /new slash-command semantics (#3071 review fix)

PR review on #3189 (houko) caught two stale references describing the
pre-#3071 behavior of /new ('wipe the session' / 'clear history'). The
new semantics fork off a fresh session while the previous one stays
resumable on the same channel — phrasing updated in 4 places (en + zh
× 2 files), plus a one-line clarifier in the slash-command roster
section so the cross-reference doesn't silently inherit the old
mental model:

- configuration/channels: 'wipe the session' → 'fork off into a new
  session (the prior conversation stays resumable on the channel)'
- integrations/api/realtime: '(clear history)' → 'forks into a fresh
  session — the prior session is preserved and remains resumable'
- integrations/cli/commands roster paragraph: explicit note that /new
  is a fork, not a wipe.

Same wording mirrored to docs/src/app/zh/.

* docs(channels): 9 channel-related Apr 22-25 PRs (en + zh)

Covers the channel + bridge feature wave:
- #3020 per-agent ChannelOverrides — fixes the contradicting 'without
  modifying the agent manifest' phrasing in both en and zh.
- #3077 prefix_agent_name + Signal plain-text default
- #3009 Slack reactions_enabled + #3005 Feishu @mention preservation
  consolidated into a 'Reactions and Processing State' section
- #3008 Signal media attachments
- #3012 WhatsApp send_voice + dm_policy / group_policy
- #3011 Webhook deliver_only mode
- #2972 channel file downloads (file_download_dir / max_bytes config)

* docs(config-core): provider timeout / browser CDP / cron session caps (en + zh)

Three new `config.toml` sections that landed Apr 22-23:
- #3004 `[provider_request_timeout_secs]` map
- #2993 / #2991 `[browser].cdp_endpoint` + `cdp_auth_token_env`
- #2994 `[kernel].cron_session_max_tokens` / `cron_session_max_messages`

* docs(api): GET /attach + Owner Notice envelope (en + zh)

- #3078 SSE attach endpoint for multi-client co-watching — describes
  the per-session SessionStreamHub fan-out, attacher behaviour, and
  the curl example.
- #2965 ReplyEnvelope.owner_notice + notify_owner tool — message body
  field, StreamEvent variant, WhatsApp OWNER_JIDS fan-out.

* docs(observability + ops): Tempo stack, cache_hit_ratio metric, daemon log tee (en + zh)

- #3064 + #3149 — bundled observability stack (otel-collector / Tempo
  / Grafana), bring-up commands, [telemetry] config, business spans,
  cache_hit_ratio metric formula and where it surfaces
- #3022 — `librefang start --foreground` now tees logs to
  ~/.librefang/logs/daemon-YYYY-MM-DD.log; same-day append; 7-day
  rotation pruned on daemon start

* docs: hooks transform / lazy tools / mcp taint / capability detection / providers extras

Final batch of catch-up docs covering the remaining Apr 22-25 user-facing
features:

- agent/hooks: transform_tool_result hook contract (#3003)
- agent/templates: tool_search / tool_load lazy loading + lazy_tools
  opt-out (#3047)
- integrations/mcp-a2a: TaintRuleId enum + per-tool skip_rules policy
  (#2999)
- configuration/features: compaction summaries in user's conversation
  language (#3007)
- configuration/providers/local: embedding auto-detection priority
  list (#3099) + Ollama capability detection (Modality / metadata
  pipeline, #3074 / #3133 / #3134 / #3140)
- configuration/providers/management: custom image-gen provider via
  generic OpenAI-compat driver (#2998) + Moonshot file-upload helper
  via /v1/files (#2966)

All sections mirrored to docs/src/app/zh/.

* docs: address houko fix-PR audit (8 items, en + zh)

PR review caught 1 stale-doc contradiction + 7 undocumented behaviour
changes from the fix-PR cohort.

- #3114 — configuration/core: 'api_key empty = unauthenticated' was
  stale; now documents the loopback-only policy (non-loopback bypass
  was closed)
- #3170 — features/observability: auto_start is opt-in; home_dir-
  scoped Docker labels; RAII cleanup
- #2989 — api/agents POST /message: per-request session_id override
- #3048 — Interrupting a Running Agent Turn: /stop cascades into
  agent_send subagents (recursive)
- #3056 + #3000 — desktop: dedicated Connection screen via custom
  URI scheme with retry / open-in-browser / uninstall
- #2952 — triggers: response routes to agent's home channel
- #2955 — triggers: task_posted assignee_match = 'self' | 'any'
- #3069 — providers/local: 60-second reprobe + manual 'Test
  connection' refresh

All sections mirrored in docs/src/app/zh/.
@houko houko mentioned this pull request Apr 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S 10-49 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Librefang-desktop creates empty window (AppImage and NixOS)

1 participant