Skip to content

Commit 2d30db2

Browse files
committed
Initial release (v0.1.0)
0 parents  commit 2d30db2

67 files changed

Lines changed: 9895 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
OTG_PORT=7777
2+
DEFAULT_SHELL=/bin/bash
3+
DEFAULT_CWD=/home/user

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
lint-and-build:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: pnpm/action-setup@v4
17+
with:
18+
version: 10
19+
20+
- uses: actions/setup-node@v4
21+
with:
22+
node-version: 22
23+
cache: pnpm
24+
25+
- run: pnpm install --frozen-lockfile
26+
27+
- name: TypeScript check
28+
run: pnpm run typecheck
29+
30+
- name: Build
31+
run: pnpm run build

.gitignore

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
.DS_Store
2+
.env
3+
/node_modules/
4+
5+
6+
# React Router
7+
/.react-router/
8+
/build/
9+
10+
# Editor / OS
11+
*.swp
12+
*.swo
13+
*~
14+
.vscode/
15+
.idea/
16+
Thumbs.db
17+
18+
# Local binaries (cloudflared etc.)
19+
/.bin/
20+
21+
# Claude Code local settings
22+
.claude/
23+
24+
# Logs
25+
*.log
26+
/tmp/

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 David Liu (davindicode)
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
<p align="center">
2+
<img src="public/logo-square.png" alt="OTG Code" width="128" />
3+
</p>
4+
5+
<h1 align="center">OTG Code</h1>
6+
<p align="center"><em>On-The-Go Code — a mobile-first, terminal-focused development environment in the browser</em></p>
7+
8+
<p align="center">Work on your VPS or home machine from anywhere — phone, tablet, or desktop — with zero client-side installation. A mobile-optimised terminal built for coding CLIs, with file explorer, code editor, and localhost proxy — all in a single browser tab, accessible via a single Cloudflare Quick Tunnel.</p>
9+
10+
<p align="center">
11+
<img src="https://img.shields.io/badge/version-0.1.0-blue" alt="Version">
12+
<img src="https://img.shields.io/badge/status-alpha-orange" alt="Status: alpha">
13+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green" alt="License"></a>
14+
<img src="https://img.shields.io/badge/node-%3E%3D20-brightgreen" alt="Node >= 20">
15+
<img src="https://img.shields.io/badge/TypeScript-5.9-blue?logo=typescript&logoColor=white" alt="TypeScript">
16+
<img src="https://img.shields.io/badge/React_Router-v7-red?logo=reactrouter&logoColor=white" alt="React Router">
17+
<img src="https://img.shields.io/badge/PRs-welcome-brightgreen" alt="PRs Welcome">
18+
</p>
19+
20+
## Features
21+
22+
<!-- Product demo previews (GIFs) -> use table for consistent GitHub layout -->
23+
<table align="center">
24+
<tr>
25+
<td align="center" style="padding:8px">
26+
<a href="public/videos/demo_explorer.gif" title="Open Explorer GIF"><img src="public/videos/demo_explorer.gif" alt="File explorer" width="220" style="max-width:220px;height:auto;"></a>
27+
<div style="font-size:13px;color:#555;margin-top:8px;">File explorer</div>
28+
</td>
29+
<td align="center" style="padding:8px">
30+
<a href="public/videos/demo_terminal.gif" title="Open Terminal GIF"><img src="public/videos/demo_terminal.gif" alt="Terminal interface" width="220" style="max-width:220px;height:auto;"></a>
31+
<div style="font-size:13px;color:#555;margin-top:8px;">Terminal interface</div>
32+
</td>
33+
<td align="center" style="padding:8px">
34+
<a href="public/videos/demo_localhost.gif" title="Open Localhost GIF"><img src="public/videos/demo_localhost.gif" alt="Localhost preview" width="220" style="max-width:220px;height:auto;"></a>
35+
<div style="font-size:13px;color:#555;margin-top:8px;">Localhost preview</div>
36+
</td>
37+
</tr>
38+
</table>
39+
40+
41+
Three panels — **Terminal**, **Files**, and **Browser** — responsive 3-column layout on desktop/landscape, single-panel with bottom tab bar on mobile/portrait (orientation-aware breakpoint). All panels stay mounted in the DOM with CSS visibility toggling, preserving terminal state, WebSocket connections, and iframe content across navigation. Everything routes through a single Cloudflare Quick Tunnel.
42+
43+
### Terminal
44+
- Multi-session tabs (renamable), xterm.js with configurable font size
45+
- **Quick action tab groups** — color-coded action tabs (blue) and app tabs (green):
46+
- **cmds** — common shell commands (ls, top, df, free, nvidia-smi, etc.)
47+
- **cd** — visual directory picker with server-side CWD detection (works inside tmux)
48+
- **Ctrl+** — sticky modifier combos (Ctrl, Ctrl+Shift, Alt, Alt+Shift) with full A-Z and 0-9
49+
- **code** — coding CLI launchers (Claude Code, Codex, OpenCode) with vendor selector, permission presets, and slash commands
50+
- **git** — quick actions (status, log, diff, add, fetch, pull, push, stash, branch), commit with message input, git config setup (user.name/email)
51+
- **nano / vim** — file opener with version detection, in-app command buttons, save/exit shortcuts
52+
- **tmux** — session manager (list, attach, create, kill), in-session window/pane controls, auto extended-keys compatibility
53+
- **Always-visible nav keys** below input — Enter, Bksp, arrows, Esc, Tab, PgUp/PgDn
54+
- **Context-aware tabs** — editor mode (nano/vim) disables action tabs; tmux mode hides nano/vim; plain terminal shows everything
55+
- Auto-reset of tmux/editor state on socket reconnect
56+
- System info popup with OS, kernel, CPU, memory, GPU details
57+
- Tool version detection (nano, vim, tmux, claude, codex, opencode)
58+
59+
### File Explorer
60+
- Multi-session tabs (renamable), breadcrumb + editable path navigation
61+
- Create, rename, delete files and folders; file info dialog; hidden files toggle
62+
- Context menu (right-click / long-press), selectable/scrollable file paths
63+
- Drag-and-drop file upload with progress tracking and per-file cancel
64+
- Chunked upload for large files (>80 MB) to bypass Cloudflare's 100 MB request limit
65+
- **Built-in viewers & editors:**
66+
- **Code Editor** — Monaco with syntax highlighting, configurable font size, word wrap
67+
- **Markdown Preview** — GitHub-flavored with prose styling
68+
- **Jupyter Notebook** — cells with type badges, rendered markdown, code, and outputs
69+
- **HTML Preview** — live rendered in sandboxed iframe
70+
- **PDF Viewer** — inline rendering with zoom and pinch-to-zoom
71+
- **Image Viewer** — zoom controls with full pan/scroll at any zoom level, pinch-to-zoom
72+
- **Video Player** — mp4, webm, ogg, mov, mkv, avi
73+
- **Audio Player** — mp3, wav, ogg, flac, aac, m4a
74+
75+
### Localhost Preview
76+
- Preview any localhost port in a new tab via the built-in `/proxy/:port` reverse proxy
77+
- Multi-tab port list with reachability checks and green/amber status indicators
78+
- All localhost previews route through the same main tunnel of the app
79+
80+
## Quick Start
81+
82+
```bash
83+
# Clone and install
84+
git clone https://github.com/davindicode/otgcode.git
85+
cd otgcode
86+
pnpm install
87+
88+
# Create .env
89+
cp .env.example .env
90+
# Edit .env to set OTG_PORT, DEFAULT_SHELL, DEFAULT_CWD
91+
92+
# Production with Cloudflare tunnel (all-in-one)
93+
./start.sh
94+
```
95+
96+
The `start.sh` script installs dependencies if needed, builds the app, starts the server, and launches a Cloudflare Quick Tunnel — printing a public URL you can open on any device. On macOS it also clears Gatekeeper quarantine flags on node-pty binaries. If `cloudflared` is not found in your PATH, the script auto-downloads it to `.bin/` (supports macOS, Linux, and Windows on x64/arm64).
97+
98+
<details>
99+
<summary><strong>DNS tip:</strong> Tunnel URL not resolving? Set your DNS to 1.1.1.1</summary>
100+
101+
The Quick Tunnel URL (e.g. `xxxx.trycloudflare.com`) resolves instantly on Cloudflare DNS but may take time on ISP/router DNS servers, or fail entirely if a stale NXDOMAIN gets cached. Set your DNS to **1.1.1.1** (Cloudflare) for instant resolution.
102+
103+
**macOS:**
104+
```bash
105+
networksetup -setdnsservers Wi-Fi 1.1.1.1 1.0.0.1
106+
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder
107+
# To revert: networksetup -setdnsservers Wi-Fi empty
108+
```
109+
110+
**Linux (systemd-resolved):**
111+
```bash
112+
resolvectl dns $(ip route show default | awk '{print $5}') 1.1.1.1 1.0.0.1
113+
# Or permanently via /etc/systemd/resolved.conf:
114+
# [Resolve]
115+
# DNS=1.1.1.1 1.0.0.1
116+
# sudo systemctl restart systemd-resolved
117+
```
118+
119+
**Windows (PowerShell as Admin):**
120+
```powershell
121+
Get-NetAdapter | Select Name, Status
122+
Set-DnsClientServerAddress -InterfaceAlias "Wi-Fi" -ServerAddresses 1.1.1.1,1.0.0.1
123+
ipconfig /flushdns
124+
# To revert: Set-DnsClientServerAddress -InterfaceAlias "Wi-Fi" -ResetServerAddresses
125+
```
126+
</details>
127+
128+
## Scripts
129+
130+
| Command | Description |
131+
|---------|-------------|
132+
| `pnpm dev` | Dev server with HMR (Socket.IO + proxy on same port) |
133+
| `pnpm build` | Production build |
134+
| `pnpm start` | Production server |
135+
| `pnpm start:tunnel` | Production server + Cloudflare tunnel |
136+
| `./start.sh` | Install + build + start + tunnel (all-in-one) |
137+
138+
## Architecture
139+
140+
Single Express server on one port handles everything:
141+
142+
```
143+
Express (port 7777)
144+
├── React Router v7 — UI (SSR shell + client-side app)
145+
├── Socket.IO — real-time terminal I/O via node-pty
146+
├── REST API — file operations (list, read, write, rename, delete, upload, download, mkdir)
147+
├── Reverse Proxy — /proxy/:port/* forwards HTTP + WebSocket to localhost services
148+
└── Cloudflare Tunnel — single optional tunnel via cloudflared (all traffic)
149+
```
150+
151+
### Reverse Proxy
152+
153+
The `/proxy/:port` reverse proxy is how localhost previews work — no extra tunnels or processes needed. It handles:
154+
- **Path rewriting** — strips the `/proxy/:port` prefix before forwarding to `127.0.0.1:<port>`
155+
- **WebSocket upgrades** — WS connections on `/proxy/:port/...` are forwarded (supports Vite HMR, webpack-dev-server, etc.)
156+
- **Header stripping** — removes `X-Frame-Options` and CSP headers so content can embed in the preview iframe
157+
- **Asset path rewriting** — rewrites absolute paths in HTML, CSS, and JS (src, href, url(), ES imports) to include the `/proxy/:port` prefix so assets load correctly through the proxy
158+
- **Port blocking** — blocks privileged ports (1–1023, except 80/443) and the OTG server port itself
159+
160+
**Dev server notes:** Most dev servers (Vite, webpack, Next.js) work out of the box since both HTTP and WebSocket traffic are proxied. However, dev servers that hardcode their WebSocket URL to `ws://localhost:<port>` in client-side code (bypassing the proxy path) will fail over the tunnel — the HMR connection won't reach the VPS. Vite works because its HMR client connects relative to the page origin. If a dev server's HMR breaks, configure it to use a relative or custom WebSocket path.
161+
162+
## Tech Stack
163+
164+
React Router v7, Express, Socket.IO, node-pty, xterm.js, Monaco Editor, Zustand, Tailwind CSS v4, TypeScript
165+
166+
## Requirements
167+
168+
- **Node.js** 20+
169+
- **pnpm** (package manager)
170+
- **C compiler** for node-pty on Linux (`apt install build-essential`)
171+
- **cloudflared** (auto-installed by `start.sh` if not found) for remote access via Cloudflare tunnel
172+
173+
## License
174+
175+
[MIT](LICENSE)

0 commit comments

Comments
 (0)