ShellPort is browser-based remote shell access over SSH, Telnet, ET, and Mosh. The repository combines:
- A Go backend in
shellport.goandapplication/. - A Vue 3 frontend in
ui/. - A Vite build pipeline in
vite.config.js. - Docker packaging in
Dockerfileanddocker-compose.example.yaml. - GitHub Actions automation under
.github/.
The module path is github.com/Snuffy2/shellport. The project is licensed under
AGPL-3.0-only; preserve existing license headers when editing source files.
application/configuration/: config file and environment loading.application/controller/: HTTP routes, static page serving, socket handling.application/command/andapplication/commands/: command protocol and typed command values shared with connection flows.application/network/: TCP/SOCKS dialing and connection wrappers.application/server/: HTTP server setup.application/log/: project logging helpers.ui/: Vue components, browser command protocol, stream handling, styles, static files, and frontend tests.application/controller/static_page_generater/: generator used bygo generateduring frontend/static asset generation..tmp/: generated build output. Treat it as disposable unless a task is explicitly about generated output.
Install Node dependencies with:
npm ciUse the scripts in package.json as the source of truth:
npm run generate
npm run build
npm run lint
npm run lint:fix
npm run testonly
npm testImportant behavior:
npm run generatecleans.tmp/, builds frontend assets with Vite, and runs Go static page generation.npm run buildruns generation and then builds theshellportbinary.npm run testonlyruns Vitest frontend tests andgo test ./... -race.npm testruns generation first, thentestonly.npm run devstarts the Go backend withscripts/shellport.dev.conf.ymland runs a Vite dev server with HMR and backend proxying.
For Go-only checks, use:
go test ./...
go test ./... -race -timeout 30s
go vet ./...
go mod tidyFor hook parity with CI, use the repo-local prek.toml:
prek run --all-filesRun the narrowest validation that proves the change, then broaden based on risk:
- Go backend change: run targeted
go testfor the touched package, then considergo test ./... -race -timeout 30s. - Frontend logic change: run the relevant Vitest tests or
npm run testonly. - Build pipeline, generated assets, or static serving change: run
npm run generateand, when practical,npm run build. - Lint/style-only change: run
npm run lintorprek run --all-files. - GitHub Actions change: run
prek run --all-filessoactionlintruns through the configured hook.
CI runs npm ci, npm run generate, and prek on pushes to main, pull
requests, and manual dispatch.
- Keep imports at the top of files and preserve existing comments.
- New source files under
application/,scripts/, andui/should use the concise AGPL SPDX header style at the top of the file:Copyright (C) 2026 Snuffy2, thenSPDX-License-Identifier: AGPL-3.0-only, using the file's native comment syntax. Do not add the full AGPL boilerplate to new files. - Prefer small, root-cause fixes over broad rewrites.
- Match existing Go package structure and frontend component patterns.
- Add or update tests for changed behavior.
- Keep Go code formatted with
gofmt. - Keep frontend code compatible with Vue 3 and the current Vite setup.
- Use existing command, stream, and connector abstractions instead of duplicating protocol logic.
- Treat hook commands and connection inputs as untrusted; avoid command-line injection and keep error handling explicit.
- Do not commit generated
.tmp/output unless the user explicitly asks.
The UI uses Vue 3 single-file components and plain CSS under ui/. Tests live
beside frontend modules as *_test.js and run under Vitest.
- Keep terminal behavior, stream handling, and keyboard handling stable.
- Check mobile and desktop layout assumptions for visible UI changes.
- Prefer existing widgets under
ui/widgets/over new one-off controls. - Preserve accessible, inspectable text and avoid unnecessary visual churn.
The backend serves the web application and proxies SSH/Telnet sessions over the project command protocol.
- Keep configuration compatibility with both file and environment loaders.
- Preserve timeout semantics for dialing, hooks, HTTP reads, and writes.
- Keep hook execution bounded by configured deadlines and sanitize any new external-process inputs.
- Avoid logging secrets such as shared keys, SOCKS credentials, TLS key material, or preset credentials.
Dockerfile is the canonical reference for container builds. It builds the
application in Debian-based stages, then copies the final binary into an Alpine
runtime image.
Release Please is configured in .github/workflows/release-please.yml and requires
the RELEASE_PLEASE_TOKEN secret. It manages release PRs, version
bump updates, and GitHub releases. Docker publishing is configured in
.github/workflows/release.yml for GHCR image ghcr.io/snuffy2/shellport: main
pushes publish edge, published releases publish version tags, and only GitHub’s
current latest stable release updates latest.
Do not push branches, publish images, or open pull requests unless the user explicitly asks.
-
All PRs created must have Conventional Commit titles:
type: descriptionortype(scope): description, with!before:for breaking changes. Use one ofbuild,chore,ci,deps,docs,feat,fix,perf,refactor,revert,style, ortest, as enforced by the PR title lint workflow. -
Do not revert user changes unless explicitly instructed.
-
Before editing a file that already has uncommitted changes, inspect it and work with the current contents.
-
Keep changes scoped to the requested task.