Repository navigation
fix(cli): accept --server and --standalone as global flags - #428
Conversation
Papercut pc_16ace9037047 Register --standalone and --server as global settings so they parse before or after a subcommand, including plugin list.
|
Global
Help makes this worse: both flags are documented on every command, including these, as “Connect to a server URL instead of the background service” / “Run with a private server…”. Ignoring them on commands that do not touch a server (
|
…dalone-global-flag-1969
|
Follow-up to #428 (comment), addressed in the pushed head e6fc678:
Validation: 54 focused CLI tests passed before the pipeline extension; the final server-flags suite has 25 passing tests. The no-mistakes fix review reported no remaining findings, and its runtime scenarios passed against an isolated server. The service-config regression fails against the pre-fix runtime. Fresh CI is running on this pushed head. The captain's installed binary, real config, and live service were not used for these probes. |
Intent
The captain approved resuming the issue backlog (2026-10-04): "triage the ~22 Cursor draft PRs first, then small batches", and later answered yes that shuvbro's triage review counts as the first review for these Cursor PRs. The read-only triage report is at ~/repos/shuvbro/data/triage-cursor-shuvcode/report.md; read the section for each PR you handle. Verdicts: #424 (fix(cli): continue explicit --server after legacy health 404, issue #399) is land: only a modern-server UnexpectedStatus 404 on /api/info falls back to probing /api/health then /api/status and continues with a warning; 401/503 still fail; 10 local tests pass. #428 (fix(cli): accept --standalone before subcommands, issue #416) is fix-then-land with an open review finding (#428 (comment)): globally accepted --server/--standalone are silently ignored by handlers that bypass ServerConnection.resolve - service stop/restart/start/set/unset, pair, acp, serve - so e.g. shuvcode --server http://other:4096 service stop stops the LOCAL service. Required: keep true global parsing for supported client commands but reject explicitly requested unsupported connection flags BEFORE any side effect on those paths (or implement real endpoint support where valid), update help with the support boundary, and add regressions for rejection, no local effects, and real endpoint/private selection across flag placements. Both PRs change packages/cli/src/services/server-connection.ts. The triage's land verdict preserves explicit endpoint selection without managed-service replacement, warns on modern version skew, legacy version skew, versionless health, or all-404, and falls back only on modern UnexpectedStatus 404. For the global flag repair, every local lifecycle/config/pair/serve/ACP case listed must reject unsupported explicitly requested connection flags before effects; ignoring flags on unrelated non-server commands is allowed. Existing tests only prove placements reach mutual exclusion; actual requested remote endpoint and standalone selection must be exercised.
What Changed
--serverand--standaloneare now global CLI flags (packages/cli/src/services/server-flags.ts, registered inframework/runtime.ts), so they work before or after the subcommand. The per-commandServerParamswere removed.ServerConnection.resolvenow reads the global settings when the caller passes no override, and auth, api, models, reload, run, mini, stats, session, and default handlers stop passing the flags through by hand.connectionFlags: "unsupported":service(and its subcommands),pair,acp,serve,mcp add, andplugin add/update/remove. If either flag is passed to one of them, the runtime rejects the command before its handler loads, so nothing happens locally. For example,--server <url> service stopnow errors out instead of stopping the local service.services/wwwCLI docs now state which commands don't support these flags. Newtest/server-flags.test.tscovers: rejection with no local side effects;--serverand--standalonestill being mutually exclusive in every flag placement;plugin listreaching the requested endpoint; and--standalonestarting a private server instead of using the registered service, across flag placements.Risk Assessment
✅ Low: The fix round marks only mcp add and plugin add/update/remove as unsupported. Its runtime change builds the full nested command path for the rejection message and still rejects before the handler loads. The help text now names the new boundary, and the new regression checks the error message and that the project and global config files are unchanged for every flag placement. I found no reachable incorrect behavior.
Testing
I ran the focused server-flags regression suite (25/25 pass), then drove the real CLI end-to-end. A realshuvcode serveran in one isolated sandbox and the client ran from another. In all three placements,--serverreached the requested remote (api GET /api/inforeturned the remote serve's pid 3832825).--standalonein all three placements started a separate private server (a different pid), and a dead--serverURL failed rather than falling back. Combining the two flags was rejected. Every unsupported service/pair/acp/serve/mcp add/plugin add|update|remove invocation exited 1 with "<cmd> does not support --server or --standalone", left the config untouched and left the remote server alive. Help shows the support boundary on both the root command and subcommands. Everything passed, and the sandboxes and serve processes were cleaned up. There is no visual UI surface, so the evidence is CLI transcripts.api GET /api/info --serverreturn the remote serve pid 3832825; session list and plugin list exit 0--server http://127.0.0.1:1 session list→ 'Could not reach server', exit 1service stop --helplist both flags as 'unsupported by service, pair, acp, serve, mcp add, and plugin add/update/remove'shuvcode plugin list→ 'No plugins found', exit 0Evidence: Live CLI transcript (stack frames trimmed)
Evidence: Full live CLI transcript
Evidence: Help GLOBAL FLAGS output
Evidence: Live drive script
Evidence: Endpoint selection proof
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
⏭️ **Rebase** - skipped
Step was skipped.
🔧 **Review** - 1 issue found → auto-fixed ✅
packages/cli/src/services/server-flags.ts:14- Before this change,shuvcode --server http://remote mcp add …andshuvcode --server … plugin add|remove|update …failed with "Unrecognized flag", because--serverwas only a root or per-command param. With global parsing those commands now accept the flag and ignore it: they write the LOCAL project or global opencode config (mcp/add.ts resolveConfigPath and write, plugin add/remove through Config.Service) and exit 0. Meanwhile siblingmcp auth/mcp list/plugin listdo go to the requested remote. A user targeting a remote server gets a silent local config mutation instead of an error. The intent allows ignoring flags only on "unrelated non-server commands", and these are config writers that live in the same groups as remote-honoring commands, so whether they should also be markedconnectionFlags: "unsupported"is a product decision. Recommended remedy: mark mcp add and plugin add/remove/update unsupported (and list them in the help boundary), or confirm that ignoring the flag there is intended.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Test** - passed
✅ No issues found.
api GET /api/info --serverreturn the remote serve pid 3832825; session list and plugin list exit 0--server http://127.0.0.1:1 session list→ 'Could not reach server', exit 1service stop --helplist both flags as 'unsupported by service, pair, acp, serve, mcp add, and plugin add/update/remove'shuvcode plugin list→ 'No plugins found', exit 0cd packages/cli && bun test test/server-flags.test.ts(25 pass: rejection with no local service/config/registration effects across 3 placements for service/pair/acp/serve/mcp add/plugin add|update|remove; requested-endpoint and standalone selection across placements; mutual exclusion; help boundary)Live: started a realshuvcode serve --hostname 127.0.0.1 --port 47830in an isolated XDG sandbox (OPENCODE_PASSWORD set), then ran the real CLI from a separate sandbox with--server <url>before the command, between the command and subcommand, and after the subcommand, forapi GET /api/info,session listandplugin listLive:shuvcode --server http://127.0.0.1:1 session list(dead endpoint is honored, no fallback)Live:--standaloneplaced before, between and after the command forapi GET /api/info,session listandplugin listLive:shuvcode --standalone session list --server <url>(mutual exclusion)Live:--server <url>(leading) and--standalone(trailing) for service stop/status/set port/unset disabled, pair, acp, serve, mcp add --global, plugin add/remove/update; checked that global opencode.json was unchanged, that no service config was written, and that the remote serve was still aliveLive:shuvcode --helpandshuvcode service stop --helpGLOBAL FLAGS section✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.