Skip to content

Commit 8b96959

Browse files
Improve CLI UX with auto-apply, global packages, and one-off mode (#18)
- Rename 'download' command to 'get' (with 'download' as hidden alias) - Auto-apply patches after download by default, with --no-apply to opt out - Add --global/-g flag to apply/rollback/remove patches on global npm packages - Add --global-prefix option for custom global node_modules path (supports yarn/pnpm, enables safe testing) - Add --one-off mode for ephemeral patching without saving to .socket folder - Add global-packages.ts utility for detecting npm/yarn/pnpm global paths 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude <[email protected]>
1 parent 4bbff48 commit 8b96959

File tree

8 files changed

+879
-35
lines changed

8 files changed

+879
-35
lines changed

src/cli.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import yargs from 'yargs'
44
import { hideBin } from 'yargs/helpers'
55
import { applyCommand } from './commands/apply.js'
6-
import { downloadCommand } from './commands/download.js'
6+
import { getCommand } from './commands/get.js'
77
import { listCommand } from './commands/list.js'
88
import { removeCommand } from './commands/remove.js'
99
import { rollbackCommand } from './commands/rollback.js'
@@ -14,12 +14,12 @@ async function main(): Promise<void> {
1414
await yargs(hideBin(process.argv))
1515
.scriptName('socket-patch')
1616
.usage('$0 <command> [options]')
17+
.command(getCommand)
1718
.command(applyCommand)
1819
.command(rollbackCommand)
19-
.command(setupCommand)
20-
.command(downloadCommand)
21-
.command(listCommand)
2220
.command(removeCommand)
21+
.command(listCommand)
22+
.command(setupCommand)
2323
.command(repairCommand)
2424
.demandCommand(1, 'You must specify a command')
2525
.help()

src/commands/apply.ts

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,16 @@ import {
2020
fetchMissingBlobs,
2121
formatFetchResult,
2222
} from '../utils/blob-fetcher.js'
23+
import { getGlobalPrefix } from '../utils/global-packages.js'
2324

2425
interface ApplyArgs {
2526
cwd: string
2627
'dry-run': boolean
2728
silent: boolean
2829
'manifest-path': string
2930
offline: boolean
31+
global: boolean
32+
'global-prefix'?: string
3033
}
3134

3235
async function applyPatches(
@@ -35,6 +38,8 @@ async function applyPatches(
3538
dryRun: boolean,
3639
silent: boolean,
3740
offline: boolean,
41+
useGlobal: boolean,
42+
globalPrefix?: string,
3843
): Promise<{ success: boolean; results: ApplyResult[] }> {
3944
// Read and parse manifest
4045
const manifestContent = await fs.readFile(manifestPath, 'utf-8')
@@ -89,12 +94,27 @@ async function applyPatches(
8994
}
9095
}
9196

92-
// Find all node_modules directories
93-
const nodeModulesPaths = await findNodeModules(cwd)
97+
// Find node_modules directories
98+
let nodeModulesPaths: string[]
99+
if (useGlobal || globalPrefix) {
100+
try {
101+
nodeModulesPaths = [getGlobalPrefix(globalPrefix)]
102+
if (!silent) {
103+
console.log(`Using global npm packages at: ${nodeModulesPaths[0]}`)
104+
}
105+
} catch (error) {
106+
if (!silent) {
107+
console.error('Failed to find global npm packages:', error instanceof Error ? error.message : String(error))
108+
}
109+
return { success: false, results: [] }
110+
}
111+
} else {
112+
nodeModulesPaths = await findNodeModules(cwd)
113+
}
94114

95115
if (nodeModulesPaths.length === 0) {
96116
if (!silent) {
97-
console.error('No node_modules directories found')
117+
console.error(useGlobal || globalPrefix ? 'No global npm packages found' : 'No node_modules directories found')
98118
}
99119
return { success: false, results: [] }
100120
}
@@ -187,6 +207,20 @@ export const applyCommand: CommandModule<{}, ApplyArgs> = {
187207
type: 'boolean',
188208
default: false,
189209
})
210+
.option('global', {
211+
alias: 'g',
212+
describe: 'Apply patches to globally installed npm packages',
213+
type: 'boolean',
214+
default: false,
215+
})
216+
.option('global-prefix', {
217+
describe: 'Custom path to global node_modules (overrides auto-detection, useful for yarn/pnpm)',
218+
type: 'string',
219+
})
220+
.example('$0 apply', 'Apply all patches to local packages')
221+
.example('$0 apply --global', 'Apply patches to global npm packages')
222+
.example('$0 apply --global-prefix /custom/path', 'Apply patches to custom global location')
223+
.example('$0 apply --dry-run', 'Preview patches without applying')
190224
},
191225
handler: async argv => {
192226
try {
@@ -210,6 +244,8 @@ export const applyCommand: CommandModule<{}, ApplyArgs> = {
210244
argv['dry-run'],
211245
argv.silent,
212246
argv.offline,
247+
argv.global,
248+
argv['global-prefix'],
213249
)
214250

215251
// Print results if not silent

0 commit comments

Comments
 (0)