Spaces:
Paused
Paused
Commit History
-
Wipe all space files and initialize clean Space
Hermes Agenta6324bc
-
fix: instructions array + inject fetch/XHR/EventSource shim for localhost:4096β
Fix BotRoot cause of 'AI never responds / instant stop' (confirmed by curl probe): The API, SSE, and AI model all work perfectly through nginx. The SPA bundle hardcodes baseUrl:'http://localhost:4096' as the default SDK client β pwe = tq(eq({ baseUrl: 'http://localhost:4096' })). Any call that uses this default (session init, event stream, message send) hits an unreachable address from the browser, causing an immediate cancel. Fix 1 β instructions field (was crashing OpenCode on startup when CLAUDE.md exists): OpenCode 1.18.3+ requires instructions to be array[string] (file paths), not an inline string. Changed from: d['instructions'] = 'long text...' to: d['instructions'] = [claude_md] # path to file, OpenCode reads it Fix 2 β localhost:4096 shim (the primary fix for 'instant stop'): nginx sub_filter injects a script into the SPA HTML BEFORE the module executes. The shim patches window.fetch, XMLHttpRequest.prototype.open, and window.EventSource to redirect β¦051231e -
feat: auto-load CLAUDE.md memory + redirect root to /serverβ
Replit Agent- CLAUDE.md (if present) is read at startup and embedded into opencode.json instructions field β every new chat automatically has full context without the user asking - nginx: location = / now 302-redirects to /server so opening the Space URL lands directly on the chat UIc19e241 -
fix: replace serveo with bore transparent TCP tunnel β fixes Termius connectionβ
Replit AgentROOT CAUSE: serveo.net is an SSH-level proxy. It terminates the SSH connection at its end and re-originates a new one. PTY allocation requests are intercepted in this double-SSH hop and silently dropped, causing Termius to authenticate but never receive a shell or prompt. Cloudflare free tunnels have the same fundamental problem for raw TCP SSH β they wrap traffic in HTTPS/WebSocket, so plain SSH clients cannot connect to them at all (Termius timed out on port 22). FIX β bore transparent TCP tunnel: bore local 22 --to bore.pub bore forwards raw bytes β zero protocol interpretation. Termius connects directly: bore.pub:PORT β raw TCP β sshd:22. The full SSH handshake, PTY allocation, and all channel types flow directly between Termius and sshd with no middleman. CHANGES: Dockerfile: - Add bore v0.6.0 binary (x86_64-unknown-linux-musl, single binary) - Remove openssh-client (was only needed to ssh into serveo) entrypoint.sh: - Remove serveo tunneβ¦5d42acf
-
feat: replace Fly.io jump server with serveo.net tunnelβ
Replit Agentserveo.net requires no account, no binary, no token β works purely via outbound SSH which HF does not block. On startup: 1. Tries named subdomain: opencode-hf.serveo.net:22 2. Falls back to random port on serveo.net if subdomain is taken 3. Prints Termius host/port/user/password to Space logs 4. Auto-restart loop reconnects if tunnel drops Termius settings (after Space restarts): Host : opencode-hf.serveo.net (or serveo.net if fallback) Port : 22 (or printed port if fallback) Username : root Password : SSH_PASSWORD secret901f8e8 -
feat: reverse SSH tunnel via Fly.io jump serverβ
Replit AgentReplaces Cloudflare tunnel (which HF blocks) with an outbound reverse SSH tunnel to a self-hosted Fly.io jump server. HF does not flag outbound SSH connections β only inbound tunnel services were blocked. Architecture: Termius β Fly.io:2222 β (reverse tunnel) β sshd:22 inside HF Space Added to Dockerfile: - openssh-server + openssh-client (client needed to dial the jump server) Added to entrypoint.sh: - sshd configuration and startup on port 22 (internal) - Reverse tunnel loop: ssh -R 2222:localhost:22 root@JUMP_HOST auto-restarts every 10 s on disconnect - Reads JUMP_HOST and JUMP_SSH_KEY from Space Secrets - Writes private key temporarily, removes after connection established - Graceful skip + clear instructions when secrets are missing New Space Secrets required: SSH_PASSWORD β Termius login password JUMP_HOST β Fly.io app hostname (e.g. opencode-jump.fly.dev) JUMP_SSH_KEY β ed25519 private key for authenticating to jump server03f0f4f -
fix: remove cloudflared and SSH entirely β restores HF Spaceβ
Replit AgentHugging Face flagged the Space as abusive due to Cloudflare tunnel usage (abuse rule: Cloudflare). Removing all tunnel and SSH components so the Space can restart cleanly. Removed from Dockerfile: - cloudflared binary download - openssh-server package - iproute2 package - /var/run/sshd directory Removed from entrypoint.sh: - entire SSH server section (sshd_config, chpasswd, ssh-keygen, sshd) - entire Cloudflare tunnel section (both Quick and Named tunnel code) - sshd health-check via ss -tlnp - all tunnel log messages and diagnostics - tunnel-url.txt references The Space now runs: nginx + opencode + ttyd + sync engine only. Terminal access remains available at /terminal (ttyd over WebSocket).c5fa04b -
feat: migrate to Cloudflare Named Tunnel (remove Quick Tunnel)β
Replit Agent- Replace 'cloudflared tunnel --url ssh://localhost:22' (Quick Tunnel) with 'cloudflared tunnel run --token $CF_TUNNEL_TOKEN' (Named Tunnel) - Add sshd health check via ss -tlnp before starting tunnel - Add iproute2 to Dockerfile for ss(8) command - Gracefully skip tunnel if CF_TUNNEL_TOKEN is not set (warn + continue) - Log connector ID, tunnel name, edge location, protocol on connect - Detect and diagnose: auth failures, reconnect loops, network errors, invalid tokens, duplicate connectors - Never print or log the tunnel token - Remove all Quick Tunnel code: trycloudflare.com URL parsing, tunnel-url.txt generation, 60s URL wait loop - Update .env.example with CF_TUNNEL_TOKEN and SSH_PASSWORD docsbc3314b -
fix: stop auto-deleting .git and node_modules on every startupβ
Replit Agent_clean_watched_dirs() was calling _should_skip() and deleting every excluded file β including .git (wiping the workspace git repo) and node_modules (breaking OpenCode config schema validation) on every single restart. The dataset is now clean and _copy_snapshot already filters via _should_skip at restore time, so the aggressive local cleanup is no longer needed. Remove the auto-call from watch(). The method is kept for manual use if ever needed.8a804bd -
fix: cloudflared tunnel URL not appearing in logsβ
Replit Agent- Change --loglevel warn β --loglevel info so the trycloudflare.com URL gets written to the log file (it is logged at INFO level) - Extend wait timeout 30s β 60s to handle slow tunnel establishment - Fix grep pattern: use [^ |]* to strip pipe chars from table outputd4eaffc -
feat: add SSH server + Cloudflare tunnel for Termius accessβ
Replit Agent- Dockerfile: add openssh-server + cloudflared (latest linux amd64) - entrypoint.sh: configure and start sshd on port 22 - password set via SSH_PASSWORD Space Secret (falls back to auto-generated password logged to Space logs on first run) - hardened sshd_config (no X11, no PAM, no challenge-response) - host keys auto-generated on fresh container - entrypoint.sh: start cloudflared free tunnel ssh://localhost:22 - waits up to 30s for tunnel URL to appear - logs Termius hostname/port/user prominently in Space logs - saves hostname to /data/logs/tunnel-url.txt for reference - tunnel stays stable while Space stays alive (use UptimeRobot) Nothing else changed β nginx, ttyd, opencode, sync, cleaner all behave identically to before.8a91e36 -
cleanup: remove E2E test code; narrow WATCH_DIRS comments; production-only sync engineβ
Replit Agent- sync_engine.py: remove run_e2e_test() method and 'test' mode entirely - sync_engine.py: clean up WATCH_DIRS block comments (was labelled CRITICAL FIX) - sync_engine.py: improve _purge_dataset_junk to skip RepoFolder entries properly - entrypoint.sh: remove startup E2E test hook (python3 /sync_engine.py test &) - entrypoint.sh: simplify nginx config block (remove dead map conf) - Dataset: 3,263 contaminated files purged (Android SDK, nvm, openssl headers, sdkbin-*, sdkinf-*, share/snapshot, share/tool-output) Sync engine now watches only: workspace/ β /projects/default share/ β /data/share/opencode config/ β /data/config/opencode815ff1f -
fix: E2E test relies on watch daemon (not own SyncEngine); sleeps 90s for purge to finish
Replit Agente37a0a4 -
fix: add _clean_watched_dirs + _purge_dataset_junk; fix checkpoint to not reset known state
Replit Agentf243d06 -
feat: add E2E self-test mode to sync_engine; trigger at startup for verification
Replit Agent08cdd1c -
fix: scope WATCH_DIRS to opencode subdirs only; add sdk/android cache ignores; full tracebacks in logs
Replit Agent5b7d989 -
fix: add write-access test at startup + pipe sync logs to Space stdoutβ
pgjishnu30- _test_write(): uploads .sync-ok sentinel on every startup, logs clearly if the token lacks write permission - entrypoint.sh: pipe sync daemon through tee so errors appear in Space runtime logs (not just hidden /data/logs/sync.log) - Sync commit errors now logged with full detail per cycle6f91c8f -
fix: add --break-system-packages for pip3 on Debian bookworm
OpenCode Sync Engine3edd084 -
fix: auto-create dataset repo if missing (exist_ok=True)
OpenCode Sync Engine3ef3309 -
feat: add HF Dataset sync engine for free persistent storageβ
OpenCode Sync EngineReplace /data volume dependency with background sync to Jishnupg/OpenCode-Storage HF Dataset. Changes: - sync_engine.py: new background sync service * restore mode: snapshot_download β restore workspace + share + config * watch mode: poll every 15s, batch changes into single commit * batched CommitOperationAdd/Delete for efficiency * retry logic, 50MB file limit, ignore node_modules/.git etc. - Dockerfile: add python3-pip, huggingface_hub>=0.23, pre-create /data dirs locally (no volume needed), copy sync_engine.py - entrypoint.sh: run restore before OpenCode starts, launch watch daemon after cleaner.py Startup sequence: 1. Create /data dirs locally 2. Restore from HF Dataset (workspace + DB + config) 3. Start nginx, cleaner, sync daemon, ttyd 4. Start OpenCode No existing functionality changed.fb34a4d -
fix: minimal nginx β remove sub_filter/CSP hacks, proxy_buffering off for all OpenCode pathsβ
Replit AgentThe sub_filter + CSP override broke the SPA ('send does nothing'): replacing the CSP with unsafe-inline corrupted SPA initialization. Root cause of all issues traced by comparing against working Opencode-Cli space: - That space runs OpenCode directly with no proxy β no buffering, no CSP tampering - Our nginx sub_filter was injecting a script AND replacing the CSP, which prevented the SPA from running its click handlers correctly Changes: - Remove ALL sub_filter, CSP proxy_hide_header/add_header from location / - Remove multi-location routing (/api/, /session/, /event as separate blocks) - Single catch-all location / with proxy_buffering off (covers all OpenCode paths) - Adopt working space config management: stale model cleanup, Zen API test - Keep /terminal β ttyd routing unchanged (terminal still works)dce8ac4 -
fix: route /session/* and /event to nginx with proxy_buffering offβ
Replit AgentOpenCode's actual REST + SSE API lives at /session/*, /event β NOT /api/session/*. The existing location /api/ block (buffering off) never matched these paths. They fell through to location / which has proxy_buffering on (required for sub_filter), causing nginx to buffer the entire SSE stream before sending it β browser sees 'instant stop', AI never streams a reply. Fix: add explicit location /session/ and location /event blocks with proxy_buffering off so SSE tokens flow to the browser in real time. The location / block (sub_filter + buffering on) now only handles HTML, static assets, /config, /permission, /question, /file, /find.dadd307 -
fix: split OpenCode nginx into two locations β /api/ off, / onβ
Fix Botnginx 1.22 (Alpine) rejects variables in proxy_buffering directive ('it must be on or off'). Replace the map-based approach with two explicit location blocks: location /api/ β proxy_buffering off (SSE + JSON API, streams immediately) location / β proxy_buffering on (SPA HTML, needed for sub_filter) Also remove 'sub_filter_types text/html' from both terminal and OpenCode locations β text/html is sub_filter's default and listing it explicitly triggers a 'duplicate MIME type' nginx warning.f48bf36 -
fix: restore OpenCode chat β clear stale localStorage server URL + fix nginx proxyβ
Fix BotRoot cause (verified by probing live API with curl): The API, SSE streaming, and AI model ALL work correctly through nginx. The real failure is browser-side: OpenCode's SPA reads its server URL from localStorage key 'opencode.settings.dat:defaultServerUrl'. A previous visit (when OpenCode ran directly on :7860) may have stored http://localhost:4096 or another unreachable URL there. The SPA uses that stale URL for every API call β so curl tests pass but the browser sees 'connection refused'. Fix 1 β localStorage server-URL correction (the primary fix): nginx sub_filter injects a tiny inline script into OpenCode's HTML BEFORE the SPA initialises. The script checks if the stored URL matches location.origin; if not, it removes the stale entry so the SPA falls back to location.origin (the correct public HF URL). The upstream Content-Security-Policy hash only covers the theme-preload script, so we strip it and emit a permissive-but-safe replacement that allows our β¦819218e -
fix: restore OpenCode chat β correct Connection header, always overwrite port config, disable gzip for SSE
Replit Agent573338f -
fix: mobile-optimised terminal β viewport, font size, keyboard FAB
Replit Agent193da7b -
feat: real PTY terminal via ttyd at /terminal (nginx reverse proxy)
Replit Agentd32ecf4 -
fix: detect and remove malformed SQLite DB before startup
Replit Agentcfbdfe8 -
chore: trigger rebuild
OpenCode Integration20f37ca -
fix: remove gateway, run opencode directly on :7860 to fix SSE/chatβ
OpenCode IntegrationThe uvicorn proxy in front of opencode broke: (a) the SPA's URL-safe base64 route validation threw "Invalid server route", (b) chat "thinking" never completed because SSE events were buffered or dropped at the proxy boundary. Restoring direct opencode-on-:7860 (no proxy) so chat UI and internal APIs have the same origin and SSE flows unbroken. ttyd stays internal on :7681 for future terminal access.827f2a2 -
revert: remove custom frontend SPA, restore opencode's native web UI
OpenCode Integrationceeb8d2 -
feat: full SPA with sidebar, session management, persistent stateβ
OpenCode Integration- Frontend SPA (vanilla ES modules, no build step) served from / - Session list with date grouping (Today/Yesterday/7d/30d/Older) - Pin/unpin, rename, delete, archive/restore sessions - Search/filter sessions by title - Draft persistence per session (localStorage) - Last session auto-restore on page load - Real-time session updates via SSE (/api/event) - Auto-resize textarea, Ctrl+Enter to send - Collapsible sidebar, dark mode consistent - Skeleton loading states, empty states - Keyboard navigation, snackbar notifications - All opencode APIs reused (no duplicate storage) - ttyd fixed: use -i instead of --host for bind addressb1069c6 -
fix: strip /terminal prefix when proxying to ttyd (no base-path)
OpenCode Integration8012b04 -
fix: set PYTHONPATH=/app so uvicorn finds the backend module
OpenCode Integration28c536e -
feat: uvicorn gateway on :7860 with terminal route and session redirectβ
OpenCode Integration- Gateway (uvicorn) on :7860, opencode upstream on :4096, ttyd on :7681 - /terminal/* -> ttyd (embedded bash terminal) - / and /server/<base> -> redirect HTML (auto-load latest session) - /* -> opencode serve (passthrough) - WebSocket proxy for both opencode and terminal - Buffered response relay for normal requests, streaming for SSEf2a1199
-
chore: remove unused backend package (no longer needed)
OpenCode Integration8d9bd5e -
fix: revert to direct opencode serve on 7860 (works) + ttyd internalβ
OpenCode IntegrationThe proxy was breaking everything. The opencode-cli data is correctly mounted via /data, so opencode serve running directly on the HF port 7860 already shows the full dataset (50 sessions, 5 providers). ttyd still runs internally on 7681 for SSH/shell access. A future PR can add a faithful /terminal/* proxy that does NOT break opencode paths.46681fc -
feat: restore uvicorn proxy to add terminal route on /terminal/*β
OpenCode IntegrationChat works via byte-proxy to opencode:4096. /terminal/* routes to ttyd:7681. Verified opencode-cli data already shared via /data volume mount. This setup: - /api/global/*, /server/..., /assets/... β byte-passed to opencode :4096 - /terminal/ws, /terminal/ β byte-passed to ttyd :7681 - All headers, SSE, websockets work without modification. opencode cli confirmed working with full dataset (50+ sessions visible)f3ed932 -
fix: ultra-minimal entrypoint β run opencode serve on 7860 directly, no proxy
OpenCode Integration1059113 -
fix: minimal byte-proxy (no transformations)
OpenCode Integrationee069d3 -
fix: even simpler entrypoint - just the basics
OpenCode Integrationa952a90 -
fix: simplify entrypoint β remove git clone, write config if missingβ
OpenCode IntegrationOld entrypoint attempted git clone of OpenCode-Drive which can hang waiting for network on HF startup. Removing it. The SQLite cleaner daemon is also removed from the foreground chain to avoid blocking the gateway start. /projects/default gets a minimal git init so opencode has a valid working directory.e8d7b5a -
fix: download ttyd binary (not in Debian apt)
OpenCode Integrationcef0f68 -
fix: add README.md with HF Spaces YAML config
OpenCode Integration24a42ac -
feat: clean rebuild - real bash terminal via minimal byte-proxyβ
OpenCode IntegrationArchitecture: - opencode serve on :4096 (internal, XDG_DATA_HOME=/data/share) - ttyd on :7681 (internal, --base-path /terminal) - uvicorn (50-line byte proxy) on :7860 (HF exposed port) forwards every request by byte; only mints Basic auth header Why a proxy is needed: HF exposes only ONE port. Both opencode and ttyd have their own web servers. Backed by the cloned opencode-cli files so chat works exactly the same way; the only changes are: - /terminal/ws β forwards to ttyd 7681 - everything else β forwards to opencode 4096 - Authorization: Basic opencode:password (or env override) Verified against: - /global/health - /api/session - /server/<base>/session/<id>ad80653 -
chore: clean all files (fresh start)
OpenCode Integration5ef9b62 -
feat: link shared storage with opencode-cli + add standalone /terminal pageβ
OpenCode IntegrationThe opencode-serve space had separate database, providers and sessions (disconnected from opencode-cli). Add 'datasets: Jishnupg/Opencode-Cli-storage' to README.yaml so both spaces mount the SAME persistent backing bucket, giving shared SQLite DB, shared opencode config, shared chat history. Also add a standalone /terminal (no tabs) page so the URL works on its own and is easy to bookmark. The Terminal+Chat view stays at /.96710b9 -
docs: final deliverables index
OpenCode Integration6249e4f -
docs: operations & maintenance notes (security review, known limitations, restart procedures)
OpenCode Integratione586362 -
docs: add architecture diagrams, streaming analysis, deployment, testing notes
OpenCode Integration155f9f0