Skip to content

feat(ui): enhance console window management with geometry persistence and improved z-index handling - #213

Merged
paulocorcino merged 93 commits into
mainfrom
feat/mini-ide
Jul 19, 2026
Merged

feat(ui): enhance console window management with geometry persistence and improved z-index handling#213
paulocorcino merged 93 commits into
mainfrom
feat/mini-ide

Conversation

@paulocorcino

Copy link
Copy Markdown
Owner

Summary

  • Enhance console window management with geometry persistence
  • Improve z-index handling for proper window layering
  • Refactor UI styles for better maintainability

Testing

Manual testing of console window management and z-index behavior in the workbench shell.

🤖 Generated with Claude Code

paulocorcino and others added 30 commits July 13, 2026 02:05
Run-lock-aware CLI surface per ADR-0036 §6: guard_run_lock refuses each
verb under a held run.lock before any git/gh call, otherwise delegates
to existing ralphy_core primitives.
Rust helper bin (runlock_test_child) drives the HeldAlive refusal path
without a shell-script child; branch_create proves the happy path on an
isolated temp repo.
Self-review finding: no test proved require_some_label wins over
resolve_toplevel end-to-end. Adds label_set_rejects_empty_labels_before_touching_repo.
Transplant the daemon UI terminal body into the workbench mock: vendor the
xterm build set, load it in index.html, replace the faux console in
wb-console.js with a live xterm attached to /ws/session (new launch, plain
console, and reattach-on-load per live session), and refit on Agents-tab
activation. Prove the embedding with workbench_serves_vendored_xterm.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… server close (#190)

Run cargo fmt over the workbench_serves_vendored_xterm assert (verify gate runs
fmt --check). Also disconnect the per-window ResizeObserver in wb-console.js's
server-initiated ws.onclose branch so a dead-ws terminal stops firing fit()
until the window is closed (self-review LOW).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…rgv (#191)

Add EffectClass + Verb::ALL/effect_class and replace the static blessed_args
with spawn_argv, composing the run argv from closed-enum params (agent /
planAgent via session::Agent, branchMode via BranchMode) — out-of-enum or
free-text values are refused. command_ws refuses malformed params with one
error frame and no spawn; the test child echoes its argv.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…s are refused (#191)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…ns panel (#191)

Add the ACTION_TO_VERB adapter that turns run-start/triage/push workbench:action
events into a /ws/command Command, streaming status:output chunks into a capped
Runs-panel raw feed. Assert the adapter ships and the page loads it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…elpers (#191)

The run verb now validates agent+branchMode; the existing spawn-lifecycle and
survives-disconnect tests must send them or hit the refusal path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
/api/repos now includes branch, derived by reading <path>/.git/HEAD
directly (no git invocation, per ADR-0036 §3): Some(name) for a
symbolic ref, None for detached HEAD or an unreadable/missing file.
loadRepos() fetches the daemon's real repo registry at init and
overwrites the static projects seed; state maps reachable->idle/offline,
remote is inferred from the slug shape. Swallows fetch errors so the
file:// standalone shell still falls back to the seed.
…stry (#194)

Two new deep modules — `confine` (path confinement, the read path's only
security boundary) and `tree` (gitignore-aware `list` + text/binary `read`) —
plus `TreeList`/`FileRead` Observe verbs wired through `command_ws`, which
answers reads in-daemon on the requesting id and never reaches the spawn path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…y refusal (#194)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…path (#194)

`WBDaemon.observe` drives a one-reply `/ws/command` read; `mountTree` seeds the
root and lazy-loads folders from `tree.list`, and `openTab` fetches real bytes
via `file.read`, surfacing a refusal reason. Static `file://` fallback kept.
These legs are review-only (no JS harness, PRD #185).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
#194)

A botched `git add` pathspec dropped confine.rs, tree.rs, lib.rs, and Cargo.toml
from 6e93d96 (which shipped only dispatch.rs/Cargo.lock) — commit the actual
security-critical modules and the `command_ws` Observe branch here.

Self-review fixes folded in: read() decides UTF-8 on the whole file, not the
8 KiB window (a valid multibyte char split at the boundary no longer
false-positives as binary); adds tests for the window-boundary case and for
escape-masked-as-not-found at both the tree and wire layers.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…derr signal

Drain the child line-by-line (read_until) instead of read_to_end, so the run
log is teed to disk as it arrives — observable live and crash-surviving,
rather than buffered in memory and written once at exit. The file is rewritten
once at the end in canonical stdout-then-stderr order, keeping it byte-identical
to the returned `log` the detectors scan.

Add `run_headless_logged_watched`: a stderr-only early-kill predicate that reaps
the child the moment a matching line prints, instead of leaving it to idle in
its own silent backoff until the wall timeout. Watches stderr only so the
agent's own stdout (which may legitimately mention "rate limit") can't trip it.
Existing signatures unchanged; the four adapters keep calling the same runner.

Tests: early-kill fires on the marker line; a non-matching predicate still
times out normally; the `stderr-then-sleep` child helper drives it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…locks

OpenCode fronts many providers whose reset strings can't be trusted: live
(FinCal #73) a "5 hour" limit reported a reset ~12h out — impossible, yet it
parses cleanly and would park the run 11h on a bogus instant. Collapse every
detected OpenCode limit to `Limit(None)` (`unschedulable_opencode_limit`) so the
runner uses the ~30-min synthetic cadence (ADR-0030 D1) instead of scheduling on
the hint. Claude/Codex are stable and keep theirs — trust is a per-vendor
extraction decision (ADR-0023).

Drive execute() through `run_headless_logged_watched` with `usage_limit_regex`
over stderr, so a provider quota block (which only prints to `--print-logs`
stderr and never reaches the JSON stream) is reaped in ~sub-second instead of
burning the whole per-issue budget in silent backoff. The predicate matches the
same signal the post-run classifier keys on, so an early-killed run classifies
identically — only faster. plan() passes a no-op (no limit surfaces there).

Killing on the agent's explicit stderr line is the sanctioned interruption
(ADR-0003 D1 / ADR-0030), not a clock; the 60-min wall timeout is demoted to the
last-resort net for a truly mute hang. Amend ADR-0005 D9 accordingly (D9a
reset-discard, D9b early-kill) and correct the stale "stop-on-limit is forced"
and module-doc claims.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
paulocorcino and others added 29 commits July 13, 2026 22:15
…bind (#205)

Localhost/Bearer disable the Require-login toggle with an explanation instead of implying a login gate they can't drop to; Log off no longer strands the operator behind a dead-end form under those policies. Drop the mock-login hint (no longer true post-#179).
Localhost daemon: Require-login disabled with loopback explanation, TOTP enroll stays enabled, Log off doesn't strand the operator behind the gate. Smoke script itself lives at .ralphy/wb_auth_205.py (gitignored scratch, mirrors #204's wb_smoke_204.py).
…ved UI (#208)

- A2: isolation:isolate on .stage traps floating consoles below .kanban's
  z-index regardless of console focus counter.
- B1: sweep every mock/Mock reference and false-in-daemon claim
  (settings/security footnotes) from served UI comments and strings.
- test served_ui_copy_has_no_mock_or_false_claims asserts absence across
  all 13 non-vendor served files.
projectQuery + filteredProjects() filter by slug/branch substring; a
global / shortcut focuses the search input (reusing
consoleShortcutsBlocked so it never hijacks a field/modal/login);
Escape clears it. Removes the dead sidebar ellipsis affordance.
…209)

One consolidated Playwright pass over two real daemons (7357 loopback,
7358 network-bind Session) asserting none of the five audited symptoms
(docs/audit-workbench-2026-07-13.md) reproduce, plus three extras
corroborating #202-#208: 30/30 checks, ALL SYMPTOMS NOT REPRODUCIBLE.

Includes the network-bind Session TOTP login (C3's hard half, #179/#205)
driven through the real login form with a stdlib RFC 6238 TOTP compute.
Reworks the Security panel and its daemon backend across three phases.

Phase A — UI polish: Security-modal scrollbar joins the themed design system;
Login password requires a matching confirmation (two fields); shortened copy.

Phase B — two-phase TOTP enrolment (§C): `enroll` writes a pending seed
(`daemon-totp.pending`) and shows the QR; new `POST /api/security/totp/confirm`
verifies a code before arming the live seed — no more lockout from enrolling
without scanning.

Phase C — real session control + OWASP ASVS L1 (§A/§B/§D):
- Require-login is a persisted `daemon-require-login` flag that gates the browser
  UI even on a loopback bind. `auth::AuthState` holds a runtime-swappable policy
  (RwLock), so toggling promotes Localhost→Session immediately (no restart) and
  mints the access token so local machine clients use a bearer.
- Session epoch (`epoch.rs`, `daemon-session-epoch`) mixed into cookie format v2
  gives instant server-side invalidation on logout / re-mint / TOTP revoke /
  toggle — real logout, still stateless.
- Login throttle (lockout after repeated failures), TOTP anti-replay
  (`daemon-totp-laststep`, step must strictly increase), sliding idle timeout
  (cookie carries `iat`; 30-min idle under a 12h absolute cap), and PBKDF2-SHA1
  raised to OWASP's ~1.3M floor.

Green: cargo fmt --check, clippy -D warnings, 201 tests across 28 binaries.
Note: does NOT stage the unrelated `wss://` change in wb-console.js/wb-daemon.js.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…he gate

When the daemon boots gated (require-login), the SPA's initial loadRepos/
loadIdentity return 401 and record "could not load projects". A successful
login lifted the gate but nothing re-ran those one-shot fetches, so the shell
stayed empty. submitLogin now calls rehydrateAfterAuth() on success (both the
daemon and demo paths); the presence socket already self-reconnects on its 3s
backoff, so it is not re-run here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the reveal eye

- The authenticator-code input carried no autocomplete, so Edge captured the
  6-digit TOTP code as a saved "username". Mark it autocomplete="one-time-code"
  (name one-time-code) so the browser treats it as an OTP, not a credential.
- Edge/IE render a native black reveal/clear eye inside password inputs that
  vanished on the warm-dark theme; invert it to a light, muted glyph.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…shell

- Introduced `wb-settings.js` to define a comprehensive settings schema for the workbench shell, including daemon, events, telegram, queue, branch, verify, claude, opencode, remote control, and schedule configurations.
- Implemented `wb-translate.js` for on-device translation capabilities using the browser's Translator API and LanguageDetector, supporting multiple languages.
- Created `wb-viewer.js` to manage file viewers for source code and Markdown, featuring editing capabilities, in-page search, and Markdown rendering with mermaid support.
@paulocorcino
paulocorcino merged commit 3021e1b into main Jul 19, 2026
5 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant