@socketsecurity/lib 3.2.0 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,75 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [3.2.2](https://github.com/SocketDev/socket-lib/releases/tag/v3.2.2) - 2025-11-03
11
+
12
+ ### Added
13
+
14
+ - **DLX**: Binary permission management with chmod 0o755 for all package binaries
15
+ - New `makePackageBinsExecutable()` function ensures all binaries in installed packages are executable
16
+ - Aligns with npm's cmd-shim approach for binary permissions
17
+ - Handles both single and multiple binary packages
18
+ - No-op on Windows (permissions not needed)
19
+
20
+ - **DLX**: npm-compatible bin resolution via vendored `getBinFromManifest`
21
+ - Cherry-picked `getBinFromManifest` from libnpmexec@10.1.8 (~1.5 KB)
22
+ - Avoids 1.1 MB bundle by vendoring single function instead of full package
23
+ - Provides battle-tested npm bin resolution strategy
24
+ - Maintains user-friendly fallbacks for edge cases
25
+
26
+ ### Changed
27
+
28
+ - **DLX**: Enhanced `findBinaryPath()` with npm's resolution strategy
29
+ - Primary: npm's `getBinFromManifest` (handles standard cases and aliases)
30
+ - Fallback: user-provided `binaryName` parameter
31
+ - Fallback: last segment of package name
32
+ - Last resort: first binary in list
33
+
34
+ ### Performance
35
+
36
+ - **Optimized package size**: Reduced bundle size through strategic export minimization and vendoring
37
+ - Vendored `getBinFromManifest` function instead of bundling full libnpmexec (~1.1 MB savings)
38
+ - Minimized external module exports for better tree-shaking:
39
+ - `fast-sort`: Now exports only `{ createNewSortInstance }` (2.1 KB, 96% reduction from ~56 KB)
40
+ - `fast-glob`: Now exports only `{ globStream }` (82 KB bundle)
41
+ - `del`: Now exports only `{ deleteAsync, deleteSync }` (100 KB bundle)
42
+ - `streaming-iterables`: Now exports only `{ parallelMap, transform }` (11 KB, 93% reduction from ~168 KB)
43
+ - Total savings: ~1.3 MB (1.1 MB from vendoring + 211 KB from minimized exports)
44
+ - Establishes pattern for future external module additions
45
+
46
+ ## [3.2.1](https://github.com/SocketDev/socket-lib/releases/tag/v3.2.1) - 2025-11-02
47
+
48
+ ### Changed
49
+
50
+ - **Logger/Spinner**: Use module-level constants to prevent duplicate and rogue spinner indicators
51
+ - Call `getDefaultLogger()` and `getDefaultSpinner()` once at module scope instead of repeated calls
52
+ - Prevents multiple spinner instances that can cause duplicate or lingering indicators in terminal output
53
+ - Applied in `src/dlx-manifest.ts`, `src/stdio/mask.ts`, and `src/spinner.ts`
54
+ - Follows DRY principle and aligns with socket-registry/socket-sdk-js patterns
55
+
56
+ ### Fixed
57
+
58
+ - **Scripts**: Fixed undefined logger variable in update script
59
+ - Replaced undefined `log` references with `_logger` throughout `scripts/update.mjs`
60
+ - Resolves ESLint errors that blocked test execution
61
+ - **Tests**: Improved stdout test stability by checking call delta instead of absolute counts
62
+ - Fixed flaky CI failures where spy call count was 101 instead of expected 100
63
+ - More robust approach handles potential state leakage between tests
64
+ - **Tests**: Removed unnecessary 10ms delay in cache-with-ttl test
65
+ - Cache with memoization enabled updates in-memory storage synchronously
66
+ - Delay was insufficient in CI and unnecessary given synchronous behavior
67
+ - Resolves flaky CI failures where cached values returned undefined
68
+
69
+ ## [3.2.0](https://github.com/SocketDev/socket-lib/releases/tag/v3.2.0) - 2025-11-02
70
+
71
+ ### Added
72
+
73
+ - **DLX**: Unified manifest for packages and binaries
74
+ - Centralized manifest system for tracking DLX-compatible packages
75
+ - Simplifies package and binary lookups for dependency-free execution
76
+
8
77
  ## [3.1.3](https://github.com/SocketDev/socket-lib/releases/tag/v3.1.3) - 2025-11-02
9
78
 
10
79
  ### Changed
@@ -40,6 +40,7 @@ var import_fs2 = require("./fs");
40
40
  var import_logger = require("./logger");
41
41
  var import_paths = require("./paths");
42
42
  var import_process_lock = require("./process-lock");
43
+ const logger = (0, import_logger.getDefaultLogger)();
43
44
  const MANIFEST_FILE_NAME = ".dlx-manifest.json";
44
45
  function isPackageEntry(entry) {
45
46
  return entry.type === "package";
@@ -69,7 +70,7 @@ class DlxManifest {
69
70
  }
70
71
  return JSON.parse(content);
71
72
  } catch (error) {
72
- (0, import_logger.getDefaultLogger)().warn(
73
+ logger.warn(
73
74
  `Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`
74
75
  );
75
76
  return /* @__PURE__ */ Object.create(null);
@@ -136,7 +137,7 @@ class DlxManifest {
136
137
  try {
137
138
  (0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
138
139
  } catch (error) {
139
- (0, import_logger.getDefaultLogger)().warn(
140
+ logger.warn(
140
141
  `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
141
142
  );
142
143
  }
@@ -176,7 +177,7 @@ class DlxManifest {
176
177
  }
177
178
  }
178
179
  } catch (error) {
179
- (0, import_logger.getDefaultLogger)().warn(
180
+ logger.warn(
180
181
  `Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`
181
182
  );
182
183
  }
@@ -185,7 +186,7 @@ class DlxManifest {
185
186
  try {
186
187
  (0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
187
188
  } catch (error) {
188
- (0, import_logger.getDefaultLogger)().warn(
189
+ logger.warn(
189
190
  `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
190
191
  );
191
192
  }
@@ -229,7 +230,7 @@ class DlxManifest {
229
230
  const updatedContent = JSON.stringify(data, null, 2);
230
231
  (0, import_fs.writeFileSync)(this.manifestPath, updatedContent, "utf8");
231
232
  } catch (error) {
232
- (0, import_logger.getDefaultLogger)().warn(
233
+ logger.warn(
233
234
  `Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`
234
235
  );
235
236
  }
@@ -245,7 +246,7 @@ class DlxManifest {
245
246
  (0, import_fs.unlinkSync)(this.manifestPath);
246
247
  }
247
248
  } catch (error) {
248
- (0, import_logger.getDefaultLogger)().warn(
249
+ logger.warn(
249
250
  `Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`
250
251
  );
251
252
  }
@@ -277,7 +278,7 @@ class DlxManifest {
277
278
  const data = JSON.parse(content);
278
279
  return Object.keys(data);
279
280
  } catch (error) {
280
- (0, import_logger.getDefaultLogger)().warn(
281
+ logger.warn(
281
282
  `Failed to get package list: ${error instanceof Error ? error.message : String(error)}`
282
283
  );
283
284
  return [];
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/dlx-manifest.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview DLX manifest storage utilities.\n * Manages persistent caching of DLX package and binary metadata with TTL support\n * and atomic file operations.\n *\n * Key Functions:\n * - getManifestEntry: Retrieve manifest entry by spec\n * - setPackageEntry: Store npm package metadata\n * - setBinaryEntry: Store binary download metadata\n *\n * Features:\n * - TTL-based cache expiration\n * - Atomic file operations with locking\n * - JSON-based persistent storage\n * - Error-resistant implementation\n *\n * Storage Format:\n * - Stores in ~/.socket/_dlx/.dlx-manifest.json\n * - Per-spec manifest entries with timestamps\n * - Thread-safe operations using process lock utility\n *\n * Usage:\n * - Update check caching\n * - Binary metadata tracking\n * - Rate limiting registry requests\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs'\nimport path from 'path'\n\nimport { readFileUtf8Sync, safeMkdirSync } from './fs'\nimport { getDefaultLogger } from './logger'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\n\n/**\n * Manifest file name.\n */\nconst MANIFEST_FILE_NAME = '.dlx-manifest.json'\n\n/**\n * Details for npm package entries.\n */\nexport interface PackageDetails {\n installed_version: string\n size?: number\n update_check?: {\n last_check: number\n last_notification: number\n latest_known: string\n }\n}\n\n/**\n * Details for binary download entries.\n */\nexport interface BinaryDetails {\n checksum: string\n checksum_algorithm: 'sha256' | 'sha512'\n platform: string\n arch: string\n size: number\n source: {\n type: 'download'\n url: string\n }\n}\n\n/**\n * Unified manifest entry for all cached items (packages and binaries).\n * Shared fields at root, type-specific fields in details.\n */\nexport interface ManifestEntry {\n type: 'package' | 'binary'\n cache_key: string\n timestamp: number\n details: PackageDetails | BinaryDetails\n}\n\n/**\n * Type guard for package entries.\n */\nexport function isPackageEntry(\n entry: ManifestEntry,\n): entry is ManifestEntry & { details: PackageDetails } {\n return entry.type === 'package'\n}\n\n/**\n * Type guard for binary entries.\n */\nexport function isBinaryEntry(\n entry: ManifestEntry,\n): entry is ManifestEntry & { details: BinaryDetails } {\n return entry.type === 'binary'\n}\n\n/**\n * Legacy store record format (deprecated, for migration).\n */\nexport interface StoreRecord {\n timestampFetch: number\n timestampNotification: number\n version: string\n}\n\nexport interface DlxManifestOptions {\n /**\n * Custom manifest file path (defaults to ~/.socket/_dlx/.dlx-manifest.json).\n */\n manifestPath?: string\n}\n\n/**\n * DLX manifest storage manager with atomic operations.\n * Supports both legacy format (package name keys) and new unified manifest format (spec keys).\n */\nexport class DlxManifest {\n private readonly manifestPath: string\n private readonly lockPath: string\n\n constructor(options: DlxManifestOptions = {}) {\n this.manifestPath =\n options.manifestPath ?? path.join(getSocketDlxDir(), MANIFEST_FILE_NAME)\n this.lockPath = `${this.manifestPath}.lock`\n }\n\n /**\n * Read the entire manifest file.\n */\n private readManifest(): Record<string, ManifestEntry | StoreRecord> {\n try {\n if (!existsSync(this.manifestPath)) {\n return Object.create(null)\n }\n\n const rawContent = readFileUtf8Sync(this.manifestPath)\n const content = (\n typeof rawContent === 'string'\n ? rawContent\n : rawContent.toString('utf8')\n ).trim()\n\n if (!content) {\n return Object.create(null)\n }\n\n return JSON.parse(content) as Record<string, ManifestEntry | StoreRecord>\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`,\n )\n return Object.create(null)\n }\n }\n\n /**\n * Get a manifest entry by spec (e.g., \"@socketsecurity/cli@^2.0.11\").\n */\n getManifestEntry(spec: string): ManifestEntry | undefined {\n const data = this.readManifest()\n const entry = data[spec]\n\n // Check if it's a new-format entry (has 'type' field).\n if (entry && 'type' in entry) {\n return entry as ManifestEntry\n }\n\n return undefined\n }\n\n /**\n * Get cached update information for a package (legacy format).\n * @deprecated Use getManifestEntry() for new code.\n */\n get(name: string): StoreRecord | undefined {\n const data = this.readManifest()\n const entry = data[name]\n\n // Return legacy format entries only.\n if (entry && !('type' in entry)) {\n return entry as StoreRecord\n }\n\n return undefined\n }\n\n /**\n * Set a package manifest entry.\n */\n async setPackageEntry(\n spec: string,\n cacheKey: string,\n details: PackageDetails,\n ): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n const data = this.readManifest()\n\n data[spec] = {\n type: 'package',\n cache_key: cacheKey,\n timestamp: Date.now(),\n details,\n }\n\n await this.writeManifest(data)\n })\n }\n\n /**\n * Set a binary manifest entry.\n */\n async setBinaryEntry(\n spec: string,\n cacheKey: string,\n details: BinaryDetails,\n ): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n const data = this.readManifest()\n\n data[spec] = {\n type: 'binary',\n cache_key: cacheKey,\n timestamp: Date.now(),\n details,\n }\n\n await this.writeManifest(data)\n })\n }\n\n /**\n * Write the manifest file atomically.\n */\n private async writeManifest(\n data: Record<string, ManifestEntry | StoreRecord>,\n ): Promise<void> {\n // Ensure directory exists.\n const manifestDir = path.dirname(this.manifestPath)\n try {\n safeMkdirSync(manifestDir, { recursive: true })\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Write atomically.\n const content = JSON.stringify(data, null, 2)\n const tempPath = `${this.manifestPath}.tmp`\n\n try {\n writeFileSync(tempPath, content, 'utf8')\n writeFileSync(this.manifestPath, content, 'utf8')\n\n // Clean up temp file.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Cleanup failed, not critical.\n }\n } catch (error) {\n // Clean up temp file on error.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Best effort cleanup.\n }\n throw error\n }\n }\n\n /**\n * Store update information for a package (legacy format).\n * @deprecated Use setPackageEntry() for new code.\n */\n async set(name: string, record: StoreRecord): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n let data: Record<string, StoreRecord> = Object.create(null)\n\n // Read existing data.\n try {\n if (existsSync(this.manifestPath)) {\n const content = readFileSync(this.manifestPath, 'utf8')\n if (content.trim()) {\n data = JSON.parse(content) as Record<string, StoreRecord>\n }\n }\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Update record.\n data[name] = record\n\n // Ensure directory exists.\n const manifestDir = path.dirname(this.manifestPath)\n try {\n safeMkdirSync(manifestDir, { recursive: true })\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Write atomically.\n const content = JSON.stringify(data, null, 2)\n const tempPath = `${this.manifestPath}.tmp`\n\n try {\n writeFileSync(tempPath, content, 'utf8')\n writeFileSync(this.manifestPath, content, 'utf8')\n\n // Clean up temp file.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Cleanup failed, not critical.\n }\n } catch (error) {\n // Clean up temp file on error.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Best effort cleanup.\n }\n throw error\n }\n })\n }\n\n /**\n * Clear cached data for a specific entry.\n */\n async clear(name: string): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n try {\n if (!existsSync(this.manifestPath)) {\n return\n }\n\n const content = readFileSync(this.manifestPath, 'utf8')\n if (!content.trim()) {\n return\n }\n\n const data = JSON.parse(content) as Record<string, StoreRecord>\n delete data[name]\n\n const updatedContent = JSON.stringify(data, null, 2)\n writeFileSync(this.manifestPath, updatedContent, 'utf8')\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n })\n }\n\n /**\n * Clear all cached data.\n */\n async clearAll(): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n try {\n if (existsSync(this.manifestPath)) {\n unlinkSync(this.manifestPath)\n }\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n })\n }\n\n /**\n * Check if cached data is fresh based on TTL.\n */\n isFresh(record: StoreRecord | undefined, ttlMs: number): boolean {\n if (!record) {\n return false\n }\n\n const age = Date.now() - record.timestampFetch\n return age < ttlMs\n }\n\n /**\n * Get all cached package names.\n */\n getAllPackages(): string[] {\n try {\n if (!existsSync(this.manifestPath)) {\n return []\n }\n\n const rawContent = readFileUtf8Sync(this.manifestPath)\n const content = (\n typeof rawContent === 'string'\n ? rawContent\n : rawContent.toString('utf8')\n ).trim()\n if (!content) {\n return []\n }\n\n const data = JSON.parse(content) as Record<string, StoreRecord>\n return Object.keys(data)\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to get package list: ${error instanceof Error ? error.message : String(error)}`,\n )\n return []\n }\n }\n}\n\n// Export singleton instance using default manifest location.\nexport const dlxManifest = new DlxManifest()\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BA,gBAAoE;AACpE,kBAAiB;AAEjB,IAAAA,aAAgD;AAChD,oBAAiC;AACjC,mBAAgC;AAChC,0BAA4B;AAK5B,MAAM,qBAAqB;AA4CpB,SAAS,eACd,OACsD;AACtD,SAAO,MAAM,SAAS;AACxB;AAKO,SAAS,cACd,OACqD;AACrD,SAAO,MAAM,SAAS;AACxB;AAsBO,MAAM,YAAY;AAAA,EACN;AAAA,EACA;AAAA,EAEjB,YAAY,UAA8B,CAAC,GAAG;AAC5C,SAAK,eACH,QAAQ,gBAAgB,YAAAC,QAAK,SAAK,8BAAgB,GAAG,kBAAkB;AACzE,SAAK,WAAW,GAAG,KAAK,YAAY;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKQ,eAA4D;AAClE,QAAI;AACF,UAAI,KAAC,sBAAW,KAAK,YAAY,GAAG;AAClC,eAAO,uBAAO,OAAO,IAAI;AAAA,MAC3B;AAEA,YAAM,iBAAa,6BAAiB,KAAK,YAAY;AACrD,YAAM,WACJ,OAAO,eAAe,WAClB,aACA,WAAW,SAAS,MAAM,GAC9B,KAAK;AAEP,UAAI,CAAC,SAAS;AACZ,eAAO,uBAAO,OAAO,IAAI;AAAA,MAC3B;AAEA,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,SAAS,OAAO;AACd,0CAAiB,EAAE;AAAA,QACjB,4BAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACpF;AACA,aAAO,uBAAO,OAAO,IAAI;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,MAAyC;AACxD,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,QAAQ,KAAK,IAAI;AAGvB,QAAI,SAAS,UAAU,OAAO;AAC5B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,MAAuC;AACzC,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,QAAQ,KAAK,IAAI;AAGvB,QAAI,SAAS,EAAE,UAAU,QAAQ;AAC/B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,MACA,UACA,SACe;AACf,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,YAAM,OAAO,KAAK,aAAa;AAE/B,WAAK,IAAI,IAAI;AAAA,QACX,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,KAAK,cAAc,IAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,MACA,UACA,SACe;AACf,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,YAAM,OAAO,KAAK,aAAa;AAE/B,WAAK,IAAI,IAAI;AAAA,QACX,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,KAAK,cAAc,IAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cACZ,MACe;AAEf,UAAM,cAAc,YAAAA,QAAK,QAAQ,KAAK,YAAY;AAClD,QAAI;AACF,oCAAc,aAAa,EAAE,WAAW,KAAK,CAAC;AAAA,IAChD,SAAS,OAAO;AACd,0CAAiB,EAAE;AAAA,QACjB,wCAAwC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAChG;AAAA,IACF;AAGA,UAAM,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC;AAC5C,UAAM,WAAW,GAAG,KAAK,YAAY;AAErC,QAAI;AACF,mCAAc,UAAU,SAAS,MAAM;AACvC,mCAAc,KAAK,cAAc,SAAS,MAAM;AAGhD,UAAI;AACF,gBAAI,sBAAW,QAAQ,GAAG;AACxB,oCAAW,QAAQ;AAAA,QACrB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,SAAS,OAAO;AAEd,UAAI;AACF,gBAAI,sBAAW,QAAQ,GAAG;AACxB,oCAAW,QAAQ;AAAA,QACrB;AAAA,MACF,QAAQ;AAAA,MAER;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,MAAc,QAAoC;AAC1D,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,UAAI,OAAoC,uBAAO,OAAO,IAAI;AAG1D,UAAI;AACF,gBAAI,sBAAW,KAAK,YAAY,GAAG;AACjC,gBAAMC,eAAU,wBAAa,KAAK,cAAc,MAAM;AACtD,cAAIA,SAAQ,KAAK,GAAG;AAClB,mBAAO,KAAK,MAAMA,QAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC7F;AAAA,MACF;AAGA,WAAK,IAAI,IAAI;AAGb,YAAM,cAAc,YAAAD,QAAK,QAAQ,KAAK,YAAY;AAClD,UAAI;AACF,sCAAc,aAAa,EAAE,WAAW,KAAK,CAAC;AAAA,MAChD,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,wCAAwC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAChG;AAAA,MACF;AAGA,YAAM,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC;AAC5C,YAAM,WAAW,GAAG,KAAK,YAAY;AAErC,UAAI;AACF,qCAAc,UAAU,SAAS,MAAM;AACvC,qCAAc,KAAK,cAAc,SAAS,MAAM;AAGhD,YAAI;AACF,kBAAI,sBAAW,QAAQ,GAAG;AACxB,sCAAW,QAAQ;AAAA,UACrB;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF,SAAS,OAAO;AAEd,YAAI;AACF,kBAAI,sBAAW,QAAQ,GAAG;AACxB,sCAAW,QAAQ;AAAA,UACrB;AAAA,QACF,QAAQ;AAAA,QAER;AACA,cAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,MAA6B;AACvC,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,UAAI;AACF,YAAI,KAAC,sBAAW,KAAK,YAAY,GAAG;AAClC;AAAA,QACF;AAEA,cAAM,cAAU,wBAAa,KAAK,cAAc,MAAM;AACtD,YAAI,CAAC,QAAQ,KAAK,GAAG;AACnB;AAAA,QACF;AAEA,cAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,eAAO,KAAK,IAAI;AAEhB,cAAM,iBAAiB,KAAK,UAAU,MAAM,MAAM,CAAC;AACnD,qCAAc,KAAK,cAAc,gBAAgB,MAAM;AAAA,MACzD,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,6BAA6B,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC9F;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA0B;AAC9B,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,UAAI;AACF,gBAAI,sBAAW,KAAK,YAAY,GAAG;AACjC,oCAAW,KAAK,YAAY;AAAA,QAC9B;AAAA,MACF,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,8BAA8B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QACtF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,QAAiC,OAAwB;AAC/D,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,IAAI,IAAI,OAAO;AAChC,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA2B;AACzB,QAAI;AACF,UAAI,KAAC,sBAAW,KAAK,YAAY,GAAG;AAClC,eAAO,CAAC;AAAA,MACV;AAEA,YAAM,iBAAa,6BAAiB,KAAK,YAAY;AACrD,YAAM,WACJ,OAAO,eAAe,WAClB,aACA,WAAW,SAAS,MAAM,GAC9B,KAAK;AACP,UAAI,CAAC,SAAS;AACZ,eAAO,CAAC;AAAA,MACV;AAEA,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,aAAO,OAAO,KAAK,IAAI;AAAA,IACzB,SAAS,OAAO;AACd,0CAAiB,EAAE;AAAA,QACjB,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACvF;AACA,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AACF;AAGO,MAAM,cAAc,IAAI,YAAY;",
4
+ "sourcesContent": ["/**\n * @fileoverview DLX manifest storage utilities.\n * Manages persistent caching of DLX package and binary metadata with TTL support\n * and atomic file operations.\n *\n * Key Functions:\n * - getManifestEntry: Retrieve manifest entry by spec\n * - setPackageEntry: Store npm package metadata\n * - setBinaryEntry: Store binary download metadata\n *\n * Features:\n * - TTL-based cache expiration\n * - Atomic file operations with locking\n * - JSON-based persistent storage\n * - Error-resistant implementation\n *\n * Storage Format:\n * - Stores in ~/.socket/_dlx/.dlx-manifest.json\n * - Per-spec manifest entries with timestamps\n * - Thread-safe operations using process lock utility\n *\n * Usage:\n * - Update check caching\n * - Binary metadata tracking\n * - Rate limiting registry requests\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs'\nimport path from 'path'\n\nimport { readFileUtf8Sync, safeMkdirSync } from './fs'\nimport { getDefaultLogger } from './logger'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\n\nconst logger = getDefaultLogger()\n\n/**\n * Manifest file name.\n */\nconst MANIFEST_FILE_NAME = '.dlx-manifest.json'\n\n/**\n * Details for npm package entries.\n */\nexport interface PackageDetails {\n installed_version: string\n size?: number\n update_check?: {\n last_check: number\n last_notification: number\n latest_known: string\n }\n}\n\n/**\n * Details for binary download entries.\n */\nexport interface BinaryDetails {\n checksum: string\n checksum_algorithm: 'sha256' | 'sha512'\n platform: string\n arch: string\n size: number\n source: {\n type: 'download'\n url: string\n }\n}\n\n/**\n * Unified manifest entry for all cached items (packages and binaries).\n * Shared fields at root, type-specific fields in details.\n */\nexport interface ManifestEntry {\n type: 'package' | 'binary'\n cache_key: string\n timestamp: number\n details: PackageDetails | BinaryDetails\n}\n\n/**\n * Type guard for package entries.\n */\nexport function isPackageEntry(\n entry: ManifestEntry,\n): entry is ManifestEntry & { details: PackageDetails } {\n return entry.type === 'package'\n}\n\n/**\n * Type guard for binary entries.\n */\nexport function isBinaryEntry(\n entry: ManifestEntry,\n): entry is ManifestEntry & { details: BinaryDetails } {\n return entry.type === 'binary'\n}\n\n/**\n * Legacy store record format (deprecated, for migration).\n */\nexport interface StoreRecord {\n timestampFetch: number\n timestampNotification: number\n version: string\n}\n\nexport interface DlxManifestOptions {\n /**\n * Custom manifest file path (defaults to ~/.socket/_dlx/.dlx-manifest.json).\n */\n manifestPath?: string\n}\n\n/**\n * DLX manifest storage manager with atomic operations.\n * Supports both legacy format (package name keys) and new unified manifest format (spec keys).\n */\nexport class DlxManifest {\n private readonly manifestPath: string\n private readonly lockPath: string\n\n constructor(options: DlxManifestOptions = {}) {\n this.manifestPath =\n options.manifestPath ?? path.join(getSocketDlxDir(), MANIFEST_FILE_NAME)\n this.lockPath = `${this.manifestPath}.lock`\n }\n\n /**\n * Read the entire manifest file.\n */\n private readManifest(): Record<string, ManifestEntry | StoreRecord> {\n try {\n if (!existsSync(this.manifestPath)) {\n return Object.create(null)\n }\n\n const rawContent = readFileUtf8Sync(this.manifestPath)\n const content = (\n typeof rawContent === 'string'\n ? rawContent\n : rawContent.toString('utf8')\n ).trim()\n\n if (!content) {\n return Object.create(null)\n }\n\n return JSON.parse(content) as Record<string, ManifestEntry | StoreRecord>\n } catch (error) {\n logger.warn(\n `Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`,\n )\n return Object.create(null)\n }\n }\n\n /**\n * Get a manifest entry by spec (e.g., \"@socketsecurity/cli@^2.0.11\").\n */\n getManifestEntry(spec: string): ManifestEntry | undefined {\n const data = this.readManifest()\n const entry = data[spec]\n\n // Check if it's a new-format entry (has 'type' field).\n if (entry && 'type' in entry) {\n return entry as ManifestEntry\n }\n\n return undefined\n }\n\n /**\n * Get cached update information for a package (legacy format).\n * @deprecated Use getManifestEntry() for new code.\n */\n get(name: string): StoreRecord | undefined {\n const data = this.readManifest()\n const entry = data[name]\n\n // Return legacy format entries only.\n if (entry && !('type' in entry)) {\n return entry as StoreRecord\n }\n\n return undefined\n }\n\n /**\n * Set a package manifest entry.\n */\n async setPackageEntry(\n spec: string,\n cacheKey: string,\n details: PackageDetails,\n ): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n const data = this.readManifest()\n\n data[spec] = {\n type: 'package',\n cache_key: cacheKey,\n timestamp: Date.now(),\n details,\n }\n\n await this.writeManifest(data)\n })\n }\n\n /**\n * Set a binary manifest entry.\n */\n async setBinaryEntry(\n spec: string,\n cacheKey: string,\n details: BinaryDetails,\n ): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n const data = this.readManifest()\n\n data[spec] = {\n type: 'binary',\n cache_key: cacheKey,\n timestamp: Date.now(),\n details,\n }\n\n await this.writeManifest(data)\n })\n }\n\n /**\n * Write the manifest file atomically.\n */\n private async writeManifest(\n data: Record<string, ManifestEntry | StoreRecord>,\n ): Promise<void> {\n // Ensure directory exists.\n const manifestDir = path.dirname(this.manifestPath)\n try {\n safeMkdirSync(manifestDir, { recursive: true })\n } catch (error) {\n logger.warn(\n `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Write atomically.\n const content = JSON.stringify(data, null, 2)\n const tempPath = `${this.manifestPath}.tmp`\n\n try {\n writeFileSync(tempPath, content, 'utf8')\n writeFileSync(this.manifestPath, content, 'utf8')\n\n // Clean up temp file.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Cleanup failed, not critical.\n }\n } catch (error) {\n // Clean up temp file on error.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Best effort cleanup.\n }\n throw error\n }\n }\n\n /**\n * Store update information for a package (legacy format).\n * @deprecated Use setPackageEntry() for new code.\n */\n async set(name: string, record: StoreRecord): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n let data: Record<string, StoreRecord> = Object.create(null)\n\n // Read existing data.\n try {\n if (existsSync(this.manifestPath)) {\n const content = readFileSync(this.manifestPath, 'utf8')\n if (content.trim()) {\n data = JSON.parse(content) as Record<string, StoreRecord>\n }\n }\n } catch (error) {\n logger.warn(\n `Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Update record.\n data[name] = record\n\n // Ensure directory exists.\n const manifestDir = path.dirname(this.manifestPath)\n try {\n safeMkdirSync(manifestDir, { recursive: true })\n } catch (error) {\n logger.warn(\n `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Write atomically.\n const content = JSON.stringify(data, null, 2)\n const tempPath = `${this.manifestPath}.tmp`\n\n try {\n writeFileSync(tempPath, content, 'utf8')\n writeFileSync(this.manifestPath, content, 'utf8')\n\n // Clean up temp file.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Cleanup failed, not critical.\n }\n } catch (error) {\n // Clean up temp file on error.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Best effort cleanup.\n }\n throw error\n }\n })\n }\n\n /**\n * Clear cached data for a specific entry.\n */\n async clear(name: string): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n try {\n if (!existsSync(this.manifestPath)) {\n return\n }\n\n const content = readFileSync(this.manifestPath, 'utf8')\n if (!content.trim()) {\n return\n }\n\n const data = JSON.parse(content) as Record<string, StoreRecord>\n delete data[name]\n\n const updatedContent = JSON.stringify(data, null, 2)\n writeFileSync(this.manifestPath, updatedContent, 'utf8')\n } catch (error) {\n logger.warn(\n `Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n })\n }\n\n /**\n * Clear all cached data.\n */\n async clearAll(): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n try {\n if (existsSync(this.manifestPath)) {\n unlinkSync(this.manifestPath)\n }\n } catch (error) {\n logger.warn(\n `Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n })\n }\n\n /**\n * Check if cached data is fresh based on TTL.\n */\n isFresh(record: StoreRecord | undefined, ttlMs: number): boolean {\n if (!record) {\n return false\n }\n\n const age = Date.now() - record.timestampFetch\n return age < ttlMs\n }\n\n /**\n * Get all cached package names.\n */\n getAllPackages(): string[] {\n try {\n if (!existsSync(this.manifestPath)) {\n return []\n }\n\n const rawContent = readFileUtf8Sync(this.manifestPath)\n const content = (\n typeof rawContent === 'string'\n ? rawContent\n : rawContent.toString('utf8')\n ).trim()\n if (!content) {\n return []\n }\n\n const data = JSON.parse(content) as Record<string, StoreRecord>\n return Object.keys(data)\n } catch (error) {\n logger.warn(\n `Failed to get package list: ${error instanceof Error ? error.message : String(error)}`,\n )\n return []\n }\n }\n}\n\n// Export singleton instance using default manifest location.\nexport const dlxManifest = new DlxManifest()\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_fs", "path", "content"]
7
7
  }
@@ -58,6 +58,14 @@ function getNpmPackageArg() {
58
58
  }
59
59
  return _npmPackageArg;
60
60
  }
61
+ let _libnpmexec;
62
+ // @__NO_SIDE_EFFECTS__
63
+ function getLibnpmexec() {
64
+ if (_libnpmexec === void 0) {
65
+ _libnpmexec = require("./external/libnpmexec");
66
+ }
67
+ return _libnpmexec;
68
+ }
61
69
  let _pacote;
62
70
  // @__NO_SIDE_EFFECTS__
63
71
  function getPacote() {
@@ -186,6 +194,7 @@ function findBinaryPath(packageDir, packageName, binaryName) {
186
194
  const pkgJsonPath = import_path.default.join(installedDir, "package.json");
187
195
  const pkgJson = (0, import_fs.readJsonSync)(pkgJsonPath);
188
196
  const bin = pkgJson["bin"];
197
+ let binName;
189
198
  let binPath;
190
199
  if (typeof bin === "string") {
191
200
  binPath = bin;
@@ -193,22 +202,35 @@ function findBinaryPath(packageDir, packageName, binaryName) {
193
202
  const binObj = bin;
194
203
  const binKeys = Object.keys(binObj);
195
204
  if (binKeys.length === 1) {
196
- binPath = binObj[binKeys[0]];
205
+ binName = binKeys[0];
206
+ binPath = binObj[binName];
197
207
  } else {
198
- const lastSegment = packageName.split("/").pop();
199
- const candidates = [
200
- binaryName,
201
- lastSegment,
202
- packageName.replace(/^@[^/]+\//, "")
203
- ].filter(Boolean);
204
- for (const candidate of candidates) {
205
- if (candidate && binObj[candidate]) {
206
- binPath = binObj[candidate];
207
- break;
208
+ try {
209
+ const { getBinFromManifest } = /* @__PURE__ */ getLibnpmexec();
210
+ binName = getBinFromManifest({
211
+ name: packageName,
212
+ bin: binObj,
213
+ _id: `${packageName}@${pkgJson.version || "unknown"}`
214
+ });
215
+ binPath = binObj[binName];
216
+ } catch {
217
+ const lastSegment = packageName.split("/").pop();
218
+ const candidates = [
219
+ binaryName,
220
+ lastSegment,
221
+ packageName.replace(/^@[^/]+\//, "")
222
+ ].filter(Boolean);
223
+ for (const candidate of candidates) {
224
+ if (candidate && binObj[candidate]) {
225
+ binName = candidate;
226
+ binPath = binObj[candidate];
227
+ break;
228
+ }
229
+ }
230
+ if (!binPath && binKeys.length > 0) {
231
+ binName = binKeys[0];
232
+ binPath = binObj[binName];
208
233
  }
209
- }
210
- if (!binPath && binKeys.length > 0) {
211
- binPath = binObj[binKeys[0]];
212
234
  }
213
235
  }
214
236
  }
@@ -231,8 +253,41 @@ async function dlxPackage(args, options, spawnExtra) {
231
253
  spawnPromise
232
254
  };
233
255
  }
234
- async function downloadPackage(options) {
256
+ function makePackageBinsExecutable(packageDir, packageName) {
257
+ if (import_platform.WIN32) {
258
+ return;
259
+ }
235
260
  const fs = /* @__PURE__ */ getFs();
261
+ const installedDir = (0, import_path2.normalizePath)(
262
+ import_path.default.join(packageDir, "node_modules", packageName)
263
+ );
264
+ const pkgJsonPath = import_path.default.join(installedDir, "package.json");
265
+ try {
266
+ const pkgJson = (0, import_fs.readJsonSync)(pkgJsonPath);
267
+ const bin = pkgJson["bin"];
268
+ if (!bin) {
269
+ return;
270
+ }
271
+ const binPaths = [];
272
+ if (typeof bin === "string") {
273
+ binPaths.push(bin);
274
+ } else if (typeof bin === "object" && bin !== null) {
275
+ const binObj = bin;
276
+ binPaths.push(...Object.values(binObj));
277
+ }
278
+ for (const binPath of binPaths) {
279
+ const fullPath = (0, import_path2.normalizePath)(import_path.default.join(installedDir, binPath));
280
+ if (fs.existsSync(fullPath)) {
281
+ try {
282
+ fs.chmodSync(fullPath, 493);
283
+ } catch {
284
+ }
285
+ }
286
+ }
287
+ } catch {
288
+ }
289
+ }
290
+ async function downloadPackage(options) {
236
291
  const {
237
292
  binaryName,
238
293
  force: userForce,
@@ -252,12 +307,7 @@ async function downloadPackage(options) {
252
307
  force
253
308
  );
254
309
  const binaryPath = findBinaryPath(packageDir, packageName, binaryName);
255
- if (!import_platform.WIN32 && fs.existsSync(binaryPath)) {
256
- try {
257
- fs.chmodSync(binaryPath, 493);
258
- } catch {
259
- }
260
- }
310
+ makePackageBinsExecutable(packageDir, packageName);
261
311
  return {
262
312
  binaryPath,
263
313
  installed,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/dlx-package.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview DLX package execution - Install and execute npm packages.\n *\n * This module provides functionality to install and execute npm packages\n * in the ~/.socket/_dlx directory, similar to npx but with Socket's own cache.\n *\n * Uses content-addressed storage like npm's _npx:\n * - Hash is generated from package spec (name@version)\n * - Each unique spec gets its own directory: ~/.socket/_dlx/<hash>/\n * - Allows caching multiple versions of the same package\n *\n * Concurrency protection:\n * - Uses process-lock to prevent concurrent installation corruption\n * - Lock file created at ~/.socket/_dlx/<hash>/concurrency.lock\n * - Uses npm npx's concurrency.lock naming convention (5s stale, 2s touching)\n * - Prevents multiple processes from corrupting the same package installation\n *\n * Version range handling:\n * - Exact versions (1.0.0) use cache if available\n * - Range versions (^1.0.0, ~1.0.0) auto-force to get latest within range\n * - User can override with explicit force: false\n *\n * Key difference from dlx-binary.ts:\n * - dlx-binary.ts: Downloads standalone binaries from URLs\n * - dlx-package.ts: Installs npm packages from registries\n *\n * Implementation:\n * - Uses pacote for package installation (no npm CLI required)\n * - Split into downloadPackage() and executePackage() for flexibility\n * - dlxPackage() combines both for convenience\n */\n\nimport path from 'path'\n\nimport { WIN32 } from './constants/platform'\nimport { getPacoteCachePath } from './constants/packages'\nimport { generateCacheKey } from './dlx'\nimport { readJsonSync, safeMkdir } from './fs'\nimport { normalizePath } from './path'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\nimport type { SpawnExtra, SpawnOptions } from './spawn'\nimport { spawn } from './spawn'\n\nlet _fs: typeof import('fs') | undefined\n/**\n * Lazily load the fs module to avoid Webpack errors.\n * Uses non-'node:' prefixed require to prevent Webpack bundling issues.\n *\n * @returns The Node.js fs module\n * @private\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getFs() {\n if (_fs === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _fs = /*@__PURE__*/ require('node:fs')\n }\n return _fs as typeof import('fs')\n}\n\nlet _npmPackageArg: typeof import('npm-package-arg') | undefined\n/*@__NO_SIDE_EFFECTS__*/\nfunction getNpmPackageArg() {\n if (_npmPackageArg === undefined) {\n _npmPackageArg = /*@__PURE__*/ require('./external/npm-package-arg')\n }\n return _npmPackageArg as typeof import('npm-package-arg')\n}\n\nlet _pacote: typeof import('pacote') | undefined\n/*@__NO_SIDE_EFFECTS__*/\nfunction getPacote() {\n if (_pacote === undefined) {\n _pacote = /*@__PURE__*/ require('./external/pacote')\n }\n return _pacote as typeof import('pacote')\n}\n\n/**\n * Regex to check if a version string contains range operators.\n * Matches any version with range operators: ~, ^, >, <, =, x, X, *, spaces, or ||.\n */\nconst rangeOperatorsRegExp = /[~^><=xX* ]|\\|\\|/\n\nexport interface DownloadPackageResult {\n /** Path to the installed package directory. */\n packageDir: string\n /** Path to the binary. */\n binaryPath: string\n /** Whether the package was newly installed. */\n installed: boolean\n}\n\nexport interface DlxPackageOptions {\n /**\n * Package to install (e.g., '@cyclonedx/cdxgen@10.0.0').\n * Aligns with npx --package flag.\n */\n package: string\n\n /**\n * Binary name to execute (optional - auto-detected in most cases).\n *\n * Auto-detection logic:\n * 1. If package has only one binary, uses it automatically\n * 2. Tries user-provided binaryName\n * 3. Tries last segment of package name (e.g., 'cli' from '@socketsecurity/cli')\n * 4. Falls back to first binary\n *\n * Only needed when package has multiple binaries and auto-detection fails.\n *\n * @example\n * // Auto-detected (single binary)\n * { package: '@socketsecurity/cli' } // Finds 'socket' binary automatically\n *\n * // Explicit (multiple binaries)\n * { package: 'some-tool', binaryName: 'specific-tool' }\n */\n binaryName?: string | undefined\n\n /**\n * Force reinstallation even if package exists.\n * Aligns with npx --yes/-y flag behavior.\n */\n force?: boolean | undefined\n\n /**\n * Skip confirmation prompts (auto-approve).\n * Aligns with npx --yes/-y flag.\n */\n yes?: boolean | undefined\n\n /**\n * Suppress output (quiet mode).\n * Aligns with npx --quiet/-q and pnpm --silent/-s flags.\n */\n quiet?: boolean | undefined\n\n /**\n * Additional spawn options for the execution.\n */\n spawnOptions?: SpawnOptions | undefined\n}\n\nexport interface DlxPackageResult {\n /** Path to the installed package directory. */\n packageDir: string\n /** Path to the binary that was executed. */\n binaryPath: string\n /** Whether the package was newly installed. */\n installed: boolean\n /** The spawn promise for the running process. */\n spawnPromise: ReturnType<typeof spawn>\n}\n\n/**\n * Parse package spec into name and version using npm-package-arg.\n * Examples:\n * - 'lodash@4.17.21' \u2192 { name: 'lodash', version: '4.17.21' }\n * - '@scope/pkg@1.0.0' \u2192 { name: '@scope/pkg', version: '1.0.0' }\n * - 'lodash' \u2192 { name: 'lodash', version: undefined }\n */\nfunction parsePackageSpec(spec: string): {\n name: string\n version: string | undefined\n} {\n try {\n const npa = getNpmPackageArg()\n const parsed = npa(spec)\n\n // Extract version from different types of specs.\n // For registry specs, use fetchSpec (the version/range).\n // For git/file/etc, version will be undefined.\n const version =\n parsed.type === 'tag'\n ? parsed.fetchSpec\n : parsed.type === 'version' || parsed.type === 'range'\n ? parsed.fetchSpec\n : undefined\n\n return {\n name: parsed.name || spec,\n version,\n }\n } catch {\n // Fallback to simple parsing if npm-package-arg fails.\n const atIndex = spec.lastIndexOf('@')\n if (atIndex === -1 || spec.startsWith('@')) {\n // No version or scoped package without version.\n return { name: spec, version: undefined }\n }\n return {\n name: spec.slice(0, atIndex),\n version: spec.slice(atIndex + 1),\n }\n }\n}\n\n/**\n * Install package to ~/.socket/_dlx/<hash>/ if not already installed.\n * Uses pacote for installation (no npm CLI required).\n * Protected by process lock to prevent concurrent installation corruption.\n */\nasync function ensurePackageInstalled(\n packageName: string,\n packageSpec: string,\n force: boolean,\n): Promise<{ installed: boolean; packageDir: string }> {\n const cacheKey = generateCacheKey(packageSpec)\n const packageDir = normalizePath(path.join(getSocketDlxDir(), cacheKey))\n const installedDir = normalizePath(\n path.join(packageDir, 'node_modules', packageName),\n )\n\n // Ensure package directory exists before creating lock.\n // The lock directory will be created inside this directory.\n try {\n await safeMkdir(packageDir)\n } catch (e) {\n const code = (e as NodeJS.ErrnoException).code\n if (code === 'EACCES' || code === 'EPERM') {\n throw new Error(\n `Permission denied creating package directory: ${packageDir}\\n` +\n 'Please check directory permissions or run with appropriate access.',\n { cause: e },\n )\n }\n if (code === 'EROFS') {\n throw new Error(\n `Cannot create package directory on read-only filesystem: ${packageDir}\\n` +\n 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.',\n { cause: e },\n )\n }\n throw new Error(`Failed to create package directory: ${packageDir}`, {\n cause: e,\n })\n }\n\n // Use process lock to prevent concurrent installations.\n // Uses npm npx's concurrency.lock naming convention.\n const lockPath = path.join(packageDir, 'concurrency.lock')\n\n return await processLock.withLock(\n lockPath,\n async () => {\n const fs = getFs()\n // Double-check if already installed (unless force).\n // Another process may have installed while waiting for lock.\n if (!force && fs.existsSync(installedDir)) {\n // Verify package.json exists.\n const pkgJsonPath = path.join(installedDir, 'package.json')\n if (fs.existsSync(pkgJsonPath)) {\n return { installed: false, packageDir }\n }\n }\n\n // Use pacote to extract the package.\n // Pacote leverages npm cache when available but doesn't require npm CLI.\n const pacoteCachePath = getPacoteCachePath()\n try {\n await getPacote().extract(packageSpec, installedDir, {\n // Use consistent pacote cache path (respects npm cache locations when available).\n cache: pacoteCachePath || path.join(packageDir, '.cache'),\n })\n } catch (e) {\n const code = (e as any).code\n if (code === 'E404' || code === 'ETARGET') {\n throw new Error(\n `Package not found: ${packageSpec}\\n` +\n 'Verify the package exists on npm registry and check the version.\\n' +\n `Visit https://www.npmjs.com/package/${packageName} to see available versions.`,\n { cause: e },\n )\n }\n if (\n code === 'ENOTFOUND' ||\n code === 'ETIMEDOUT' ||\n code === 'EAI_AGAIN'\n ) {\n throw new Error(\n `Network error installing ${packageSpec}\\n` +\n 'Check your internet connection and try again.',\n { cause: e },\n )\n }\n throw new Error(\n `Failed to install package: ${packageSpec}\\n` +\n `Destination: ${installedDir}\\n` +\n 'Check npm registry connectivity or package name.',\n { cause: e },\n )\n }\n\n return { installed: true, packageDir }\n },\n {\n // Align with npm npx locking strategy.\n staleMs: 5000,\n touchIntervalMs: 2000,\n },\n )\n}\n\n/**\n * Resolve binary path with cross-platform wrapper support.\n * On Windows, checks for .cmd, .bat, .ps1, .exe wrappers in order.\n * On Unix, uses path directly.\n *\n * Aligns with npm/npx binary resolution strategy.\n */\nfunction resolveBinaryPath(basePath: string): string {\n const fs = getFs()\n\n if (!WIN32) {\n // Unix: use path directly\n return basePath\n }\n\n // Windows: check for wrappers in priority order\n // Order matches npm bin-links creation: .cmd, .ps1, .exe, then bare\n const extensions = ['.cmd', '.bat', '.ps1', '.exe', '']\n\n for (const ext of extensions) {\n const testPath = basePath + ext\n if (fs.existsSync(testPath)) {\n return testPath\n }\n }\n\n // Fallback to original path if no wrapper found\n return basePath\n}\n\n/**\n * Find the binary path for an installed package.\n * Intelligently handles packages with single or multiple binaries.\n * Resolves platform-specific wrappers (.cmd, .ps1, etc.) on Windows.\n */\nfunction findBinaryPath(\n packageDir: string,\n packageName: string,\n binaryName?: string,\n): string {\n const installedDir = normalizePath(\n path.join(packageDir, 'node_modules', packageName),\n )\n const pkgJsonPath = path.join(installedDir, 'package.json')\n\n // Read package.json to find bin entry.\n const pkgJson = readJsonSync(pkgJsonPath) as Record<string, unknown>\n const bin = pkgJson['bin']\n\n let binPath: string | undefined\n\n if (typeof bin === 'string') {\n // Single binary - use it directly.\n binPath = bin\n } else if (typeof bin === 'object' && bin !== null) {\n const binObj = bin as Record<string, string>\n const binKeys = Object.keys(binObj)\n\n // If only one binary, use it regardless of name.\n if (binKeys.length === 1) {\n binPath = binObj[binKeys[0]!]\n } else {\n // Multiple binaries - try to find the right one:\n // 1. User-provided binaryName\n // 2. Last segment of package name (e.g., 'cli' from '@socketsecurity/cli')\n // 3. Full package name without scope (e.g., 'cli' from '@socketsecurity/cli')\n // 4. First binary as fallback\n const lastSegment = packageName.split('/').pop()\n const candidates = [\n binaryName,\n lastSegment,\n packageName.replace(/^@[^/]+\\//, ''),\n ].filter(Boolean)\n\n for (const candidate of candidates) {\n if (candidate && binObj[candidate]) {\n binPath = binObj[candidate]\n break\n }\n }\n\n // Fallback to first binary if nothing matched.\n if (!binPath && binKeys.length > 0) {\n binPath = binObj[binKeys[0]!]\n }\n }\n }\n\n if (!binPath) {\n throw new Error(`No binary found for package \"${packageName}\"`)\n }\n\n const rawPath = normalizePath(path.join(installedDir, binPath))\n\n // Resolve platform-specific wrapper (Windows .cmd/.ps1/etc.)\n return resolveBinaryPath(rawPath)\n}\n\n/**\n * Execute a package via DLX - install if needed and run its binary.\n *\n * This is the Socket equivalent of npx/pnpm dlx/yarn dlx, but using\n * our own cache directory (~/.socket/_dlx) and installation logic.\n *\n * Auto-forces reinstall for version ranges to get latest within range.\n *\n * @example\n * ```typescript\n * // Download and execute cdxgen\n * const result = await dlxPackage(\n * ['--version'],\n * { package: '@cyclonedx/cdxgen@10.0.0' }\n * )\n * await result.spawnPromise\n * ```\n */\nexport async function dlxPackage(\n args: readonly string[] | string[],\n options?: DlxPackageOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): Promise<DlxPackageResult> {\n // Download the package.\n const downloadResult = await downloadPackage(options!)\n\n // Execute the binary.\n const spawnPromise = executePackage(\n downloadResult.binaryPath,\n args,\n options?.spawnOptions,\n spawnExtra,\n )\n\n return {\n ...downloadResult,\n spawnPromise,\n }\n}\n\n/**\n * Download and install a package without executing it.\n * This is useful for self-update or when you need the package files\n * but don't want to run the binary immediately.\n *\n * @example\n * ```typescript\n * // Install @socketsecurity/cli without running it\n * const result = await downloadPackage({\n * package: '@socketsecurity/cli@1.2.0',\n * force: true\n * })\n * console.log('Installed to:', result.packageDir)\n * console.log('Binary at:', result.binaryPath)\n * ```\n */\nexport async function downloadPackage(\n options: DlxPackageOptions,\n): Promise<DownloadPackageResult> {\n const fs = getFs()\n const {\n binaryName,\n force: userForce,\n package: packageSpec,\n yes,\n } = {\n __proto__: null,\n ...options,\n } as DlxPackageOptions\n\n // Parse package spec.\n const { name: packageName, version: packageVersion } =\n parsePackageSpec(packageSpec)\n\n // Determine force behavior:\n // 1. Explicit force takes precedence\n // 2. --yes flag implies force (auto-approve/skip prompts)\n // 3. Version ranges auto-force to get latest\n const isVersionRange =\n packageVersion !== undefined && rangeOperatorsRegExp.test(packageVersion)\n const force =\n userForce !== undefined ? userForce : yes === true ? true : isVersionRange\n\n // Build full package spec for installation.\n const fullPackageSpec = packageVersion\n ? `${packageName}@${packageVersion}`\n : packageName\n\n // Ensure package is installed.\n const { installed, packageDir } = await ensurePackageInstalled(\n packageName,\n fullPackageSpec,\n force,\n )\n\n // Find binary path.\n const binaryPath = findBinaryPath(packageDir, packageName, binaryName)\n\n // Make binary executable on Unix systems.\n if (!WIN32 && fs.existsSync(binaryPath)) {\n try {\n fs.chmodSync(binaryPath, 0o755)\n } catch {\n // Ignore chmod errors.\n }\n }\n\n return {\n binaryPath,\n installed,\n packageDir,\n }\n}\n\n/**\n * Execute a package's binary with cross-platform shell handling.\n * The package must already be installed (use downloadPackage first).\n *\n * On Windows, script files (.bat, .cmd, .ps1) require shell: true.\n * Matches npm/npx execution behavior.\n *\n * @example\n * ```typescript\n * // Execute an already-installed package\n * const downloaded = await downloadPackage({ package: 'cowsay@1.5.0' })\n * const result = await executePackage(\n * downloaded.binaryPath,\n * ['Hello World'],\n * { stdio: 'inherit' }\n * )\n * ```\n */\nexport function executePackage(\n binaryPath: string,\n args: readonly string[] | string[],\n spawnOptions?: SpawnOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): ReturnType<typeof spawn> {\n // On Windows, script files (.bat, .cmd, .ps1) require shell: true\n // because they are not executable on their own and must be run through cmd.exe.\n // .exe files are actual binaries and don't need shell mode.\n const needsShell = WIN32 && /\\.(?:bat|cmd|ps1)$/i.test(binaryPath)\n\n const finalOptions = needsShell\n ? {\n ...spawnOptions,\n shell: true,\n }\n : spawnOptions\n\n return spawn(binaryPath, args, finalOptions, spawnExtra)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @fileoverview DLX package execution - Install and execute npm packages.\n *\n * This module provides functionality to install and execute npm packages\n * in the ~/.socket/_dlx directory, similar to npx but with Socket's own cache.\n *\n * Uses content-addressed storage like npm's _npx:\n * - Hash is generated from package spec (name@version)\n * - Each unique spec gets its own directory: ~/.socket/_dlx/<hash>/\n * - Allows caching multiple versions of the same package\n *\n * Concurrency protection:\n * - Uses process-lock to prevent concurrent installation corruption\n * - Lock file created at ~/.socket/_dlx/<hash>/concurrency.lock\n * - Uses npm npx's concurrency.lock naming convention (5s stale, 2s touching)\n * - Prevents multiple processes from corrupting the same package installation\n *\n * Version range handling:\n * - Exact versions (1.0.0) use cache if available\n * - Range versions (^1.0.0, ~1.0.0) auto-force to get latest within range\n * - User can override with explicit force: false\n *\n * Key difference from dlx-binary.ts:\n * - dlx-binary.ts: Downloads standalone binaries from URLs\n * - dlx-package.ts: Installs npm packages from registries\n *\n * Implementation:\n * - Uses pacote for package installation (no npm CLI required)\n * - Split into downloadPackage() and executePackage() for flexibility\n * - dlxPackage() combines both for convenience\n */\n\nimport path from 'path'\n\nimport { WIN32 } from './constants/platform'\nimport { getPacoteCachePath } from './constants/packages'\nimport { generateCacheKey } from './dlx'\nimport { readJsonSync, safeMkdir } from './fs'\nimport { normalizePath } from './path'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\nimport type { SpawnExtra, SpawnOptions } from './spawn'\nimport { spawn } from './spawn'\n\nlet _fs: typeof import('fs') | undefined\n/**\n * Lazily load the fs module to avoid Webpack errors.\n * Uses non-'node:' prefixed require to prevent Webpack bundling issues.\n *\n * @returns The Node.js fs module\n * @private\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getFs() {\n if (_fs === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _fs = /*@__PURE__*/ require('node:fs')\n }\n return _fs as typeof import('fs')\n}\n\nlet _npmPackageArg: typeof import('npm-package-arg') | undefined\n/*@__NO_SIDE_EFFECTS__*/\nfunction getNpmPackageArg() {\n if (_npmPackageArg === undefined) {\n _npmPackageArg = /*@__PURE__*/ require('./external/npm-package-arg')\n }\n return _npmPackageArg as typeof import('npm-package-arg')\n}\n\nlet _libnpmexec: typeof import('./external/libnpmexec') | undefined\n/*@__NO_SIDE_EFFECTS__*/\nfunction getLibnpmexec() {\n if (_libnpmexec === undefined) {\n _libnpmexec = /*@__PURE__*/ require('./external/libnpmexec')\n }\n return _libnpmexec!\n}\n\nlet _pacote: typeof import('pacote') | undefined\n/*@__NO_SIDE_EFFECTS__*/\nfunction getPacote() {\n if (_pacote === undefined) {\n _pacote = /*@__PURE__*/ require('./external/pacote')\n }\n return _pacote as typeof import('pacote')\n}\n\n/**\n * Regex to check if a version string contains range operators.\n * Matches any version with range operators: ~, ^, >, <, =, x, X, *, spaces, or ||.\n */\nconst rangeOperatorsRegExp = /[~^><=xX* ]|\\|\\|/\n\nexport interface DownloadPackageResult {\n /** Path to the installed package directory. */\n packageDir: string\n /** Path to the binary. */\n binaryPath: string\n /** Whether the package was newly installed. */\n installed: boolean\n}\n\nexport interface DlxPackageOptions {\n /**\n * Package to install (e.g., '@cyclonedx/cdxgen@10.0.0').\n * Aligns with npx --package flag.\n */\n package: string\n\n /**\n * Binary name to execute (optional - auto-detected in most cases).\n *\n * Auto-detection logic:\n * 1. If package has only one binary, uses it automatically\n * 2. Tries user-provided binaryName\n * 3. Tries last segment of package name (e.g., 'cli' from '@socketsecurity/cli')\n * 4. Falls back to first binary\n *\n * Only needed when package has multiple binaries and auto-detection fails.\n *\n * @example\n * // Auto-detected (single binary)\n * { package: '@socketsecurity/cli' } // Finds 'socket' binary automatically\n *\n * // Explicit (multiple binaries)\n * { package: 'some-tool', binaryName: 'specific-tool' }\n */\n binaryName?: string | undefined\n\n /**\n * Force reinstallation even if package exists.\n * Aligns with npx --yes/-y flag behavior.\n */\n force?: boolean | undefined\n\n /**\n * Skip confirmation prompts (auto-approve).\n * Aligns with npx --yes/-y flag.\n */\n yes?: boolean | undefined\n\n /**\n * Suppress output (quiet mode).\n * Aligns with npx --quiet/-q and pnpm --silent/-s flags.\n */\n quiet?: boolean | undefined\n\n /**\n * Additional spawn options for the execution.\n */\n spawnOptions?: SpawnOptions | undefined\n}\n\nexport interface DlxPackageResult {\n /** Path to the installed package directory. */\n packageDir: string\n /** Path to the binary that was executed. */\n binaryPath: string\n /** Whether the package was newly installed. */\n installed: boolean\n /** The spawn promise for the running process. */\n spawnPromise: ReturnType<typeof spawn>\n}\n\n/**\n * Parse package spec into name and version using npm-package-arg.\n * Examples:\n * - 'lodash@4.17.21' \u2192 { name: 'lodash', version: '4.17.21' }\n * - '@scope/pkg@1.0.0' \u2192 { name: '@scope/pkg', version: '1.0.0' }\n * - 'lodash' \u2192 { name: 'lodash', version: undefined }\n */\nfunction parsePackageSpec(spec: string): {\n name: string\n version: string | undefined\n} {\n try {\n const npa = getNpmPackageArg()\n const parsed = npa(spec)\n\n // Extract version from different types of specs.\n // For registry specs, use fetchSpec (the version/range).\n // For git/file/etc, version will be undefined.\n const version =\n parsed.type === 'tag'\n ? parsed.fetchSpec\n : parsed.type === 'version' || parsed.type === 'range'\n ? parsed.fetchSpec\n : undefined\n\n return {\n name: parsed.name || spec,\n version,\n }\n } catch {\n // Fallback to simple parsing if npm-package-arg fails.\n const atIndex = spec.lastIndexOf('@')\n if (atIndex === -1 || spec.startsWith('@')) {\n // No version or scoped package without version.\n return { name: spec, version: undefined }\n }\n return {\n name: spec.slice(0, atIndex),\n version: spec.slice(atIndex + 1),\n }\n }\n}\n\n/**\n * Install package to ~/.socket/_dlx/<hash>/ if not already installed.\n * Uses pacote for installation (no npm CLI required).\n * Protected by process lock to prevent concurrent installation corruption.\n */\nasync function ensurePackageInstalled(\n packageName: string,\n packageSpec: string,\n force: boolean,\n): Promise<{ installed: boolean; packageDir: string }> {\n const cacheKey = generateCacheKey(packageSpec)\n const packageDir = normalizePath(path.join(getSocketDlxDir(), cacheKey))\n const installedDir = normalizePath(\n path.join(packageDir, 'node_modules', packageName),\n )\n\n // Ensure package directory exists before creating lock.\n // The lock directory will be created inside this directory.\n try {\n await safeMkdir(packageDir)\n } catch (e) {\n const code = (e as NodeJS.ErrnoException).code\n if (code === 'EACCES' || code === 'EPERM') {\n throw new Error(\n `Permission denied creating package directory: ${packageDir}\\n` +\n 'Please check directory permissions or run with appropriate access.',\n { cause: e },\n )\n }\n if (code === 'EROFS') {\n throw new Error(\n `Cannot create package directory on read-only filesystem: ${packageDir}\\n` +\n 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.',\n { cause: e },\n )\n }\n throw new Error(`Failed to create package directory: ${packageDir}`, {\n cause: e,\n })\n }\n\n // Use process lock to prevent concurrent installations.\n // Uses npm npx's concurrency.lock naming convention.\n const lockPath = path.join(packageDir, 'concurrency.lock')\n\n return await processLock.withLock(\n lockPath,\n async () => {\n const fs = getFs()\n // Double-check if already installed (unless force).\n // Another process may have installed while waiting for lock.\n if (!force && fs.existsSync(installedDir)) {\n // Verify package.json exists.\n const pkgJsonPath = path.join(installedDir, 'package.json')\n if (fs.existsSync(pkgJsonPath)) {\n return { installed: false, packageDir }\n }\n }\n\n // Use pacote to extract the package.\n // Pacote leverages npm cache when available but doesn't require npm CLI.\n const pacoteCachePath = getPacoteCachePath()\n try {\n await getPacote().extract(packageSpec, installedDir, {\n // Use consistent pacote cache path (respects npm cache locations when available).\n cache: pacoteCachePath || path.join(packageDir, '.cache'),\n })\n } catch (e) {\n const code = (e as any).code\n if (code === 'E404' || code === 'ETARGET') {\n throw new Error(\n `Package not found: ${packageSpec}\\n` +\n 'Verify the package exists on npm registry and check the version.\\n' +\n `Visit https://www.npmjs.com/package/${packageName} to see available versions.`,\n { cause: e },\n )\n }\n if (\n code === 'ENOTFOUND' ||\n code === 'ETIMEDOUT' ||\n code === 'EAI_AGAIN'\n ) {\n throw new Error(\n `Network error installing ${packageSpec}\\n` +\n 'Check your internet connection and try again.',\n { cause: e },\n )\n }\n throw new Error(\n `Failed to install package: ${packageSpec}\\n` +\n `Destination: ${installedDir}\\n` +\n 'Check npm registry connectivity or package name.',\n { cause: e },\n )\n }\n\n return { installed: true, packageDir }\n },\n {\n // Align with npm npx locking strategy.\n staleMs: 5000,\n touchIntervalMs: 2000,\n },\n )\n}\n\n/**\n * Resolve binary path with cross-platform wrapper support.\n * On Windows, checks for .cmd, .bat, .ps1, .exe wrappers in order.\n * On Unix, uses path directly.\n *\n * Aligns with npm/npx binary resolution strategy.\n */\nfunction resolveBinaryPath(basePath: string): string {\n const fs = getFs()\n\n if (!WIN32) {\n // Unix: use path directly\n return basePath\n }\n\n // Windows: check for wrappers in priority order\n // Order matches npm bin-links creation: .cmd, .ps1, .exe, then bare\n const extensions = ['.cmd', '.bat', '.ps1', '.exe', '']\n\n for (const ext of extensions) {\n const testPath = basePath + ext\n if (fs.existsSync(testPath)) {\n return testPath\n }\n }\n\n // Fallback to original path if no wrapper found\n return basePath\n}\n\n/**\n * Find the binary path for an installed package.\n * Uses npm's bin resolution strategy with user-friendly fallbacks.\n * Resolves platform-specific wrappers (.cmd, .ps1, etc.) on Windows.\n *\n * Resolution strategy (cherry-picked from libnpmexec):\n * 1. Use npm's getBinFromManifest (handles aliases and standard cases)\n * 2. Fall back to user-provided binaryName if npm's strategy fails\n * 3. Try last segment of package name as final fallback\n * 4. Use first binary as last resort\n */\nfunction findBinaryPath(\n packageDir: string,\n packageName: string,\n binaryName?: string,\n): string {\n const installedDir = normalizePath(\n path.join(packageDir, 'node_modules', packageName),\n )\n const pkgJsonPath = path.join(installedDir, 'package.json')\n\n // Read package.json to find bin entry.\n const pkgJson = readJsonSync(pkgJsonPath) as Record<string, unknown>\n const bin = pkgJson['bin']\n\n let binName: string | undefined\n let binPath: string | undefined\n\n if (typeof bin === 'string') {\n // Single binary - use it directly.\n binPath = bin\n } else if (typeof bin === 'object' && bin !== null) {\n const binObj = bin as Record<string, string>\n const binKeys = Object.keys(binObj)\n\n // If only one binary, use it regardless of name.\n if (binKeys.length === 1) {\n binName = binKeys[0]!\n binPath = binObj[binName]\n } else {\n // Multiple binaries - use npm's battle-tested resolution strategy first.\n try {\n const { getBinFromManifest } = getLibnpmexec()\n binName = getBinFromManifest({\n name: packageName,\n bin: binObj,\n _id: `${packageName}@${(pkgJson as any).version || 'unknown'}`,\n })\n binPath = binObj[binName]\n } catch {\n // npm's strategy failed - fall back to user-friendly resolution:\n // 1. User-provided binaryName\n // 2. Last segment of package name (e.g., 'cli' from '@socketsecurity/cli')\n // 3. First binary as fallback\n const lastSegment = packageName.split('/').pop()\n const candidates = [\n binaryName,\n lastSegment,\n packageName.replace(/^@[^/]+\\//, ''),\n ].filter(Boolean)\n\n for (const candidate of candidates) {\n if (candidate && binObj[candidate]) {\n binName = candidate\n binPath = binObj[candidate]\n break\n }\n }\n\n // Fallback to first binary if nothing matched.\n if (!binPath && binKeys.length > 0) {\n binName = binKeys[0]!\n binPath = binObj[binName]\n }\n }\n }\n }\n\n if (!binPath) {\n throw new Error(`No binary found for package \"${packageName}\"`)\n }\n\n const rawPath = normalizePath(path.join(installedDir, binPath))\n\n // Resolve platform-specific wrapper (Windows .cmd/.ps1/etc.)\n return resolveBinaryPath(rawPath)\n}\n\n/**\n * Execute a package via DLX - install if needed and run its binary.\n *\n * This is the Socket equivalent of npx/pnpm dlx/yarn dlx, but using\n * our own cache directory (~/.socket/_dlx) and installation logic.\n *\n * Auto-forces reinstall for version ranges to get latest within range.\n *\n * @example\n * ```typescript\n * // Download and execute cdxgen\n * const result = await dlxPackage(\n * ['--version'],\n * { package: '@cyclonedx/cdxgen@10.0.0' }\n * )\n * await result.spawnPromise\n * ```\n */\nexport async function dlxPackage(\n args: readonly string[] | string[],\n options?: DlxPackageOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): Promise<DlxPackageResult> {\n // Download the package.\n const downloadResult = await downloadPackage(options!)\n\n // Execute the binary.\n const spawnPromise = executePackage(\n downloadResult.binaryPath,\n args,\n options?.spawnOptions,\n spawnExtra,\n )\n\n return {\n ...downloadResult,\n spawnPromise,\n }\n}\n\n/**\n * Make all binaries in an installed package executable.\n * Reads the package.json bin field and makes all binaries executable (chmod 0o755).\n * Handles both single binary (string) and multiple binaries (object) formats.\n *\n * Aligns with npm's approach:\n * - Uses 0o755 permission (matches npm's cmd-shim)\n * - Reads bin field from package.json (matches npm's bin-links and libnpmexec)\n * - Handles both string and object bin formats\n *\n * References:\n * - npm cmd-shim: https://github.com/npm/cmd-shim/blob/main/lib/index.js\n * - npm getBinFromManifest: https://github.com/npm/libnpmexec/blob/main/lib/get-bin-from-manifest.js\n */\nfunction makePackageBinsExecutable(\n packageDir: string,\n packageName: string,\n): void {\n if (WIN32) {\n // Windows doesn't need chmod\n return\n }\n\n const fs = getFs()\n const installedDir = normalizePath(\n path.join(packageDir, 'node_modules', packageName),\n )\n const pkgJsonPath = path.join(installedDir, 'package.json')\n\n try {\n const pkgJson = readJsonSync(pkgJsonPath) as Record<string, unknown>\n const bin = pkgJson['bin']\n\n if (!bin) {\n return\n }\n\n const binPaths: string[] = []\n\n if (typeof bin === 'string') {\n // Single binary\n binPaths.push(bin)\n } else if (typeof bin === 'object' && bin !== null) {\n // Multiple binaries\n const binObj = bin as Record<string, string>\n binPaths.push(...Object.values(binObj))\n }\n\n // Make all binaries executable\n for (const binPath of binPaths) {\n const fullPath = normalizePath(path.join(installedDir, binPath))\n if (fs.existsSync(fullPath)) {\n try {\n fs.chmodSync(fullPath, 0o755)\n } catch {\n // Ignore chmod errors on individual binaries\n }\n }\n }\n } catch {\n // Ignore errors reading package.json or making binaries executable\n // This is non-critical functionality\n }\n}\n\n/**\n * Download and install a package without executing it.\n * This is useful for self-update or when you need the package files\n * but don't want to run the binary immediately.\n *\n * @example\n * ```typescript\n * // Install @socketsecurity/cli without running it\n * const result = await downloadPackage({\n * package: '@socketsecurity/cli@1.2.0',\n * force: true\n * })\n * console.log('Installed to:', result.packageDir)\n * console.log('Binary at:', result.binaryPath)\n * ```\n */\nexport async function downloadPackage(\n options: DlxPackageOptions,\n): Promise<DownloadPackageResult> {\n const {\n binaryName,\n force: userForce,\n package: packageSpec,\n yes,\n } = {\n __proto__: null,\n ...options,\n } as DlxPackageOptions\n\n // Parse package spec.\n const { name: packageName, version: packageVersion } =\n parsePackageSpec(packageSpec)\n\n // Determine force behavior:\n // 1. Explicit force takes precedence\n // 2. --yes flag implies force (auto-approve/skip prompts)\n // 3. Version ranges auto-force to get latest\n const isVersionRange =\n packageVersion !== undefined && rangeOperatorsRegExp.test(packageVersion)\n const force =\n userForce !== undefined ? userForce : yes === true ? true : isVersionRange\n\n // Build full package spec for installation.\n const fullPackageSpec = packageVersion\n ? `${packageName}@${packageVersion}`\n : packageName\n\n // Ensure package is installed.\n const { installed, packageDir } = await ensurePackageInstalled(\n packageName,\n fullPackageSpec,\n force,\n )\n\n // Find binary path.\n const binaryPath = findBinaryPath(packageDir, packageName, binaryName)\n\n // Make all binaries in the package executable on Unix systems.\n makePackageBinsExecutable(packageDir, packageName)\n\n return {\n binaryPath,\n installed,\n packageDir,\n }\n}\n\n/**\n * Execute a package's binary with cross-platform shell handling.\n * The package must already be installed (use downloadPackage first).\n *\n * On Windows, script files (.bat, .cmd, .ps1) require shell: true.\n * Matches npm/npx execution behavior.\n *\n * @example\n * ```typescript\n * // Execute an already-installed package\n * const downloaded = await downloadPackage({ package: 'cowsay@1.5.0' })\n * const result = await executePackage(\n * downloaded.binaryPath,\n * ['Hello World'],\n * { stdio: 'inherit' }\n * )\n * ```\n */\nexport function executePackage(\n binaryPath: string,\n args: readonly string[] | string[],\n spawnOptions?: SpawnOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): ReturnType<typeof spawn> {\n // On Windows, script files (.bat, .cmd, .ps1) require shell: true\n // because they are not executable on their own and must be run through cmd.exe.\n // .exe files are actual binaries and don't need shell mode.\n const needsShell = WIN32 && /\\.(?:bat|cmd|ps1)$/i.test(binaryPath)\n\n const finalOptions = needsShell\n ? {\n ...spawnOptions,\n shell: true,\n }\n : spawnOptions\n\n return spawn(binaryPath, args, finalOptions, spawnExtra)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_path", "path"]
7
7
  }
@@ -2,7 +2,7 @@
2
2
  * Bundled from @socketregistry/yocto-spinner
3
3
  * This is a zero-dependency bundle created by esbuild.
4
4
  */
5
- var $=Object.create;var a=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var L=Object.getPrototypeOf,P=Object.prototype.hasOwnProperty;var c=(s,t)=>a(s,"name",{value:t,configurable:!0});var I=(s,t)=>()=>(t||s((t={exports:{}}).exports,t),t.exports),k=(s,t)=>{for(var r in t)a(s,r,{get:t[r],enumerable:!0})},x=(s,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of O(t))!P.call(s,o)&&o!==r&&a(s,o,{get:()=>t[o],enumerable:!(n=N(t,o))||n.enumerable});return s};var q=(s,t,r)=>(r=s!=null?$(L(s)):{},x(t||!s||!s.__esModule?a(r,"default",{value:s,enumerable:!0}):r,s)),U=s=>x(a({},"__esModule",{value:!0}),s);var w=I((z,v)=>{var W=require("node:tty"),A=W?.WriteStream?.prototype?.hasColors?.()??!1,i=c((s,t)=>{if(!A)return o=>o;let r=`\x1B[${s}m`,n=`\x1B[${t}m`;return o=>{let h=o+"",u=h.indexOf(n);if(u===-1)return r+h+n;let g=r,f=0,G=(t===22?n:"")+r;for(;u!==-1;)g+=h.slice(f,u)+G,f=u+n.length,u=h.indexOf(n,f);return g+=h.slice(f)+n,g}},"format"),e={};e.reset=i(0,0);e.bold=i(1,22);e.dim=i(2,22);e.italic=i(3,23);e.underline=i(4,24);e.overline=i(53,55);e.inverse=i(7,27);e.hidden=i(8,28);e.strikethrough=i(9,29);e.black=i(30,39);e.red=i(31,39);e.green=i(32,39);e.yellow=i(33,39);e.blue=i(34,39);e.magenta=i(35,39);e.cyan=i(36,39);e.white=i(37,39);e.gray=i(90,39);e.bgBlack=i(40,49);e.bgRed=i(41,49);e.bgGreen=i(42,49);e.bgYellow=i(43,49);e.bgBlue=i(44,49);e.bgMagenta=i(45,49);e.bgCyan=i(46,49);e.bgWhite=i(47,49);e.bgGray=i(100,49);e.redBright=i(91,39);e.greenBright=i(92,39);e.yellowBright=i(93,39);e.blueBright=i(94,39);e.magentaBright=i(95,39);e.cyanBright=i(96,39);e.whiteBright=i(97,39);e.bgRedBright=i(101,49);e.bgGreenBright=i(102,49);e.bgYellowBright=i(103,49);e.bgBlueBright=i(104,49);e.bgMagentaBright=i(105,49);e.bgCyanBright=i(106,49);e.bgWhiteBright=i(107,49);v.exports=e});var R=I((Q,_)=>{"use strict";var p;function F(){return p===void 0&&(p={frames:E()?["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]:["-","\\","|","/"],interval:80}),p}c(F,"getDefaultSpinner");var m;function V(){if(m===void 0){let s=E(),t=M();m={error:t.red(s?"✖":"×"),info:t.blue(s?"ℹ":"i"),success:t.green(s?"✔":"√"),warning:t.yellow(s?"⚠":"‼")}}return m}c(V,"getLogSymbols");var b;function y(){return b===void 0&&(b=require("process")),b}c(y,"getProcess");var C;function M(){return C===void 0&&(C={...w()}),C}c(M,"getYoctocolors");var S;function Y(){if(S===void 0){let{env:s}=y();S=s.TERM!=="dumb"&&!("CI"in s)}return S}c(Y,"isProcessInteractive");var l;function E(){if(l===void 0){let s=y();if(s.platform!=="win32")return l=s.env.TERM!=="linux",l;let{env:t}=s;if(t.WT_SESSION||t.TERMINUS_SUBLIME||t.ConEmuTask==="{cmd::Cmder}")return l=!0,l;let{TERM:r,TERM_PROGRAM:n}=t;l=n==="Terminus-Sublime"||n==="vscode"||r==="xterm-256color"||r==="alacritty"||r==="rxvt-unicode"||r==="rxvt-unicode-256color"||t.TERMINAL_EMULATOR==="JetBrains-JediTerm"}return l}c(E,"isUnicodeSupported");var T;function D(s){return T===void 0&&(T=require("util").stripVTControlCharacters),T(s)}c(D,"stripVTControlCharacters");var B=class{static{c(this,"YoctoSpinner")}#n;#o=-1;#r;#a;#t="";#f;#e;#d=!1;#p=0;#g=0;#i;#s;#h;constructor(t={}){let r={__proto__:null,...t},n=r.spinner??F(),o=r.stream??y().stderr;this.#a=n.frames,this.#f=n.interval,this.#s=t.text??"",this.#i=o??process.stderr,this.#n=t.color??"cyan",this.#e=!!o.isTTY&&Y(),this.#r=this.#m.bind(this)}#m(t){this.isSpinning&&this.stop();let r=t==="SIGINT"?130:t==="SIGTERM"?143:1;process.exit(r)}#b(){this.#e&&this.#u("\x1B[?25l")}#C(t){let r=this.#i.columns??80,n=D(t).split(`
6
- `),o=0;for(let h of n)o+=Math.max(1,Math.ceil(h.length/r));return o}#c(){let t=Date.now();(this.#o===-1||t-this.#p>=this.#f)&&(this.#o=++this.#o%this.#a.length,this.#p=t);let r=M(),n=r[this.#n]??r.cyan,o=this.#a[this.#o],h=`${n(o)} ${this.#s}`;h&&(this.#t.length&&(h=`${this.#t}${h}`),this.#e||(h+=`
7
- `)),this.clear(),this.#u(h),this.#e&&(this.#g=this.#C(h))}#S(){this.#e&&this.#u("\x1B[?25h")}#T(){process.once("SIGINT",this.#r),process.once("SIGTERM",this.#r)}#l(t,r){let n=V();return this.stop(`${n[t]} ${r??this.#s}`)}#u(t){this.#i.write(t)}#B(){process.off("SIGINT",this.#r),process.off("SIGTERM",this.#r)}get color(){return this.#n}set color(t){this.#n=t,this.#c()}get isSpinning(){return this.#d}get text(){return this.#s}set text(t){this.#s=t??"",this.#c()}clear(){if(!this.#e)return this;this.#i.cursorTo(0);for(let t=0;t<this.#g;t++)t>0&&this.#i.moveCursor(0,-1),this.#i.clearLine(1);return this.#g=0,this}dedent(t=2){return this.#t=this.#t.slice(0,-t),this}error(t){return this.#l("error",t)}indent(t=2){return this.#t+=" ".repeat(t),this}info(t){return this.#l("info",t)}resetIndent(){return this.#t="",this}start(t){return t&&(this.#s=t),this.isSpinning?this:(this.#d=!0,this.#b(),this.#c(),this.#T(),this.#e&&(this.#h=setInterval(()=>{this.#c()},this.#f)),this)}stop(t){return this.isSpinning?(this.#d=!1,this.#h&&(clearInterval(this.#h),this.#h=void 0),this.#S(),this.clear(),this.#B(),t&&this.#u(`${this.#t}${t}
8
- `),this):this}success(t){return this.#l("success",t)}warning(t){return this.#l("warning",t)}};_.exports=c(function(t){return new B(t)},"yoctoSpinner")});var H={};k(H,{default:()=>d.default,"module.exports":()=>d.default});module.exports=U(H);var d=q(R(),1);0&&(module.exports={"module.exports":null});
5
+ var A=Object.create;var f=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var U=Object.getOwnPropertyNames;var P=Object.getPrototypeOf,k=Object.prototype.hasOwnProperty;var u=(e,t)=>f(e,"name",{value:t,configurable:!0});var B=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),L=(e,t)=>{for(var s in t)f(e,s,{get:t[s],enumerable:!0})},w=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of U(t))!k.call(e,o)&&o!==s&&f(e,o,{get:()=>t[o],enumerable:!(n=N(t,o))||n.enumerable});return e};var q=(e,t,s)=>(s=e!=null?A(P(e)):{},w(t||!e||!e.__esModule?f(s,"default",{value:e,enumerable:!0}):s,e)),W=e=>w(f({},"__esModule",{value:!0}),e);var v=B((et,I)=>{var D=require("node:tty"),V=D?.WriteStream?.prototype?.hasColors?.()??!1,i=u((e,t)=>{if(!V)return o=>o;let s=`\x1B[${e}m`,n=`\x1B[${t}m`;return o=>{let h=o+"",l=h.indexOf(n);if(l===-1)return s+h+n;let a=s,d=0,O=(t===22?n:"")+s;for(;l!==-1;)a+=h.slice(d,l)+O,d=l+n.length,l=h.indexOf(n,d);return a+=h.slice(d)+n,a}},"format"),r={};r.reset=i(0,0);r.bold=i(1,22);r.dim=i(2,22);r.italic=i(3,23);r.underline=i(4,24);r.overline=i(53,55);r.inverse=i(7,27);r.hidden=i(8,28);r.strikethrough=i(9,29);r.black=i(30,39);r.red=i(31,39);r.green=i(32,39);r.yellow=i(33,39);r.blue=i(34,39);r.magenta=i(35,39);r.cyan=i(36,39);r.white=i(37,39);r.gray=i(90,39);r.bgBlack=i(40,49);r.bgRed=i(41,49);r.bgGreen=i(42,49);r.bgYellow=i(43,49);r.bgBlue=i(44,49);r.bgMagenta=i(45,49);r.bgCyan=i(46,49);r.bgWhite=i(47,49);r.bgGray=i(100,49);r.redBright=i(91,39);r.greenBright=i(92,39);r.yellowBright=i(93,39);r.blueBright=i(94,39);r.magentaBright=i(95,39);r.cyanBright=i(96,39);r.whiteBright=i(97,39);r.bgRedBright=i(101,49);r.bgGreenBright=i(102,49);r.bgYellowBright=i(103,49);r.bgBlueBright=i(104,49);r.bgMagentaBright=i(105,49);r.bgCyanBright=i(106,49);r.bgWhiteBright=i(107,49);I.exports=r});var F=B((it,G)=>{"use strict";var{isArray:M}=Array,{defineProperty:Y}=Object,j=80,p;function R(){return p===void 0&&(p={frames:$()?["⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"]:["-","\\","|","/"],interval:80}),p}u(R,"getDefaultSpinner");var m;function z(){if(m===void 0){let e=$(),t=E();m={error:t.red(e?"✖":"×"),info:t.blue(e?"ℹ":"i"),success:t.green(e?"✔":"√"),warning:t.yellow(e?"⚠":"‼")}}return m}u(z,"getLogSymbols");var b;function C(){return b===void 0&&(b=require("node:process")),b}u(C,"getProcess");var y;function E(){return y===void 0&&(y={...v()}),y}u(E,"getYoctocolors");var S;function H(){if(S===void 0){let{env:e}=C();S=e.TERM!=="dumb"&&!("CI"in e)}return S}u(H,"isProcessInteractive");var c;function $(){if(c===void 0){let e=C();if(e.platform!=="win32")return c=e.env.TERM!=="linux",c;let{env:t}=e;if(t.WT_SESSION||t.TERMINUS_SUBLIME||t.ConEmuTask==="{cmd::Cmder}")return c=!0,c;let{TERM:s,TERM_PROGRAM:n}=t;c=n==="Terminus-Sublime"||n==="vscode"||s==="xterm-256color"||s==="alacritty"||s==="rxvt-unicode"||s==="rxvt-unicode-256color"||t.TERMINAL_EMULATOR==="JetBrains-JediTerm"}return c}u($,"isUnicodeSupported");var T;function J(e){return T===void 0&&(T=require("node:util").stripVTControlCharacters),T(e)}u(J,"stripVTControlCharacters");function K(e,t){let{frames:s}=e,n=s?.length??0;return t>-1&&t<n?s[t]:""}u(K,"getFrame");function Q(e){let{frames:t}=e,s=t?.length??0;return s<1?1:s}u(Q,"getFrameCount");function x(e){return typeof e=="string"?e.trimStart():""}u(x,"normalizeText");var _=class e{static{u(this,"YoctoSpinner")}#t;#h=-1;#o;#r="";#e;#l=!1;#b=0;#d=0;#g;#p;#m=!1;#i;#n;#s;#u;static spinners={get default(){return R()},set default(t){Y(this,"default",{__proto__:null,configurable:!0,enumerable:!0,value:t,writable:!0})},ci:{frames:[""],interval:2147483647}};constructor(t={}){let s={__proto__:null,...t},n=s.stream??C().stderr;this.#i=s.spinner??e.spinners.default??R(),this.#s=x(t.text),this.#n=n??process.stderr;let o=t.color??"cyan";if(M(o)&&(o.length!==3||!o.every(h=>typeof h=="number"&&h>=0&&h<=255)))throw new TypeError("RGB color must be an array of 3 numbers between 0 and 255");this.#t=o,this.#e=!!n.isTTY&&H(),this.#o=this.#y.bind(this),this.#g=t.onFrameUpdate,this.#p=t.onRenderFrame}#y(t){this.isSpinning&&this.stop();let s=t==="SIGINT"?130:t==="SIGTERM"?143:1;process.exit(s)}#S(){this.#e&&this.#f("\x1B[?25l")}#T(t){let s=this.#n.columns??j,n=J(t).split(`
6
+ `),o=0;for(let h of n)o+=Math.max(1,Math.ceil(h.length/s));return o}#c(){if(!this.#l)return;let t=Date.now(),s=!1;if((this.#h===-1||t-this.#b>=this.#i.interval)&&(s=!0,this.#h=++this.#h%Q(this.#i),this.#b=t),s&&typeof this.#g=="function"){this.#m=!0;try{this.#g()}finally{this.#m=!1}}let n=E(),o=M(this.#t)?a=>`\x1B[38;2;${this.#t[0]};${this.#t[1]};${this.#t[2]}m${a}\x1B[39m`:n[this.#t]??n.cyan,h=K(this.#i,this.#h),l;typeof this.#p=="function"?l=this.#p(h,this.#s,o):l=`${h?`${o(h)} `:""}${this.#s}`,l&&(this.#r.length&&(l=`${this.#r}${l}`),this.#e||(l+=`
7
+ `)),this.#e&&this.clear(),l&&this.#f(l),this.#e&&(this.#d=this.#T(l))}#x(){this.#e&&this.#f("\x1B[?25h")}#_(){process.once("SIGINT",this.#o),process.once("SIGTERM",this.#o)}#a(t,s){let n=z();return this.stop(`${n[t]} ${s??this.#s}`)}#f(t){this.#n.write(t)}#C(){process.off("SIGINT",this.#o),process.off("SIGTERM",this.#o)}get color(){return this.#t}set color(t){this.#t=t,this.#c()}get isSpinning(){return this.#l}get spinner(){return this.#i}set spinner(t){this.#i=t}get text(){return this._textMethod?this._textMethod:this.#s}set text(t){if(this._textMethod&&!this._inTextSetter){this._inTextSetter=!0;try{this._textMethod(t)}finally{this._inTextSetter=!1}return}this.#s=x(t),this.#m||this.#c()}clear(){if(!this.#e)return this;this.#n.cursorTo(0);for(let t=0;t<this.#d;t+=1)t>0&&this.#n.moveCursor(0,-1),this.#n.clearLine(1);return this.#d=0,this}dedent(t=2){return this.#r=this.#r.slice(0,-t),this}error(t){return this.#a("error",t)}indent(t=2){return this.#r+=" ".repeat(t),this}info(t){return this.#a("info",t)}resetIndent(){return this.#r="",this}start(t){let s=x(t);return s&&(this.#s=s),this.isSpinning?this:(this.#l=!0,this.#S(),this.#c(),this.#_(),this.#e&&(this.#u=setInterval(()=>{this.#c()},this.#i.interval)),this)}stop(t){return this.isSpinning?(this.#u&&(clearInterval(this.#u),this.#u=void 0),this.#l=!1,this.#x(),this.clear(),this.#C(),t&&this.#f(`${this.#r}${t}
8
+ `),this):this}success(t){return this.#a("success",t)}warning(t){return this.#a("warning",t)}};G.exports=u(function(t){return new _(t)},"yoctoSpinner")});var X={};L(X,{default:()=>g.default,"module.exports":()=>g.default});module.exports=W(X);var g=q(F(),1);0&&(module.exports={"module.exports":null});
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Package manifest interface (subset of package.json)
3
+ */
4
+ export interface PackageManifest {
5
+ name: string
6
+ bin?: string | Record<string, string>
7
+ _id?: string
8
+ }
9
+
10
+ /**
11
+ * Get the binary name to execute from a package manifest.
12
+ * Uses npm's bin resolution strategy:
13
+ * 1. If all bin values are identical (aliases), use first key
14
+ * 2. Try unscoped package name (e.g., 'cli' from '@scope/cli')
15
+ * 3. Throw error if cannot determine
16
+ *
17
+ * @param manifest - Package manifest object
18
+ * @returns Binary name to execute
19
+ * @throws Error if binary cannot be determined
20
+ *
21
+ * @example
22
+ * ```typescript
23
+ * const manifest = { name: '@scope/pkg', bin: { 'pkg': './bin/cli.js' } }
24
+ * getBinFromManifest(manifest) // Returns 'pkg'
25
+ * ```
26
+ */
27
+ export function getBinFromManifest(manifest: PackageManifest): string
28
+
29
+ declare const libnpmexec: {
30
+ getBinFromManifest: typeof getBinFromManifest
31
+ }
32
+
33
+ export = libnpmexec
package/dist/ipc.js CHANGED
@@ -129,7 +129,7 @@ async function cleanupIpcStubs(appName) {
129
129
  const files = await import_fs.promises.readdir(stubDir);
130
130
  const now = Date.now();
131
131
  const maxAgeMs = 5 * 60 * 1e3;
132
- await Promise.all(
132
+ await Promise.allSettled(
133
133
  files.map(async (file) => {
134
134
  if (file.startsWith("stub-") && file.endsWith(".json")) {
135
135
  const filePath = import_path.default.join(stubDir, file);