* fix(files): refresh open file content after external edits
Previously, opening a file in the Files view and then editing it externally
(e.g. via CLI or another editor) would show stale content. Even closing and
reopening the file returned cached content — a full page reload was required.
Root causes:
1. The in-memory readFile cache used path-only hits, with no metadata
validation. External edits were invisible until the cache was evicted.
2. No polling mechanism existed to detect external changes to the open file.
Fix:
- Add mtimeMs to statFile across all runtimes (web, VS Code, desktop).
- Cache layer (RuntimeAPIProvider): validate cache hits against current stat
metadata (mtimeMs + size). On miss, use stat→read→stat to avoid TOCTOU.
- UI layer (FilesView): poll the open file every 2s; on detected change, set
loadedFilePath=null to trigger the existing load effect once (no double
reload). Skip polling when tab is hidden or editor has unsaved changes.
- After save, refresh the stat ref so the next poll doesn't see a spurious
change from the save itself.
Addresses review feedback from PR #827 (double reload + TOCTOU).
* fix(files): address P2 review findings
- readFreshFile retry now uses stat→read→stat to maintain TOCTOU
protection during the retry path (not just the initial read).
- Replace isDirty in polling effect deps with isDirtyRef to avoid
unnecessary interval teardown/restart on every edit/save cycle.
Run OpenChamber and OpenCode as separate persistent services — useful when you want to access your
dev machine over a VPN (e.g. Tailscale) or LAN without a Cloudflare tunnel.
How it works:
OpenCode runs as its own service, binding only to localhost.
OpenChamber connects to it via OPENCODE_HOST and --host 0.0.0.0 makes it reachable on your VPN IP.
--foreground keeps the CLI process alive so systemd can track and restart it.
Why set PATH and SSH_AUTH_SOCK?
systemd user services start with a minimal environment — no shell profile is sourced.
Without an explicit PATH, OpenCode won't find tools installed via Homebrew, npm, or ~/.local/bin.
Without SSH_AUTH_SOCK, git operations over SSH (push, pull, clone) will fail because the agent socket isn't inherited.
Adjust the PATH to match your own tool installation paths.
%t expands to $XDG_RUNTIME_DIR (e.g. /run/user/1000), where most SSH agents write their socket.
OpenChamber will be reachable at http://<your-vpn-hostname>:3000 from any device on your VPN.
Note:--host 0.0.0.0 is required to listen on all interfaces. The default
bind address is 127.0.0.1 (localhost only). Use --host <ip> or
OPENCHAMBER_HOST=<ip> to bind to a specific interface instead.
Managed-local path note: OPENCHAMBER_TUNNEL_CONFIG must point to a path inside the container user home (/home/openchamber/...). If your Cloudflare config references a credentials JSON file, that file path must also be accessible inside the container (mount with volumes).
Website docs source lives at packages/docs/content/docs/reverse-proxy.mdx.
Tunnel behavior notes
OpenChamber supports one active tunnel per running instance (port).
Starting a tunnel with a different mode/provider on the same instance replaces the current tunnel.
Replacing or stopping a tunnel revokes existing connect links and invalidates remote tunnel sessions for that instance.
Connect links are one-time tokens; generating a new link revokes the previous unused link.
Data Directory Permission Note: The data/ directory is mounted into the container for persistent storage (config, sessions, SSH keys, workspaces). Before running, ensure the directory exists and has proper permissions:
My wife, who - with zero AI background - sat down with the app for the first time and built the firework celebration that plays on every successful push.
Every contributor who shaped this project with their PRs, ideas, and attention to detail.