From 30c1f1b8b561882cdd333986213bab52f5b39d64 Mon Sep 17 00:00:00 2001 From: jdalton Date: Sat, 2 May 2026 11:50:07 -0400 Subject: [PATCH] chore(publish): strip iocraft download/publish pipeline MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The @socketaddon/iocraft* packages now publish from a dedicated repo (SocketDev/socket-addon). socket-cli's role narrows to *consuming* @socketaddon/iocraft as a runtime dep — it no longer downloads .node binaries from socket-btm or republishes them to npm. Removed: - scripts/download-iocraft-binaries.mts - packages/package-builder/scripts/publish-socketaddon-placeholders.mts - packages/package-builder/scripts/PUBLISHING-PLACEHOLDERS.md - packages/package-builder/test-iocraft-package.mts Edited .github/workflows/provenance.yml: - removed the 'iocraft' workflow_dispatch input - removed the iocraft version/tag computation in the 'Get versions' step - removed the four iocraft steps (Download binaries, Copy binaries, Publish main, Publish platform packages) - removed the iocraft branches in the Summary step Net change: 1088 lines deleted, 1 added. Dev plumbing (templates/socketaddon-{main,package}/, generate-socketaddon- packages.mts, setup-iocraft-dev.mts, the cli/package.json `file:` link to the dev build dir, the CI shim heredocs in ci.yml, the iocraft test exclusion list in vitest.config.mts) is intentionally untouched — socket-cli still needs @socketaddon/iocraft installable at install time for tests + dev. The follow-up commit replaces the `file:` link with a registry version once SocketDev/socket-addon publishes a real version. Pre-commit tests skipped (DISABLE_PRECOMMIT_TEST=1) — the iocraft renderer tests require a real native iocraft.node which this worktree doesn't have. CI excludes those same tests via vitest.config.mts. --- .github/workflows/provenance.yml | 99 +--- .../scripts/PUBLISHING-PLACEHOLDERS.md | 139 ----- .../publish-socketaddon-placeholders.mts | 532 ------------------ .../package-builder/test-iocraft-package.mts | 81 --- scripts/download-iocraft-binaries.mts | 238 -------- 5 files changed, 1 insertion(+), 1088 deletions(-) delete mode 100644 packages/package-builder/scripts/PUBLISHING-PLACEHOLDERS.md delete mode 100644 packages/package-builder/scripts/publish-socketaddon-placeholders.mts delete mode 100644 packages/package-builder/test-iocraft-package.mts delete mode 100755 scripts/download-iocraft-binaries.mts diff --git a/.github/workflows/provenance.yml b/.github/workflows/provenance.yml index 77a436b53..ef6f184e2 100644 --- a/.github/workflows/provenance.yml +++ b/.github/workflows/provenance.yml @@ -23,10 +23,6 @@ on: description: 'socket (+ 8 bins)' type: boolean default: true - iocraft: - description: '@socketaddon/iocraft (+ 8 platforms)' - type: boolean - default: false permissions: contents: read @@ -155,12 +151,7 @@ jobs: echo "cli_version=$CLI_VERSION" >> $GITHUB_OUTPUT echo "Socket CLI version: $CLI_VERSION" - # iocraft ecosystem version (independent) - IOCRAFT_VERSION=$(node -p "require('./packages/package-builder/templates/socketaddon-main/package.json').version") - echo "iocraft_version=$IOCRAFT_VERSION" >> $GITHUB_OUTPUT - echo "iocraft version: $IOCRAFT_VERSION" - - # Determine npm dist-tags based on versions + # Determine npm dist-tags based on version if [[ "$CLI_VERSION" =~ -pre\. ]]; then CLI_TAG="pre" else @@ -169,14 +160,6 @@ jobs: echo "cli_tag=$CLI_TAG" >> $GITHUB_OUTPUT echo "Socket CLI dist-tag: $CLI_TAG" - if [[ "$IOCRAFT_VERSION" =~ -pre\. ]]; then - IOCRAFT_TAG="pre" - else - IOCRAFT_TAG="latest" - fi - echo "iocraft_tag=$IOCRAFT_TAG" >> $GITHUB_OUTPUT - echo "iocraft dist-tag: $IOCRAFT_TAG" - # Download and publish binary packages. - name: Download binaries if: ${{ inputs.socket }} @@ -280,79 +263,6 @@ jobs: cd "$PKG_DIR" npm publish --provenance --access public --no-git-checks --tag "$TAG" - # Download iocraft binaries from socket-btm. - - name: Download iocraft binaries - if: ${{ inputs.iocraft }} - run: | - echo "Downloading iocraft .node binaries for all platforms..." - node scripts/download-iocraft-binaries.mts - - # Copy iocraft binaries to package directories. - - name: Copy iocraft binaries to packages - if: ${{ inputs.iocraft }} - shell: bash - run: | - set -euo pipefail - - # Get platform targets from single source of truth. - PLATFORMS_STR=$(node scripts/get-platform-targets.mts) - read -ra PLATFORMS <<< "$PLATFORMS_STR" - - for target in "${PLATFORMS[@]}"; do - echo "Copying iocraft.node for ${target}..." - - # Source path (downloaded binary). - SRC_PATH="packages/build-infra/build/downloaded/iocraft/${target}/iocraft.node" - - # Destination path (package directory). - PKG_DIR="packages/package-builder/build/prod/out/socketaddon-iocraft-${target}" - mkdir -p "$PKG_DIR" - cp "$SRC_PATH" "$PKG_DIR/iocraft.node" - - echo "Copied to ${PKG_DIR}/iocraft.node" - done - - # Publish @socketaddon/iocraft packages (main + platform-specific). - - name: Publish @socketaddon/iocraft main package - if: ${{ inputs.iocraft && !inputs.dry-run }} - env: - VERSION: ${{ steps.version.outputs.iocraft_version }} - TAG: ${{ steps.version.outputs.iocraft_tag }} - run: | - PKG_DIR="packages/package-builder/build/prod/out/socketaddon-iocraft" - node scripts/prepare-package-for-publish.mts "$PKG_DIR" "$VERSION" - cd "$PKG_DIR" - npm publish --provenance --access public --no-git-checks --tag "$TAG" - - - name: Publish @socketaddon/iocraft platform packages - if: ${{ inputs.iocraft && !inputs.dry-run }} - shell: bash - env: - VERSION: ${{ steps.version.outputs.iocraft_version }} - TAG: ${{ steps.version.outputs.iocraft_tag }} - run: | - set -euo pipefail - - # Get platform targets from single source of truth. - PLATFORMS_STR=$(node scripts/get-platform-targets.mts) - read -ra PLATFORMS <<< "$PLATFORMS_STR" - - for target in "${PLATFORMS[@]}"; do - echo "::group::Publishing @socketaddon/iocraft-${target}" - - PKG_DIR="packages/package-builder/build/prod/out/socketaddon-iocraft-${target}" - - # Prepare package. - node scripts/prepare-package-for-publish.mts "$PKG_DIR" "$VERSION" - - # Publish. - cd "$PKG_DIR" - npm publish --provenance --access public --no-git-checks --tag "$TAG" - cd - - - echo "::endgroup::" - done - - name: Summary # zizmor: ignore[template-injection] run: | @@ -361,9 +271,6 @@ jobs: if [ "${{ inputs.socket }}" = "true" ] || [ "${{ inputs.cli }}" = "true" ] || [ "${{ inputs.cli-sentry }}" = "true" ]; then echo "Socket CLI version: \`${{ steps.version.outputs.cli_version }}\` (tag: \`${{ steps.version.outputs.cli_tag }}\`)" >> $GITHUB_STEP_SUMMARY fi - if [ "${{ inputs.iocraft }}" = "true" ]; then - echo "iocraft version: \`${{ steps.version.outputs.iocraft_version }}\` (tag: \`${{ steps.version.outputs.iocraft_tag }}\`)" >> $GITHUB_STEP_SUMMARY - fi echo "" >> $GITHUB_STEP_SUMMARY if [ "${{ inputs.dry-run }}" = "true" ]; then echo "**Dry run - nothing was published**" >> $GITHUB_STEP_SUMMARY @@ -381,8 +288,4 @@ jobs: if [ "${{ inputs.cli-sentry }}" = "true" ]; then echo "- @socketsecurity/cli-with-sentry" >> $GITHUB_STEP_SUMMARY fi - if [ "${{ inputs.iocraft }}" = "true" ]; then - echo "- @socketaddon/iocraft (main)" >> $GITHUB_STEP_SUMMARY - echo "- @socketaddon/iocraft-* (8 platforms)" >> $GITHUB_STEP_SUMMARY - fi fi diff --git a/packages/package-builder/scripts/PUBLISHING-PLACEHOLDERS.md b/packages/package-builder/scripts/PUBLISHING-PLACEHOLDERS.md deleted file mode 100644 index 11c32f5a9..000000000 --- a/packages/package-builder/scripts/PUBLISHING-PLACEHOLDERS.md +++ /dev/null @@ -1,139 +0,0 @@ -# Publishing @socketaddon/iocraft Placeholder Packages - -This guide shows how to publish placeholder packages for @socketaddon/iocraft to reserve the namespace on npm. - -## Available Packages - -Run this to see all available packages: - -```bash -node scripts/publish-socketaddon-placeholders.mjs --list -``` - -### Main Package -- `--main` → `@socketaddon/iocraft` - -### Platform-Specific Packages -- `--darwin-arm64` → `@socketaddon/iocraft-darwin-arm64` (macOS Apple Silicon) -- `--darwin-x64` → `@socketaddon/iocraft-darwin-x64` (macOS Intel) -- `--linux-arm64` → `@socketaddon/iocraft-linux-arm64` (Linux ARM64 glibc) -- `--linux-arm64-musl` → `@socketaddon/iocraft-linux-arm64-musl` (Linux ARM64 musl) -- `--linux-x64` → `@socketaddon/iocraft-linux-x64` (Linux x64 glibc) -- `--linux-x64-musl` → `@socketaddon/iocraft-linux-x64-musl` (Linux x64 musl) -- `--win-arm64` → `@socketaddon/iocraft-win-arm64` (Windows ARM64) -- `--win-x64` → `@socketaddon/iocraft-win-x64` (Windows x64) - -## Usage - -### Publish Individual Packages - -Publish just the main package: -```bash -node scripts/publish-socketaddon-placeholders.mjs --main -``` - -Publish a specific platform: -```bash -node scripts/publish-socketaddon-placeholders.mjs --darwin-arm64 -``` - -Publish multiple specific packages: -```bash -node scripts/publish-socketaddon-placeholders.mjs --main --darwin-arm64 --linux-x64 -``` - -### Publish All Packages - -Publish all 9 packages at once: -```bash -node scripts/publish-socketaddon-placeholders.mjs -``` - -### Dry Run Mode - -Test what would be published without actually publishing: -```bash -# Dry run for single package -node scripts/publish-socketaddon-placeholders.mjs --main --dry-run - -# Dry run for all packages -node scripts/publish-socketaddon-placeholders.mjs --dry-run -``` - -## Prerequisites - -You must be authenticated to npm with access to publish to the `@socketaddon` scope: - -```bash -npm login -``` - -Ensure your account is a maintainer of the @socketaddon organization. - -## Publishing Individual Packages (Step-by-Step) - -Here's how to publish each package one at a time: - -```bash -# 1. Main package -node scripts/publish-socketaddon-placeholders.mjs --main - -# 2. macOS packages -node scripts/publish-socketaddon-placeholders.mjs --darwin-arm64 -node scripts/publish-socketaddon-placeholders.mjs --darwin-x64 - -# 3. Linux glibc packages -node scripts/publish-socketaddon-placeholders.mjs --linux-arm64 -node scripts/publish-socketaddon-placeholders.mjs --linux-x64 - -# 4. Linux musl packages -node scripts/publish-socketaddon-placeholders.mjs --linux-arm64-musl -node scripts/publish-socketaddon-placeholders.mjs --linux-x64-musl - -# 5. Windows packages -node scripts/publish-socketaddon-placeholders.mjs --win-arm64 -node scripts/publish-socketaddon-placeholders.mjs --win-x64 -``` - -## What Gets Published - -Each placeholder package contains: -- `package.json` with version 0.0.0 -- `README.md` explaining it's a placeholder -- Proper metadata (os, cpu, keywords, etc.) - -The placeholders reserve the namespace until the real packages with native bindings are ready. - -## Checking Existing Packages - -The script automatically checks if a package already exists and skips it: - -```bash -# This will skip packages that already exist on npm -node scripts/publish-socketaddon-placeholders.mjs --main -# Output: "Package already exists: @socketaddon/iocraft" -``` - -## Troubleshooting - -**Authentication Error:** -``` -npm ERR! code E403 -npm ERR! 403 Forbidden -``` -Solution: Run `npm login` and ensure you have publish access to @socketaddon scope. - -**Package Already Exists:** -``` -npm ERR! code E403 -npm ERR! You cannot publish over the previously published versions -``` -This is expected if the placeholder was already published. The script will detect this and skip it. - -## After Publishing - -Verify the published packages on npm: -- Main: https://www.npmjs.com/package/@socketaddon/iocraft -- Platforms: https://www.npmjs.com/package/@socketaddon/iocraft-darwin-arm64 (etc.) - -The placeholders will show version 0.0.0 and a message explaining they're reserving the namespace. diff --git a/packages/package-builder/scripts/publish-socketaddon-placeholders.mts b/packages/package-builder/scripts/publish-socketaddon-placeholders.mts deleted file mode 100644 index 2375c3932..000000000 --- a/packages/package-builder/scripts/publish-socketaddon-placeholders.mts +++ /dev/null @@ -1,532 +0,0 @@ -/** - * Publish placeholder packages for @socketaddon/iocraft platform binaries. - * - * This reserves the namespace on npm before the real packages are ready. - * Pattern follows @socketbin/cli-* placeholder packages. - * - * Usage: - * # Publish all packages - * node scripts/publish-socketaddon-placeholders.mts - * node scripts/publish-socketaddon-placeholders.mts --dry-run - * - * # Publish specific packages - * node scripts/publish-socketaddon-placeholders.mts --main - * node scripts/publish-socketaddon-placeholders.mts --darwin-arm64 - * node scripts/publish-socketaddon-placeholders.mts --linux-x64-musl - * node scripts/publish-socketaddon-placeholders.mts --win-x64 - * - * # Publish multiple specific packages - * node scripts/publish-socketaddon-placeholders.mts --main --darwin-arm64 --linux-x64 - * - * # List available packages - * node scripts/publish-socketaddon-placeholders.mts --list - */ - -import { spawnSync } from 'node:child_process' -import { existsSync, promises as fs } from 'node:fs' -import path from 'node:path' - -import { PLATFORM_CONFIGS } from 'build-infra/lib/platform-targets' -import { getDefaultLogger } from '@socketsecurity/lib/logger' - -const logger = getDefaultLogger() - -const isDryRun = process.argv.includes('--dry-run') -const showList = process.argv.includes('--list') - -/** - * Get list of requested platforms from command line args. - */ -function getRequestedPlatforms() { - const args = process.argv.slice(2).filter((arg) => !arg.startsWith('--dry-run')) - - // If --list flag, return empty array (handled separately) - if (showList) { - return [] - } - - // If no platform flags, publish all - const platformFlags = args.filter((arg) => arg.startsWith('--')) - if (!platformFlags.length) { - return 'all' - } - - const requested = [] - - // Check for --main flag - if (args.includes('--main')) { - requested.push('main') - } - - // Check for platform-specific flags - for (const config of PLATFORM_CONFIGS) { - const { arch, libc, releasePlatform } = config - const muslSuffix = libc === 'musl' ? '-musl' : '' - const platformId = `${releasePlatform}-${arch}${muslSuffix}` - - if (args.includes(`--${platformId}`)) { - requested.push(platformId) - } - } - - return requested -} - -/** - * Platform-specific description suffixes. - */ -const PLATFORM_DESCRIPTIONS = { - __proto__: null, - 'darwin-arm64': 'macOS Apple Silicon (M1, M2, M3)', - 'darwin-x64': 'macOS Intel', - 'linux-arm64': 'Linux ARM64 (glibc)', - 'linux-arm64-musl': 'Linux ARM64 (musl/Alpine)', - 'linux-x64': 'Linux x64 (glibc)', - 'linux-x64-musl': 'Linux x64 (musl/Alpine)', - 'win-arm64': 'Windows ARM64', - 'win-x64': 'Windows x64', -} - -/** - * OS mapping for package.json os field. - */ -const OS_MAP = { - __proto__: null, - darwin: 'darwin', - linux: 'linux', - win: 'win32', -} - -/** - * Generate README content for a placeholder package. - */ -function generateReadme(packageName, platformDesc) { - return `# ${packageName} - -**PLACEHOLDER PACKAGE** - -This is a placeholder package to reserve the namespace for iocraft Node.js bindings. - -The real package with native bindings will be published soon. - -## What is this? - -This package will contain native iocraft bindings for ${platformDesc}. - -iocraft is a Rust-based TUI library that provides fast, beautiful terminal interfaces with React-like declarative syntax. - -## Installation - -Once the real package is available, it will be installed automatically as an optional dependency of: - -\`\`\`bash -npm install @socketaddon/iocraft -\`\`\` - -## More Information - -- Repository: https://github.com/SocketDev/socket-cli -- Issues: https://github.com/SocketDev/socket-cli/issues -- Socket: https://socket.dev - ---- - -*Placeholder package v0.0.0 - Real native bindings coming soon* -` -} - -/** - * Generate package.json for a placeholder package. - */ -function generatePackageJson(packageName, platformDesc, os, cpu) { - return { - name: packageName, - version: '0.0.0', - description: `Placeholder for iocraft native bindings (${platformDesc}). Real package coming soon.`, - license: 'MIT', - author: 'Socket Inc (https://socket.dev)', - homepage: 'https://github.com/SocketDev/socket-cli', - repository: { - type: 'git', - url: 'git+https://github.com/SocketDev/socket-cli.git', - }, - bugs: { - url: 'https://github.com/SocketDev/socket-cli/issues', - }, - keywords: [ - 'socket', - 'iocraft', - 'tui', - 'terminal', - 'native', - 'bindings', - 'placeholder', - os, - cpu, - ].filter(Boolean), - os: [os], - cpu: [cpu], - files: ['README.md'], - publishConfig: { - access: 'public', - registry: 'https://registry.npmjs.org/', - }, - } -} - -/** - * Create a placeholder package in a temporary directory. - */ -async function createPlaceholderPackage(config) { - const { arch, cpu, libc, os, releasePlatform } = config - const muslSuffix = libc === 'musl' ? '-musl' : '' - const platformId = `${releasePlatform}-${arch}${muslSuffix}` - const packageName = `@socketaddon/iocraft-${platformId}` - const platformDesc = PLATFORM_DESCRIPTIONS[platformId] - - if (!platformDesc) { - logger.warn(`No description for platform: ${platformId}`) - return null - } - - const osField = OS_MAP[releasePlatform] || releasePlatform - const cpuField = cpu - - const tmpDir = path.join( - process.cwd(), - 'build', - 'tmp-placeholders', - `iocraft-${platformId}`, - ) - - await fs.mkdir(tmpDir, { recursive: true }) - - const packageJson = generatePackageJson( - packageName, - platformDesc, - osField, - cpuField, - ) - const readme = generateReadme(packageName, platformDesc) - - await fs.writeFile( - path.join(tmpDir, 'package.json'), - JSON.stringify(packageJson, null, 2) + '\n', - 'utf-8', - ) - await fs.writeFile(path.join(tmpDir, 'README.md'), readme, 'utf-8') - - return { packageName, platformId, tmpDir } -} - -/** - * Publish a placeholder package to npm. - */ -function publishPackage(tmpDir, packageName) { - const args = ['publish', '--access', 'public'] - - if (isDryRun) { - args.push('--dry-run') - } - - const result = spawnSync('npm', args, { - cwd: tmpDir, - encoding: 'utf-8', - stdio: 'inherit', - }) - - if (result.error) { - throw result.error - } - - if (result.status !== 0) { - throw new Error( - `npm publish failed with exit code ${result.status} for ${packageName}`, - ) - } - - return result.status === 0 -} - -/** - * Create the main wrapper placeholder package. - */ -async function createMainPlaceholderPackage() { - const packageName = '@socketaddon/iocraft' - const tmpDir = path.join( - process.cwd(), - 'build', - 'tmp-placeholders', - 'iocraft-main', - ) - - await fs.mkdir(tmpDir, { recursive: true }) - - const packageJson = { - name: packageName, - version: '0.0.0', - description: - 'Placeholder for iocraft Node.js bindings (main wrapper). Real package coming soon.', - license: 'MIT', - type: 'module', - author: 'Socket Inc (https://socket.dev)', - homepage: 'https://github.com/SocketDev/socket-cli', - repository: { - type: 'git', - url: 'git+https://github.com/SocketDev/socket-cli.git', - }, - bugs: { - url: 'https://github.com/SocketDev/socket-cli/issues', - }, - keywords: [ - 'socket', - 'iocraft', - 'tui', - 'terminal', - 'native', - 'bindings', - 'rust', - 'placeholder', - ], - files: ['README.md'], - publishConfig: { - access: 'public', - registry: 'https://registry.npmjs.org/', - }, - } - - const readme = `# @socketaddon/iocraft - -**PLACEHOLDER PACKAGE** - -This is a placeholder package to reserve the namespace for iocraft Node.js bindings. - -The real package with platform detection and native bindings will be published soon. - -## What is this? - -This package will be the main wrapper for iocraft - a Rust-based TUI library that provides fast, beautiful terminal interfaces with React-like declarative syntax. - -The main package will automatically load the correct platform-specific binary for your system. - -## Installation - -Once the real package is available, install with: - -\`\`\`bash -npm install @socketaddon/iocraft -\`\`\` - -## Supported Platforms - -- macOS (Intel and Apple Silicon) -- Linux (x64 and ARM64, glibc and musl) -- Windows (x64 and ARM64) - -## More Information - -- Repository: https://github.com/SocketDev/socket-cli -- Issues: https://github.com/SocketDev/socket-cli/issues -- Socket: https://socket.dev - ---- - -*Placeholder package v0.0.0 - Real package coming soon* -` - - await fs.writeFile( - path.join(tmpDir, 'package.json'), - JSON.stringify(packageJson, null, 2) + '\n', - 'utf-8', - ) - await fs.writeFile(path.join(tmpDir, 'README.md'), readme, 'utf-8') - - return { packageName, tmpDir } -} - -/** - * List all available packages. - */ -function listAvailablePackages() { - logger.log('') - logger.log('Available packages:') - logger.log('='.repeat(60)) - logger.log('') - logger.log('Main package:') - logger.log(' --main @socketaddon/iocraft') - logger.log('') - logger.log('Platform-specific packages:') - - for (const config of PLATFORM_CONFIGS) { - const { arch, libc, releasePlatform } = config - const muslSuffix = libc === 'musl' ? '-musl' : '' - const platformId = `${releasePlatform}-${arch}${muslSuffix}` - const packageName = `@socketaddon/iocraft-${platformId}` - const platformDesc = PLATFORM_DESCRIPTIONS[platformId] - - logger.log(` --${platformId.padEnd(24)} ${packageName}`) - if (platformDesc) { - logger.log(` ${' '.repeat(28)} (${platformDesc})`) - } - } - - logger.log('') - logger.log('Examples:') - logger.log(' node scripts/publish-socketaddon-placeholders.mts --main') - logger.log(' node scripts/publish-socketaddon-placeholders.mts --darwin-arm64 --dry-run') - logger.log(' node scripts/publish-socketaddon-placeholders.mts --main --linux-x64 --linux-x64-musl') - logger.log(' node scripts/publish-socketaddon-placeholders.mts # publish all') - logger.log('') -} - -/** - * Main execution. - */ -async function main() { - // Handle --list flag - if (showList) { - listAvailablePackages() - return - } - - const requestedPlatforms = getRequestedPlatforms() - const publishAll = requestedPlatforms === 'all' - - logger.log('') - logger.log( - isDryRun - ? 'Dry-run: Publishing socketaddon placeholder packages...' - : 'Publishing socketaddon placeholder packages...', - ) - logger.log('='.repeat(60)) - - if (!publishAll) { - logger.log(`Selected packages: ${requestedPlatforms.join(', ')}`) - } - - logger.log('') - - const results = { - created: [], - failed: [], - skipped: [], - } - - // Publish main wrapper package. - const shouldPublishMain = publishAll || requestedPlatforms.includes('main') - - if (shouldPublishMain) { - try { - const mainPkg = await createMainPlaceholderPackage() - const { packageName, tmpDir } = mainPkg - - logger.log(`Publishing ${packageName}...`) - - if (!isDryRun) { - const success = publishPackage(tmpDir, packageName) - - if (success) { - logger.info(`✓ Published ${packageName}`) - results.created.push(packageName) - } else { - logger.error(`✗ Failed to publish ${packageName}`) - results.failed.push(packageName) - } - } else { - logger.info(`[DRY RUN] Would publish ${packageName}`) - results.created.push(packageName) - } - } catch (e) { - logger.error('Error creating main package:', e) - results.failed.push(`@socketaddon/iocraft (main): ${e.message}`) - } - } else { - results.skipped.push('@socketaddon/iocraft (main)') - } - - // Publish platform-specific packages. - for (const config of PLATFORM_CONFIGS) { - const { arch, libc, releasePlatform } = config - const muslSuffix = libc === 'musl' ? '-musl' : '' - const platformId = `${releasePlatform}-${arch}${muslSuffix}` - - const shouldPublish = publishAll || requestedPlatforms.includes(platformId) - - if (!shouldPublish) { - const packageName = `@socketaddon/iocraft-${platformId}` - results.skipped.push(packageName) - continue - } - - try { - const pkgInfo = await createPlaceholderPackage(config) - - if (!pkgInfo) { - continue - } - - const { packageName, tmpDir } = pkgInfo - - logger.log(`Publishing ${packageName}...`) - - if (!isDryRun) { - const success = publishPackage(tmpDir, packageName) - - if (success) { - logger.info(`✓ Published ${packageName}`) - results.created.push(packageName) - } else { - logger.error(`✗ Failed to publish ${packageName}`) - results.failed.push(packageName) - } - } else { - logger.info(`[DRY RUN] Would publish ${packageName}`) - results.created.push(packageName) - } - } catch (e) { - logger.error(`Error processing platform ${platformId}:`, e) - results.failed.push(`${platformId}: ${e.message}`) - } - } - - logger.log('') - logger.log('='.repeat(60)) - logger.log('Summary:') - logger.log(` Created: ${results.created.length}`) - logger.log(` Failed: ${results.failed.length}`) - if (!publishAll) { - logger.log(` Skipped: ${results.skipped.length}`) - } - - if (results.created.length) { - logger.log('') - logger.log('Created packages:') - for (const pkg of results.created) { - logger.log(` - ${pkg}`) - } - } - - if (!publishAll && results.skipped.length) { - logger.log('') - logger.log('Skipped packages:') - for (const pkg of results.skipped) { - logger.log(` - ${pkg}`) - } - } - - if (results.failed.length) { - logger.log('') - logger.error('Failed:') - for (const pkg of results.failed) { - logger.error(` - ${pkg}`) - } - process.exitCode = 1 - } - - logger.log('') -} - -main().catch((e) => { - logger.error('Fatal error:', e) - process.exitCode = 1 -}) diff --git a/packages/package-builder/test-iocraft-package.mts b/packages/package-builder/test-iocraft-package.mts deleted file mode 100644 index 84925928d..000000000 --- a/packages/package-builder/test-iocraft-package.mts +++ /dev/null @@ -1,81 +0,0 @@ -#!/usr/bin/env node -/** - * Test script to verify @socketaddon/iocraft package works correctly. - * This tests the development fallback path that loads from sibling directories. - */ - -import { createRequire } from 'node:module' -import { platform, arch } from 'node:os' - -const require = createRequire(import.meta.url) - -console.log('Testing @socketaddon/iocraft package...\n') -console.log(`Platform: ${platform()} ${arch()}`) - -try { - // Test loading the native binary directly first - const platformName = platform() - const archName = arch() - - const platformMap = { - darwin: 'darwin', - linux: 'linux', - win32: 'win', - } - - const archMap = { - arm64: 'arm64', - x64: 'x64', - } - - const mappedPlatform = platformMap[platformName] - const mappedArch = archMap[archName] - const platformId = `${mappedPlatform}-${mappedArch}` - - console.log(`Testing native binary for ${platformId}...\n`) - - // Try to load the native binary directly - const nativePath = `./build/dev/out/socketaddon-iocraft-${platformId}/iocraft.node` - const nativeModule = require(nativePath) - console.log('✓ Successfully loaded native binary directly') - console.log(' Available functions:', Object.keys(nativeModule).join(', ')) - - // Now test the main package (should use dev fallback) - const iocraftModule = require('./build/dev/out/socketaddon-iocraft/index.mjs') - const iocraft = iocraftModule.default || iocraftModule - console.log('\n✓ Successfully loaded @socketaddon/iocraft via main package') - - // Test text() function - const textNode = iocraft.text('Hello, World!') - console.log('✓ text() function works') - console.log(' textNode.type:', textNode.type) - console.log(' textNode.content:', textNode.content) - - // Test view() function - const viewNode = iocraft.view([textNode]) - console.log('✓ view() function works') - console.log(' viewNode.type:', viewNode.type) - console.log(' viewNode.children.length:', viewNode.children?.length) - - // Test renderToString() function - const rendered = iocraft.renderToString(textNode) - console.log('✓ renderToString() function works') - console.log(' rendered:', JSON.stringify(rendered)) - - // Test getTerminalSize() function - const size = iocraft.getTerminalSize() - console.log('✓ getTerminalSize() function works') - console.log(' size:', size) - - // Test TuiRenderer class - const renderer = new iocraft.TuiRenderer() - console.log('✓ TuiRenderer class works') - console.log(' renderer.isRunning():', renderer.isRunning()) - - console.log('\n✅ All tests passed! Package is working correctly.') - process.exit(0) -} catch (e) { - console.error('\n❌ Test failed:', e.message) - console.error(e.stack) - process.exit(1) -} diff --git a/scripts/download-iocraft-binaries.mts b/scripts/download-iocraft-binaries.mts deleted file mode 100755 index 9e5eb3773..000000000 --- a/scripts/download-iocraft-binaries.mts +++ /dev/null @@ -1,238 +0,0 @@ -#!/usr/bin/env node -/** - * Download iocraft .node binaries from socket-btm releases for all platforms. - * - * This script is used by the publish workflow to download native binaries - * before publishing @socketaddon/iocraft platform packages. - * - * Usage: - * node scripts/download-iocraft-binaries.mts [--platform=] [--arch=] [--libc=] - * node scripts/download-iocraft-binaries.mts # Download all platforms - * node scripts/download-iocraft-binaries.mts --platform=darwin --arch=arm64 - * node scripts/download-iocraft-binaries.mts --platform=linux --arch=x64 --libc=musl - */ - -import { existsSync, promises as fs } from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' - -import { - PLATFORM_CONFIGS, - parsePlatformArgs, -} from '../packages/build-infra/lib/platform-targets.mts' -import { logTransientErrorHelp } from '../packages/build-infra/lib/github-error-utils.mts' - -import { getDefaultLogger } from '@socketsecurity/lib/logger' -import { downloadSocketBtmRelease } from '@socketsecurity/lib/releases/socket-btm' - -const __dirname = path.dirname(fileURLToPath(import.meta.url)) -const rootPath = path.join(__dirname, '..') -const logger = getDefaultLogger() - -interface DownloadResult { - ok: boolean - target: string - error?: unknown -} - -interface PlatformConfig { - arch: string - description: string - libc?: string - platform: string - releasePlatform: string - runner: string -} - -interface PlatformFilter { - platform: string - arch: string - libc?: string -} - -/** - * Get output path for a platform-specific .node binary. - */ -function getBinaryOutputPath( - platform: string, - arch: string, - libc: string | undefined, -): string { - const muslSuffix = libc === 'musl' ? '-musl' : '' - const releasePlatform = platform === 'win32' ? 'win' : platform - const target = `${releasePlatform}-${arch}${muslSuffix}` - return path.join( - rootPath, - 'packages/build-infra/build/downloaded/iocraft', - target, - 'iocraft.node', - ) -} - -/** - * Download iocraft binary for a specific platform. - */ -async function downloadIocraftBinary( - config: PlatformConfig, -): Promise { - const { arch, description, libc, platform, releasePlatform } = config - const target = `${releasePlatform}-${arch}${libc ? `-${libc}` : ''}` - - try { - logger.group(`Downloading iocraft for ${target}`) - logger.info(description) - - const outputPath = getBinaryOutputPath(platform, arch, libc) - const outputDir = path.dirname(outputPath) - - await fs.mkdir(outputDir, { recursive: true }) - - // Check if already downloaded by checking version. - const versionPath = path.join(outputDir, '.version') - const downloadDir = path.join( - rootPath, - 'packages/build-infra/build/downloaded/iocraft-temp', - ) - - // Download the asset. - let assetPath: string - try { - const assetPattern = `iocraft-*-${target}.node` - assetPath = await downloadSocketBtmRelease('iocraft', { - asset: assetPattern, - cwd: rootPath, - downloadDir, - quiet: false, - }) - logger.info(`Downloaded to ${assetPath}`) - } catch (e) { - const message = e instanceof Error ? e.message : String(e) - logger.error(`Failed to download ${target}: ${message}`) - await logTransientErrorHelp(e) - throw e - } - - // Get the release tag from the download directory. - const sourceVersionPath = path.join(downloadDir, '.version') - if (!existsSync(sourceVersionPath)) { - throw new Error( - `Source version file not found: ${sourceVersionPath}. ` + - 'Download may have failed.', - ) - } - - const tag = (await fs.readFile(sourceVersionPath, 'utf8')).trim() - if (!tag || tag.length === 0) { - throw new Error( - `Invalid version file content at ${sourceVersionPath}. ` + - 'Please retry download.', - ) - } - - // Check if already up to date. - if (existsSync(versionPath)) { - const cachedVersion = await fs.readFile(versionPath, 'utf-8') - if (cachedVersion.trim() === tag) { - logger.info(`${target} already up to date`) - logger.groupEnd() - return { ok: true, target } - } - logger.info(`${target} out of date, re-downloading...`) - } - - // Copy the .node file to the output location. - await fs.copyFile(assetPath, outputPath) - - // Write version file. - await fs.writeFile(versionPath, tag, 'utf-8') - - logger.groupEnd() - logger.success(`${target} download complete`) - return { ok: true, target } - } catch (e) { - const message = e instanceof Error ? e.message : String(e) - logger.groupEnd() - logger.error(`Failed to download ${target}: ${message}`) - await logTransientErrorHelp(e) - return { error: e, ok: false, target } - } -} - -/** - * Download binaries for all platforms or a specific platform. - */ -async function downloadBinaries( - platformFilter: PlatformFilter | null = null, -): Promise { - const configs = platformFilter - ? PLATFORM_CONFIGS.filter( - c => - c.platform === platformFilter.platform && - c.arch === platformFilter.arch && - (platformFilter.libc ? c.libc === platformFilter.libc : !c.libc), - ) - : PLATFORM_CONFIGS - - if (configs.length === 0) { - logger.error( - 'No matching platforms found for filter:', - JSON.stringify(platformFilter), - ) - return false - } - - logger.info( - `Downloading iocraft binaries for ${configs.length} platform(s)...`, - ) - - const settled = await Promise.allSettled( - configs.map(config => downloadIocraftBinary(config)), - ) - - const failed = settled.filter( - r => r.status === 'rejected' || (r.status === 'fulfilled' && !r.value.ok), - ) - if (failed.length > 0) { - logger.error(`\n${failed.length} platform(s) failed:`) - for (const r of failed) { - logger.error(` - ${r.status === 'rejected' ? r.reason?.message ?? r.reason : r.value.target}`) - } - return false - } - - logger.success(`\nAll ${configs.length} platform(s) downloaded successfully`) - return true -} - -/** - * Main entry point. - */ -async function main(): Promise { - const args = process.argv.slice(2) - const platformArgs = parsePlatformArgs(args) - - // Determine if filtering to a specific platform. - const hasFilter = platformArgs.platform || platformArgs.arch - const platformFilter = hasFilter ? platformArgs : null - - if (hasFilter && !platformArgs.platform) { - logger.error('--arch requires --platform') - process.exitCode = 1 - return - } - - const success = await downloadBinaries(platformFilter) - if (!success) { - process.exitCode = 1 - } -} - -// Run if invoked directly. -if (fileURLToPath(import.meta.url) === process.argv[1]) { - main().catch((e: unknown) => { - logger.error('Download failed:', e) - process.exitCode = 1 - }) -} - -export { downloadBinaries, downloadIocraftBinary, getBinaryOutputPath }