cli: add Go CLI (subtext binary + @fullstory/subtext-cli npm wrapper)#75
Merged
Conversation
Copies the Go subtext CLI from the fullstory/mn monorepo. Source: projects/fullstory/go/src/fs/services/lidar/main/subtext/ Branch: subtext/sightmap-upload-cmd at 68b9093217 Includes the --format flag, Go-native tunnel client, and sightmap upload command. BUILD.bazel files removed; main.go moved to cmd/subtext/main.go per Go conventions. No code edits in this commit.
Replace all monorepo-internal import paths: - fs/services/lidar/main/subtext/internal/* -> github.com/fullstory/subtext/cli/internal/* - fs/fstesting -> github.com/fullstory/subtext/cli/internal/fstesting
- go.mod: module github.com/fullstory/subtext/cli - internal/fstesting: local Ok/Equals/Assert helpers replacing fs/fstesting - go mod tidy resolves cobra, yaml.v2, gorilla/websocket, hashicorp/yamux go build ./... and go test ./... both pass (6 test packages).
.goreleaser.yml builds subtext for darwin/linux/windows x amd64/arm64. Triggered by cli-v* tags; posts GitHub release + homebrew tap update. npm publish gated behind PUBLISH_NPM repo variable.
cli/npm/ contains: - package.json: name @fullstory/subtext-cli, bin subtext - install.js: postinstall script downloads binary from GitHub releases (SUBTEXT_SKIP_DOWNLOAD=1 bypasses download before first tag exists) - bin/subtext.js: thin spawnSync wrapper around the vendored binary npm publish in the release workflow is gated behind PUBLISH_NPM repo variable.
Replace the internal Bazel-build README with an end-user-focused doc. Covers install (npx/npm/brew/go install/binary), quickstart, command table, calling conventions, auth, config, env vars, and sightmap upload.
- Rename all github.com/fullstory -> github.com/fullstorydev throughout (matches the actual remote: github.com/fullstorydev/subtext) - cli/internal/cli.Version var: injected via goreleaser ldflags so 'subtext version' prints the real release tag, not 'dev' - tunnel.go: add //go:build !windows; add tunnel_windows.go stub (syscall.Kill / Setsid are not available on Windows) - .goreleaser.yml: fix archive format fields (formats: [] array), update ldflags to inject Version - cli/.gitignore: exclude dist/ - cli/RELEASING.md: step-by-step release guide for the team goreleaser snapshot builds all 6 OS/arch archives cleanly. go test ./... passes on all 6 packages.
- tunnel/transport.go: discard io.Copy returns in bidirectional proxy goroutines - cli/tunnel.go: discard os.Unsetenv returns in daemon cleanup - test files: discard returns from Close, WriteString, json.Encode in test handlers golangci-lint: 0 issues. go test -race: all 6 packages pass.
- release-cli.yml: remove NPM_TOKEN echo interpolation; use setup-node registry-url so NODE_AUTH_TOKEN handles .npmrc automatically - release-cli.yml/RELEASING.md: switch tags from cli-v to cli/v so the Go module proxy can resolve go install ...@vX.Y.Z for nested module - release-cli.yml: add validation step that fails the job when the git tag version disagrees with cli/npm/package.json - install.js: update releaseTag to cli/v prefix to match new tag scheme - install.js: guard early-exit with X_OK access check so a non-executable binary triggers a fresh download instead of silently failing at runtime - install.js: wrap unlinkSync in error handler with try/catch so ENOENT on a never-created file doesn't swallow the original network error - call.go: pass cmd.Context() to GetTool/CallTool so Ctrl-C cancels in-flight MCP requests - sightmap.go: same context fix for Upload - mcpclient/client.go: drain response body before close on all error paths so connections return to the pool on auth failures - tunnel_windows.go: register connect/disconnect/status subcommands on Windows so help and shell completion show the full command surface - auth/resolve.go: implement SECRET_SUBTEXT_API_KEY and FULLSTORY_API_KEY lookups that were documented but never read; update tests
- auth.go: runWhoami already held cmd; switch tools/list call - call.go: thread ctx through runCallHelp so --help on a tool name is also cancellable - tunnel.go: runTunnelForeground now takes a parent context so the signal.NotifyContext chains off the cobra command context instead of context.Background() The daemon re-exec path (runTunnelDaemon) has no cobra cmd and correctly keeps context.Background() as the signal-context base.
5 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What's in this PR
This adds a standalone Go CLI to the subtext repo under
cli/. It replaces the previous internal-only Bazel build with a standard Go module, ships binaries via GoReleaser, and wraps them fornpxconsumption via@fullstory/subtext-cli.The source was ported from the
fullstory/mnmonorepo (subtext/sightmap-upload-cmd@68b9093), which itself incorporates two completed feature branches:cli-format-flag—--format json/textflag, Go-native reverse tunnel clientsubtext/sightmap-upload-cmd—subtext sightmap uploadcommand for uploading.sightmap/definitions to a live sessionNo code logic was changed during the port — only import paths and build infrastructure.
What the CLI does
subtextis a terminal interface to the Subtext MCP server. It lets you drive the same tools an AI agent uses — live browser sessions, comments, proof documents, sightmap uploads — directly from a shell or CI script.Structure
Distribution
npx @fullstory/subtext-clinpm install -g @fullstory/subtext-cligo install github.com/fullstorydev/subtext/cli/cmd/subtext@latestA new GitHub Actions workflow (
.github/workflows/release-cli.yml) fires oncli-v*tags, runs tests, and calls GoReleaser to publish the GitHub Release. The npm publish step is gated behind aPUBLISH_NPM=truerepo variable (pending@fullstorynpm scope provisioning).Before the first release
See
cli/RELEASING.mdfor the full runbook. The two things that need to exist before taggingcli-v0.1.0:NPM_TOKENsecret +PUBLISH_NPM=truerepo variable (once@fullstoryscope is provisioned)Test plan
go build ./...— cleango test ./...— all 6 packages passGOOS=windows go build ./...— cross-compiles cleanly (Unix-specific tunnel code excluded via build tag)goreleaser release --snapshot --clean --skip=publish— all 6 OS/arch archives produced,subtext versionprints the injected version string