hop2 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +33 -0
- package/MULTI-AGENT-CHECKLIST.md +30 -0
- package/README-MCP.md +213 -0
- package/README.md +117 -17
- package/hay/CHANGELOG.md +6 -0
- package/hay/apps/cli/src/index.ts +285 -48
- package/hay/apps/server/src/index.ts +4 -3
- package/hay/apps/server/src/lib.ts +4 -3
- package/hay/apps/server/src/pty.ts +20 -7
- package/hay/apps/server/src/rooms.ts +93 -12
- package/hay/apps/server/test/rooms.test.ts +82 -3
- package/hay/apps/web/src/App.tsx +253 -40
- package/hay/apps/web/src/components/MobileKeyboard.tsx +43 -2
- package/hay/apps/web/src/styles.css +9 -2
- package/hay/package-lock.json +4 -4
- package/hay/packages/shared/src/protocol.ts +4 -0
- package/hay-web/assets/{index-CTTzApRp.css → index-B7rkCY1_.css} +1 -1
- package/hay-web/assets/index-kr4B-B06.js +60 -0
- package/hay-web/assets/{index-FDfdolCs.js.map → index-kr4B-B06.js.map} +1 -1
- package/hay-web/index.html +2 -2
- package/hop +4896 -585
- package/hop.bak2 +8071 -0
- package/lib/terminal-access.js +17 -0
- package/mcp/hop-mcp.js +4530 -0
- package/mcp/hop-mcp.js.bak +4492 -0
- package/mcp/hop-mcp.js.bak2 +4530 -0
- package/package.json +6 -3
- package/scripts/hay-host.js +189 -0
- package/sessions.html +314 -26
- package/setup-mcp.js +443 -0
- package/tests/hop-mcp.integration.test.cjs +3014 -0
- package/tests/terminal-access.unit.test.cjs +21 -0
- package/tests/terminal-api.integration.test.cjs +298 -0
- package/hay-web/assets/index-FDfdolCs.js +0 -60
package/AGENTS.md
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# AGENTS.md (hop2)
|
|
2
|
+
|
|
3
|
+
Guidance for agents working on hop2.
|
|
4
|
+
|
|
5
|
+
## Project shape
|
|
6
|
+
- `hop` is the main Node.js CLI/server entry point (bin target).
|
|
7
|
+
- `sessions.html` is the built-in session picker UI.
|
|
8
|
+
- `hay/` contains the terminal sharing stack (server/cli/web).
|
|
9
|
+
- `hay-web/` is the built web client output served by `hop`.
|
|
10
|
+
|
|
11
|
+
## Local state & config
|
|
12
|
+
- Default config dir is `~/.hop2` (override via `HOP_HOME`).
|
|
13
|
+
- State files here should remain private (permissions matter).
|
|
14
|
+
- Be careful with migrations: preserve backward compatibility where possible.
|
|
15
|
+
|
|
16
|
+
## Change discipline
|
|
17
|
+
- Keep changes focused and consistent with existing patterns.
|
|
18
|
+
- Avoid unrelated refactors; minimize surface area.
|
|
19
|
+
- Add concise comments only for non-obvious logic.
|
|
20
|
+
- Update docs when user-visible behavior changes.
|
|
21
|
+
|
|
22
|
+
## Build & test
|
|
23
|
+
- Build web assets via `npm run build` (builds `hay` then syncs to `hay-web`).
|
|
24
|
+
- Basic sanity check: `npm test` (runs `node --check hop`).
|
|
25
|
+
- If you don’t run tests, say so and suggest likely commands.
|
|
26
|
+
|
|
27
|
+
## UI work
|
|
28
|
+
- Preserve existing visual language unless a redesign is intended.
|
|
29
|
+
- Ensure layouts remain usable on desktop and mobile.
|
|
30
|
+
|
|
31
|
+
## Server/CLI work
|
|
32
|
+
- Prefer clear errors and non-zero exit codes on failures.
|
|
33
|
+
- Keep security-sensitive behavior conservative and explicit.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Multi-Agent Run Checklist
|
|
2
|
+
|
|
3
|
+
## Goal
|
|
4
|
+
Ensure concurrent agent sessions stay isolated, time-bounded, and recoverable.
|
|
5
|
+
|
|
6
|
+
## Safety Gates
|
|
7
|
+
|
|
8
|
+
- [ ] **Isolated terminals** — assign each agent its own PTY via `hop_create_terminal`; never share a session between agents.
|
|
9
|
+
- [ ] **Destructive-command approval** — gate every `rm -rf`, force-push, or `DROP TABLE` behind explicit user confirmation, regardless of autonomy level.
|
|
10
|
+
- [ ] **Per-command timeouts** — enforce `idle_ms` and `max_wait_ms` on every `hop_wait_terminal` call; escalate or kill on deadline breach.
|
|
11
|
+
|
|
12
|
+
## Execution Loop
|
|
13
|
+
|
|
14
|
+
1. **Create session** — one `hop_create_terminal` per agent.
|
|
15
|
+
2. **Validate prompt** — call `hop_wait_terminal(until_prompt=true)` to confirm the shell is ready before sending any command.
|
|
16
|
+
3. **Send command** — write via `hop_write_terminal`; never blind-write into mid-execution output.
|
|
17
|
+
4. **Await result** — use `until_regex` or `until_prompt` with `max_wait_ms` to capture output and detect completion.
|
|
18
|
+
5. **Assert state** — verify exit code / expected output before proceeding.
|
|
19
|
+
6. **Repeat** steps 2–5 for each command in the plan.
|
|
20
|
+
|
|
21
|
+
## Recovery
|
|
22
|
+
|
|
23
|
+
| Step | Action |
|
|
24
|
+
|------|--------|
|
|
25
|
+
| 1 | Send `ctrl_c` via `hop_send_key` |
|
|
26
|
+
| 2 | If unresponsive after 5 s → `hop_close_terminal(killSession=true)` |
|
|
27
|
+
| 3 | On orchestrator crash → kill **all** child terminals (kill switch) |
|
|
28
|
+
| 4 | Verify zero orphaned processes before declaring shutdown complete |
|
|
29
|
+
|
|
30
|
+
**Rule:** Never skip escalation. Always tear down — never leave orphaned sessions.
|
package/README-MCP.md
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
# Hop MCP Server
|
|
2
|
+
|
|
3
|
+
The Hop MCP server exposes hop’s terminal/session APIs over the Model Context Protocol (MCP), so agents can create terminals, stream output, and send input through Hop.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
1) Ensure Hop daemon is running locally (creates `~/.hop2/.tunnel-state`).
|
|
8
|
+
|
|
9
|
+
2) Auto-configure supported MCP clients:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
hop-mcp-setup
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
If you are running from source in this repo:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm run setup-mcp
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Supported auto-detected clients:
|
|
22
|
+
- Claude Code
|
|
23
|
+
- Claude Desktop
|
|
24
|
+
- Cursor IDE
|
|
25
|
+
- Gemini CLI
|
|
26
|
+
- Codex CLI
|
|
27
|
+
- VS Code / GitHub Copilot (workspace via `.vscode/mcp.json`)
|
|
28
|
+
- Antigravity
|
|
29
|
+
|
|
30
|
+
3) Or configure your MCP client manually:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{
|
|
34
|
+
"mcpServers": {
|
|
35
|
+
"hop": {
|
|
36
|
+
"command": "hop-mcp"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
4) Restart your MCP client.
|
|
43
|
+
|
|
44
|
+
The server auto-connects to the local Hop daemon via `~/.hop2/.tunnel-state`.
|
|
45
|
+
|
|
46
|
+
## One Subagent Terminal (Claude/Codex)
|
|
47
|
+
|
|
48
|
+
Recommended flow for driving one agent CLI safely:
|
|
49
|
+
|
|
50
|
+
1) Launch a dedicated terminal:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
hop_create_terminal(name="subagent", cwd="/path/to/repo")
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
2) Start the agent CLI:
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
hop_write_terminal(data="claude\n")
|
|
60
|
+
# or
|
|
61
|
+
hop_write_terminal(data="codex\n")
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
3) Wait for a prompt before sending work:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
hop_wait_terminal(until_prompt=true, start_from="latest")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
4) Run a multi-turn loop:
|
|
71
|
+
- preferred: `hopx_send_and_wait(data="<task>", press_enter=true, capture="readable_raw")`
|
|
72
|
+
- helper alternative: `hopx_agent_turn(data="<task>", mode="auto")`
|
|
73
|
+
- manual split (if needed):
|
|
74
|
+
- send one instruction with `hop_write_terminal(data="<task>\n")`
|
|
75
|
+
- wait for output with `hop_wait_terminal(capture="readable_raw")` (defaults to `until_agent_done`)
|
|
76
|
+
- continue with cursor-deltas via `hop_read_terminal(start_from="cursor", cursor=...)`
|
|
77
|
+
- send the next instruction only after output is captured
|
|
78
|
+
|
|
79
|
+
5) Stop/cleanup:
|
|
80
|
+
- interrupt with `hop_send_key(key="ctrl_c")`
|
|
81
|
+
- close with `hop_close_terminal(killSession=false)`
|
|
82
|
+
|
|
83
|
+
Safety notes:
|
|
84
|
+
- Keep one subagent per terminal (no multiplexing multiple agent CLIs in one PTY).
|
|
85
|
+
- For existing user sessions, verify `agentPermitted` (or set with `hop_set_agent_permission`) before writing input.
|
|
86
|
+
|
|
87
|
+
## Remote Hop
|
|
88
|
+
|
|
89
|
+
To connect to a remote hop instance, set env vars or use `connect_server`:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
HOP_API_URL="https://hop2.example.com" HOP_TOKEN="<token>" hop-mcp
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Or from tools:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
connect_server(base_url="https://hop2.example.com", token="<token>")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Optional verification:
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
connect_server(base_url="https://hop2.example.com", token="<token>", verify=true, verify_endpoint="/api/sessions")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Tools
|
|
108
|
+
|
|
109
|
+
Core tools (`hop_`): stable atomic operations.
|
|
110
|
+
- `connect_server`
|
|
111
|
+
- `hop_server_info`
|
|
112
|
+
- `hop_list_sessions`
|
|
113
|
+
- `hop_list_terminals`
|
|
114
|
+
- `hop_create_terminal`
|
|
115
|
+
- `hop_attach_terminal`
|
|
116
|
+
- `hop_write_terminal`
|
|
117
|
+
- `hop_send_key`
|
|
118
|
+
- `hop_wait_terminal`
|
|
119
|
+
- `hop_wait_start`
|
|
120
|
+
- `hop_wait_poll`
|
|
121
|
+
- `hop_resize_terminal`
|
|
122
|
+
- `hop_read_terminal`
|
|
123
|
+
- `hop_close_terminal`
|
|
124
|
+
- `hop_set_agent_permission`
|
|
125
|
+
- `hop_list_workspaces`
|
|
126
|
+
- `hop_save_workspace`
|
|
127
|
+
- `hop_load_workspace`
|
|
128
|
+
- `hop_use_workspace`
|
|
129
|
+
|
|
130
|
+
Helper tools (`hopx_`): convenience wrappers built on top of core tools.
|
|
131
|
+
- `hopx_send_and_wait` (single-call send + wait wrapper)
|
|
132
|
+
- `hopx_agent_turn` (single-turn send + wait + mode-aware output, default `mode="auto"`)
|
|
133
|
+
|
|
134
|
+
## Resources
|
|
135
|
+
|
|
136
|
+
- `hop://sessions`
|
|
137
|
+
- `hop://terminals`
|
|
138
|
+
- `hop://workspaces`
|
|
139
|
+
|
|
140
|
+
## Notes
|
|
141
|
+
|
|
142
|
+
- Agent access is gated by `agentPermitted` for sessions created by users.
|
|
143
|
+
- `terminal_id` is an ephemeral daemon attachment handle; underlying hop `sessionName` is the stable identity.
|
|
144
|
+
- On daemon restart, terminal-scoped tools auto-reattach once using stored session identity and retry transparently when possible.
|
|
145
|
+
- `hop_read_terminal` returns a cursor for incremental polling.
|
|
146
|
+
- `hop_read_terminal` supports `mode: "ui"` for structured terminal snapshots:
|
|
147
|
+
- `ui.lines`: visible screen lines
|
|
148
|
+
- `ui.cursor`: cursor position
|
|
149
|
+
- `ui.window.strategy`: `cursor_centered` with auto fallback to `densest_nonempty` when needed
|
|
150
|
+
- `rawTail`: optional lossless tail of recent raw events (for transient output)
|
|
151
|
+
- Hop server now replays buffered terminal events on stream connect, so late attaches get immediate context instead of an empty first read.
|
|
152
|
+
- `hop_read_terminal` supports `mode: "readable_raw"`:
|
|
153
|
+
- preserves printable text in `events[].text`
|
|
154
|
+
- includes compact control hints in `events[].controls` (cursor, erase, alt-screen, visibility)
|
|
155
|
+
- `control_level` tunes control noise:
|
|
156
|
+
- `full`
|
|
157
|
+
- `structural` (cursor/edit/screen controls; omits CR/LF noise)
|
|
158
|
+
- `none` (default; text only)
|
|
159
|
+
- `noise_filter` tunes status/spinner suppression:
|
|
160
|
+
- `balanced` (default; suppresses CR/erase rewrite bursts, commits stable lines, strips spinner-prefix/dot animation for dedupe)
|
|
161
|
+
- in `balanced`, recent shell echo lines for agent-sent input (prompt + command) and prompt-padding artifacts are compacted
|
|
162
|
+
- `off` (raw parsed text; useful for parser debugging)
|
|
163
|
+
- in default `none`, empty output frames are dropped to reduce event noise
|
|
164
|
+
- `coalesce_ms` and `coalesce_max_chars` can merge adjacent output frames for cleaner streaming text
|
|
165
|
+
- defaults: `coalesce_ms=250`, `coalesce_max_chars=32768`
|
|
166
|
+
- parses incrementally across chunk boundaries to avoid split ANSI artifacts
|
|
167
|
+
- reconstructs common inline edits (backspace/cursor rewrites) so text is cleaner for agent parsing
|
|
168
|
+
- avoids full ANSI noise while retaining interaction structure
|
|
169
|
+
- `hop_send_key` sends normalized named keys (for example `enter`, `esc`, `up`, `ctrl_c`) to improve interactive TUI control without raw escape-string handling.
|
|
170
|
+
- `hop_wait_terminal` blocks on output conditions without client polling loops:
|
|
171
|
+
- `start_from` controls where matching begins:
|
|
172
|
+
- `latest` (default): stream tail / new output only
|
|
173
|
+
- `cursor`: requires `cursor` argument
|
|
174
|
+
- `beginning`: oldest buffered event
|
|
175
|
+
- if no explicit condition is provided, it defaults to `until_agent_done=true`
|
|
176
|
+
- `async=true` starts a background wait job and returns `wait_id` immediately
|
|
177
|
+
- `until_agent_done` matches when output has started, terminal becomes quiet, and interactive cursor is visible (agent-friendly completion)
|
|
178
|
+
- regex match via `until_regex`
|
|
179
|
+
- prompt match via `until_prompt` (optional custom `prompt_regex`)
|
|
180
|
+
- quiet-period detection via `idle_ms`
|
|
181
|
+
- bounded event capture in `raw` or `readable_raw`
|
|
182
|
+
- for `capture="readable_raw"`, supports `control_level`, `noise_filter`, `coalesce_ms`, `coalesce_max_chars`, and optional `includeMetaEvents`
|
|
183
|
+
- `hop_wait_start` / `hop_wait_poll` provide explicit async wait orchestration for long-running conditions:
|
|
184
|
+
- start with `hop_wait_start(...)` and poll with `hop_wait_poll(wait_id=..., wait=true)`
|
|
185
|
+
- use `consume=true` on poll to remove completed jobs
|
|
186
|
+
- `hopx_send_and_wait` combines input send + optional enter/key + wait, and defaults to cursor-based delta capture from just before send.
|
|
187
|
+
- helper defaults are token-thrifty for interactive loops: `capture_max_events=60`, `control_level=none`, `noise_filter=balanced`, `coalesce_ms=350` (unless overridden)
|
|
188
|
+
- for `capture="readable_raw"`, `text_only` defaults to `true`; this condenses wait payloads by returning joined `wait.text`, setting `wait.events=[]`, `wait.eventCount=0`, and preserving prior count in `wait.originalEventCount` (set `text_only=false` to keep full events)
|
|
189
|
+
- `hop_read_terminal` supports deterministic delta reads:
|
|
190
|
+
- `start_from`: `beginning` (default), `cursor`, or `latest`
|
|
191
|
+
- response includes `cursorStart`, `cursorEnd`, and `next_cursor`
|
|
192
|
+
- `hopx_agent_turn` is a helper wrapper (not a core primitive):
|
|
193
|
+
- default `mode="auto"` chooses `ui` when terminal is in alternate-screen, otherwise `readable_raw`
|
|
194
|
+
- in `mode="auto"`, if alternate-screen starts during the same turn, it auto-promotes to `ui` for that response
|
|
195
|
+
- wait-only continuation is supported: omit `data`/`message` and use `control="wait"` to keep waiting on a terminal without sending new input
|
|
196
|
+
- `async=true` starts the turn wait in the background and returns `wait_id` immediately; continue polling or controlling that turn with `hopx_agent_turn(wait_id=..., wait=true|false, control=...)`
|
|
197
|
+
- `control="interrupt"` / `control="terminate"` send an explicit interrupt key (default `esc`); `terminate_message` can send a final follow-up after the interrupt
|
|
198
|
+
- `mode="ui"` returns a UI snapshot payload after wait
|
|
199
|
+
- for readable modes, `text_only` defaults to `true` and condenses waits the same way as `hopx_send_and_wait` (set `text_only=false` to keep full wait events)
|
|
200
|
+
- `text_only` is ignored for `mode="ui"` output snapshots
|
|
201
|
+
- `mode="ui"` defaults `includeRawTail=false` to reduce noisy tail payloads (opt in with `includeRawTail=true`)
|
|
202
|
+
- `mode="ui"` defaults wait capture to `capture_max_events=0` (override when you need readable wait-event diagnostics)
|
|
203
|
+
- when using default `until_agent_done` semantics in `mode="ui"`, hopx applies a short UI busy-guard pass to avoid returning while status lines still indicate active work (`esc to interrupt`, `working`, `waiting for process`, etc.)
|
|
204
|
+
- `mode="readable_raw"` / `mode="raw"` returns the same wait payload shape as `hopx_send_and_wait`
|
|
205
|
+
- Tool calls that fail at the Hop API layer now return MCP errors (`isError: true`) with normalized fields:
|
|
206
|
+
- `ok`
|
|
207
|
+
- `status`
|
|
208
|
+
- `endpoint`
|
|
209
|
+
- `error`
|
|
210
|
+
- Hop now isolates shell history per session and writes per-session NDJSON audit logs under `~/.hop2/workspaces/<workspace>/logs/<session>/audit.ndjson` with truncation metadata for large chunks.
|
|
211
|
+
- Audit logging auto-switches to diff-suppressed `tui_keyframe` snapshots when alternate-screen apps (vim/htop/agent TUIs) are detected, while still capturing all input events.
|
|
212
|
+
- Default fallback terminal size is `140x40` when no explicit `cols`/`rows` are provided.
|
|
213
|
+
- `hop_create_terminal` / `hop_attach_terminal` now do a short output warmup before returning, reducing first-command races in interactive shells.
|
package/README.md
CHANGED
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
Access your Mac's terminal from your phone, tablet, or any browser — secured with password + 2FA, tunneled through Cloudflare.
|
|
6
6
|
|
|
7
|
+
Hop also ships with a built-in MCP server, so Claude Code, Codex, Gemini, Cursor, and other MCP clients can create terminals, stream output, and drive agent sessions through Hop.
|
|
8
|
+
|
|
7
9
|
> **🍎 macOS/Linux** — Requires cloudflared for tunneling
|
|
8
10
|
|
|
9
11
|
```
|
|
@@ -16,6 +18,7 @@ Access your Mac's terminal from your phone, tablet, or any browser — secured w
|
|
|
16
18
|
|
|
17
19
|
- 🔐 **Password + 2FA** — Optional password plus TOTP (required for custom domains)
|
|
18
20
|
- 🌍 **Access Anywhere** — Cloudflare tunnel, no port forwarding
|
|
21
|
+
- 🤖 **Built-in MCP Server** — Turn Hop into an agent-facing terminal platform for Claude Code, Codex, Gemini, Cursor, and more
|
|
19
22
|
- 🌐 **Custom Domains + Multi‑User** — Share subdomains with per‑user credentials
|
|
20
23
|
- 📱 **Mobile Virtual Keyboard** — Custom keyboard with Esc, Ctrl, Alt, arrows, and more
|
|
21
24
|
- ⌨️ **Native Keyboard Support** — Tap the blue button for dictation, spellcheck & autocomplete
|
|
@@ -33,6 +36,11 @@ Access your Mac's terminal from your phone, tablet, or any browser — secured w
|
|
|
33
36
|
npm install -g hop2
|
|
34
37
|
```
|
|
35
38
|
|
|
39
|
+
This installs:
|
|
40
|
+
- `hop` — main CLI / daemon / browser terminal entrypoint
|
|
41
|
+
- `hop-mcp` — MCP server exposing Hop terminals and sessions
|
|
42
|
+
- `hop-mcp-setup` — MCP client auto-config helper
|
|
43
|
+
|
|
36
44
|
Then just run:
|
|
37
45
|
```bash
|
|
38
46
|
hop
|
|
@@ -69,9 +77,6 @@ source ~/.zshrc
|
|
|
69
77
|
```bash
|
|
70
78
|
# Start hopping!
|
|
71
79
|
hop
|
|
72
|
-
|
|
73
|
-
# Use iTerm control mode for local session
|
|
74
|
-
hop --iterm
|
|
75
80
|
```
|
|
76
81
|
|
|
77
82
|
**First time:**
|
|
@@ -86,6 +91,27 @@ hop --iterm
|
|
|
86
91
|
3. Pick or create a session
|
|
87
92
|
4. 🐰 You're in! Use the virtual keyboard for terminal keys, or tap the blue button for native input
|
|
88
93
|
|
|
94
|
+
## 🤖 Hop MCP
|
|
95
|
+
|
|
96
|
+
Hop is not just a browser terminal. It also exposes terminals and sessions over MCP so agents can safely operate through the same platform.
|
|
97
|
+
|
|
98
|
+
Use cases:
|
|
99
|
+
- Launch a dedicated Claude Code / Codex / Gemini terminal and drive it over multiple turns
|
|
100
|
+
- Create isolated agent sessions with per-session history and audit logs
|
|
101
|
+
- Read terminal output incrementally instead of screen-scraping a browser
|
|
102
|
+
- Build higher-level agent workflows on top of stable terminal/session primitives
|
|
103
|
+
|
|
104
|
+
Quick start:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
hop
|
|
108
|
+
hop-mcp-setup
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Then restart your MCP client. `hop-mcp-setup` auto-detects and configures supported clients such as Claude Code, Claude Desktop, Cursor, Gemini CLI, Codex CLI, VS Code / Copilot, and Antigravity.
|
|
112
|
+
|
|
113
|
+
For full MCP usage, tools, and subagent workflows, see [README-MCP.md](./README-MCP.md).
|
|
114
|
+
|
|
89
115
|
## 🪟 Sessions
|
|
90
116
|
|
|
91
117
|
Create multiple independent terminal sessions from the Session Picker (`/sessions`):
|
|
@@ -98,8 +124,37 @@ You can also create **Port Sessions** that proxy to a local HTTP/WS service on y
|
|
|
98
124
|
Use the Session Picker or:
|
|
99
125
|
```bash
|
|
100
126
|
hop session add myapp --port 3000
|
|
127
|
+
hop session add workspace-shell --cwd ~/src/my-project
|
|
101
128
|
```
|
|
102
129
|
|
|
130
|
+
## 🧾 Session History & Audit Logs
|
|
131
|
+
|
|
132
|
+
Hop always writes per-session audit logs.
|
|
133
|
+
Shell history isolation is role-based by default:
|
|
134
|
+
|
|
135
|
+
- Agent-created terminal sessions: isolated history file per session
|
|
136
|
+
- User-created terminal sessions: keep your shell default history file (opt-in isolation available)
|
|
137
|
+
|
|
138
|
+
- Isolated history file path: `~/.hop2/workspaces/<workspace>/history/<internal-session>.history`
|
|
139
|
+
- Audit log (NDJSON): `~/.hop2/workspaces/<workspace>/logs/<internal-session>/audit.ndjson`
|
|
140
|
+
- Audit events include `session_start`, `input`, `resize`, `session_end`, plus:
|
|
141
|
+
- `audit_mode` / `pty_state` transitions (auto-switches between `stream` and `tui_keyframe`)
|
|
142
|
+
- `tui_keyframe` snapshots (diff-suppressed; emitted only when content changes)
|
|
143
|
+
- `command_launch` metadata (captures launched command token and detected agent CLI type)
|
|
144
|
+
- Large input/output chunks are truncated with metadata (`bytes`, `omittedBytes`, `dataHead`, `dataTail`)
|
|
145
|
+
|
|
146
|
+
Tunable defaults:
|
|
147
|
+
|
|
148
|
+
- `HOP_SESSION_HISTORY_SIZE` (default `5000`)
|
|
149
|
+
- `HOP_AGENT_HISTORY_ISOLATION` (default `1`)
|
|
150
|
+
- `HOP_USER_HISTORY_ISOLATION` (default `0`)
|
|
151
|
+
- `HOP_AGENT_POST_START_HISTORY_INIT` (default `1`)
|
|
152
|
+
- `HOP_POST_START_HISTORY_INIT` (default `0`, forces post-start history init for all sessions)
|
|
153
|
+
- `HOP_SESSION_AUDIT_INLINE_MAX_BYTES` (default `4096`)
|
|
154
|
+
- `HOP_SESSION_TUI_KEYFRAME_INTERVAL_MS` (default `750`)
|
|
155
|
+
- `HOP_SESSION_TUI_KEYFRAME_TAIL_CHARS` (default `20000`)
|
|
156
|
+
- `HOP_SESSION_TUI_KEYFRAME_MAX_LINES` (default `80`)
|
|
157
|
+
|
|
103
158
|
## 🌐 Custom Domains & Multi‑User
|
|
104
159
|
|
|
105
160
|
### Admin (your machine)
|
|
@@ -145,13 +200,13 @@ On mobile devices, Hop provides a custom virtual keyboard designed for terminal
|
|
|
145
200
|
- First-time users will see a tooltip pointing to the native keyboard button
|
|
146
201
|
- Use the native keyboard for longer text input with autocomplete
|
|
147
202
|
|
|
148
|
-
## 🖥️
|
|
203
|
+
## 🖥️ Local Attach
|
|
149
204
|
|
|
150
205
|
```bash
|
|
151
|
-
hop
|
|
206
|
+
hop attach <session>
|
|
152
207
|
```
|
|
153
208
|
|
|
154
|
-
|
|
209
|
+
Attach your local terminal client to an existing hop terminal session.
|
|
155
210
|
|
|
156
211
|
## 🔌 Port Sessions
|
|
157
212
|
|
|
@@ -168,10 +223,12 @@ Works with dev servers, Jupyter, APIs — anything on localhost. Supports WebSoc
|
|
|
168
223
|
|
|
169
224
|
| Command | Description |
|
|
170
225
|
|---------|-------------|
|
|
171
|
-
| `hop` | Start hop
|
|
172
|
-
| `hop
|
|
226
|
+
| `hop` | Start hop daemon/tunnel if needed, then launch a local terminal |
|
|
227
|
+
| `hop attach all` | Attach sequentially to all terminal sessions |
|
|
228
|
+
| `hop local [session]` | Start a daemonless local terminal (`[session]` attaches if it exists) |
|
|
173
229
|
| `hop url` | Print current tunnel URL |
|
|
174
|
-
| `hop qr` | Show QR code for current URL |
|
|
230
|
+
| `hop qr` | Show QR code for current tunnel URL |
|
|
231
|
+
| `hop qr auth` | Show QR code for authenticator app setup |
|
|
175
232
|
| `hop domain <hostname>` | Set custom domain (named tunnel) |
|
|
176
233
|
| `hop domain-clear` | Remove custom domain, use random URLs |
|
|
177
234
|
| `hop password set` | Set/change password |
|
|
@@ -180,19 +237,36 @@ Works with dev servers, Jupyter, APIs — anything on localhost. Supports WebSoc
|
|
|
180
237
|
| `hop user add <name>` | Add user + subdomain |
|
|
181
238
|
| `hop user remove <name>` | Remove user |
|
|
182
239
|
| `hop user export <name>` | Export user credentials |
|
|
183
|
-
| `hop session list` | List sessions |
|
|
184
|
-
| `hop session add <name
|
|
240
|
+
| `hop session list` | List sessions with `LIVE` vs `SAVED` terminal status |
|
|
241
|
+
| `hop session add <name> [--cwd P]` | Create a terminal session |
|
|
185
242
|
| `hop session add <name> --port N` | Create a port session (proxy) |
|
|
243
|
+
| `hop session rename <old> <new>` | Rename a session |
|
|
186
244
|
| `hop session remove <name>` | Remove a session |
|
|
187
245
|
| `hop client <credentials>` | Run hop with exported credentials |
|
|
188
|
-
| `hop wipe` |
|
|
246
|
+
| `hop wipe [--all]` | Remove saved sessions (`--all` also kills live sessions) |
|
|
189
247
|
| `quit` | Type at exit prompt to shutdown tunnel |
|
|
190
248
|
|
|
249
|
+
Additional installed binaries:
|
|
250
|
+
- `hop-mcp` — Start the Hop MCP server directly
|
|
251
|
+
- `hop-mcp-setup` — Auto-configure supported MCP clients
|
|
252
|
+
|
|
253
|
+
Startup behavior:
|
|
254
|
+
- Hop reconciles already-running external Hay sessions first, then applies the default workspace as additional startup state.
|
|
255
|
+
|
|
256
|
+
## 🧪 Terminal Backend
|
|
257
|
+
|
|
258
|
+
Hop always uses the `external` terminal runtime (PTYs in a separate local hay host process).
|
|
259
|
+
|
|
260
|
+
- The host persists across hop daemon restarts.
|
|
261
|
+
- Host state is tracked in `~/.hop2/.hay-host-state`.
|
|
262
|
+
- On startup and session listing, Hop discovers live hay-host processes and adopts the one(s) that still own runtime rooms if the state file is stale.
|
|
263
|
+
- Local CLI transport is direct to hay-host; daemon restarts do not terminate local terminal sessions.
|
|
264
|
+
- Bare `hop` prompts on cwd match (`Attach existing` vs `Create new`, default `Create new`); non-interactive runs always create new.
|
|
265
|
+
- `HOP_TERMINAL_BACKEND` is accepted for compatibility but ignored.
|
|
266
|
+
|
|
191
267
|
## 📦 Dependencies
|
|
192
268
|
|
|
193
269
|
Installed automatically via Homebrew:
|
|
194
|
-
- `tmux` — Terminal multiplexer
|
|
195
|
-
- `ttyd` — Web terminal
|
|
196
270
|
- `cloudflared` — Cloudflare tunnel
|
|
197
271
|
|
|
198
272
|
Node.js packages:
|
|
@@ -206,6 +280,7 @@ Node.js packages:
|
|
|
206
280
|
- **Password + TOTP** — Password optional, but required for custom domains
|
|
207
281
|
- **Rate Limiting** — Exponential backoff on failed attempts
|
|
208
282
|
- **Secure Cookies** — `httpOnly`, `secure`, `sameSite=lax`
|
|
283
|
+
- **Session persistence** — Login cookies are signed with a stable session secret by default, so browser sessions can survive `hop stop/start` without reauth.
|
|
209
284
|
- **Random URL** — Unguessable tunnel URL for quick tunnels
|
|
210
285
|
- **Fixed URL** — Custom domains keep a stable URL
|
|
211
286
|
- **Local Binding** — Server only listens on 127.0.0.1
|
|
@@ -214,6 +289,7 @@ Node.js packages:
|
|
|
214
289
|
**Passwords:** Recommended for any public URL; required for custom domains.
|
|
215
290
|
|
|
216
291
|
**Secrets:** Stored in `~/.hop2/` (treat like `~/.ssh/`)
|
|
292
|
+
Set `HOP_PERSIST_SESSION_SECRET=0` to force a fresh login cookie secret every daemon restart.
|
|
217
293
|
|
|
218
294
|
## 🛠 Development (Hay)
|
|
219
295
|
|
|
@@ -226,10 +302,31 @@ npm run build
|
|
|
226
302
|
This builds hay (web + cli) and syncs `hay/apps/web/dist` into `hay-web/` for Hop to serve.
|
|
227
303
|
If `./hay` exists and the dist folder is missing, `hop` will auto-build hay on startup.
|
|
228
304
|
|
|
305
|
+
## 🤖 Hop MCP (One Subagent Terminal)
|
|
306
|
+
|
|
307
|
+
Use one dedicated terminal when driving a subagent CLI through Hop MCP.
|
|
308
|
+
|
|
309
|
+
1. Create a terminal with `hop_create_terminal` (set `name` and `cwd`).
|
|
310
|
+
2. Start the agent CLI with `hop_write_terminal` (`claude` or `codex`).
|
|
311
|
+
3. Wait for readiness with `hop_wait_terminal(until_prompt=true)`.
|
|
312
|
+
4. Send one instruction at a time via `hopx_send_and_wait` (or `hop_write_terminal` + `hop_wait_terminal`).
|
|
313
|
+
5. Optional helper path: use `hopx_agent_turn(mode="auto")` for a single send+wait turn with mode-aware output (`ui` for TUI screens, `readable_raw` otherwise); it auto-promotes to `ui` if alternate-screen starts mid-turn and uses lean capture defaults (`capture_max_events=60` for readable modes, `0` for `ui` unless overridden, plus `text_only=true` by default for readable waits).
|
|
314
|
+
6. For long waits, prefer `hopx_agent_turn(async=true, ...)` and continue with `hopx_agent_turn(wait_id=..., wait=true, control="wait")`; fall back to `hop_wait_start(...)` / `hop_wait_poll(...)` when you want the lower-level primitives directly.
|
|
315
|
+
7. After each turn, collect output with `hop_wait_terminal` or incremental `hop_read_terminal` cursor reads.
|
|
316
|
+
8. Interrupt with `hop_send_key(key="ctrl_c")` and close using `hop_close_terminal`.
|
|
317
|
+
|
|
318
|
+
Safety tips:
|
|
319
|
+
- Keep one subagent per terminal.
|
|
320
|
+
- Do not queue a second instruction before reading the first response.
|
|
321
|
+
- For attached user sessions, confirm `agentPermitted` before sending input.
|
|
322
|
+
|
|
229
323
|
## 🐛 Troubleshooting
|
|
230
324
|
|
|
231
|
-
**QR code
|
|
232
|
-
|
|
325
|
+
**Authenticator QR code needed again?**
|
|
326
|
+
Run `hop qr auth` to re-show the current TOTP setup QR for Duo/Authy/1Password.
|
|
327
|
+
|
|
328
|
+
**Need to reset TOTP entirely?**
|
|
329
|
+
Delete `.auth_secret` and restart hop to generate a new authenticator secret and QR code.
|
|
233
330
|
|
|
234
331
|
**Client reset (user mode)?**
|
|
235
332
|
Delete `~/.hop2/clients/<tunnel-id>/` and run `hop client` again.
|
|
@@ -237,9 +334,12 @@ Delete `~/.hop2/clients/<tunnel-id>/` and run `hop client` again.
|
|
|
237
334
|
**Tunnel not starting?**
|
|
238
335
|
Make sure `cloudflared` is installed: `brew install cloudflared`
|
|
239
336
|
|
|
337
|
+
**Tunnel returns 502 or died after network changes?**
|
|
338
|
+
Run `hop health --restart`. Hop now waits for the public URL to become healthy again instead of only sending a fire-and-forget restart request.
|
|
339
|
+
|
|
240
340
|
**Stuck processes?**
|
|
241
341
|
```bash
|
|
242
|
-
pkill
|
|
342
|
+
pkill cloudflared
|
|
243
343
|
```
|
|
244
344
|
|
|
245
345
|
## 📝 License
|
package/hay/CHANGELOG.md
CHANGED