Skip to content

Commit 15f24c7

Browse files
committed
Added support for CLI global flag configurations through coder.globalFlags
1 parent 83391f9 commit 15f24c7

File tree

6 files changed

+73
-19
lines changed

6 files changed

+73
-19
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## Unreleased
44

5+
### Added
6+
7+
- Add support for CLI global flag configurations.
8+
59
## [1.10.1](https://github.com/coder/vscode-coder/releases/tag/v1.10.1) 2025-08-13
610

711
### Fixed

package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,14 @@
119119
"markdownDescription": "Disable Coder CLI signature verification, which can be useful if you run an unsigned fork of the binary.",
120120
"type": "boolean",
121121
"default": false
122+
},
123+
"coder.globalFlags": {
124+
"markdownDescription": "Global flags to pass to every Coder CLI invocation. Enter each flag as a separate array item; values are passed verbatim and in order. Do **not** include the `coder` command itself. See the [CLI reference](https://coder.com/docs/reference/cli) for available global flags.\n\nNote that the `#coder.headerCommand#` setting **takes precedence** and will override any `--header-command` value specified here.",
125+
"type": "array",
126+
"items": {
127+
"type": "string"
128+
},
129+
"default": []
122130
}
123131
}
124132
},

src/api.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import * as ws from "ws";
1313
import { errToStr } from "./api-helper";
1414
import { CertificateError } from "./error";
1515
import { FeatureSet } from "./featureSet";
16-
import { getHeaderArgs } from "./headers";
16+
import { getGlobalFlags } from "./globalFlags";
1717
import { getProxyForUrl } from "./proxy";
1818
import { Storage } from "./storage";
1919
import { expandPath } from "./util";
@@ -186,9 +186,7 @@ export async function startWorkspaceIfStoppedOrFailed(
186186

187187
return new Promise((resolve, reject) => {
188188
const startArgs = [
189-
"--global-config",
190-
globalConfigDir,
191-
...getHeaderArgs(vscode.workspace.getConfiguration()),
189+
...getGlobalFlags(vscode.workspace.getConfiguration(), globalConfigDir),
192190
"start",
193191
"--yes",
194192
workspace.owner_name + "/" + workspace.name,

src/commands.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ import * as vscode from "vscode";
1010
import { makeCoderSdk, needToken } from "./api";
1111
import { extractAgents } from "./api-helper";
1212
import { CertificateError } from "./error";
13+
import { getGlobalFlags } from "./globalFlags";
1314
import { Storage } from "./storage";
14-
import { toRemoteAuthority, toSafeHost } from "./util";
15+
import { escapeCommandArg, toRemoteAuthority, toSafeHost } from "./util";
1516
import {
1617
AgentTreeItem,
1718
WorkspaceTreeItem,
@@ -494,12 +495,16 @@ export class Commands {
494495
this.restClient,
495496
toSafeHost(url),
496497
);
497-
const escape = (str: string): string =>
498-
`"${str.replace(/"/g, '\\"')}"`;
498+
499+
const configDir = path.dirname(
500+
this.storage.getSessionTokenPath(toSafeHost(url)),
501+
);
502+
const globalFlags = getGlobalFlags(
503+
vscode.workspace.getConfiguration(),
504+
configDir,
505+
);
499506
terminal.sendText(
500-
`${escape(binary)} ssh --global-config ${escape(
501-
path.dirname(this.storage.getSessionTokenPath(toSafeHost(url))),
502-
)} ${app.workspace_name}`,
507+
`${escapeCommandArg(binary)}${globalFlags.length === 0 ? "" : ` ${globalFlags.join(" ")}`} ssh ${app.workspace_name}`,
503508
);
504509
await new Promise((resolve) => setTimeout(resolve, 5000));
505510
terminal.sendText(app.command ?? "");

src/globalFlags.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { WorkspaceConfiguration } from "vscode";
2+
import { getHeaderArgs } from "./headers";
3+
import { escapeCommandArg } from "./util";
4+
5+
export function getGlobalFlags(
6+
configs: WorkspaceConfiguration,
7+
configDir?: string,
8+
): string[] {
9+
const globalFlags = configs.get<string[]>("coder.globalFlags") || [];
10+
const headerArgs = getHeaderArgs(configs);
11+
const globalConfigArgs = configDir
12+
? ["--global-config", escapeCommandArg(configDir)]
13+
: [];
14+
15+
// Precedence of "coder.headerCommand" is higher than "coder.globalConfig" with the "--header-command" flag
16+
let filteredGlobalFlags = globalFlags;
17+
if (headerArgs.length > 0) {
18+
filteredGlobalFlags = globalFlags.filter(
19+
(flag) => !flag.startsWith("--header-command"),
20+
);
21+
}
22+
23+
if (globalConfigArgs.length > 0) {
24+
filteredGlobalFlags = globalFlags.filter(
25+
(flag) => !flag.startsWith("--global-config"),
26+
);
27+
}
28+
return [...filteredGlobalFlags, ...headerArgs, ...globalConfigArgs];
29+
}

src/remote.ts

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import { extractAgents } from "./api-helper";
2626
import * as cli from "./cliManager";
2727
import { Commands } from "./commands";
2828
import { featureSetForVersion, FeatureSet } from "./featureSet";
29-
import { getHeaderArgs } from "./headers";
29+
import { getGlobalFlags } from "./globalFlags";
3030
import { Inbox } from "./inbox";
3131
import { SSHConfig, SSHValues, mergeSSHConfigValues } from "./sshConfig";
3232
import { computeSSHProperties, sshSupportsSetEnv } from "./sshSupport";
@@ -758,19 +758,15 @@ export class Remote {
758758
const sshConfig = new SSHConfig(sshConfigFile);
759759
await sshConfig.load();
760760

761-
const headerArgs = getHeaderArgs(vscode.workspace.getConfiguration());
762-
const headerArgList =
763-
headerArgs.length > 0 ? ` ${headerArgs.join(" ")}` : "";
764-
765761
const hostPrefix = label
766762
? `${AuthorityPrefix}.${label}--`
767763
: `${AuthorityPrefix}--`;
768764

765+
const globalConfigs = this.globalConfigs(featureSet, label);
766+
769767
const proxyCommand = featureSet.wildcardSSH
770-
? `${escapeCommandArg(binaryPath)}${headerArgList} --global-config ${escapeCommandArg(
771-
path.dirname(this.storage.getSessionTokenPath(label)),
772-
)} ssh --stdio --usage-app=vscode --disable-autostart --network-info-dir ${escapeCommandArg(this.storage.getNetworkInfoPath())}${await this.formatLogArg(logDir)} --ssh-host-prefix ${hostPrefix} %h`
773-
: `${escapeCommandArg(binaryPath)}${headerArgList} vscodessh --network-info-dir ${escapeCommandArg(
768+
? `${escapeCommandArg(binaryPath)}${globalConfigs} ssh --stdio --usage-app=vscode --disable-autostart --network-info-dir ${escapeCommandArg(this.storage.getNetworkInfoPath())}${await this.formatLogArg(logDir)} --ssh-host-prefix ${hostPrefix} %h`
769+
: `${escapeCommandArg(binaryPath)}${globalConfigs} vscodessh --network-info-dir ${escapeCommandArg(
774770
this.storage.getNetworkInfoPath(),
775771
)}${await this.formatLogArg(logDir)} --session-token-file ${escapeCommandArg(this.storage.getSessionTokenPath(label))} --url-file ${escapeCommandArg(
776772
this.storage.getUrlPath(label),
@@ -828,6 +824,20 @@ export class Remote {
828824
return sshConfig.getRaw();
829825
}
830826

827+
private globalConfigs(featureSet: FeatureSet, label: string): string {
828+
const vscodeConfig = vscode.workspace.getConfiguration();
829+
let args: string[];
830+
if (featureSet.wildcardSSH) {
831+
args = getGlobalFlags(
832+
vscodeConfig,
833+
path.dirname(this.storage.getSessionTokenPath(label)),
834+
);
835+
} else {
836+
args = getGlobalFlags(vscodeConfig);
837+
}
838+
return args.length === 0 ? "" : ` ${args.join(" ")}`;
839+
}
840+
831841
// showNetworkUpdates finds the SSH process ID that is being used by this
832842
// workspace and reads the file being created by the Coder CLI.
833843
private showNetworkUpdates(sshPid: number): vscode.Disposable {

0 commit comments

Comments
 (0)