Doors: progressive tool disclosure + agent hardening + web-pane migration completion#132
Merged
Conversation
Full code-mapped plan: 57 ghost + 67 MCP tools -> core + doors (<=20 live), DoorState (LRU, cap, auto-open-on-call), ghost loop wiring, identity-keyed external MCP gating (flagged, compat default), 8k token budget, Sailfish answers Q1-Q5 with file:line evidence, 6 tested phases. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 0 baseline instrumentation, no behavior change. - ghost run_loop: log per-iteration effective tool count + serialized schema byte size (target=doors) just before the provider stream call. - mcp: hand-write ServerHandler call_tool/list_tools/get_tool verbatim from the #[tool_handler] macro so list_tools can log the full tool surface count + serialized bytes. Behavior is byte-identical to the macro; gating arrives in Phase 4. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 1: new pure, unit-tested sidecar/src/doors.rs shared by both tool surfaces (registered as `mod doors;` in main.rs). No wiring yet. - Door taxonomy (plan §3): a single unified DOORS catalog where each Door carries a ghost_tools and an mcp_tools slice; surface-specific doors leave the other slice empty. GHOST_CORE (11) + 8 ghost doors partition all 57 registry tools exactly; MCP_CORE (12) + 9 MCP doors cover the router. - DoorState: LRU-ordered open Vec (front=oldest), live-tool cap (default 20, env HYPERIA_TOOL_CAP), enabled flag. open_door -> evicted list (never evicts the door being opened), touch (tool -> MRU), close_door, door_of lookup. - 17 unit tests: cap enforcement, LRU order + eviction, single-oversized-door, touch/reopen MRU, per-surface partition, every door <= 10 tools, and a registry cross-check asserting every ghost tool_defs name is in exactly one door or core. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire DoorState into the ghost registry + agent loop behind HYPERIA_TOOL_DOORS (default off). Flag off = byte-identical tool surface. - registry: tool_defs(provider, model, doors) — Some+enabled emits core + open_tools/close_tools/tool_search meta + only open doors' schemas; None/disabled returns the full catalog unchanged. open_tools/close_tools ToolDefs added. handle_tool_search is door-aware (open/closed hints + unlock instruction) when a DoorState is passed. - agent: base tool_defs moved inside run_loop per-iteration; throttle tiers filter on top. open_tools/close_tools intercepted in the executor like tool_mount (gather-on-entry text). Closed-door call guard auto-opens + annotates. Bare door names accepted as open_tools aliases. touch() on every executed tool. DoorState threaded run->run_loop->session, reset in reset(). Doors-mode system prompt swaps the honesty paragraph. - settings/api.rs passes None (own DoorState is a later phase). Tests: 22 doors tests pass (cargo test doors); cargo build --release passes. Flag-off count/order asserted identical to the full catalog. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…x 400) Compat endpoints (llama.cpp/Sailfish, vLLM, Ollama) keep max_tokens. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 3 of MCP tool-doors. Delete the is_small_ollama allowlist (doors replaces it), add config.agent.tool_doors=on|off|auto (default auto), slim the doors-mode system prompt for small/local models, send temperature:0 on OpenAI-compatible endpoints, and add a hard context-token budget guard in the compressor. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…eate Closing a sibling pane (BSP reparent) or any layout reshuffle remounts the WebPane component, which fired destroy+create and rebuilt the native view — full page reload, agent chat log wiped. Renderer-driven destroys are now delayed 400ms (view hidden meanwhile); a create for the same uid cancels the teardown and reuses the live view, skipping loadURL when the URL is unchanged. Window teardown stays immediate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…for now Chat still cleared on pane open/close: layout collapses can re-key the term GROUP, so the remount arrives as destroy(oldUid)+create(newUid) and the same-uid reuse never fired. create() now ADOPTS a pending-destroy view in the same window with the same URL (re-keyed to the new uid) — page state survives. Known follow-up: webContents handlers still capture the old uid, so pushed title/loading state can go stale after adoption until next navigation. Ferricula recall/remember disabled (empty url no-op) behind HYPERIA_FERRICULA=1 until the service returns. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wire Sailfish (local OpenAI-compatible llama.cpp CUDA endpoint) as a
first-class ghost provider per nuts.services/sailfish/HYPERIA_INTEGRATION.md.
- provider.rs: "sailfish" arm in AnyProvider::from_config → OpenAIProvider;
provider_name() reports "sailfish" via a provider_label field carried from
config.provider. Documented the no-timeout client for ~120s warmup.
- ghost/mod.rs load_config: sailfish is LOCAL (no api_key required, never
falls back to ollama on empty key); default endpoint built from
config.agent.services.sailfish.port (default 22343); default_model fallback
"gemma4-e4b" (guide's id; /v1/models is authoritative).
- doors.rs: is_small_model classifies provider=="sailfish" as small (cap 20);
added unit tests.
- agent-config.html: enabled the Sailfish provider button (cat:'sailfish'),
CHEAP_PICK matches first model, warmup/down model note.
- ghost/api.rs get_agent_models: fresh (uncached) probe of sailfish
/v1/models (2s timeout) injected as providers.sailfish {ok,default,models}.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…w_size - The built-in agent rode a plain hyp_agent_ token and hit NeedConsent on every pane action — prompting the user to approve the thing they just asked it to do. Bridge now holds a trusted-token set (populated with the minted ghost token at startup; trust is by TOKEN, never spoofable name) and the three authorize_* short-circuit to Allow for it. - Ghost catalog gains terminal_set_window_size (POST /api/window/size) in the terminal door — "resize to double width / height 1200" now has a real tool (tool_search correctly found nothing before; the tool did not exist). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…; local status lights - Bridge trusted-token set: the minted ghost token bypasses authorize_drive/ create/capability — the built-in agent stops asking the user to approve the actions they just requested. Trust by TOKEN, never name. - terminal_set_window_size added to the ghost catalog (terminal door) — the "resize" ask now has a real tool. - Config pane: live status lights on Ollama (daemon probe) and Sailfish (OpenAI-compat /v1/models probe) provider buttons — green answering, red not. Refreshed on the 5s services poll. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… + local status lights - Repeat guard now also trips when the SAME tool+input fires 3x recently even if the output differs — terminal_split with no args spawns a new pane each call, so output never repeated and a small model (gemma4) split forever. The 3rd identical call now gets the "you are repeating, stop" system note. - Expanded tool rows in the shell show the FULL call: pretty-printed input args + output (was output-only, input just a compact label). - Config pane: green/red status lights on Ollama + Sailfish provider buttons from the live endpoint probes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- The sidecar/providers/level system=> lines moved into printBootBanner(), called only from boot() and guarded by bannerPrinted — re-probes (set-model, wipe) refresh the status strip silently instead of re-spamming the banner every config change. - Local-provider detection now covers Sailfish: active provider shown first; sailfish reachability from the /api/agent/services probe (not just ollama). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… shell - Renderer reports WindowBounds (OS pixel w/h/x/y) to the sidecar on window create + resize; cached per window id and attached to each window node in terminal_status. The agent can now answer "how big is the window" and resize relative to it (it already knew its own window/tab/pane). - Shell HUD gains a live tok/s readout (output tokens over decode time, clock starts on first token so warmup doesn't drag it down). - Click anywhere in the transcript focuses the input — but not when selecting text (drag-selects leave a selection → skipped) or clicking a link / button / input / expandable tool row / widget. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ready-to-show fired before the sidecar WS was up, so terminal_status had no window size. Now bounds also ride the focus handler (fires at launch) plus two short delayed sends as a safety net. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Window create/focus/resize bounds sends fired before the sidecar WS finished connecting (connect is the last step at launch), so send() no-oped and terminal_status never learned window pixel size. Replay bounds for all windows in the ws 'open' handler. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Diagnostic tracing served its purpose; window pixel size is verified in /api/status. Removed to keep the log clean (it fired on every move/resize). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lick Opens the Hyperia shell (/shell agentic surface) in a new web-pane tab. Web pane: native context menu emits 'open web pane req' on the window rpc. Terminal: pane-band menu reuses the module-level openUrl() localhost path. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The terminal body pops the main-window contextmenu.ts menu, not the pane-band menu — add 'Open Hyperia' there via the existing pane:openShellPane command so it appears when right-clicking a terminal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ext overflow + open_tools logging Four related fixes for the "which model am I talking to / it 400'd" confusion: - Titlebar model lights: a blinking dot per enabled model (sailfish/ollama from probes, frontier from keycheck), the active agent provider marked + brighter. Hybrid mode runs more than one brain; now you can see which. - HUD tok/s split into t/s max (peak) and t/s avg (running, folds the live turn in so it settles as it streams). Reset clears both. - Provider errors name the ACTUAL provider + host, not "OpenAI" — Sailfish rides the OpenAI code path, so an 8k-ctx llama.cpp 400 read as "OpenAI error", making a local model look like a cloud one. - Dynamic context handling: local/small models (Sailfish/Ollama) default to an 8k window when config.agent.context_tokens is unset (was 0 = no trim → "exceeds context size" 400). Output reservation scales down on small windows. New hard_trim_to_budget() guarantees a mechanical fit even when the Ollama compressor is down or its summary fails (no more full-history fallback into a bounded window); strips orphaned tool results so the trim can't 400 the provider. - open_tools/open_door_result now logs (target=doors): the requested door, unknown-door failures, and success with live/cap counts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bug telemetry - Runaway-pane guard: hard-cap view-creating tools (open_web_pane, terminal_new_tab/new_window/split) at 4 per user message. Each open is a fresh side effect so the identical-output repeat guard never tripped — a small model could open panes forever. Past the cap, refuse the side effect and nudge it to use existing panes / finish / ask. - t/s HUD: decode meter now counts thinking-delta tokens too, not just final text. Thinking-heavy local turns produced sparse text_deltas so max/avg read ~0; shared accrueDecode() fixes both stats. - /api/ghost/debug: per-turn telemetry ring buffer (provider, model, endpoint, in/out tokens per turn + total, decode tps, context budget, tools, stop reason, panes opened) + configured provider/model/doors. Lets a dev/agent troubleshoot the run loop without the human relaying the shell — pairs with the existing SSE /api/ghost/chat to drive + observe the agent headless. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A small model reading raw width/height/x/y confused the y-offset for the
height ("1267 wide and 238 from the top" — 238 was y, height dropped). Add
an unambiguous `size` string ("1267 px wide × 783 px tall, positioned at
x=.. y=..") it can parrot; raw fields stay for resize math.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/ *-deep-research
Those models 404 on /v1/chat/completions ("Use the v1/responses endpoint
instead"). Route responses-only models to /v1/responses with the correct
request shape (flat tools, top-level `instructions`, `input` items with
function_call/function_call_output correlated by call_id, `max_output_tokens`)
and a typed-event SSE parser (response.output_text.delta,
function_call_arguments.delta keyed via item_id→call_id, response.completed
usage, response.failed/error). Base chat + standard reasoning models
(o1/o3/o4-mini) keep chat/completions.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…testing Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…thful hybrid models.rs is now the single source of truth for model knowledge. It ends the drift that let a stale claude-opus-4-7 sit in the picker and claude-sonnet-4-6 be duplicated as the anthropic default in THREE places (ghost/mod.rs, bootstub.rs, provider.rs): - defaults per provider (anthropic bumped to claude-sonnet-5), curated ollama allowlist, responses-API routing (codex/-pro/deep-research), max_tokens vs max_completion_tokens keying, small-model classification (doors.rs now a shim), 8k default context for small models, compressor default model. - capabilities now serves `model_defaults` — shell.html picker reads it instead of hardcoding model ids (skips providers without a default). - catalog refresh: claude-opus-4-8 / claude-sonnet-5 / haiku-4-5 (drop 3-7), add gpt-5 + gpt-5-codex, o3-mini/o1 -> o4-mini. - tool-harness slim for small models (slim_tool_defs): descriptions capped to first line, per-property schema descriptions stripped (structure/enums/ required kept), open_tools door menu exempt. Frontier keeps full prose. - hybrid greeting now truthful: names the ONE answering provider/model; local models are aux (Maximus compression), not a parallel brain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cap_not_breached_by_a_single_fitting_door hardcoded core=11 + terminal=9; terminal_set_window_size made the terminal door 10. Size the cap from the actual door definition so taxonomy growth can not silently break it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ornith:latest emitted valid schema JSON (thought + tool_name:"none") but legally OMITTED reply — it was not in the required list — so the shell showed thinking followed by pure silence. Require reply in the tools-mode format schema (empty string allowed for tool turns), and belt-and-suspenders: a no-tool turn that still arrives with an empty reply promotes its thought to the visible reply instead of saying nothing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nswering turn
Making `reply` required (the ornith-silence fix) over-corrected: small models
now fill it with self-narration on every tool turn ("I am checking the
status..."), and the provider emitted any non-empty reply as visible text per
turn — a 4-turn status poll rendered as the agent talking to itself. Repro
also caught it parroting the compressor's synthetic "Context noted." message.
- Visible reply (and the thought-promotion fallback) now emit ONLY on
non-tool turns; reasoning stays in the thinking row. Narration also stops
accumulating in history, which starves the mimicry loop.
- Schema description hardened: reply MUST be "" when calling a tool, never
tool narration, shown to the user verbatim.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 'quick small notes' scale opened brand-new stickys at ~117x104 px — ridiculously small. New stickys now open at the user's default size (defaults.json, currently 466x417), and a hard floor (220x170) guards against tiny opens from corrupt persisted geometry or tiny explicit sizes. Restored notes keep their exact saved dimensions as before. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…num + display fixes - Live streaming: single-generation stream:true path streams native message.thinking deltas to the shell AS THE MODEL GENERATES (was: ~60s of silence, then a fake word-by-word replay). Structured JSON content is accumulated and parsed at the end with the same validation. One generation instead of 3 parallel candidates also ends the VRAM contention on 12GB cards; the parallel-candidate path remains as transport-failure fallback, and a parse failure reuses the raw content instead of re-generating. - Fast stop: stop_requested is honored per provider event mid-generation — Escape lands in seconds, not at the next turn boundary. - Doors on the enum: door names are callable entries in the structured-output enum (agent.rs already aliases a bare door-name call to open_tools). The enum IS a structured-output model'\''s tool universe — without doors in it, "split the pane" dead-ended in "I don'\''t have terminal_split". - Host anchor: system prompt names the real host OS/arch (ornith greeted a Windows user with a "2019 Apple Silicon MacBook Pro"). - Shell display: tool-row summaries are mouse-selectable (click-toggle skips when a selection exists), terminal-screen outputs collapse blank-line floods, and a truncated structured reply extracts the reply text to end-of-string instead of leaking a raw JSON fragment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l config link - The in-box "enter" badges are now the hotkey letters: URL box shows "w", shell/agent boxes show "s"/"a" (falls back to "enter" when no hotkey). - Latest-version fetch accepts ONLY a strict version string — the endpoint can return an error page/file content today, which rendered as raw garbage (a stray Rust line) in the picker footer. - Hyperia shell status strip gains a "config" item linking to /agent/config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dges carry the hint Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lick menus Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lue flash, green lights, activity-based t/s avg - Titlebar reads "hyperia shell" (rendered HYPERIA SHELL), no separator. - Gear button next to reset opens /agent/config (status-strip config item removed in its favor). - HUD metrics are bordered badges; a value change flashes the badge blue. - Model lights are green only: steady green = enabled, pulsing green = the active answering model (no accent-colored blink). - t/s avg measures ACTIVITY time only: the live window ends at the last token delta (not now()), and a >3s delta gap folds the burst and starts a fresh window — tool waits and idle no longer decay the average. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shell: HYPERIA SHELL title, gear-to-config by reset, badge metrics with blue update-flash, green-only model lights, activity-based t/s avg (live window ends at the last token delta; >3s gaps fold the burst — tool waits no longer decay the average). Defaults (models.rs): each provider now defaults to its top cheap/fast model per user policy — claude-haiku-4-5, gpt-5-mini, gemini-3-flash-preview (pulled from the live catalog). Picker still offers the full lists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…> code sticky - Shell: HYPERIA SHELL title, gear-to-config by reset, badge metrics with blue update-flash, green-only lights, activity-based t/s avg. - Defaults: top cheap/fast per provider - claude-haiku-4-5, gpt-5-mini, gemini-3-flash-preview (from the live catalog). - Config page: "config.agent" is now a link that opens the raw config file in a code-mode sticky (syntax-highlighted, editable, bound to the file); get_agent_config serves config_path for it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
One huge resize poisoned defaults.json (1313x1133) so every new sticky opened huge. Resize persists per-note geometry only; the default stays stable (reset to 480x420 on disk). saveStickyDefaultSize kept for future explicit 'set as default' UI. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…button - When a provider has a stored key: heading shows "API key [set]" and a remove button sits INSIDE the entry box on the left (sends the "-" clear sentinel, refreshes the keycheck dot). Placeholder flips to "key is set - paste to replace". - Bottom button row gains "Open config" - opens the raw config file in a syntax-highlighted, editable code sticky (same as the config.agent link). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ve, no unconfigure - Stored key: "API key [set]" heading, remove button INSIDE the entry box (flex-row box: wrapper carries border/bg, button + borderless input are children - cannot drift outside). - "Open config" button opens the raw config in an editable code sticky. - Save status is just "saved". - Unconfigure removed everywhere: Hyperia is ALWAYS in the agent list and always configurable. Empty provider in POST /api/agent/config is ignored. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ort under model; v0.15.12 - "Edit config" opens the config file in a syntax-highlighted code sticky via a dedicated system-side endpoint (POST /api/agent/config/edit) - the page fetch is anonymous so the general /api/notes create was silently identity-blocked. Fixed action: can only open THE config file. - Button row: Back (left), Save, Edit config. - Services: ollama row removed (its port now lives under the Model select when ollama is the provider, saved with Save); real default ports for shivvr (8085), grub (6792), transcription (8765); nuts.services note is now "WIP - allows use of nuts.services serverless services. Coming soon." - Version bump 0.15.11 -> 0.15.12 for the local installer build. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
….15.13 The route was registered in the GhostState section (E0308) so the 0.15.12 installer shipped WITHOUT the new sidecar - Edit config would 404 there. Moved next to /api/notes (AppState). Bumped to 0.15.13; 0.15.12 exe on disk is orphaned/do-not-ship. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
toNavigableUrl treated ANY whitespace-free token as a host, so 'hello' navigated to https://hello. Host rule now requires a dotted host or an explicit host:port; bare words fall through to search. The open/split web-pane rpc handlers also route through toNavigableUrl instead of naively prefixing https:// (they bypassed the omnibox logic entirely). Unresolvable dotted hosts still hit the web pane's did-fail-load -> DDG fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ed to 'Picker' Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Input first (flex:1, min-width:0 so it shrinks instead of pushing), button last with white-space:nowrap and flex:0 0 auto - pinned to the right edge, never wraps. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… open The native dropdown list is unstylable and square; the select box kept its 8px rounding while open, so the two shapes clashed. A tiny open/close class toggle (mousedown/change/blur/Esc/Enter) zeroes the bottom radii only while the list is showing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-turn Live transcript: the agent said 'Open the terminal tool door for me and I'll split it' — treating doors as human-gated, then self-diagnosed exactly the right fix. Contract now states: doors are the AGENT'S to open (never ask, never request permission — consent lives at the action layer); capability- seeming-missing = tool_search -> open_tools -> ACT in the same turn, report missing only after both fail; request-to-door routing hints (layout->terminal, pages->web, notes->stickys); act first, commentary after. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ing) During a streaming turn every token changed out/t-s, and each change re-triggered the 450ms blue glow — the whole HUD strobed. Flash is now a faint yellow border only (no box-shadow), throttled to at most one flash per badge per 1.5s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…nt-attributed shell turns Prompt fixes from live transcript failures (gpt-5-codex balking): - FULL SEND default: never ask permission for routine actions (the consent layer prompts the human itself — asking first is double-asking); confirm only destructive/irreversible ops. Finish the WHOLE request before replying. - Show pages with open_web_pane, never start/system browser (HN went to Chrome instead of a web pane). - Typing into TUI panes: submit is a separate \r — trailing \n does not submit in Ink (agent typed into claude pane and never pressed Enter). plan/agent-to-agent-shell.md: design for a second, agent-attributed entry line in the shell when an external agent talks to the ghost (broadcast bus + /api/ghost/events SSE fan-out + typing animation). Plan only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…broke the literal) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…D icons, remove-button vertical fix
- Prompt: NEVER claim done without the tool result this conversation — repro
showed gpt-5.3-codex calling terminal_status then replying 'Done.' with
zero split; if the tool isn't live, next action MUST be open_tools/search.
- HUD: t/s -> TPS labels; TPS now also measured from API usage deltas per
stats event (cloud tool-call turns stream no visible text, so char-count
TPS read 0 on codex). statsLastMs declared + reset.
- Gear is a bare emoji (no button chrome); reset is a red X with 'reset'
hover tooltip.
- Config: remove button vertical mis-align root-caused — global
button{margin-top:20px} margin box shoved it to the bottom of the flex row;
margin:0 + align-self:center inline.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…hell-pane menu trim, full-row service expand - web-pane-manager: pane adoption re-keys the map but wireWebContents closures captured the ORIGINAL uid — every lookup went stale after a React remount, so the context menu (and zoom keys, find results, nav state, window-open splits) silently died in adopted panes. All handlers now resolve the live uid from the webContents (liveUidOf). This is why the Hyperia Agent pane had NO right-click menu. - The agent-shell pane's menu omits the 'Hyperia Agent' item (it would only focus itself — the renderer already dedupes to one agent tab). - Config services: the whole row header toggles expansion, not just the chevron. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Web panes are fully on native WebContentsView (app/web-pane-manager.ts),
so the <webview>-tag plumbing is dead code:
- window.ts: drop the entire did-attach-webview guest handler (session
config, remote.enable(guest), guest context menu, guest
setWindowOpenHandler with its web-pane-find / web-pane-open-split
channels — all reimplemented in the manager and keyed by pane uid,
not guest webContents id, which no longer exists)
- window.ts: drop webviewTag:true from BrowserWindow webPreferences and
the now-unused ipcMain import; remoteEnable(window.webContents) stays
(renderer pane/tab menus still use @electron/remote)
- web-pane.tsx: remove dead openOAuthExternal/_lastOAuthOpenAt (manager
owns OAuth punting via will-navigate/will-redirect + window-open),
the never-passed params/wc args + Inspect branch of handleContextMenu
(in-page menu incl. Inspect-in-split lives in the manager), and the
orphaned webview{} CSS rule; retire the stale "temporarily NOT
wired" TODO — zoom keys / OAuth bail / focus ARE wired in main
- terms.tsx: drop the dead target.closest('webview') guard
- find-bar.tsx: comment accuracy (native view, not <webview>)
Live WebContentsView behavior is unchanged: navigation, find, zoom,
screenshot, context menu, OAuth hand-off, _blank splits.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Phase 4/5 of MCP tool doors, plus the #119 default-targeting fix. Doors Phase 4 — opt-in progressive disclosure for the external MCP surface: - config.agent.mcp_tool_doors ("on"|"off", default OFF) via new doors::resolve_mcp_door_config; HYPERIA_TOOL_DOORS / HYPERIA_TOOL_CAP override. - MCP door state is process-global (rmcp stateless streamable-HTTP rebuilds the handler per request, so per-connection state is impractical — documented). - list_tools filters to core + open doors and appends open_tools/close_tools/ search_tools meta-tools; call_tool intercepts the meta-tools and auto-opens a closed door on a direct tool call (mirrors ghost/agent.rs). Doors off is byte-identical to the pre-doors server. Doors Phase 5 — tools/listChanged: - open/close/auto-open fire peer.notify_tool_list_changed(); capability is advertised in get_info only when doors are on. Verified it is delivered on the stateless HTTP transport (rides the tool call's own SSE response via OneshotTransport). docs/doors.md documents the model, config, meta-tools, auto-open, and the listChanged delivery nuance. Fix #119 — post_split/post_new_tab default targeting: - post_split now resolves the focused window's active tab's active pane even when window/tab/pane are all omitted (was passing a null uid, letting the renderer pick from divergent UI focus). Explicit-but-missing address -> 404; omitted with no sessions -> null (renderer bootstraps first pane). - post_new_tab resolves a target window (focused if omitted) via new Bridge::resolve_window_id and passes windowId; terminal_new_tab gains a window arg. - Unit tests for resolve_window_id and the MCP resolver. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… on agent-shell updates Two user-facing fixes to web panes: 1. De-flash: the pane header's onMouseEnter/Leave hid+screenshotted the native WebContentsView on EVERY crossing (freeze-swap), so simply mousing out of a pane — or across it to the tab bar — flashed the page constantly. The swap now fires only after the cursor DWELLS on the header for 350ms (HEADER_HOVER_DWELL_MS), i.e. when the header's DOM tooltips actually need to paint over the page. Transient passes, mouse-out, and focus changes never touch native-view visibility. Real overlays (URL navigator, find bar, tab switch) are unchanged. 2. Background-tab notify for the Hyperia Agent pane: when a /shell web pane's page <title> changes (manager page-title-updated -> web-pane:state) while its tab is NOT active, raise the STANDARD tab bell — the same ui.bellMarkers 🔔/flash a terminal BEL sets (markTabBell), plus the same bell sound rung via a live Term's ringBell() (respects the bell=false config). Marker is keyed by the pane's term-group uid so it can never clobber a session bell; header.ts now counts group-uid markers for web leaves. Cleared when the human activates the tab (mirror of SESSION_SET_ACTIVE) or the pane unmounts. Never steals focus. NOTE: shell.html must tick document.title on completed turns for the signal to fire — reported upstream, page not edited here. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…bell/flash for a backgrounded agent tab Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Author
|
Ship it. 🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Doors: progressive tool disclosure + agent hardening + web-pane migration completion
~65 commits. Three arcs:
1. Doors — progressive disclosure across both tool surfaces (epic #15)
2. Built-in agent (ghost) overhaul
3. Web panes + UX
Known follow-ups (tracked): web-pane Phase 3 remainder (#9), web-pane pulse (#13), Sailfish-as-Maximus, agent-attributed shell turns (plan/agent-to-agent-shell.md), pane editor (plan/pane-editor-spec.md).
Pre-existing test debt unchanged (3 env-dependent failures in bootstub/compressor/fsnav); doors suite 32/32, bridge tests green, tsc clean, eslint improved.
🤖 Generated with Claude Code