Commit Graph

342 Commits

Author SHA1 Message Date
Thomas Marchand
814cd430b3 fix: resolve Bugbot review findings for Claude Code backend
- Add Claude Code support to run_single_control_turn (control.rs)
  Previously only parallel execution via MissionRunner worked.
  Now single-mission execution also supports Claude Code backend.

- Read CLI path from backend config file (mission_runner.rs)
  The cli_path setting in dashboard was ignored; now it reads from
  ~/.openagent/data/backend_configs.json before falling back to
  env var or default.

- Kill CLI process on mission cancellation (client.rs, mission_runner.rs)
  Added ClaudeProcessHandle wrapper with kill() method to properly
  terminate the subprocess when a mission is cancelled, preventing
  continued API resource consumption.
2026-01-18 17:21:19 +00:00
Thomas Marchand
d002aebf35 feat: use AI Providers for Claude Code authentication
Replace the separate API key field in Claude Code backend settings with
integration into the AI Providers system:

- Add use_for_backends field to provider data model (stored in opencode.json)
- Add backend selection step in Add Provider modal for Anthropic (OpenCode/Claude Code)
- Add /api/ai/providers/for-backend/:id endpoint to get provider credentials
- Update mission runner to get Anthropic API key from provider system
- Replace API key input with provider status display in Claude Code settings
- Show backend badges on provider cards in AI Providers section

This allows users to authenticate Claude Code using:
- Claude Pro/Max subscription via OAuth
- Anthropic API key through the unified provider system
2026-01-18 15:28:24 +00:00
Thomas Marchand
3b63819402 refactor: merge backend selection into agent dropdown
Simplify the Create New Mission dialog by removing the separate
Backend dropdown and combining it with Agent selection. Agents
are now grouped by backend (OpenCode, Claude Code) using optgroups.
2026-01-18 15:09:49 +00:00
Thomas Marchand
36fafe193e feat: implement Claude Code backend and harness-aware UI
- Implement ClaudeCodeClient with subprocess JSON streaming to Claude CLI
- Implement ClaudeCodeBackend with Backend trait for mission execution
- Update mission runner to support both OpenCode and Claude Code backends
- Add harness tabs to Library Configs page (OpenCode/Claude Code)
- Add CLI path configuration for Claude Code in Settings
- Add comprehensive harness system documentation
2026-01-18 14:58:04 +00:00
Thomas Marchand
0303c5e6ae fix: fix MCP scope migration and add duplicate cleanup
- Move scope migration for workspace/desktop MCPs outside the binary
  resolution block so it runs even when binaries don't exist locally
- Add automatic duplicate removal on startup (keeps first entry by name)
- This fixes the issue where old configs with scope: Global weren't
  being migrated, and duplicate entries weren't being cleaned up
2026-01-18 14:19:18 +00:00
Thomas Marchand
fbf2715e1e fix: add database migration for backend column and fix agent selection race condition
- Add run_migrations() to SQLite store that adds 'backend' column to existing
  missions tables (CREATE TABLE IF NOT EXISTS doesn't add columns to existing tables)
- Fix race condition in new-mission-dialog when switching backends: wait for
  backendAgents to finish loading before setting default agent, and only use
  fallback agents for opencode backend
2026-01-18 11:55:26 +00:00
Thomas Marchand
699473576b fix: use persisted OpenCode settings for registry 2026-01-18 11:26:50 +00:00
Thomas Marchand
a809ddd162 feat: add backend config settings and tests 2026-01-18 11:25:34 +00:00
Thomas Marchand
e872eee19c fix: make mission workspaces backend-aware 2026-01-18 11:10:03 +00:00
Thomas Marchand
3ea5c79b95 feat: add claude support 2026-01-18 10:34:26 +00:00
Thomas Marchand
6389dccfc3 Add persistent settings storage for library_remote
Replace env-var-only LIBRARY_REMOTE configuration with disk-persisted
settings. The setting can now be edited in the dashboard Settings page,
with LIBRARY_REMOTE env var serving as initial default when no settings
file exists.

Changes:
- Add src/settings.rs for settings storage with JSON persistence
- Add src/api/settings.rs for settings API endpoints
- Update dashboard Settings page with editable library remote field
- Update library-unavailable component to link to Settings page
- Update documentation to recommend Settings page method
2026-01-17 18:01:23 +00:00
Thomas Marchand
38df08deae Remove client-side library remote override
The dashboard was storing libraryRepo in localStorage and sending it as
x-openagent-library-remote header, which could override the server's
configured LIBRARY_REMOTE. This caused confusion when client and server
configs diverged (e.g., skills not showing despite being present on server).

Changes:
- Remove libraryRepo from localStorage settings type
- Remove x-openagent-library-remote header from apiFetch
- Add library_remote to HealthResponse type
- Update settings page to show library remote as read-only from server
- Simplify library-unavailable component to show server config instructions
- Fix unrelated TypeScript error (progress: null -> undefined)

The server's LIBRARY_REMOTE env var is now the single source of truth.
2026-01-17 17:11:39 +00:00
Thomas Marchand
47c2c9f083 Add library_remote to health endpoint
Expose the server's configured LIBRARY_REMOTE in the health response.
This allows the dashboard to display the server's library configuration
without relying on client-side localStorage overrides.
2026-01-17 17:08:06 +00:00
Thomas Marchand
92c14e14ef Fix DNS resolution when shared_network=false without Tailscale
When shared_network was set to false but Tailscale wasn't configured,
the container would get no DNS configuration at all. Now we fall back
to binding /etc/resolv.conf to ensure DNS always works.
2026-01-17 16:20:10 +00:00
Thomas Marchand
b51dac9687 Fix context folder timing issue in container workspaces
The MCP process can start before the mission's context file is written,
causing OPEN_AGENT_CONTEXT_ROOT to not be set. This results in uploaded
files being inaccessible inside containers.

Add read_runtime_context() to dynamically read the context file before
each container bash command, ensuring the context folder bind mount is
always configured correctly regardless of startup timing.
2026-01-17 16:16:49 +00:00
Thomas Marchand
4d89205844 Fix workspace update cannot reset shared_network to default
Use direct assignment for shared_network to allow resetting it to
None (default behavior). The frontend always sends shared_network
in update requests, so None means "reset to default", not "don't change".
2026-01-17 15:47:44 +00:00
Thomas Marchand
49b9ea77cb Fix EventSource leak when starting concurrent plugin updates
Clean up any previous EventSource before starting a new one to
prevent resource leaks when users click update on multiple plugins.
2026-01-17 15:34:05 +00:00
Thomas Marchand
ec73910f05 Fix context bind mount for chroot workspaces
The bind mount was incorrectly using workspace_root/context instead of the
global context root. Mission context files are stored in the global context
root (e.g., /root/context/{mission_id}), so that's what needs to be bind-mounted
into the container for the context symlink to resolve correctly.
2026-01-17 15:18:55 +00:00
Thomas Marchand
81feecbd48 Fix plugin update bugs from Bugbot review
- Fix SSE error handler not calling onEvent, leaving UI stuck in updating state
- Fix plugin name prefix matching to avoid corrupting wrong config entries
- Fix EventSource cleanup on component unmount using useRef
2026-01-17 15:12:43 +00:00
Thomas Marchand
5c2f898234 feat: Add shared_network option for container workspaces
Add a new `shared_network` option to workspaces and workspace templates
that controls network configuration for container (nspawn) workspaces:

- When true (default): Share host network, bind-mount /etc/resolv.conf
  for DNS resolution
- When false: Use isolated networking (--network-veth) for Tailscale
  or other custom network configurations

This fixes DNS resolution issues in container workspaces that don't use
Tailscale by properly sharing the host's DNS configuration.

Changes:
- Add shared_network field to Workspace and WorkspaceTemplate structs
- Update nspawn command building to use shared_network setting
- Add UI toggles in workspace template editor and workspace settings
- Update API types and endpoints
2026-01-17 15:01:03 +00:00
Thomas Marchand
e5c0427c14 Fix file uploads not reaching container workspaces
resolve_upload_base was using container-relative paths (e.g., /workspaces/...)
directly on the host filesystem. Added the same container path mapping logic
that resolve_download_path uses to correctly map to host paths.
2026-01-17 14:53:46 +00:00
Thomas Marchand
a36647c63f Fix context bind mount for container workspaces
For chroot workspaces, the context directory bind mount was using the
global OPEN_AGENT_CONTEXT_ROOT env var which is set for the host workspace.
This meant the bind mount was skipped because the path didn't exist.

Now we compute the context root from the workspace_root directly:
workspace_root.join("context"). This ensures each container workspace
gets its own context directory properly bind-mounted at /root/context.

Also creates the context directory if it doesn't exist before the bind mount.
2026-01-17 14:20:03 +00:00
Thomas Marchand
c17a9f3891 Fix broken context symlink in container workspaces
For chroot workspaces, the context symlink was pointing to the host path
(e.g., /root/.openagent/workspaces/xxx/context/mission-id) which doesn't
exist inside the container. Now it points to the container path
(/root/context/mission-id) where the directory is bind-mounted.

Also ensures the mission context directory is created on the host before
the container starts, so the bind mount isn't empty.
2026-01-17 13:58:32 +00:00
Thomas Marchand
407d2f8c16 Auto-start build for template-based container workspaces
When creating a chroot workspace with a template specified,
automatically trigger the build instead of leaving it in
"pending" status. This improves UX by not requiring a
separate POST to /api/workspaces/:id/build.

The build runs asynchronously in the background, same as
the manual build endpoint.
2026-01-17 13:28:37 +00:00
Thomas Marchand
2a9aaa3fda Hide separator line above pagination in docs
Use :has() selectors to remove the divider that appears above prev/next
navigation links for cleaner page transitions.
2026-01-17 11:17:55 +00:00
Thomas Marchand
dae2e088f4 Add installed plugins UI with update functionality
- Add InstalledPluginsSection showing plugins from OpenCode config
- Display installed version vs latest available with update indicators
- Support one-click updates with real-time SSE progress feedback
- Distinguish between "Installed OpenCode Plugins" and "Library Plugins"
- Add API client functions for getInstalledPlugins and updatePlugin
2026-01-17 11:17:45 +00:00
Thomas Marchand
68725134de Add installed plugins API with version checking and update support
- Add GET /api/system/plugins/installed endpoint to discover plugins from OpenCode config
- Add POST /api/system/plugins/:package/update endpoint with SSE progress streaming
- Query npm registry for latest versions and detect available updates
- Check bun cache for currently installed versions
- Support both scoped (@scope/name) and unscoped package names
2026-01-17 11:17:38 +00:00
Thomas Marchand
cb36560526 Rename host MCP to workspace MCP for clarity
- Rename binary from host-mcp to workspace-mcp
- Rename src/bin/host_mcp.rs to src/bin/workspace_mcp.rs
- Update tool prefix from host_* to workspace_*
- Update MCP registration name from "host" to "workspace"
- Add "Builtin" tag to UI for workspace and desktop MCPs
- Update documentation (CLAUDE.md, INSTALL.md, docs-site)

The "workspace MCP" name better reflects that it runs in the
workspace's execution context - inside containers for container
workspaces, on host for host workspaces.
2026-01-17 08:56:09 +00:00
Thomas Marchand
fa40ad8574 Add command parameter support with autocomplete display
- Add CommandParam struct with name, required, and description fields
- Parse params from command frontmatter (supports simple list and detailed object formats)
- Display params in autocomplete: <required> and [optional]
- Update TypeScript interfaces to include params
2026-01-16 17:03:55 +00:00
Thomas Marchand
dc95f5b692 Add disabled state to Send/Queue buttons for visual feedback
EnhancedInput now exposes canSubmit state via onCanSubmitChange callback,
allowing parent components to show proper disabled styling when input is
empty or only has a locked agent without content. This fixes the issue
where buttons remained visually enabled even when clicking would have no
effect.
2026-01-16 16:55:55 +00:00
Thomas Marchand
7f9165682e docs: Move AI callout after title for better layout 2026-01-16 16:51:41 +00:00
Thomas Marchand
58e10a5a95 Add library item rename with cascading reference updates
- Add POST /api/library/rename/:item_type/:name endpoint supporting
  skills, commands, rules, agents, tools, and workspace templates
- Implement dry_run mode to preview changes before applying
- Auto-update all cross-references in related configs and workspaces
- Add RenameDialog component with preview and apply workflow
- Integrate rename action into Skills, Commands, and Rules config pages
- Fix settings page to sync config before restarting OpenCode
- Clarify INSTALL.md dashboard deployment options (Vercel vs local)
- Add docs-site scaffolding (Nextra-based documentation)
2026-01-16 16:48:52 +00:00
Thomas Marchand
9daa328941 Fix update process: reset repo before checkout and ensure SSE flush
- Add git reset --hard HEAD before checkout to prevent local changes blocking updates
- Add git clean -fd to remove untracked files that might interfere
- Add 100ms delay before restart to ensure the "restarting" SSE event is flushed
2026-01-16 15:58:45 +00:00
Thomas Marchand
724803d2f1 docs: Document git clone requirement for one-click updates
The update system in Settings relies on git to fetch tags and checkout
releases. Updated INSTALL.md to clarify:
- Repository must be git clone'd (not rsync'd) at /opt/open_agent/vaduz-v1
- How to create releases with version tags for update detection
- Dashboard one-click update flow vs manual CLI updates
2026-01-16 15:01:39 +00:00
Thomas Marchand
836f9ddfa0 Remove SSE inactivity timeout - let OpenCode handle all timeouts
Open Agent now acts as a pure pass-through frontend to OpenCode.
We no longer impose any timeouts on the SSE event stream.

Changes:
- Remove SSE_INACTIVITY_TIMEOUT (180s) and TOOL_STATUS_CHECK_INTERVAL (30s)
- Remove tool tracking for timeout extension
- Simplify SSE loop to blocking read without timeout
- Document timeout philosophy in module docs and CLAUDE.md

This ensures long-running tools complete naturally and avoids
timeout mismatches between Open Agent and OpenCode. Users can
still abort missions manually via the dashboard.
2026-01-16 14:51:26 +00:00
Thomas Marchand
e3cf4657b7 Fix Bugbot findings: button state, timeout extension, periodic logging
- Remove disabled attribute from Send/Queue buttons since EnhancedInput
  handles submission validation internally (supports lockedAgent badge)
- Fix tool timeout extension by resetting last_activity when continuing
  to wait for running tools (prevents immediate timeout on next loop)
- Fix periodic logging to use time-based tracking instead of modulo
  check which rarely triggers due to irregular loop timing
2026-01-16 14:44:29 +00:00
Thomas Marchand
ac198e780b Fix update stream error handling and unreachable code
- Add exit status check for git fetch command (previously only checked
  spawn errors, not fetch failures)
- Remove unreachable dead code after service restart (process gets
  terminated by systemctl, so code after restart never executes)
- Send "restarting" event at 100% progress before restart so clients
  can detect completion when connection drops
2026-01-16 14:31:23 +00:00
Thomas Marchand
8d0dcade2a feat(system): Add GitHub release detection and one-click updates for Open Agent
Add automatic update checking and one-click updates for Open Agent:

- Check GitHub releases API for latest version
- Fall back to git tags if no releases exist
- Build from source when update available (git checkout + cargo build)
- Install binaries and restart service automatically
- Enable Update button in dashboard for Open Agent

Version bump to 0.2.0
2026-01-16 14:14:57 +00:00
Thomas Marchand
2cf2b9663e fix(dashboard): Use ref to trigger enhanced input submit
Connect Send button to EnhancedInput via ref so it properly triggers
the submit handler instead of relying on form submission.
2026-01-16 14:14:50 +00:00
Thomas Marchand
a93f0552a4 feat(dashboard): Improve settings UX with header Save button
- Move Save button from bottom to header for easier access
- Add forwardRef to EnhancedInput for external submit control
- Expose submit() method via useImperativeHandle
2026-01-16 14:14:45 +00:00
Thomas Marchand
c4aba7798a feat(library): Copy system oh-my-opencode config to Library
When oh-my-opencode.json exists in the system location but not in the
Library, copy it to the Library directory so it can be versioned and
edited via the dashboard.
2026-01-16 14:14:40 +00:00
Thomas Marchand
670c456136 docs: Add SSH key setup guide and link to INSTALL.md
- Add detailed SSH key generation and setup instructions
- Include troubleshooting tips for common connection issues
- Add README link to INSTALL.md for easy discovery
2026-01-16 14:14:34 +00:00
Thomas Marchand
8bd8d85e6c Fix agent name badge truncation in iOS phase bubble
Replace fixedSize modifier with truncationMode(.tail) to properly
show ellipsis when agent names are too long to fit.
2026-01-16 14:14:06 +00:00
Thomas Marchand
582bba78ad Remove tool.running event handling, keep tool tracking only
The tool tracking approach (tracking ToolCall/ToolResult events to extend
timeout) works without any OpenCode changes. Removed the speculative
tool.running/tool.progress event handling that would require OpenCode
modifications.
2026-01-16 13:45:47 +00:00
Thomas Marchand
80d79c40fb Track running tools to extend SSE timeout during execution
Instead of requiring OpenCode to send heartbeats, the backend now tracks
which tools are running based on tool-call/tool-result events. When tools
are executing, the SSE inactivity timeout is extended from 3 minutes to
10 minutes to accommodate long-running tools like vision analysis.

This approach:
- Requires no OpenCode changes
- Uses information already available from SSE events
- Still detects real crashes when no tools are running
- Logs periodically so operators know tools are still running
2026-01-16 13:39:41 +00:00
Thomas Marchand
d2c990961b iOS UI improvements: keyboard handling and sheet layout
- Auto-hide keyboard when opening desktop stream
- Expand NewMissionSheet to 90% height for better content visibility
- Fix agent name text wrapping in phase bubbles
2026-01-16 13:21:05 +00:00
Thomas Marchand
887173df90 Support tool progress heartbeats in SSE stream
Add handling for tool.running/tool.progress events from OpenCode to reset
the SSE inactivity timeout. This prevents premature disconnection when
long-running tools (like vision analysis) execute without streaming output.
2026-01-16 13:20:46 +00:00
Thomas Marchand
b519f02b62 Th0rgal/ios compat review (#37)
* Add hardcoded Google/Gemini OAuth credentials

Use the same client credentials as Gemini CLI for seamless OAuth flow.
This removes the need for GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET env vars.

* Add iOS Settings view and first-launch setup flow

- Add SetupSheet for configuring server URL on first launch
- Add SettingsView for managing server URL and appearance
- Add isConfigured flag to APIService to detect unconfigured state
- Show setup sheet automatically when no server URL is configured

* Add iOS global workspace state management

- Add WorkspaceState singleton for shared workspace selection
- Refactor ControlView to use global workspace state
- Refactor FilesView with workspace picker in toolbar
- Refactor HistoryView with workspace picker in toolbar
- Refactor TerminalView with workspace picker and improved UI
- Update Xcode project with new files

* Add reusable EnvVarsEditor component and fix page scrolling

- Extract EnvVarsEditor as reusable component with password masking
- Refactor workspaces page to use EnvVarsEditor component
- Refactor workspace-templates page to use EnvVarsEditor component
- Fix workspace-templates page to use h-screen with overflow-hidden
- Add min-h-0 to flex containers to enable proper internal scrolling
- Environment and Init Script tabs now scroll internally

* Improve workspace creation UX and build log auto-scroll

- Auto-scroll build log to bottom when new content arrives
- Fix chroot workspace creation to show correct building status immediately
- Prevent status flicker by triggering build before closing dialog

* Improve iOS control view empty state and input styling

- Show workspace name in empty state subtitle
- Distinguish between host and isolated workspaces
- Refine input field alignment and padding

* Add production security and self-hosting documentation

- Add Section 10: TLS + Reverse Proxy setup (Caddy and Nginx examples)
- Add Section 11: Authentication modes documentation (disabled, single tenant, multi-user)
- Add Section 12: Dashboard configuration (web and iOS)
- Add Section 13: OAuth provider setup information
- Add Production Deployment Checklist

* fix: wip

* wip

* Improve settings sync UX and fix failed mission display

Settings page:
- Add out-of-sync warning when Library and System settings differ
- Add post-save modal prompting to restart OpenCode
- Load both Library and System settings for comparison

Control client:
- Fix missionHistoryToItems to show "Failed" status for failed missions
- Last assistant message now inherits mission's failed status
- Show resume button for failed resumable missions

* Fix: restore original URL on connection failure in SetupSheet

Previously, SetupSheet.connectToServer() persisted the URL before validation.
If the health check failed, the invalid URL remained in UserDefaults, causing
the app to skip the setup flow on next launch and attempt to connect to an
unreachable server. Now the original URL is restored on failure, matching
the behavior in SettingsView.testConnection().

* Fix: restore queueLength on failed removal in ControlView

The removeFromQueue function now properly saves and restores both
queuedItems and queueLength on API error, matching the behavior of
clearQueue. Previously only queuedItems was refreshed via loadQueueItems()
while queueLength remained incorrectly decremented until the next SSE event.

* Add selective encryption for template environment variables

- Add lock/unlock icon to each env var row for encryption toggle
- When locking, automatically hide value and show eye icon
- Auto-enable encryption when key matches sensitive patterns
- Backend selectively encrypts only keys in encrypted_keys array
- Backwards compatible: detects encrypted values in legacy templates
- Refactor workspaces page to use SWR for data fetching

Frontend:
- env-vars-editor.tsx: Add encrypted field, lock toggle, getEncryptedKeys()
- api.ts: Add encrypted_keys to WorkspaceTemplate types
- workspaces/page.tsx: Use SWR, pass encrypted_keys on save
- workspace-templates/page.tsx: Load/save encrypted_keys

Backend:
- library/types.rs: Add encrypted_keys field to WorkspaceTemplate
- library/mod.rs: Selective encryption logic + legacy detection
- api/library.rs: Accept encrypted_keys in save request

* Fix: Settings Cancel restores URL and queue ops refresh on error

SettingsView:
- Store original URL at view init and restore it on Cancel
- Ensures Cancel properly discards unsaved changes including tested URLs

ControlView:
- Queue operations now refresh from server on error instead of restoring
  captured state, avoiding race conditions with concurrent operations

* Fix: preserve undefined for encrypted_keys to enable auto-detection

Passing `template.encrypted_keys || []` converted undefined to an empty
array, which broke the auto-detection logic in toEnvRows. The nullish
coalescing in `encryptedKeys?.includes(key) ?? secret` only falls back
to `secret` when encryptedKeys is undefined, not when it's an empty array.

* Add Queue button and fix SSE/desktop session handling

- Dashboard: Show Queue button when agent is busy to allow message queuing
- OpenCode: Fix SSE inactivity timeout to only reset on meaningful events,
  not heartbeats, preventing false timeout resets
- Desktop: Deduplicate sessions by display to prevent showing duplicate entries
- Docs: Add dashboard password to installation prerequisites

* Fix race conditions in default agent selection and workspace creation

- Fix default agent config being ignored: wait for config to finish loading
  before setting defaults to prevent race between agents and config SWR fetches
- Fix workspace list not refreshing after build failure: move mutateWorkspaces
  call to immediately after createWorkspace, add try/catch around getWorkspace

* Fix encryption lock icon and add skill content encryption

- Fix lock icon showing unlocked for sensitive keys when encrypted_keys is
  empty: now falls back to auto-detection based on key name patterns
- Add showEncryptionToggle prop to EnvVarsEditor to conditionally show
  encryption toggle (only for workspace templates)
- Add skill content encryption with <encrypted>...</encrypted> tags
- Update config pages with consistent styling and encryption support
2026-01-16 01:41:11 -08:00
Thomas Marchand
169e82821a Add password UI for sensitive env vars in workspace settings
- Auto-detect sensitive keys (KEY, TOKEN, SECRET, PASSWORD, etc.)
- Show password input type with eye icon to toggle visibility
- Display lock icon for sensitive values with encryption tooltip
- Update help text to mention encryption at rest
2026-01-15 13:28:48 +00:00
Thomas Marchand
740451e8a1 Add AES-256-GCM encryption for workspace template env vars (cherry-pick from PR #36) 2026-01-15 13:24:50 +00:00