Skip to content

pr/6e4e30251 featssh server ac 01 add sshremoteserver#256

Merged
plusplusoneplusplus merged 7 commits into
mainfrom
pr/6e4e30251-featssh-server-ac-01-add-sshremoteserver
Jun 1, 2026
Merged

pr/6e4e30251 featssh server ac 01 add sshremoteserver#256
plusplusoneplusplus merged 7 commits into
mainfrom
pr/6e4e30251-featssh-server-ac-01-add-sshremoteserver

Conversation

@plusplusoneplusplus
Copy link
Copy Markdown
Owner

  • feat(ssh-server): AC-01 — add SshRemoteServer data model
  • fix(dashboard): clear Ralph session pane when clicking New Chat
  • feat(ralph): add resume route for stuck executing sessions
  • fix(ralph): allow /continue for NO_SIGNAL sessions regardless of cap position
  • feat(servers): implement SshConnector for SSH tunnel remote servers (AC-02)
  • feat(servers): add SSH Tunnel radio and fields to AddServerDialog
  • feat(coc): auto-reconnect on unexpected SSH exit + SSH route integration tests

plusplusoneplusplus and others added 7 commits May 31, 2026 23:24
- Add SshRemoteServer interface (kind: 'ssh', host: string, localPort: number)
  to remote-server-types.ts; extend RemoteServerKind, RemoteServer,
  RemoteServerCreateInput, and RemoteServerUpdateInput unions
- Mirror SshRemoteServer, RemoteServerInput, and RemoteServerPatch in
  packages/coc-client/src/contracts/servers.ts
- Add normalizeSshHost / normalizeSshLocalPort helpers in remote-server-store.ts;
  update parseRemoteServer, buildCreateInput, buildUpdateInput, create, and update
  to handle ssh kind
- Update remote-server-routes.ts: toRuntime handles ssh (idle stub until AC-02);
  /api/servers/test endpoint handles ssh input; import SshRemoteServer type
- Add SSH store tests: CRUD lifecycle, validation, and persistence round-trip

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The onNewChat handler in RepoChatTab was not clearing selectedRalphSessionId,
so clicking "New chat" while viewing a Ralph session left the Ralph workflow
pane mounted (it takes priority over ChatDetailPane in the render path).
Now the handler also resets the Ralph selection and updates the URL hash.

Co-authored-by: Cursor <cursoragent@cursor.com>
When a Ralph iteration task fails, is cancelled, or the server crashes
mid-loop, the session stays in phase=executing with no in-flight task.
Previously there was no way to continue such sessions — /continue only
works for completed-at-cap sessions and /new-loop requires
RALPH_COMPLETE.

Add POST .../ralph-sessions/:sessionId/resume that detects stuck
executing sessions (phase=executing, under cap, no queued/running task)
and enqueues the next iteration without changing maxIterations.

- Server: new ralph-resume-routes.ts with full validation
- Store: appendResumeMarker() for progress.md audit trail
- Client: resumeRalphSession() in coc-client WorkspacesClient
- UI: amber "Resume" button in RalphWorkflowPane for stuck sessions
- Tests: route tests, store tests, and UI component tests (24 new)
- Docs: updated ralph.md and rest-api.md references

Co-authored-by: Cursor <cursoragent@cursor.com>
…position

The /continue route previously only accepted NO_SIGNAL sessions where
currentIteration >= maxIterations (cap-reached). This left early
NO_SIGNAL stops (agent failure mid-run, iteration 2 of 20) with no
recovery path — neither /continue, /resume, nor /new-loop accepted them.

Expand isResumableTerminalState to accept any NO_SIGNAL-terminated
session, and update the UI isContinuable check to match. This covers
the real-world scenario where an agent crashes or fails to emit a
RALPH_NEXT signal before hitting the iteration cap.

- Server: isResumableTerminalState now accepts all NO_SIGNAL sessions
- UI: renamed isCapHit → isContinuable, removed cap position guard
- Tests: flipped the NO_SIGNAL-under-cap test from reject to accept

Co-authored-by: Cursor <cursoragent@cursor.com>
…AC-02)

- Add SshConnector class (ssh-connector.ts) modeled on DevTunnelConnector:
  spawns 'ssh -N <host>', polls health at http://127.0.0.1:<port>/api/health,
  marks 'online' on success, 'failed' on timeout or unexpected exit
- Surfaces 'ssh binary not found on PATH' when process emits ENOENT error
- Supports connect, disconnect, reconnect, connectConfigured, dispose
- Wire SshConnector into remote-server-routes (toRuntime, connect/disconnect/
  reconnect endpoints now handle ssh kind alongside devtunnel)
- Instantiate SshConnector in server/index.ts and routes/index.ts; call
  connectConfigured on startup; dispose on server close
- Add 14 unit tests covering connect-success, dedup, timeout, binary-not-found,
  unexpected-exit, reconnect, old-exit-guard, disconnect, getState, getStates,
  dispose, connectConfigured, and already-online short-circuit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add third radio option 'SSH Tunnel' (kind='ssh') to the connection
  type fieldset, always visible alongside Direct URL and DevTunnel ID.
- Selecting SSH Tunnel reveals two inputs: Host alias (maps to
  server.host, placeholder 'ubuntu-arm') and Local port (number,
  placeholder '4000', validated 1-65535).
- Update buildInput to handle ssh kind; submit emits
  RemoteServerInput with kind/host/localPort.
- Update inputFromServer to pre-populate SSH fields when editing an
  existing ssh-kind server.
- Test indicator shows 'Connecting SSH...' while debounce is pending
  and shows localPort in the ok description (same as devtunnel).
- Add 9 new tests covering: radio visibility, field rendering,
  submit enable/disable validation, submit payload, test indicator
  text, and EditServerDialog pre-population for ssh-kind servers.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ion tests

GAP-01: Add exponential-backoff auto-reconnect to SshConnector
- New options: initialReconnectBackoffMs (default 2s), maxReconnectBackoffMs (default 30s)
- When SSH child exits unexpectedly (intentionalStop false), scheduleReconnect
  fires after backoff, doubles for next attempt (capped at maxReconnectBackoffMs)
- Backoff resets to initial on successful reconnect
- disconnect() and reconnect() clear any pending reconnect timer
- Added ManagedSshConnection.reconnectTimer and reconnectBackoffMs fields
- New unit test: 'auto-reconnects after unexpected exit' verifies second child
  is spawned and reaches online after unexpected exit event

GAP-02: SSH-specific integration tests in remote-server-routes.test.ts
- Added SshConnector import and optional sshConnector param to startApi()
- ssh-kind routes describe block with 4 tests:
  - POST /connect calls sshConnector.connect, returns online state
  - POST /disconnect calls sshConnector.disconnect, returns idle state
  - POST /reconnect (success) calls reconnect, returns online state
  - POST /reconnect (failure) connector throws, returns failed state
- New lifecycle test: autoconnects configured SSH entries and disposes SshConnector on close

All 29 ssh-connector + remote-server-routes tests pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@plusplusoneplusplus plusplusoneplusplus merged commit 12443b4 into main Jun 1, 2026
34 checks passed
@plusplusoneplusplus plusplusoneplusplus deleted the pr/6e4e30251-featssh-server-ac-01-add-sshremoteserver branch June 1, 2026 06:34
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.

1 participant