Skip to content

Commit a831ce0

Browse files
authored
Update copilot cli command prompt scripts (#1387)
1 parent 1c67c04 commit a831ce0

File tree

1 file changed

+52
-15
lines changed

1 file changed

+52
-15
lines changed

src/extension/chatSessions/vscode-node/copilotCLITerminalIntegration.ts

Lines changed: 52 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export class CopilotCLITerminalIntegration extends Disposable implements ICopilo
4141
@IEnvService private readonly envService: IEnvService,
4242
) {
4343
super();
44-
this.updateGHTokenInTerminalEnvVars();
44+
void this.updateGHTokenInTerminalEnvVars().catch(console.error);
4545
this.initialization = this.initialize();
4646
}
4747

@@ -62,13 +62,13 @@ export class CopilotCLITerminalIntegration extends Disposable implements ICopilo
6262
await fs.mkdir(storageLocation, { recursive: true });
6363

6464
if (process.platform === 'win32') {
65-
this.shellScriptPath = path.join(storageLocation, `${COPILOT_CLI_COMMAND}.ps1`);
66-
this.powershellScriptPath = this.shellScriptPath;
67-
await fs.writeFile(this.shellScriptPath, powershellScript);
65+
this.powershellScriptPath = path.join(storageLocation, `${COPILOT_CLI_COMMAND}.ps1`);
66+
await fs.writeFile(this.powershellScriptPath, powershellScript);
6867
const copilotPowershellScript = `@echo off
69-
powershell -ExecutionPolicy Bypass -File "${this.shellScriptPath}" %*
68+
powershell -ExecutionPolicy Bypass -File "${this.powershellScriptPath}" %*
7069
`;
71-
await fs.writeFile(path.join(storageLocation, `${COPILOT_CLI_COMMAND}.bat`), copilotPowershellScript);
70+
this.shellScriptPath = path.join(storageLocation, `${COPILOT_CLI_COMMAND}.bat`);
71+
await fs.writeFile(this.shellScriptPath, copilotPowershellScript);
7272
} else {
7373
const copilotShellScript = `#!/bin/sh
7474
unset NODE_OPTIONS
@@ -96,7 +96,7 @@ ELECTRON_RUN_AS_NODE=1 "${process.execPath}" "${path.join(storageLocation, COPIL
9696
await this.updateGHTokenInTerminalEnvVars();
9797
await this.initialization;
9898

99-
const shellPathAndArgs = this.getShellInfo(cliArgs);
99+
const shellPathAndArgs = await this.getShellInfo(cliArgs);
100100
if (shellPathAndArgs) {
101101
const options = getCommonTerminalOptions(name);
102102
options.shellPath = shellPathAndArgs.shellPath;
@@ -144,7 +144,7 @@ ELECTRON_RUN_AS_NODE=1 "${process.execPath}" "${path.join(storageLocation, COPIL
144144
}
145145
}
146146

147-
private getShellInfo(cliArgs: string[]): { shellPath: string; shellArgs: string[]; iconPath?: ThemeIcon } | undefined {
147+
private async getShellInfo(cliArgs: string[]): Promise<{ shellPath: string; shellArgs: string[]; iconPath?: ThemeIcon } | undefined> {
148148
const configPlatform = process.platform === 'win32' ? 'windows' : process.platform === 'darwin' ? 'osx' : 'linux';
149149
const defaultProfile = this.getDefaultShellProfile();
150150
if (!defaultProfile) {
@@ -164,7 +164,8 @@ ELECTRON_RUN_AS_NODE=1 "${process.execPath}" "${path.join(storageLocation, COPIL
164164
//
165165
}
166166
const shellArgs = Array.isArray(profile.args) ? profile.args : [];
167-
const shellPath = ((Array.isArray(profile.path) && profile.path.length) ? profile.path[0] : !Array.isArray(profile.path) ? profile.path : undefined) || this.envService.shell;
167+
const paths = profile.path ? (Array.isArray(profile.path) ? profile.path : [profile.path]) : [];
168+
const shellPath = (await getFirstAvailablePath(paths)) || this.envService.shell;
168169
if (defaultProfile === 'zsh' && this.shellScriptPath) {
169170
return {
170171
shellPath: shellPath || 'zsh',
@@ -190,14 +191,14 @@ ELECTRON_RUN_AS_NODE=1 "${process.execPath}" "${path.join(storageLocation, COPIL
190191
iconPath
191192
};
192193
} else if (defaultProfile === 'Command Prompt' && this.shellScriptPath && configPlatform === 'windows') {
193-
// return {
194-
// shellPath: this.shellScriptPath,
195-
// shellArgs: cliArgs,
196-
// iconPath
197-
// };
198-
return;
194+
return {
195+
shellPath: shellPath || 'cmd.exe',
196+
shellArgs: ['/c', this.shellScriptPath, ...cliArgs],
197+
iconPath
198+
};
199199
}
200200
}
201+
201202
private getDefaultShellProfile(): string | undefined {
202203
const configPlatform = process.platform === 'win32' ? 'windows' : process.platform === 'darwin' ? 'osx' : 'linux';
203204
const defaultProfile = workspace.getConfiguration('terminal').get<string | undefined>(`integrated.defaultProfile.${configPlatform}`);
@@ -238,3 +239,39 @@ function getCommonTerminalOptions(name: string): TerminalOptions {
238239
};
239240
}
240241

242+
const pathValidations = new Map<string, boolean>();
243+
async function getFirstAvailablePath(paths: string[]): Promise<string | undefined> {
244+
for (const p of paths) {
245+
// Sometimes we can have paths like `${env:HOME}\Systemycmd.exe` which need to be resolved
246+
const resolvedPath = resolveEnvVariables(p);
247+
if (pathValidations.get(resolvedPath) === true) {
248+
return resolvedPath;
249+
}
250+
if (pathValidations.get(resolvedPath) === false) {
251+
continue;
252+
}
253+
// Possible its just a command name without path
254+
if (path.basename(p) === p) {
255+
return p;
256+
}
257+
try {
258+
const stat = await fs.stat(resolvedPath);
259+
if (stat.isFile()) {
260+
pathValidations.set(resolvedPath, true);
261+
return resolvedPath;
262+
}
263+
pathValidations.set(resolvedPath, false);
264+
} catch {
265+
// Ignore errors and continue checking other paths
266+
pathValidations.set(resolvedPath, false);
267+
}
268+
}
269+
return undefined;
270+
}
271+
272+
function resolveEnvVariables(value: string): string {
273+
return value.replace(/\$\{env:([^}]+)\}/g, (match, envVarName) => {
274+
const envValue = process.env[envVarName];
275+
return envValue !== undefined ? envValue : match;
276+
});
277+
}

0 commit comments

Comments
 (0)