Skip to content

Commit d33af87

Browse files
zkochanclaude
andcommitted
feat: add proxyVarSubDir option to path extenders
Allow specifying a subdirectory of the proxy variable to add to PATH, e.g. PNPM_HOME/bin instead of PNPM_HOME. Supports posix (bash, fish, nushell) and windows shells. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5a7eefc commit d33af87

4 files changed

Lines changed: 47 additions & 6 deletions

File tree

os/env/path-extender-posix/path-extender-posix.spec.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,36 @@ case ":$PATH:" in
8383
*) export PATH="${pnpmHomeDir}:$PATH" ;;
8484
esac
8585
# pnpm end
86+
`)
87+
})
88+
it('should append to shell script with proxyVarSubDir', async () => {
89+
fs.writeFileSync(configFile, '', 'utf8')
90+
const report = await addDirToPosixEnvPath(pnpmHomeDir, {
91+
proxyVarName: 'PNPM_HOME',
92+
proxyVarSubDir: 'bin',
93+
configSectionName: 'pnpm',
94+
})
95+
expect(report).toStrictEqual({
96+
configFile: {
97+
path: configFile,
98+
changeType: 'appended',
99+
},
100+
oldSettings: '',
101+
newSettings: `export PNPM_HOME="${pnpmHomeDir}"
102+
case ":$PATH:" in
103+
*":$PNPM_HOME/bin:"*) ;;
104+
*) export PATH="$PNPM_HOME/bin:$PATH" ;;
105+
esac`,
106+
})
107+
const configContent = fs.readFileSync(configFile, 'utf8')
108+
expect(configContent).toEqual(`
109+
# pnpm
110+
export PNPM_HOME="${pnpmHomeDir}"
111+
case ":$PATH:" in
112+
*":$PNPM_HOME/bin:"*) ;;
113+
*) export PATH="$PNPM_HOME/bin:$PATH" ;;
114+
esac
115+
# pnpm end
86116
`)
87117
})
88118
it('should put the new directory to the end of the PATH', async () => {

os/env/path-extender-posix/path-extender-posix.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export type AddingPosition = 'start' | 'end'
1717

1818
export interface AddDirToPosixEnvPathOpts {
1919
proxyVarName?: string
20+
proxyVarSubDir?: string
2021
overwrite?: boolean
2122
position?: AddingPosition
2223
configSectionName: string
@@ -93,10 +94,11 @@ async function setupShell (
9394
let newSettings!: string
9495
const _createPathValue = createPathValue.bind(null, opts.position ?? 'start')
9596
if (opts.proxyVarName) {
97+
const pathRef = opts.proxyVarSubDir ? `$${opts.proxyVarName}/${opts.proxyVarSubDir}` : `$${opts.proxyVarName}`
9698
newSettings = `export ${opts.proxyVarName}="${dir}"
9799
case ":$PATH:" in
98-
*":$${opts.proxyVarName}:"*) ;;
99-
*) export PATH="${_createPathValue(`$${opts.proxyVarName}`)}" ;;
100+
*":${pathRef}:"*) ;;
101+
*) export PATH="${_createPathValue(pathRef)}" ;;
100102
esac`
101103
} else {
102104
newSettings = `case ":$PATH:" in
@@ -141,9 +143,10 @@ async function setupFishShell (dir: string, opts: AddDirToPosixEnvPathOpts): Pro
141143
let newSettings!: string
142144
const _createPathValue = createFishPathValue.bind(null, opts.position ?? 'start')
143145
if (opts.proxyVarName) {
146+
const pathRef = opts.proxyVarSubDir ? `$${opts.proxyVarName}/${opts.proxyVarSubDir}` : `$${opts.proxyVarName}`
144147
newSettings = `set -gx ${opts.proxyVarName} "${dir}"
145-
if not string match -q -- $${opts.proxyVarName} $PATH
146-
set -gx PATH ${_createPathValue(`$${opts.proxyVarName}`)}
148+
if not string match -q -- ${pathRef} $PATH
149+
set -gx PATH ${_createPathValue(pathRef)}
147150
end`
148151
} else {
149152
newSettings = `if not string match -q -- "${dir}" $PATH
@@ -167,8 +170,11 @@ async function setupNuShell (dir: string, opts: AddDirToPosixEnvPathOpts): Promi
167170
let newSettings!: string
168171
const addingCommand = (opts.position ?? "start") === "start" ? "prepend" : "append"
169172
if (opts.proxyVarName) {
173+
const pathRef = opts.proxyVarSubDir
174+
? `($env.${opts.proxyVarName} | path join "${opts.proxyVarSubDir}")`
175+
: `$env.${opts.proxyVarName}`
170176
newSettings = `$env.${opts.proxyVarName} = "${dir}"
171-
$env.PATH = ($env.PATH | split row (char esep) | ${addingCommand} $env.${opts.proxyVarName} )`
177+
$env.PATH = ($env.PATH | split row (char esep) | ${addingCommand} ${pathRef} )`
172178
} else {
173179
newSettings = `$env.PATH = ($env.PATH | split row (char esep) | ${addingCommand} ${dir} )`
174180
}

os/env/path-extender-windows/path-extender-windows.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ export type AddingPosition = 'start' | 'end'
2323

2424
export interface AddDirToWindowsEnvPathOpts {
2525
proxyVarName?: string
26+
proxyVarSubDir?: string
2627
overwriteProxyVar?: boolean
2728
position?: AddingPosition
2829
}
@@ -69,7 +70,10 @@ async function _addDirToWindowsEnvPath (dir: string, opts: AddDirToWindowsEnvPat
6970
expandableString: false,
7071
overwrite: opts.overwriteProxyVar ?? false
7172
}))
72-
changes.push(await addToPath(registryOutput, `%${opts.proxyVarName}%`, opts.position))
73+
const pathEntry = opts.proxyVarSubDir
74+
? `%${opts.proxyVarName}%${path.sep}${opts.proxyVarSubDir}`
75+
: `%${opts.proxyVarName}%`
76+
changes.push(await addToPath(registryOutput, pathEntry, opts.position))
7377
} else {
7478
changes.push(await addToPath(registryOutput, addedDir, opts.position))
7579
}

os/env/path-extender/path-extender.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export async function addDirToEnvPath(dir: string, opts: AddDirToEnvPathOpts): P
1818
return renderWindowsReport(await addDirToWindowsEnvPath(dir, {
1919
position: opts.position,
2020
proxyVarName: opts.proxyVarName,
21+
proxyVarSubDir: opts.proxyVarSubDir,
2122
overwriteProxyVar: opts.overwrite,
2223
})
2324
)

0 commit comments

Comments
 (0)