- Replace flat step list with compact single-line rows featuring status dots,
tool-type-specific icons (read/edit/search/terminal/etc), and truncated details
- Add classifyTool() for semantic tool categorization and icon mapping
- Improve summarizeStep() to extract filenames, commands, and patterns
instead of dumping raw output with line numbers
- Replace bordered card container with clean left-border-line expand panel
- Show step count badge in collapsed state ('N steps')
- Add running state indicator with pulse animation
- Use ChevronRight rotate animation instead of ChevronDown for expand/collapse
- Extract StepsContainer as reusable component for both cluster and inline steps
- Filter out raw file content markers (<file> 00001|) from detail text
- Parse 'Success. Updated...' messages to show just the filename
The Plugins nav item was dropped during the DLS alignment refactor (bd6062c).
The PluginsView component and tab routing were still wired correctly --
only the sidebar and mobile bottom-nav buttons were missing.
- Add Plugins button to right sidebar (between Skills and Apps)
- Add Plugins button to mobile bottom nav (5-col grid)
- Import Cpu icon from lucide-solid (same icon used before removal)
The isSafeUrl function was blocking all data: URLs including
data:image/jpeg;base64,... returned by AI image generation models.
This caused markdown images like 
to render with empty src, showing only the alt text 'Image'.
Now data:image/* URIs are whitelisted while other data: schemes
(e.g. data:text/html) remain blocked to prevent XSS.
Co-authored-by: taoyuan <taoyuan@gmail.com>
When using an IME (e.g. Chinese, Japanese, Korean input methods), pressing
Enter to confirm character conversion was incorrectly triggering form
submissions, message sends, and other actions.
Changes across 10 files:
- composer.tsx: triple-check IME state (event.isComposing + manual
compositionstart/end flag + keyCode === 229) with addEventListener
binding to work around SolidJS event delegation limitations
- model-picker-modal.tsx: guard Enter for model selection
- question-modal.tsx: guard Enter for option/custom input (2 handlers)
- rename-session-modal.tsx: guard Enter for session rename
- rename-workspace-modal.tsx: guard Enter for workspace rename
- dashboard.tsx: guard Enter for workspace/session list items (3 handlers)
- session.tsx: guard Enter for workspace/session list items (3 handlers)
- proto-v1-ux.tsx: guard Enter for expandable section toggle
- skills.tsx: guard Enter for skill card activation
- onboarding.tsx: guard Enter for directory path input
Co-authored-by: taoyuan <taoyuan@gmail.com>
* feat(server): add scoped tokens, inbox/outbox, toy UI, and auth hardening
- TokenService with file-based persistence (tokens.json)
- /tokens CRUD (host auth), /whoami (client auth)
- Bearer token auth accepting OPENWORK_TOKEN or scoped tokens
- POST /workspace/:id/inbox (multipart upload)
- GET /workspace/:id/artifacts, /workspace/:id/artifacts/:id
- Toy UI at /ui with SSE, prompt send, inbox upload, outbox download
- Extended GET /capabilities with schemaVersion, serverVersion, approvals info
- Updated README with all new endpoints and auth model
* feat(headless): add sandbox runtime with Docker and Apple container backends
- --sandbox none|auto|docker|container CLI flag
- --sandbox-image, --sandbox-persist-dir, --sandbox-mount options
- Mount security: allowlist, blocked patterns, symlink resolution
- Docker backend: workspace/persist volumes, sidecar staging, entrypoint
- Apple container backend: --mount type=bind for ro mounts
- Sandbox mode proxies all OpenCode access through openwork-server
- Proxy health check (waitForHealthyViaProxy) avoids SDK auth issues
- Sandbox-specific check suite (runSandboxChecks) for --check mode
- Non-fatal verifyOpenworkServer in sandbox mode for version mismatches
- Updated README with sandbox docs and mount security
* feat(packaging): add Docker/docker-compose PaaS packaging
- Dockerfile (node:22-bookworm-slim, installs openwrk via npm)
- docker-compose.yml with workspace and data volumes
- README with usage instructions
* fix(headless): define sandbox owpenbot internal health port
- Default WhatsApp to disabled unless creds/config enable it\n- Never print QR codes from bridge startup (printQr=false)\n- Lazy-load WhatsApp adapter to avoid Bun ws warnings when disabled\n- Add REST endpoints: GET /whatsapp/qr, GET/POST /config/whatsapp-enabled\n- Only print CLI command hints in interactive TTY mode
Avoid hard-coding 3005 so owpenbot health checks don't fail when the default port is already in use. Still supports explicit --owpenbot-health-port / OWPENBOT_HEALTH_PORT overrides.
* fix(owpenbot): make token saves fast and resilient
Persist Telegram/Slack tokens even when owpenbot is offline, bound adapter restarts to avoid long hangs, and refresh UI status with apply warnings.
* chore: update Cargo.lock
Keep desktop Cargo.lock in sync with the crate version so CI cargo --locked passes.
Keep the dashboard stable when switching workspaces by preventing implicit session navigation during connect/reconnect flows. Delay the switch overlay to avoid flashes on fast switches and reuse an existing local host when bouncing remote<->local.
Filter sidebar sessions by workspace root so local workspaces don't show identical task lists. Also start the local host engine when switching from a remote workspace back to local, and hide the session count badge to prevent header overflow.
* feat(server): expose all workspaces and support mounted baseUrl
* feat(ui): keep tasks visible across workspaces
* feat(desktop): default engine runtime to openwrk
* feat(owpenbot): route chats by directory bindings
Stop pinning OpenCode in package metadata and resolve the latest release during sidecar bundling/runtime, while still allowing OPENCODE_VERSION to pin for reproducible builds.
Images are now compressed via canvas resize (max 2048px) + JPEG transcode
(quality 0.82, target <1.5MB) before base64 encoding. Uses OffscreenCanvas
when available to avoid blocking the main thread. Adds a post-encoding size
pre-check to show an explicit error instead of silently failing.
Fixes#481
* feat(workspace): add Share modal in workspace menu
* feat(workspace): share workspace from session view
* feat(workspace): store OpenWork token per workspace
* feat(workspace): scope OpenWork sharing via /w/:id mounts
Type / at the start of an empty input to trigger a command picker popup.
Commands are fetched from the OpenCode SDK (command.list()) and displayed
with fuzzy filtering via fuzzysort. Keyboard navigation (arrows, tab,
enter, escape) works like the existing @-mention popup.
Selecting a command inserts /<name> into the editor so the user can
add arguments. On submit, text starting with / is detected and routed
through session.command() instead of session.promptAsync().
Changes:
- types.ts: add SlashCommandOption type and command field on ComposerDraft
- composer.tsx: slash detection, popup UI, keyboard nav, command selection
- session.tsx: pass listCommands prop through to Composer
- app.tsx: add listCommands(), route command drafts via session.command()