-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathcli-dispatch.mts
More file actions
151 lines (132 loc) · 4.18 KB
/
cli-dispatch.mts
File metadata and controls
151 lines (132 loc) · 4.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/**
* Unified Socket CLI entry point.
*
* This single file handles all Socket CLI commands by detecting how it was invoked:
* - socket (main CLI)
* - socket-npm (calls socket npm command directly)
* - socket-npx (calls socket npx command directly)
* - socket-pnpm (calls socket pnpm command directly)
* - socket-yarn (calls socket yarn command directly)
*
* Perfect for SEA packaging and single-file distribution.
*
* Bootstrap Logic:
* When running as a SEA binary, we use IPC handshake to detect subprocess mode:
* - Initial entry (no IPC): Bootstrap to system Node.js or self with IPC
* - Subprocess entry (has IPC): Bypass bootstrap, act as regular Node.js
*/
import path from 'node:path'
import { getDefaultLogger } from '@socketsecurity/lib-internal/logger'
import { cmdNpm } from './commands/npm/cmd-npm.mts'
import { cmdNpx } from './commands/npx/cmd-npx.mts'
import { cmdPnpm } from './commands/pnpm/cmd-pnpm.mts'
import { cmdYarn } from './commands/yarn/cmd-yarn.mts'
import { waitForBootstrapHandshake } from './utils/sea/boot.mjs'
const logger = getDefaultLogger()
// Detect how this binary was invoked.
function getInvocationMode(): string {
// Check environment variable first (for explicit mode).
const envMode = process.env['SOCKET_CLI_MODE']
if (envMode) {
return envMode
}
// Check process.argv[1] for the actual script name.
const scriptPath = process.argv[1]
if (scriptPath) {
const scriptName = path
.basename(scriptPath)
.replace(/\.(js|mjs|cjs|exe)$/i, '')
// Map script names to modes.
if (scriptName.endsWith('-npm') || scriptName === 'npm') {
return 'npm'
}
if (scriptName.endsWith('-npx') || scriptName === 'npx') {
return 'npx'
}
if (scriptName.endsWith('-pnpm') || scriptName === 'pnpm') {
return 'pnpm'
}
if (scriptName.endsWith('-yarn') || scriptName === 'yarn') {
return 'yarn'
}
// For 'cli' or anything containing 'socket', default to socket mode.
if (scriptName.includes('socket') || scriptName === 'cli') {
return 'socket'
}
}
// Check process.argv0 as fallback.
const argv0 = path
.basename(process.argv0 || process.execPath)
.replace(/\.exe$/i, '')
if (argv0.endsWith('npm')) {
return 'npm'
}
if (argv0.endsWith('npx')) {
return 'npx'
}
if (argv0.endsWith('pnpm')) {
return 'pnpm'
}
if (argv0.endsWith('yarn')) {
return 'yarn'
}
// Default to main Socket CLI.
return 'socket'
}
// Route to the appropriate CLI based on invocation mode.
async function main() {
// If we're a subprocess with IPC, wait for handshake.
// This validates we're running in the correct context.
// Note: The handshake is used by shadow npm/pnpm/yarn operations to pass
// configuration (API token, bin name, etc.) to the subprocess.
try {
await waitForBootstrapHandshake(1000) // 1 second timeout.
// Handshake received - we're a validated subprocess.
} catch {
// No handshake received, or we're not a subprocess.
// This is normal for initial entry.
}
const mode = getInvocationMode()
// Set environment variable for child processes.
process.env['SOCKET_CLI_MODE'] = mode
// Import and run the appropriate CLI function.
switch (mode) {
case 'npm': {
// Call socket npm command directly.
await cmdNpm.run(process.argv.slice(2), import.meta, {
parentName: 'socket',
})
break
}
case 'npx': {
// Call socket npx command directly.
await cmdNpx.run(process.argv.slice(2), import.meta, {
parentName: 'socket',
})
break
}
case 'pnpm': {
// Call socket pnpm command directly.
await cmdPnpm.run(process.argv.slice(2), import.meta, {
parentName: 'socket',
})
break
}
case 'yarn': {
// Call socket yarn command directly.
await cmdYarn.run(process.argv.slice(2), import.meta, {
parentName: 'socket',
})
break
}
default:
await import('./cli-entry.mjs')
break
}
}
// Run the appropriate CLI.
main().catch(error => {
logger.error('Socket CLI Error:', error)
// eslint-disable-next-line n/no-process-exit -- Required for CLI error handling.
process.exit(1)
})