Skip to content

Ticket 040 docker config flow#67

Open
asieduernest12 wants to merge 168 commits intodamoahdominic:mainfrom
asieduernest12:ticket-040-docker-config-flow
Open

Ticket 040 docker config flow#67
asieduernest12 wants to merge 168 commits intodamoahdominic:mainfrom
asieduernest12:ticket-040-docker-config-flow

Conversation

@asieduernest12
Copy link
Copy Markdown
Collaborator

No description provided.

damoahdominic and others added 30 commits April 10, 2026 04:24
…onfigs

Creates openclaw-local, openclaw-docker, openclaw-ssh extension scaffolds
and new src/hosts, src/ui, src/api directories in core extension.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- apps/editor/extensions/openclaw/src/hosts/types.ts: complete shared
  interface definitions — HostAdapter, HostConnection, HostEntry,
  HostsFile, HostCache, OpenClawCoreAPI, all connection configs
  (Local/Docker/SSH/Cloud), LogFn, ExecOpts/Result, GatewayStatus, etc.
- apps/editor/extensions/openclaw-local/: new standalone extension stub
  (package.json + tsconfig.json)
- apps/editor/extensions/openclaw-docker/: new standalone extension stub
- apps/editor/extensions/openclaw-ssh/: new standalone extension stub
  (preview, 0.1.0)

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…, API export

- hosts/registry.ts: reads/writes ~/.occ/hosts.json, seeds local default,
  file-watches for external changes, CRUD for hosts + activeHostId
- hosts/manager.ts: implements OpenClawCoreAPI; owns live HostConnection map;
  registers adapters, connects persisted hosts, drives status events
- hosts/statusbar.ts: status bar item showing active host with icon
- hosts/tree.ts: Tree view provider listing all hosts (openclaw.hosts view)
- extension.ts: bootstraps registry + manager, exports OpenClawCoreAPI from
  activate(), registers openclaw.pickHost / setActiveHost / refreshHost commands
- package.json: adds views (openclaw.hosts in explorer), 3 new commands

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ostConnection

LocalHostConnection implements full HostConnection interface for the local machine:
- exec / execStream: child_process.spawn with full opts support
- Filesystem: readFile/writeFile/exists/mkdir/stat via Node fs
- CLI detection: user config → which/where → well-known paths (darwin/win32/linux)
- installCli: curl|bash on unix, irm|iex on windows
- readConfig/writeConfig: ~/.openclaw/openclaw.json
- gatewayHealthCheck: `openclaw gateway status --json`, falls back to string parse
- gatewayStart/Stop/Restart, runSetup (openclaw onboard)

LocalHostAdapter: discovers one local host, testConnection returns CLI + gateway state.

openclaw-local/extension.ts: grabs OpenClawCoreAPI from openclaw.home exports,
registers LocalHostAdapter, adds disposable to subscriptions.

tsconfig.json: removed rootDir on all three adapter extensions so cross-extension
relative imports (../../openclaw/src/hosts/types) compile correctly.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
openclaw-docker:
- preflight.ts: three-state Docker health check (cli_missing / daemon_down /
  permission_denied) with platform-specific remedies for darwin (OrbStack),
  win32 (Docker Desktop + WSL2), linux (systemd + apt/dnf)
- connection.ts: DockerHostConnection — all HostConnection methods via
  `docker exec`; writeFile via stdin+tee; portMapping aware gatewayHealthCheck
- adapter.ts: DockerHostAdapter — discovers running containers via `docker ps`;
  resolves containerId from label or compose service; testConnection runs
  preflight + CLI check inside container; full getConfigFields / validateConfig
- extension.ts: registers DockerHostAdapter against openclaw.home exports

openclaw-ssh:
- src/extension.ts: activation stub (logs "coming soon", no-op)

All four extensions compile cleanly with zero TypeScript errors.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
… inference

TypeScript infers the rootDir as apps/editor/extensions/ (common ancestor) when
import-type references span across extension directories. This causes output files
to land in out/openclaw-local/src/ and out/openclaw-docker/src/ rather than out/.

Fix: update "main" in each adapter's package.json to match the actual compiled path:
- openclaw-local: ./out/openclaw-local/src/extension
- openclaw-docker: ./out/openclaw-docker/src/extension
- openclaw-ssh: ./out/extension (no cross-extension imports, unaffected)

All four extensions verified with clean builds.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
HomePanel now delegates all host I/O through a HostConnection interface,
making it host-agnostic and ready for Docker/SSH in future:

Key changes in home.ts:
- _host: HostConnection property (DefaultLocalHostConnection by default);
  swapped to active host when HostManager fires onDidChangeActiveHost
- _buildExecEnv()     → this._host.buildExecEnv()   (eliminates 55-line method)
- _testOpenClawCli()  → this._host.testOpenClawCli() (eliminates 103-line method)
- _findOpenClawPath() → this._host.findOpenClawPath() (eliminates 65-line method)
- _quickInstallCheck() → async, delegates to this._host.exists(configPath)
- _getConfiguredPort()  → reads _cachedGatewayPort (updated async in _update())
- _update()           → host.exists()/readConfig()/getConfigPath() for config detection
- _runSetup()         → this._host.execStream() for openclaw onboard subprocess;
                         host.readConfig()/writeConfig() for openclaw.json patching;
                         host.exec() for Node.js version check
New files:
- hosts/localDefault.ts: DefaultLocalHostConnection — self-contained local
  implementation within the core extension; no cross-extension source imports
- hosts/types.ts: added shell?: boolean to ExecOpts (needed for Windows .cmd shims)
- openclaw-local/connection.ts: propagate shell option to cp.spawn

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…er tabs

- Extract _getHtml() from HomePanel into shared renderStatusHtml() in statusHtml.ts
- Create StatusPanelController (statusController.ts) with all behavioral logic:
  gateway polling, version checks, sign-in/out, CASS/Better Memory setup,
  workspace file shortcuts — usable by any adapter panel
- LocalSetupPanel: if OpenClaw already installed, show full status panel
  immediately instead of wizard; after setup success, show status panel
  in-tab instead of delegating to HomePanel
- DockerSetupPanel: after configure success, show status panel in-tab
  instead of disposing the panel
- Adapters now delegate all webview messages to StatusPanelController
  once the status panel is active

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ey prompt

Docker wizard now automatically onboards with the OCC free tier (occ-legacy
model at occ.mba.sh/v1) after the CLI installs — no API key required.
Users can sign in and change the model later from the status panel.

- Remove step 4 provider grid / API key form entirely
- After CLI install, immediately trigger onboard with occ-legacy flags
- Patch openclaw.json in container to set correct model metadata
- Write moltpilot-tier.json to the mounted host state dir

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Replace 4-step wizard (Docker Check → Container+Install → Configure →
  Status) with new 4-step flow:
  1. Docker Check (docker info)
  2. Pull Image (ghcr.io/openclaw/openclaw:latest + create state dir)
  3. Onboard (one-shot docker run --rm with occ-legacy auto-config)
  4. Launch Gateway (persistent container, port 18790:18789)

- Volume mount: ~/Desktop/occ-state-dir:/home/node/.openclaw
- Port mapping: 18790:18789 (avoids collision with local install)
- Config path fixed to /home/node/.openclaw/openclaw.json (user 'node')
- occ-legacy patched directly on host state dir after onboard

Add gatewayHostPort() to HostConnection interface so StatusPanelController
polls the host-side port (18790) instead of the container port (18789).
Implemented in DockerHostConnection (returns portMappings.gateway) and
DefaultLocalHostConnection (returns undefined / no remapping).

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Smart routing on openclaw.home command:
- Only Local installed  → open LocalSetupPanel directly
- Only Docker running   → open DockerSetupPanel directly
- Both installed        → HomePanel with hosts overview
- Neither               → HomePanel (install wizard)

Hosts overview (shown when both are active):
- Two cards: Local + Docker with live gateway status pills
  (checking/running/stopped), port labels, polls every 5 seconds
- Clicking a card opens the respective setup panel

Panel tab titles updated when status panel is active:
- LocalSetupPanel  → "OCC Home {Local:18789}" (reads port from openclaw.json)
- DockerSetupPanel → "OCC Home {Docker:18790}"

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Two root causes fixed:

1. StatusPanelController: for non-local hosts dirExists was always
   checking local ~/.openclaw (doesn't exist for Docker-only users).
   Now uses isConfigured for non-local. isInstalled also simplified:
   non-local hosts are always considered installed (status panel is
   only opened after setup — if we're here, openclaw is in the image).

2. DockerSetupPanel: add _initHtml() with auto-detection (like
   LocalSetupPanel). On open, checks synchronously if occ-openclaw
   container is running, then verifies openclaw config/CLI inside it.
   If already set up → jumps directly to status panel. If not →
   shows the setup wizard.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
Global state (workspaceState) tracks which host this window is bound to.
MoltPilot and any component can read it via occ.window.getHost command.

Commands registered:
  occ.window.setHost   — set { type, hostId, port, label }
  occ.window.clearHost — remove binding
  occ.window.getHost   — read binding (returns null if unbound)

Routing (openclaw.home / startup):
  - Bound window → routes directly to bound host panel (no picker)
  - Unbound → existing detection logic (local/docker/both/neither)

Single-tab enforcement:
  - HomePanel disposes itself before opening adapter panel (picker closes)
  - Adapter panels set occ.window.setHost when status panel activates

Disconnect flow (... menu → "Disconnect host"):
  - Clears occ.window.clearHost
  - Disposes adapter panel
  - Reopens host picker (openclaw.home)
  - StatusPanelController now accepts optional onDisconnect callback

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…st-selector bounce

Removes addHost()/setActiveHost() from DockerSetupPanel._showStatusPanel().
Firing onDidChangeActiveHost was triggering HomePanel._update() which re-rendered
the hosts overview (bouncing user back to host selector). Also eliminates the
blocking dockerPreflight() spawnSync call that was piggybacked on addHost().

Other MultiHost changes included in this commit:
- statusController: debounced setActiveOpenClawWorkspaceFolder to prevent
  concurrent .code-workspace writes ("File Modified Since" error)
- home.ts: read local port directly from disk in _getHostsOverviewHtml to
  avoid _cachedGatewayPort contamination from Docker host
- home.ts: add "Best if:" context bullets on host selection cards
- DockerSetupPanel: show loading spinner immediately on open (fire-and-forget
  _showStatusPanel) instead of blank panel
- DockerSetupPanel: _disposed guard to prevent double-dispose

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…ties

- config.ts: remove unsafe-eval from Content Security Policy
- statusController.ts: HTML-escape version strings before innerHTML injection
- statusHtml.ts: sanitize maintainerName/URL before inserting into innerHTML
- extension.ts: use imported cp module instead of require(); redact API keys from logs
- openclaw-ssh/connection.ts: validate file paths to reject null bytes and non-absolute paths
- status.ts: add localResourceRoots to restrict webview resource loading
- apps/web: upgrade Next.js to 16.2.1 to fix CSRF bypass and HTTP smuggling CVEs

Co-Authored-By: FletcherFrimpong <[email protected]>
JWT was stored in plaintext globalState (a JSON file on disk), readable
by any process running as the same OS user or any VS Code extension.

Changes:
- All reads: context.globalState.get(OCC_JWT_KEY) → context.secrets.get()
- All writes: context.globalState.update() → context.secrets.store/delete()
- One-time migration on activate: moves existing JWT from globalState to
  SecretStorage, then deletes plaintext copy
- Smoke test no longer logs any part of the JWT
- Deep-link URI handler (occode://auth) stores token in SecretStorage

JWT is now encrypted at rest via OS keychain (Keychain on macOS,
Credential Manager on Windows, libsecret on Linux).

Co-Authored-By: FletcherFrimpong <[email protected]>
Before running npm install, OCC now:
1. Fetches package metadata from registry.npmjs.org
2. Downloads the tarball to a temp file
3. Verifies SHA-512 hash against dist.integrity (SRI format)
4. Only installs from the verified local file — no re-download

All three install paths are covered:
- Main npm install path
- Sudo retry path (re-downloads and re-verifies)
- nvm fallback path

If the hash does not match, installation is aborted with a clear
error message. Temp files are always cleaned up after install.

Protects against: MITM attacks, CDN compromise, corrupted downloads.

Co-Authored-By: FletcherFrimpong <[email protected]>
…export

The site uses Next.js static export (output: "export"), which means
server-side fetches only run at build time. Moving the GitHub releases
API fetch to a client-side useEffect ensures users always get the
latest release download URLs at runtime.
- Hero and bottom CTA sections now show email signup form
- Form posts to occ-backend /api/v1/early-access endpoint
- Success/error states with loading spinner
- Updated copy to early access messaging
- Nav item changed from Download to Early Access
…me.ts

- Add panel-bootstrap-choice: two-card setup choice (Docker Recommended / Local Advanced)
- Add panel-docker-path: configurable data directory with ~/Desktop/occ shortcut note
- Add panel-docker-doctor: live dependency checklist (OS, docker/podman, daemon, port, compose)
- Add panel-docker-provision: streaming log panel for docker compose up -d
- Add detectDockerEnvironment(): platform-aware check for docker/podman + daemon + port + compose
- Add runDockerProvision(): pulls images, runs compose up, polls /health, writes openclaw.json
- Add runDockerTeardown(): docker compose down for cancel/reset flows
- Add createDesktopShortcut(): symlink ~/Desktop/occ → data dir (win: .lnk via PowerShell)
- Add getDefaultOpenClawDataPath(): ~/.openclaw (mac/linux) or %APPDATA%\openclaw (win)
- Wire dockerGetDefaultPath, dockerRunDoctor, dockerProvision, dockerCancel message handlers

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
…op/occ/.openclaw)

- getDefaultOpenClawDataPath() now returns ~/Desktop/occ/.openclaw on all platforms
  instead of platform-specific ~/.openclaw / %APPDATA%\openclaw
- HTML path input placeholder updated to ~/Desktop/occ/.openclaw
- docker-compose.full.yml: remove ~ fallback (extension always writes .env with expanded path)
- createDesktopShortcut(): skip symlink creation when dataPath is already inside
  ~/Desktop/occ/ (data is co-located, no symlink needed); fix lstat race on missing dir

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Create docker-compose.test.yml with isolated test services (fnm, nvm, node-only, node-setup)
- Add system dependency packages (build-essential, libxkbfile-dev) to Dockerfiles for native module compilation
- Implement comprehensive test script (test-node-version-detection.sh) for all Node.js runtime scenarios
- Add Makefile targets for docker-compose based testing
- Add helper scripts: node-version.sh (shared version detection logic), activate_env.sh, help.awk
- Support for fnm, nvm, system node, and auto-install scenarios with proper environment setup
- All 4 test scenarios now pass successfully
- Remove invalid extends reference in main docker-compose.yml
- Fix docker-compose.test.yml volumes/networks section ordering
- Add explicit npm install for editor dependencies in main compose file
- Test services now use proper isolated volumes and networks
- Build test images from custom Dockerfiles with all required dependencies
- Add .dockerignore to reduce build context size (exclude node_modules, .git, etc.)
- Each service now builds from its corresponding Dockerfile with proper environment
- Comprehensive guide for Docker Compose test and dev environments
- Usage examples for running tests and development
- Troubleshooting section for common issues
- Reference for all Makefile targets and scripts
- Use build config instead of image name to avoid pull conflicts
- Change entrypoint to 'sh' (Alpine has no bash)
- Use proper shell command syntax for multi-line npm script
- Map port to 3001 (3000 was blocked by other services)
- Container now starts and runs npm ci + dev server
asieduernest12 and others added 30 commits April 10, 2026 04:24
- docker-setup.spec.ts: 12 tests covering 3-step wizard flow (Config → Confirm → Start)
  Tests card visibility, modal appearance, field validation, navigation (Next/Back/Cancel),
  and stepper indicators.
- test-docker-config.spec.ts: Detailed config form validation tests
- snapshots.spec.ts: Visual regression tests using __snapshots__/
- __snapshots__/: Baseline snapshots for visual comparison

Full coverage of the new Docker setup flow from host picker through provisioning.
…anel)

- Update PRD to reflect that the config panel now appears before auto-provisioning
- The Docker setup flow correctly shows path/port configuration first
- Pre-fills from docker/.env via dockerLoadEnv
- This completes the enhanced Docker setup wizard (ticket-040 integration)
- Add prd.md with full specification of standard/VNC/CDP modes
- Add empty agent-history.md for tracking
- Documents the solution to fixture coupling problem (ticket-040 dependency)

All acceptance criteria already satisfied by prior commits.
- Add cpus: ${CPUS:-0.0} to editor service in docker-compose.yml
- Allows developers to control CPU allocation via CPUS environment variable
- Default 0.0 means unlimited (Docker default)
- Add data-card="docker" to Docker card for test selectors
- Change onclick from pick('docker') to chooseDocker()
- Implement chooseDocker() message handler (chooseDockerSetup)
- Add _openDockerConfigOnLoad flag to auto-open modal on load
- Update dockerOpenConfig to load config and send to webview
- Pass openDockerConfigOnLoad to _getSetupHtml
- Update PRD: mark Task 7 as complete
Each step in the Docker config flow is now a complete page rendered by
the extension (_getDockerConfigHtml), not a hidden panel toggled by JS.
Stepper is always visible at the top showing active step highlighted.

Extension owns all state (_dockerStep, _dockerDraft). Cancel resets
to host picker. No show/hide panel logic in the webview.

All 8 Playwright tests in docker-setup.spec.ts pass.

Co-Authored-By: Claude Sonnet 4.6 <[email protected]>
- Rewrite browser testing section with auto-connect Chrome support
- Add --autoConnect flag for chrome-devtools-mcp
- Document DevToolsActivePort detection and wrapper script
- Add port 9222 conflict warning with playwright-novnc
- Change docker-compose network_mode to host (removes bridge network)
- Update gateway bind host documentation
- Add GATEWAY_BIND_HOST support to docker-compose.openclaw.yml
- Switch main docker-compose to network_mode: host (removes bridge network)
- Add FRESH_BUILD and GATEWAY_IMAGE to .env.openclaw
- Add GATEWAY_BIND_HOST to .env.openclaw.example
- Add bindHost field to _dockerDraft interface
- Add bindHost to loadDockerConfig and saveDockerConfig
- Add GATEWAY_BIND_HOST support in runDockerProvision
- Update provision flow to write openclaw.json to both data dir and ~/.openclaw
- Add dockerGoHome and dockerOpenDashboard message handlers
- Add AI config integration with openDashboard checkbox control
- Update AI config panel to control dashboard auto-open
- Support WS_ENDPOINT for direct WebSocket connections
- Auto-detect Chrome on localhost:9222 via /json/version
- Reuse existing browser context in CDP mode
- Add VSCODE_WORKSPACE_URL for proper webview activation
- Update base config to handle both local and remote browsers
- Full end-to-end test covering:
  - Host picker → Docker card → Step 1 Config
  - Step 2 Confirm → Step 3 Provision
  - Post-provision AI config panel
  - IDE transition on Finish/Skip
- Configurable test image/port for CI environments
- Uses fixtures.ts unified browser handling
- ticket-042: Docker-to-IDE E2E flow spec with BDD tests
- ticket-043: AI config step-3 transition fix for new 3-step view
- .mcp.json: change chrome-devtools to use --autoConnect flag
- .opencode.json: removed (consolidated to .mcp.json)
- chrome-devtools-mcp-wrapper: add DevToolsActivePort detection script
- Update docker-compose.yml with improved editor service configuration
- Update Makefile with new development targets
- Changed _version field from readonly to mutable to allow updates after initialization
- Added _loadVersion() helper method to read version from workspace root's version.txt
- Version is loaded asynchronously in _update() method to avoid blocking initialization
- Falls back to empty string if version.txt cannot be read or workspace unavailable
- Displays actual product version (3.4.3) instead of extension version (0.2.2)

Fixes ticket-044: Home Panel Version Display

Co-authored-by: Copilot <[email protected]>
- Pass error details (message, stderr) from setup step handler to webview
- Display error text below step status on Step 1-4 wizard
- Show error element with error.textContent when setup fails
- Users now see 'Command exited with code X' message instead of blank screen

Ticket-045: App Logging & Error Reporting System (phase 1)

Co-authored-by: Copilot <[email protected]>
- Add max-width to confirm-data-dir to prevent long paths from breaking layout
- Add console.log debugging to trace dataDir value through workflow
- Help identify why custom paths may not display on confirmation step

Ticket-045: App Logging & Error Reporting System (phase 1)

Co-authored-by: Copilot <[email protected]>
- Created errorCodes.ts with 25+ error codes and user-friendly messages
- ErrorCode enum with retry recommendations for each failure type
- inferErrorCode() function to map errors to codes based on message patterns
- Created ErrorModal React component for displaying setup failures
- Modal includes error details, collapsible logs, and action buttons
- Supports retry, report-to-developer, and dismiss actions
- Ready for integration into Docker setup wizard

Ticket-045: App Logging & Error Reporting (phase 2)

Co-authored-by: Copilot <[email protected]>
- Log draft configuration when moving to step 2 (includes dataDir)
- Log draft state in extension output channel for troubleshooting
- Added console.log at step 2 rendering to show what data is passed
- Helps diagnose custom path display issues on confirmation page

Ticket-045: App Logging & Error Reporting (field testing prep)

Co-authored-by: Copilot <[email protected]>
- Created ErrorReporter class for collecting system info and recent logs
- getSystemInfo() captures OS, platform, arch, Node version, memory
- collectRecentLogs() reads last 100 lines from ~/.openclaw/occ-home.log
- createErrorReport() builds complete error payload with timestamp
- sendErrorReport() POSTs to backend asynchronously (fire-and-forget)
- storeFailedReport() saves locally if network unavailable (~/.openclaw/failed-error-reports.jsonl)
- getStoredFailedReports() retrieves failed reports for manual retry
- 5s timeout on POST, no blocking on failures

Ticket-045: App Logging & Error Reporting (phase 3 - reporting)

Co-authored-by: Copilot <[email protected]>
- Added 'make launch' target to fire up ./launch-editor.sh
- Checks that script exists before attempting to launch
- Provides convenient shortcut alongside watch-editor.sh workflow
- Usage: watch editor in one terminal, run 'make launch' in another

Co-authored-by: Copilot <[email protected]>
- Added 'make add-dev-build' to install .deb package (Linux only for now)
- Added 'make del-dev-build' to uninstall .deb package (Linux only for now)
- Platform detection with graceful error messages for macOS/Windows
- Automatic dependency resolution on Linux (apt-get install -f)
- Finds latest .deb from apps/editor/.build/linux/deb directory
- Usage: make build-linux, then make add-dev-build to install
- Uninstall with: make del-dev-build

Co-authored-by: Copilot <[email protected]>
Priority 1: Export npm path in launch-editor.sh before re-execution as bun user
  - Resolves npm as root (where it's available via fnm)
  - Exports NPM environment variable for use by preLaunch.js
  - Avoids ENOENT 'npm not found' error in bun user context
  - Works with any Node.js setup (fnm, nvm, system)

Priority 2: Fix Docker detection in node-version.sh to respect non-root users
  - Only skip version managers for root users in Docker (typical container setup)
  - Non-root users in Docker now proceed to fnm/nvm detection
  - Prevents Docker bypass from affecting containerized multi-user workflows
  - More robust for development containers

Changes:
  - launch-editor.sh: Added npm path resolution before su reexecution
  - apps/editor/build/lib/preLaunch.js: Use NPM env var, fallback to npm/npm.cmd
  - scripts/node-version.sh: Narrowed Docker bypass condition to root only

Fixes ENOENT errors when launching editor in Docker with non-root user.

Co-authored-by: Copilot <[email protected]>
…nment

Root cause: bun's node wrapper shadows fnm node in PATH, breaking npm's shebang
- npm couldn't be found in PATH (bun user couldn't access fnm directories)
- fnm permissions prevented bun user from traversing to fnm node/npm binaries
- bun's node wrapper doesn't support --version, breaking npm startup

Solution:
1. Fix fnm directory permissions in launch-editor.sh (before re-exec as bun)
   - chmod -R g+rx /opt/fnm (readable by group)
   - chmod -R o+rx /opt/fnm (readable by others)
   - Same for /root/.local/state/fnm_multishells

2. Use fnm npm directly in preLaunch.js
   - /opt/fnm/aliases/default/bin/npm is directly callable
   - Bypasses PATH lookup that would fail due to bun-node-fallback
   - Falls back to system npm if fnm path doesn't exist

Impact:
- ✓ npm can now be found and executed by bun user
- ✓ Editor launches successfully in Docker multi-user environment
- ✓ Maintains fallback for environments without fnm

Co-authored-by: Copilot <[email protected]>
- Fix custom data directory showing '(default)' on Step 2 confirmation
- Add error codes and user-friendly messages for provisioning failures:
  - ERR_FILE_NOT_FOUND for missing compose file
  - ERR_DOCKER_PULL_FAILED for image build failure
  - ERR_DOCKER_CONTAINER_START for container start failure
  - ERR_GATEWAY_HEALTH_CHECK for health check timeout
- Wire up ErrorReporter to send error reports to backend (fire-and-forget)
- Add _sendErrorReport() static method to HomePanel

This ensures users see error messages instead of blank screens when
Docker setup fails, and developers receive error reports with logs.
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.

3 participants