feat(web): resizable railbars with max width and reset-on-refresh - #2
Closed
ikarys wants to merge 29 commits into
Closed
feat(web): resizable railbars with max width and reset-on-refresh#2ikarys wants to merge 29 commits into
ikarys wants to merge 29 commits into
Conversation
…h cmd/PowerShell RTK only rewrites Unix-style commands and some rewrites exec Unix binaries absent from default Windows PATH. Show a contextual hint under the RTK toggle recommending Git Bash, the one shell where the integration works deterministically. Windows-only render, no server change.
describeImage already sets an Authorization header as soon as the vision backend is openai and an api key is present. The only way to get a key in there was to pick a model from a configured provider, because resolveVisionFallback forwards apiKey in the providerModelRef branch and nowhere else. The manual branch is what the onboarding form falls back to when no provider exposes a vision capable model. Pointing it at a hosted endpoint sent the request with no Authorization header and got a 401 back, and the form had no field for the key anyway. This adds an optional apiKey to the vision fallback config, uses it in the manual branch, and shows a password input in the onboarding step when the backend is openai. Ollama does not use it so the field stays hidden there. An empty field behaves exactly like today, and providerModelRef still wins when it resolves, so a provider key can never be shadowed by a manual one. VisionModelConfigSectionProps now extends ManualVisionConfigProps instead of repeating its fields, which keeps jscpd happy now that the list is one line longer.
The precommit typecheck never covered e2e/, so ~280 type errors in the e2e suite slipped verification — masked at runtime because all @openfox/shared imports are type-only (stripped by esbuild). - Wire `tsc --noEmit -p e2e/tsconfig.json` into `npm run typecheck` - Map @openfox/shared to src via paths in e2e/tsconfig.json - Widen ws-client.send type param (test harness sends non-protocol msgs) - Align ChatResponse with ChatDonePayload; annotate res.json() results - Use bracket notation for index-signature access in mock-mcp-server - Drop stale disableThinking config (replaced by reasoningEffort) - Deduplicate Session type in session-pool (use shared type)
Fresh setups (OpenFox workspaces, CI, fresh clones) only ran npm install at the root, never in the web/ sub-project — so web/node_modules was absent and web typecheck failed on unresolvable imports like overlayscrollbars-react. Root postinstall now installs web deps too. Lockfile gains hasInstallScript to mark the lifecycle script.
…ch, and permission checks on win32
* fix: make open-folder work on Windows
openFolder() ran execFile('mkdir', ['-p', dir]) which fails with ENOENT on
Windows (mkdir is a cmd.exe builtin, not an executable), so the folder icon
in the header and the plugin "Open folder" links always returned 500.
Use fs.mkdir(dir, { recursive: true }) instead. Also tolerate explorer.exe's
exit code 1, which it returns even when the folder opens successfully, so
the route no longer reports a spurious failure on win32.
* fix: detect e2e cwd with backslash separators in test auth path
getAuthConfigPath() checked cwd.endsWith('/e2e'), which never matches on
Windows where cwd uses backslashes, so the test-mode auth config resolved
to cwd/e2e/e2e/... when the server was started from the e2e directory.
Compare basename(cwd) === 'e2e' instead, which is separator-agnostic.
* fix: support backslash directory queries in file search
A query ending with a separator lists the directory contents, but only '/'
was recognized. Windows users naturally type 'src\' and got useless fuzzy
matches on the literal string instead.
Treat a trailing backslash like a trailing slash and normalize '\' to '/'
before building the glob pattern (fast-glob patterns are always POSIX).
* fix: delete workspaces with fs.rm instead of spawning rm -rf
deleteWorkspace() shelled out to execFileSync('rm', ['-rf', path]), which
does not exist on stock Windows (ENOENT) and only worked there through the
fs.rm fallback in the catch block.
Call fs.rm({ recursive, force, maxRetries: 3 }) directly on all platforms:
one code path, no process spawn, and maxRetries absorbs transient Windows
file locks (antivirus/indexer). Tests updated accordingly ÔÇö the shell
injection cases now assert that no child process is spawned at all.
* fix: skip Unix permission management on Windows
checkPermissions()/fixPermissions() are built on id/sudo/getent/chmod and
crash or return nonsense on Windows (id: ENOENT when the server is not
started from Git Bash). Return a clear 501 early instead so the
PermissionDeniedModal gets a deterministic answer.
Also skip the dead 'sudo -u $USER git init' fallback in
createDirectoryWithGit() on win32 ÔÇö sudo does not exist there, the attempt
always failed and only delayed the real error.
… server workdir Skills defined in project directories (.agents/skills/, .openfox/skills/) were not visible to agents because runtimeConfig.workdir (the global server working directory) was used instead of session.workdir (the actual project). Changes: - agent-loop, orchestrator, dynamic-context, sub-agents/manager: use session.workdir/effectiveWorkdir for getEnabledSkillMetadata - load-skill tool: use context.workdir from ToolContext - API /api/skills: accept optional ?workdir= query param with fallback to server projectDir; extracted shared resolveProjectDir helper - Frontend skills store: pass currentSession.workdir via ?workdir= - Tests: added coverage for all modified paths
* fix(workflows): guard execution git context Add SessionManager.assertExecutionGitContext and an early gate in executeWorkflow that runs before any agent or shell step. When the session branch and the actual git branch on the effective workdir differ, Dev & Verify is blocked with a clear reason and no write is performed. Non-git projects and sessions without an explicit branch expectation are not blocked. Resolves co-l#183. * fix(context): refresh agent state after workspace mutation Add SessionManager.clearCachedPrompt (and the matching clearSessionCachedPrompt DB helper) and call it from switchWorkspace after the new workdir/branch has been read authoritatively. Any cached system prompt that still references the previous workdir is now invalidated, so the same-turn continuation AND the next user turn rebuild the prompt against the current workspace/branch. No fake refreshed context is produced on failure: switchWorkspace only reaches the invalidation point after the workspace mutation has completed successfully. Refs co-l#190. * fix(workflows): fail closed when expected branch is unavailable SessionManager.assertExecutionGitContext() previously returned ok when the session had an expected branch but the actual branch could not be resolved (detached HEAD, broken workdir, missing .git). This was a fail-open bug: Dev & Verify could start on a tree whose branch could not be verified at all. Tighten the decision matrix: - expectedBranch null → ok (any actualBranch) - expectedBranch set, actualBranch set, equal → ok - expectedBranch set, actualBranch set, differ → BLOCKED - expectedBranch set, actualBranch null → BLOCKED (new, fail-closed) The BLOCKED reason includes the workdir, the expected branch and an explicit statement that no agent, no checkout and no file were performed. --------- Co-authored-by: theshwal <theshwal@users.noreply.github.com>
…kflow scoping - User steps now present interactive choices from step_result transitions; resuming with userChoice routes via the existing transition evaluator. - pendingChoices persisted (workflow_executions.pending_choices) for reload parity, broadcast on workflow.execution_changed, cleared on resume/terminal. - Editor hints/warnings for choice transitions (duplicate, always-shadowing, reserved 'continue'). - Project workflows scoped per-session: server honors ?workdir=, workflow store/modal thread project context so list, save, and launch agree. - Launch picker includes project-scoped workflows. - Demo: review.workflow.json branches approve_fixes (apply/skip); adds sandbox.workflow.json playground. - Tests: executor choice routing, messageHandler pendingChoices, migrations, crud resolveProjectDir, e2e user-choice resume.
Wire RunCommandView to useAutoScroll (dropping the dead outputRef effect left by the overlayscrollbars migration), stabilize the hook's exported handlers so effects don't re-fire on every render (fixes not being able to escape follow), settle completed output at the tail on transition and fresh mount, and teach the overlayscrollbars test mock to expose the OS viewport so the behavior is testable.
… switch The cached prompt is sacred for local LLMs — never discard it. switchWorkspace no longer clears it; the new workspace/branch is conveyed via the injected system reminder instead, and the base prompt tells the model to trust the latest reminder over the static Working directory line.
The planner now presents criteria and stops, waiting for a fresh <system-reminder> (user- or workflow-triggered) before writing, instead of soliciting an approval answer that cannot switch modes.
The postinstall guard cd'ed into web/ whenever web/node_modules was absent, but the published tarball ships no web/ directory at all, so 'npm i -g openfox' died with 'cd: can't cd to web'. Gate the auto-install on the web sub-project actually being present (source checkout) via web/package.json.
Owner
Author
|
Duplicate — created on upstream instead: co-l#204 |
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.
Summary
Add mouse-draggable resize handles to the left and right railbars (sidebars). Users can now drag the sidebar edges to resize them, subject to minimum/maximum width constraints. Width resets to default on page refresh (no localStorage persistence).
Why: The sidebars had fixed widths (300px left, 320px right). Users needed the ability to widen them for more content visibility, or narrow them for more center space, with a sensible maximum to prevent collapsing the main content area.
What changed:
useResizablehook (web/src/hooks/useResizable.ts) — handles mousedown/mousemove/mouseup drag logic, clamps width to[min, max], setsbody { cursor: col-resize; userSelect: none }during active drag, cleans up on mouseup. Width stored inuseState(resets on refresh, no localStorage).ResizeHandlecomponent (web/src/components/shared/ResizeHandle.tsx) — thin 4px vertical bar,cursor-col-resize,hover:bg-accent-primary/30,role=separatorfor a11y. Absolute-positioned at the sidebar edge.Sidebar.tsx(left railbar) — uses CSS variable--sidebar-wconsumed only by the desktop classmd:w-[var(--sidebar-w)]; mobilew-[300px]remains untouched. Handle placed at right edge,hidden md:block.SessionLayout.tsx(right railbar) — inlinestyle={{ width }}on desktop aside (which ishidden md:block; mobile has a separate aside). Handle placed at left edge.Constraints:
Testing:
useResizablehook (initial width, drag direction left/right, clamp min/max, mouseup cleanup, body style restoration)npm run typecheck— passAI-Enhanced Development
Tell what models helped shape this PR:
Cache Impact
Does this PR affect anything cached — system prompts, tool definitions, skills, or other context?