feat: support configurable CLI global config#1011
Conversation
9a72ccf to
6d03c00
Compare
7e5d315 to
36cfde3
Compare
Split src/util.ts into focused modules: src/util/uri.ts (toSafeHost,
removeTrailingSlashes, resolveUiUrl, openInBrowser) and
src/util/authority.ts (Remote SSH authority helpers), replacing
src/uri/utils.ts. Migrate all importers and mirror the unit tests.
Make CliCredentialManager.readToken return the token together with its
source ("keyring" | "files") so LoginCoordinator labels the login
method from the actual source instead of re-deriving it from whether
keyring is enabled.
…malization - Add loginCoordinator test for the keyring_token method (source: "keyring") - Add comprehensive toRemoteAuthority tests over varied URI types - Test toSafeHost/normalizeUrl with Arabic alongside Japanese IDNs - Consolidate the trim + strip-trailing-slashes logic into a shared normalizeUrl in util/uri, reused by resolveUiUrl and cliCredentialManager
Replace the dedicated `coder.globalConfig` setting with a `--global-config` passthrough in `coder.globalFlags`, honored on 2.31.0+. The extension no longer reads/writes the CLI credential files itself: it writes via `coder login` (0.25.0+, `--use-token-as-session`), reads via `coder login token` (2.31.0+), and deletes via `coder logout` (keyring or file with `--global-config`). Direct file writes remain only as a pre-0.25 fallback. The binary cache no longer follows the config dir.
36cfde3 to
b69b20b
Compare
- Bump the minimum supported deployment version to 0.25.0 (where `coder login` lives), gating on `featureSet.cliLogin`, and move the compatibility check before credential configuration so older servers get a clear message. - Remove the pre-0.25 direct-file-write fallback; credential writes now always go through `coder login`. Drop the now-unused `vscodessh` feature flag and the dead `CredentialFileError` class plus its `filesystem`/`file` telemetry categories. - Collapse the `resolveCli` overloads into one throwing resolver; the best-effort read path catches instead. - Fix the stale `coder.globalConfig` CHANGELOG entry (the setting was dropped) and two pre-existing test typecheck breaks (`toSafeHost` import path and a `CliAuth.allowOverride` literal).
Routing file-mode credentials through `coder login`/`logout` means the credential binary resolver now runs in the login and logout flows, not just on connect. It previously fell back to `fetchBinary` on a cache miss, so a file-mode user's login (including auto-login on startup) or logout could trigger a surprise CLI download with a progress popup, where before it was silent file I/O. Make the resolver locate-only. The connect and CLI-command flows still fetch the binary first, so credential ops become best-effort against an already-present binary and never download on their own. If no binary exists yet, credential sharing is simply skipped until a real connection fetches one.
| // Locate-only: never download from credential ops; the connect and | ||
| // CLI-command flows fetch the binary first. | ||
| return this.cliManager.locateBinary(url); |
There was a problem hiding this comment.
locate-only means a keyring user with no binary yet won't get their terminal token picked up at first login until something fetches the binary (main would download for them). Keep it, or revert to download-on-demand?
I'm hesitant about downloading on login/logout because that doesn't seem very UX friendly
There was a problem hiding this comment.
Yeah I think this is good, if the binary is missing then there is no credential share/sync (yet) and that seems fair to me.
There was a problem hiding this comment.
Hrm I tested and I guess it could be a little weird for first time login because if you set a global config to share with a cli you already have downloaded and configured, it does not work because VS Code has not downloaded a binary yet.
There was a problem hiding this comment.
Which I think means the read feature will basically never be useful, because pretty much the one time you need to read the login is when you have never logged in before. 🤔 (I think??)
There was a problem hiding this comment.
Yeaaah it's less useful now but consistent (CLI always does the action). It could be useful still if they login every day for example so they will have the CLI but the token will be taken from the CLI login
There was a problem hiding this comment.
Why are we not able to allow the override with the keyring?
Currently we happen to know the CLI only stores a url and token there, but this could change in the future. No harm in letting it be set, I think.
And to take it a bit further, IMO a config dir is better than --url because the user can run the CLI directly as well (like for example say we decide to expose it on PATH in the terminal or something so users can run commands directly).
There was a problem hiding this comment.
Because we have a setting coder.useKeyring, if we allow --global-config to pass through then this will result in hiding the user setting above. I am confused by the --url point though, like if we do not pass --global-config then the CLI defaults to keyring which is why we need to pass --url
- rename FeatureSet.keyringTokenRead to tokenRead (token subcommand works for both stores) - rename resolveUiUrl to resolveCoderDashboardUrl - clarify openInBrowser docstring (connectionUrl is arbitrary) - split buildGlobalFlags on auth mode to drop the nested ternary

Summary
coder.globalConfigas a machine-scoped directory setting for the CLI--global-configpath, withCODER_CONFIG_DIRfallback and existing per-deployment storage as the default.PathResolver, CLI auth flags, credential file reads/writes/deletes, active remote reload prompts, and support bundle settings.Closes #185.
Testing
pnpm test:extension ./test/unit/cliConfig.test.ts ./test/unit/core/pathResolver.test.ts ./test/unit/core/cliCredentialManager.test.ts ./test/unit/login/loginCoordinator.test.ts ./test/unit/supportBundle/settings.test.tspnpm testpnpm typecheckpnpm lintpnpm format:checkpnpm buildgit diff --checkGenerated by Coder Agents.
Implementation plan
coder.globalConfigsetting for a directory path and keepcoder.globalFlagsfrom overriding managed--global-config/--use-keyringflags.PathResolver:coder.globalConfigfirst, thenCODER_CONFIG_DIR, then the existing<globalStorage>/<safeHostname>default.--urlfor active supported keyring auth, otherwise--global-config <resolvedDir>.