Skip to content

Commit d542786

Browse files
committed
feat(self-update): improve package manager detection and error messages
Update self-update command to use socket-lib's package manager detection utilities and provide clear, context-aware update instructions. Changes: - Use detectPackageManager() from @socketsecurity/lib/env/package-manager - Show appropriate update command for npm, pnpm, yarn, or bun - Update canSelfUpdate() to use isInSocketDlx() from @socketsecurity/lib/dlx - Point to GitHub install script for manually installed binaries - Clear messaging for each installation method
1 parent 4ae3ab9 commit d542786

File tree

2 files changed

+56
-5
lines changed

2 files changed

+56
-5
lines changed

packages/cli/src/commands/self-update/handle-self-update.mts

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@ import path from 'node:path'
1111

1212
import colors from 'yoctocolors-cjs'
1313

14+
import { detectPackageManager } from '@socketsecurity/lib/env/package-manager'
1415
import { getIpcStubPath } from '@socketsecurity/lib/ipc'
1516
import { logger } from '@socketsecurity/lib/logger'
1617

1718
import { outputSelfUpdate } from './output-self-update.mts'
1819
import ENV from '../../constants/env.mts'
1920
import { commonFlags } from '../../flags.mts'
2021
import { meowOrExit } from '../../utils/cli/with-subcommands.mjs'
21-
import { isSeaBinary } from '../../utils/executable/detect.mjs'
22+
import { canSelfUpdate, isSeaBinary } from '../../utils/executable/detect.mjs'
2223
import {
2324
clearQuarantine,
2425
ensureExecutable,
@@ -236,10 +237,41 @@ export async function handleSelfUpdate(
236237
importMeta: ImportMeta,
237238
{ parentName }: { parentName: string; rawArgv?: readonly string[] },
238239
): Promise<void> {
239-
// This command is only available when running as SEA binary.
240-
if (!isSeaBinary()) {
240+
// This command is only available for standalone SEA binaries in ~/.socket/_dlx/.
241+
// Not available for npm/pnpm/yarn-installed packages.
242+
if (!canSelfUpdate()) {
243+
// Detect which package manager was used
244+
const packageManager = detectPackageManager()
245+
246+
let updateCommand: string
247+
let installedVia: string
248+
249+
if (packageManager === 'npm') {
250+
updateCommand = 'npm update -g socket'
251+
installedVia = 'npm'
252+
} else if (packageManager === 'pnpm') {
253+
updateCommand = 'pnpm update -g socket'
254+
installedVia = 'pnpm'
255+
} else if (packageManager === 'yarn') {
256+
updateCommand = 'yarn global upgrade socket'
257+
installedVia = 'yarn'
258+
} else if (packageManager === 'bun') {
259+
updateCommand = 'bun update -g socket'
260+
installedVia = 'bun'
261+
} else if (isSeaBinary()) {
262+
// SEA binary but not in DLX (e.g., manually installed to /usr/local/bin)
263+
updateCommand = 'curl -sSL https://raw.githubusercontent.com/SocketDev/socket-cli/main/install.sh | sh'
264+
installedVia = 'manual installation'
265+
} else {
266+
// Bootstrap wrapper - unknown package manager
267+
updateCommand = 'npm update -g socket'
268+
installedVia = 'a package manager'
269+
}
270+
241271
throw new Error(
242-
'self-update is only available when running as a SEA binary',
272+
'self-update is only available for Socket CLI binaries managed by Socket.\n\n' +
273+
`You installed Socket CLI via ${installedVia}. To update, run:\n` +
274+
` ${colors.cyan(updateCommand)}`,
243275
)
244276
}
245277

packages/cli/src/utils/executable/detect.mts

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
* Key Functions:
77
* - isSeaBinary: Detect if running as SEA with caching
88
* - getSeaBinaryPath: Get the current SEA binary path
9+
* - isInSocketDlx: Check if binary is in Socket's managed DLX directory
10+
* - canSelfUpdate: Check if self-update is allowed for current binary
911
*
1012
* Detection Method:
1113
* - Uses Node.js 24+ native sea.isSea() API
@@ -25,6 +27,8 @@
2527

2628
import { createRequire } from 'node:module'
2729

30+
import { isInSocketDlx } from '@socketsecurity/lib/dlx'
31+
2832
const require = createRequire(import.meta.url)
2933

3034
/**
@@ -57,4 +61,19 @@ function getSeaBinaryPath(): string | undefined {
5761
return isSeaBinary() ? process.argv[0] : undefined
5862
}
5963

60-
export { getSeaBinaryPath, isSeaBinary }
64+
/**
65+
* Detect if self-update is allowed for the current binary.
66+
* Self-update is ONLY allowed for SEA binaries running from Socket's
67+
* managed DLX directory (~/.socket/_dlx/).
68+
*
69+
* Not allowed for:
70+
* - npm/pnpm/yarn-installed packages (not in DLX directory)
71+
* - Standalone binaries in system paths like /usr/local/bin (not in DLX directory)
72+
* - Bootstrap wrappers (not SEA binaries)
73+
*/
74+
function canSelfUpdate(): boolean {
75+
const binaryPath = process.argv[0]
76+
return isSeaBinary() && !!binaryPath && isInSocketDlx(binaryPath)
77+
}
78+
79+
export { canSelfUpdate, getSeaBinaryPath, isSeaBinary }

0 commit comments

Comments
 (0)