Skip to content

Commit ac55058

Browse files
authored
chore: remove dead ink and yoga-layout dependencies (#1170)
* chore: remove dead ink and yoga-layout dependencies ink was removed from source but its catalog entries and yoga-layout WASM download remained. Remove: - ink, ink-table, ink-text-input, @types/ink from catalog - yoga-layout from catalog - yoga WASM download step from build-js.mjs and build.mjs - yoga asset config and transformYogaSync from download-assets.mjs * fix(test): replace vi.mock('node:fs') with vi.spyOn for thread-safe tests vi.mock('node:fs') auto-mocking fails intermittently with vitest's threads pool + sharding. Switch source files to namespace fs imports and tests to vi.spyOn so mocks intercept at runtime without module replacement. Also remove dead processAsset function and unused computeFileHash import from download-assets.mjs. * fix(test): replace vi.mock('node:fs') in output-cmd-json test
1 parent 6ed52fa commit ac55058

File tree

23 files changed

+136
-374
lines changed

23 files changed

+136
-374
lines changed

CLAUDE.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,6 @@ Do not read source files and assert on their contents (`.toContain('pattern')`).
344344

345345
### External Dependencies
346346

347-
- Vendored modules in `src/external/` (e.g., ink-table)
348347
- Dependencies bundled into `dist/cli.js` via esbuild
349348
- Uses Socket registry overrides for security
350349
- Custom patches applied to dependencies in `patches/`

docs/build-guide.md

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,7 @@ socket-cli/
5151
│ ├── cli/ # Main CLI package
5252
│ │ ├── src/ # TypeScript source
5353
│ │ ├── build/ # Intermediate build files
54-
│ │ │ ├── cli.js # Bundled CLI (esbuild output)
55-
│ │ │ └── yoga-sync.mjs # Downloaded WASM module
54+
│ │ │ └── cli.js # Bundled CLI (esbuild output)
5655
│ │ └── dist/ # Distribution files
5756
│ │ ├── index.js # Entry point loader
5857
│ │ ├── cli.js # CLI bundle (copied from build/)
@@ -69,7 +68,6 @@ socket-cli/
6968
│ │ └── downloaded/ # Cached downloads
7069
│ │ ├── node-smol/ # Node.js binaries
7170
│ │ ├── binject/ # Binary injection tool
72-
│ │ ├── yoga-layout/ # Yoga WASM
7371
│ │ └── models/ # AI models
7472
│ └── package-builder/ # Package generation templates
7573
└── scripts/ # Monorepo build scripts
@@ -86,7 +84,6 @@ Phase 1: Clean (optional, with --force)
8684
Phase 2: Prepare (parallel)
8785
├── Generate CLI packages from templates
8886
└── Download assets from socket-btm releases
89-
├── yoga-layout (WASM for terminal rendering)
9087
├── node-smol (minimal Node.js binaries)
9188
├── binject (binary injection tool)
9289
└── models (AI models for analysis)
@@ -191,9 +188,8 @@ pnpm build:watch
191188

192189
**What it does**:
193190

194-
1. Downloads yoga WASM (first time only)
195-
2. Starts esbuild in watch mode
196-
3. Rebuilds `build/cli.js` on changes
191+
1. Starts esbuild in watch mode
192+
2. Rebuilds `build/cli.js` on changes
197193

198194
**Note**: Watch mode only rebuilds the CLI bundle, not SEA binaries.
199195

@@ -250,7 +246,6 @@ Assets are downloaded from [socket-btm](https://github.com/SocketDev/socket-btm)
250246
| ------------- | ----------------------- | ------------------------------------ |
251247
| `node-smol` | Minimal Node.js for SEA | `node-smol/<platform>-<arch>/node` |
252248
| `binject` | Binary injection tool | `binject/<platform>-<arch>/binject` |
253-
| `yoga-layout` | Terminal layout WASM | `yoga-layout/assets/yoga-sync-*.mjs` |
254249
| `models` | AI models for analysis | `models/` |
255250

256251
### Cache Management

packages/build-infra/README.md

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ Shared build infrastructure utilities for Socket CLI. Provides esbuild plugins,
4040
This package centralizes build-time utilities that are shared across multiple Socket CLI build configurations. It provides:
4141

4242
1. **esbuild plugins** for code transformations required by SEA (Single Executable Application) binaries
43-
2. **GitHub release utilities** for downloading node-smol, yoga-wasm, and other build dependencies
43+
2. **GitHub release utilities** for downloading node-smol and other build dependencies
4444
3. **Extraction caching** to avoid regenerating files when source hasn't changed
4545

4646
## Modules
@@ -97,7 +97,7 @@ const __importMetaUrl = require('node:url').pathToFileURL(__filename).href
9797

9898
### GitHub Releases
9999

100-
Downloads assets from SocketDev/socket-btm releases with retry logic and caching. Used for node-smol binaries, yoga-wasm, AI models, and build tools.
100+
Downloads assets from SocketDev/socket-btm releases with retry logic and caching. Used for node-smol binaries, AI models, and build tools.
101101

102102
#### `getLatestRelease(tool, options)`
103103

@@ -112,7 +112,7 @@ const tag = await getLatestRelease('node-smol')
112112

113113
**Parameters:**
114114

115-
- `tool` (string) - Tool name prefix (e.g., 'node-smol', 'yoga-layout', 'binject')
115+
- `tool` (string) - Tool name prefix (e.g., 'node-smol', 'binject')
116116
- `options.quiet` (boolean) - Suppress log messages
117117

118118
**Returns:** Latest tag string or `null` if not found
@@ -154,9 +154,9 @@ Downloads a release asset with automatic redirect following.
154154
import { downloadReleaseAsset } from 'build-infra/lib/github-releases'
155155

156156
await downloadReleaseAsset(
157-
'yoga-layout-20250120-def5678',
158-
'yoga-sync-20250120.mjs',
159-
'/path/to/output.mjs',
157+
'node-smol-20250120-abc1234',
158+
'node-smol-linux-x64',
159+
'/path/to/output',
160160
)
161161
```
162162

@@ -403,7 +403,6 @@ The `build/downloaded/` directory stores cached GitHub release assets:
403403
build/downloaded/
404404
├── binject-{tag}-{platform}-{arch}
405405
├── node-smol-{tag}-{platform}-{arch}
406-
├── yoga-layout-{tag}.mjs
407406
└── models-{tag}.tar.gz
408407
```
409408

packages/cli/.config/esbuild.cli.mjs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,6 @@ const config = {
145145
},
146146
},
147147

148-
{
149-
name: 'yoga-wasm-alias',
150-
setup(build) {
151-
// Redirect yoga-layout to our custom synchronous implementation.
152-
build.onResolve({ filter: /^yoga-layout$/ }, () => {
153-
return {
154-
path: path.join(rootPath, 'build/yoga-sync.mjs'),
155-
}
156-
})
157-
},
158-
},
159-
160148
{
161149
name: 'stub-problematic-packages',
162150
setup(build) {

packages/cli/scripts/build-js.mjs

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,7 @@ const logger = getDefaultLogger()
1212

1313
async function main() {
1414
try {
15-
// Step 1: Download yoga WASM.
16-
logger.step('Downloading yoga WASM')
17-
const extractResult = await spawn(
18-
'node',
19-
['--max-old-space-size=8192', 'scripts/download-assets.mjs', 'yoga'],
20-
{ stdio: 'inherit' },
21-
)
22-
23-
if (!extractResult) {
24-
logger.error('Failed to start asset download')
25-
process.exitCode = 1
26-
return
27-
}
28-
29-
if (extractResult.code !== 0) {
30-
process.exitCode = extractResult.code
31-
return
32-
}
33-
34-
// Step 2: Build with esbuild.
15+
// Step 1: Build with esbuild.
3516
logger.step('Building CLI bundle')
3617
const buildResult = await spawn(
3718
'node',

packages/cli/scripts/build.mjs

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -104,34 +104,7 @@ async function main() {
104104
logger.info('Starting watch mode...')
105105
}
106106

107-
// First download yoga WASM (only needed asset for CLI bundle).
108-
const extractResult = await spawn(
109-
'node',
110-
[...NODE_MEMORY_FLAGS, 'scripts/download-assets.mjs', 'yoga'],
111-
{
112-
shell: WIN32,
113-
stdio: 'inherit',
114-
},
115-
)
116-
117-
if (!extractResult) {
118-
const error = new Error('Failed to start asset download process')
119-
logger.error(error.message)
120-
process.exitCode = 1
121-
throw error
122-
}
123-
124-
if (extractResult.code !== 0) {
125-
const exitCode = extractResult.code ?? 1
126-
const error = new Error(
127-
`Asset download failed with exit code ${extractResult.code ?? 'unknown'}`,
128-
)
129-
logger.error(error.message)
130-
process.exitCode = exitCode
131-
throw error
132-
}
133-
134-
// Then start esbuild in watch mode.
107+
// Start esbuild in watch mode.
135108
const watchResult = await spawn(
136109
'node',
137110
[...NODE_MEMORY_FLAGS, '.config/esbuild.cli.mjs', '--watch'],

packages/cli/scripts/download-assets.mjs

Lines changed: 2 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,14 @@
55
* Usage:
66
* node scripts/download-assets.mjs [asset-names...] [options]
77
* node scripts/download-assets.mjs # Download all assets (parallel)
8-
* node scripts/download-assets.mjs yoga models # Download specific assets (parallel)
8+
* node scripts/download-assets.mjs models # Download specific assets (parallel)
99
* node scripts/download-assets.mjs --no-parallel # Download all assets (sequential)
1010
*
1111
* Assets:
1212
* binject - Binary injection tool
1313
* iocraft - iocraft native bindings (.node files)
1414
* models - AI models tar.gz (MiniLM, CodeT5)
1515
* node-smol - Minimal Node.js binaries
16-
* yoga - Yoga layout WASM (yoga-sync.mjs)
1716
*/
1817

1918
import { existsSync, promises as fs } from 'node:fs'
@@ -26,11 +25,6 @@ import { getDefaultLogger } from '@socketsecurity/lib/logger'
2625
import { downloadSocketBtmRelease } from '@socketsecurity/lib/releases/socket-btm'
2726
import { spawn } from '@socketsecurity/lib/spawn'
2827

29-
import {
30-
computeFileHash,
31-
generateHeader,
32-
} from './utils/socket-btm-releases.mjs'
33-
3428
const __dirname = path.dirname(fileURLToPath(import.meta.url))
3529
const rootPath = path.join(__dirname, '..')
3630
const logger = getDefaultLogger()
@@ -94,36 +88,13 @@ const ASSETS = {
9488
name: 'node-smol',
9589
type: 'binary',
9690
},
97-
yoga: {
98-
description: 'Yoga layout WASM',
99-
download: {
100-
asset: 'yoga-sync-*.mjs',
101-
cwd: rootPath,
102-
downloadDir: '../../packages/build-infra/build/downloaded',
103-
quiet: false,
104-
tool: 'yoga-layout',
105-
},
106-
name: 'yoga',
107-
process: {
108-
format: 'javascript',
109-
outputPath: path.join(rootPath, 'build/yoga-sync.mjs'),
110-
},
111-
type: 'processed',
112-
},
11391
}
11492

11593
/**
11694
* Download a single asset.
11795
*/
11896
async function downloadAsset(config) {
119-
const {
120-
description,
121-
download,
122-
extract,
123-
name,
124-
process: processConfig,
125-
type,
126-
} = config
97+
const { description, download, extract, name, type } = config
12798

12899
try {
129100
logger.group(`Extracting ${name} from socket-btm releases...`)
@@ -149,8 +120,6 @@ async function downloadAsset(config) {
149120
// Process based on asset type.
150121
if (type === 'archive' && extract) {
151122
await extractArchive(assetPath, extract, name)
152-
} else if (type === 'processed' && processConfig) {
153-
await processAsset(assetPath, processConfig, name)
154123
}
155124

156125
logger.groupEnd()
@@ -221,106 +190,6 @@ async function extractArchive(tarGzPath, extractConfig, assetName) {
221190
await fs.writeFile(versionPath, tag, 'utf-8')
222191
}
223192

224-
/**
225-
* Transform yoga-sync.mjs to remove top-level await for CJS compatibility.
226-
*
227-
* The newer yoga-sync builds incorrectly use top-level await which isn't
228-
* compatible with esbuild's CJS output format. Despite the name, yogaPromise
229-
* is synchronous (-sWASM_ASYNC_COMPILATION=0), so we can call it directly.
230-
*/
231-
function transformYogaSync(content) {
232-
// Pattern: const Yoga = wrapAssembly(await yogaPromise);
233-
// Transform to: const Yoga = wrapAssembly(yogaPromise);
234-
// (yogaPromise is synchronous despite its name)
235-
const hasTopLevelAwait = content.includes('wrapAssembly(await yogaPromise)')
236-
if (!hasTopLevelAwait) {
237-
return content
238-
}
239-
240-
// Replace the top-level await pattern with synchronous call.
241-
return content.replace(
242-
/const Yoga = wrapAssembly\(await yogaPromise\);/,
243-
'const Yoga = wrapAssembly(yogaPromise);',
244-
)
245-
}
246-
247-
/**
248-
* Process and transform asset (e.g., add header to JS file).
249-
*/
250-
async function processAsset(assetPath, processConfig, assetName) {
251-
const { outputPath } = processConfig
252-
253-
// Check if extraction needed by comparing version.
254-
const assetDir = path.dirname(assetPath)
255-
const sourceVersionPath = path.join(assetDir, '.version')
256-
const outputVersionPath = path.join(
257-
path.dirname(outputPath),
258-
`${path.basename(outputPath, path.extname(outputPath))}.version`,
259-
)
260-
261-
if (
262-
existsSync(outputVersionPath) &&
263-
existsSync(outputPath) &&
264-
existsSync(sourceVersionPath)
265-
) {
266-
const cachedVersion = (await fs.readFile(outputVersionPath, 'utf8')).trim()
267-
const sourceVersion = (await fs.readFile(sourceVersionPath, 'utf8')).trim()
268-
if (cachedVersion === sourceVersion) {
269-
logger.info(`${assetName} already up to date`)
270-
return
271-
}
272-
273-
logger.info(`${assetName} version changed, re-extracting...`)
274-
}
275-
276-
// Read the downloaded asset.
277-
let content = await fs.readFile(assetPath, 'utf-8')
278-
279-
// Transform yoga-sync to remove top-level await for CJS compatibility.
280-
if (assetName === 'yoga') {
281-
content = transformYogaSync(content)
282-
}
283-
284-
// Compute source hash for cache validation.
285-
const sourceHash = await computeFileHash(assetPath)
286-
287-
// Get tag from source version file.
288-
if (!existsSync(sourceVersionPath)) {
289-
throw new Error(
290-
`Source version file not found: ${sourceVersionPath}. ` +
291-
'Please download assets first using the build system.',
292-
)
293-
}
294-
295-
const tag = (await fs.readFile(sourceVersionPath, 'utf8')).trim()
296-
if (!tag || tag.length === 0) {
297-
throw new Error(
298-
`Invalid version file content at ${sourceVersionPath}. ` +
299-
'Please re-download assets.',
300-
)
301-
}
302-
303-
// Generate output file with header.
304-
const header = generateHeader({
305-
assetName: path.basename(assetPath),
306-
scriptName: 'scripts/download-assets.mjs',
307-
sourceHash,
308-
tag,
309-
})
310-
311-
const output = `${header}
312-
313-
${content}
314-
`
315-
316-
// Ensure build directory exists before writing.
317-
await fs.mkdir(path.dirname(outputPath), { recursive: true })
318-
await fs.writeFile(outputPath, output, 'utf-8')
319-
320-
// Write version file.
321-
await fs.writeFile(outputVersionPath, tag, 'utf-8')
322-
}
323-
324193
/**
325194
* Download multiple assets (parallel by default, sequential opt-in).
326195
*

packages/cli/src/commands/json/output-cmd-json.mts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { existsSync } from 'node:fs'
1+
import fs from 'node:fs'
22
import path from 'node:path'
33

44
import { safeReadFileSync, safeStatsSync } from '@socketsecurity/lib/fs'
@@ -16,7 +16,7 @@ export async function outputCmdJson(cwd: string) {
1616
const sockJsonPath = path.join(cwd, SOCKET_JSON)
1717
const tildeSockJsonPath = VITEST ? REDACTED : tildify(sockJsonPath)
1818

19-
if (!existsSync(sockJsonPath)) {
19+
if (!fs.existsSync(sockJsonPath)) {
2020
logger.fail(`Not found: ${tildeSockJsonPath}`)
2121
process.exitCode = 1
2222
return

0 commit comments

Comments
 (0)