diff --git a/.github/scripts/smoke-npm-release.sh b/.github/scripts/smoke-npm-release.sh new file mode 100644 index 0000000..08803de --- /dev/null +++ b/.github/scripts/smoke-npm-release.sh @@ -0,0 +1,135 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +mode="${1:-}" +case "$mode" in + all) + package_dirs=(hdp-mcp hdp-cli hdp-autogen-ts) + package_names=('@helixar_ai/hdp' '@helixar_ai/hdp-mcp' '@helixar_ai/hdp-autogen') + ;; + autogen) + package_dirs=(hdp-autogen-ts) + package_names=('@helixar_ai/hdp' '@helixar_ai/hdp-autogen') + ;; + *) + echo "Usage: $0 all|autogen" >&2 + exit 2 + ;; +esac + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd "$script_dir/../.." && pwd)" +tmp_dir="$(mktemp -d)" +pack_dir="$tmp_dir/packed" +install_dir="$tmp_dir/installed" +mkdir -p "$pack_dir" "$install_dir" "$tmp_dir/manifests" + +restore_manifests() { + for package_dir in "${package_dirs[@]}"; do + cp "$tmp_dir/manifests/$package_dir.json" "$repo_root/packages/$package_dir/package.json" + done + rm -rf "$tmp_dir" +} +trap restore_manifests EXIT + +hdp_version="$(node -p "require('$repo_root/package.json').version")" +for package_dir in "${package_dirs[@]}"; do + cp "$repo_root/packages/$package_dir/package.json" "$tmp_dir/manifests/$package_dir.json" +done + +( + cd "$repo_root" + npm pack --silent --pack-destination "$pack_dir" . +) + +for package_dir in "${package_dirs[@]}"; do + package_path="$repo_root/packages/$package_dir" + ( + cd "$package_path" + npm pkg set "dependencies.@helixar_ai/hdp=^${hdp_version}" + node -e ' + const manifest = require("./package.json"); + const sections = ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"]; + const fileDependencies = sections.flatMap((section) => + Object.entries(manifest[section] || {}) + .filter(([, spec]) => typeof spec === "string" && spec.startsWith("file:")) + .map(([name, spec]) => `${section}.${name}=${spec}`) + ); + if (fileDependencies.length > 0) { + console.error(`Cannot pack ${manifest.name} with file dependencies: ${fileDependencies.join(", ")}`); + process.exit(1); + } + ' + npm pack --silent --pack-destination "$pack_dir" + ) +done + +for package_dir in "${package_dirs[@]}"; do + cp "$tmp_dir/manifests/$package_dir.json" "$repo_root/packages/$package_dir/package.json" +done + +echo "Installing packed npm packages in an empty directory" +( + cd "$install_dir" + npm install --no-audit --no-fund "$pack_dir"/*.tgz + npm ls json-canonicalize + node -e 'require("@helixar_ai/hdp"); console.log("CommonJS require: @helixar_ai/hdp: PASS")' + if [[ "$mode" == "all" ]]; then + node -e 'require("@helixar_ai/hdp-mcp"); console.log("CommonJS require: @helixar_ai/hdp-mcp: PASS")' + node -e 'require("@helixar_ai/hdp-autogen"); console.log("CommonJS require: @helixar_ai/hdp-autogen: PASS")' + + node -e ' + const fs = require("node:fs"); + const vector = require(process.argv[1]); + fs.writeFileSync(process.argv[2], JSON.stringify(vector.token)); + ' "$repo_root/tests/vectors/section3-validation.json" "$tmp_dir/token.json" + cli_entry="$install_dir/node_modules/hdp-validate/dist/cli.js" + "$install_dir/node_modules/.bin/hdp-validate" "$tmp_dir/token.json" >/dev/null + echo "CLI executable: hdp-validate: PASS" + node -e ' + const [entry, token] = process.argv.slice(1); + process.argv = [process.execPath, entry, token]; + require(entry); + ' "$cli_entry" "$tmp_dir/token.json" >/dev/null + echo "CommonJS require: hdp-validate CLI entry: PASS" + node --input-type=module -e ' + import { pathToFileURL } from "node:url"; + const [entry, token] = process.argv.slice(1); + process.argv = [process.execPath, entry, token]; + await import(pathToFileURL(entry)); + ' "$cli_entry" "$tmp_dir/token.json" >/dev/null + echo "ESM import: hdp-validate CLI entry: PASS" + else + node -e 'require("@helixar_ai/hdp-autogen"); console.log("CommonJS require: @helixar_ai/hdp-autogen: PASS")' + fi +) + +cat > "$install_dir/check-esm-imports.mjs" <<'EOF' +const packages = process.argv.slice(2) +let failures = 0 + +for (const packageName of packages) { + try { + await import(packageName) + console.log(`ESM import: ${packageName}: PASS`) + } catch (error) { + const knownAjvResolution = error.code === 'ERR_MODULE_NOT_FOUND' + && /\/ajv\/dist\/2020(?:\.js)?(?:$|[?#])/.test(error.url ?? error.message) + if (knownAjvResolution) { + console.log(`ESM import: ${packageName}: KNOWN_FAILURE (${error.code}: ${error.url ?? error.message})`) + } else { + console.error(`ESM import: ${packageName}: FAIL`, error) + failures += 1 + } + } +} + +if (failures > 0) process.exit(1) +EOF + +( + cd "$install_dir" + node "$install_dir/check-esm-imports.mjs" "${package_names[@]}" +) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d7c190..20f102e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -149,9 +149,48 @@ jobs: path: packages/hdp-autogen-ts/dist/ retention-days: 1 + smoke-node-release: + name: Smoke test packed npm release + needs: vet-node + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Download vetted hdp dist + uses: actions/download-artifact@v4 + with: + name: hdp-dist + path: dist/ + + - name: Download vetted hdp-mcp dist + uses: actions/download-artifact@v4 + with: + name: hdp-mcp-dist + path: packages/hdp-mcp/dist/ + + - name: Download vetted hdp-cli dist + uses: actions/download-artifact@v4 + with: + name: hdp-cli-dist + path: packages/hdp-cli/dist/ + + - name: Download vetted hdp-autogen-ts dist + uses: actions/download-artifact@v4 + with: + name: hdp-autogen-ts-dist + path: packages/hdp-autogen-ts/dist/ + + - name: Smoke test packed npm artifacts + run: bash .github/scripts/smoke-npm-release.sh all + publish-hdp: name: Publish @helixar_ai/hdp - needs: vet-node + needs: [vet-node, smoke-node-release] runs-on: ubuntu-latest permissions: contents: read @@ -182,7 +221,7 @@ jobs: publish-hdp-mcp: name: Publish @helixar_ai/hdp-mcp - needs: vet-node + needs: [vet-node, smoke-node-release] runs-on: ubuntu-latest permissions: contents: read @@ -238,7 +277,7 @@ jobs: publish-hdp-cli: name: Publish hdp-validate CLI - needs: vet-node + needs: [vet-node, smoke-node-release] runs-on: ubuntu-latest permissions: contents: read @@ -288,7 +327,7 @@ jobs: publish-hdp-autogen-ts: name: Publish @helixar_ai/hdp-autogen - needs: vet-node + needs: [vet-node, smoke-node-release] runs-on: ubuntu-latest permissions: contents: read @@ -412,9 +451,39 @@ jobs: path: packages/hdp-autogen-ts/dist/ retention-days: 1 + smoke-hdp-autogen-ts: + name: Smoke test standalone @helixar_ai/hdp-autogen release + needs: vet-hdp-autogen-ts + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v5 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Install dependencies + run: npm ci + + - name: Build root package for local dependency install + run: npm run build + + - name: Copy LICENSE into root dist + run: cp LICENSE dist/ + + - name: Download vetted hdp-autogen-ts dist + uses: actions/download-artifact@v4 + with: + name: hdp-autogen-ts-dist + path: packages/hdp-autogen-ts/dist/ + + - name: Smoke test packed hdp-autogen artifacts + run: bash .github/scripts/smoke-npm-release.sh autogen + publish-hdp-autogen-ts-standalone: name: Publish @helixar_ai/hdp-autogen (standalone) - needs: vet-hdp-autogen-ts + needs: [vet-hdp-autogen-ts, smoke-hdp-autogen-ts] runs-on: ubuntu-latest permissions: contents: read diff --git a/package-lock.json b/package-lock.json index 2293f23..272af82 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@helixar_ai/hdp", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@helixar_ai/hdp", - "version": "0.2.0", + "version": "0.2.1", "license": "Apache-2.0", "workspaces": [ "packages/*" @@ -16,7 +16,7 @@ "@noble/hashes": "^2.0.1", "ajv": "^8.18.0", "ajv-formats": "^3.0.1", - "json-canonicalize": "^2.0.0", + "json-canonicalize": "2.0.0", "uuid": "^13.0.0", "zod": "^4.3.6" }, @@ -2724,7 +2724,7 @@ }, "packages/hdp-autogen-ts": { "name": "@helixar_ai/hdp-autogen", - "version": "0.2.0", + "version": "0.2.1", "license": "Apache-2.0", "dependencies": { "@helixar_ai/hdp": "file:../.." @@ -2738,7 +2738,7 @@ }, "packages/hdp-cli": { "name": "hdp-validate", - "version": "0.2.0", + "version": "0.2.1", "license": "Apache-2.0", "dependencies": { "@helixar_ai/hdp": "file:../.." @@ -2755,7 +2755,7 @@ }, "packages/hdp-mcp": { "name": "@helixar_ai/hdp-mcp", - "version": "0.2.0", + "version": "0.2.1", "license": "Apache-2.0", "dependencies": { "@helixar_ai/hdp": "file:../.." diff --git a/package.json b/package.json index dd73918..ba188ba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@helixar_ai/hdp", - "version": "0.2.0", + "version": "0.2.1", "description": "", "main": "dist/index.js", "module": "dist/index.mjs", @@ -39,7 +39,7 @@ "@noble/hashes": "^2.0.1", "ajv": "^8.18.0", "ajv-formats": "^3.0.1", - "json-canonicalize": "^2.0.0", + "json-canonicalize": "2.0.0", "uuid": "^13.0.0", "zod": "^4.3.6" }, diff --git a/packages/hdp-autogen-ts/package.json b/packages/hdp-autogen-ts/package.json index f1a2f62..cdd0076 100644 --- a/packages/hdp-autogen-ts/package.json +++ b/packages/hdp-autogen-ts/package.json @@ -1,6 +1,6 @@ { "name": "@helixar_ai/hdp-autogen", - "version": "0.2.0", + "version": "0.2.1", "description": "HDP middleware for AutoGen — cryptographic audit trail for multi-agent delegation", "type": "module", "main": "dist/index.cjs", diff --git a/packages/hdp-cli/package.json b/packages/hdp-cli/package.json index 190744b..bfdbfac 100644 --- a/packages/hdp-cli/package.json +++ b/packages/hdp-cli/package.json @@ -1,6 +1,6 @@ { "name": "hdp-validate", - "version": "0.2.0", + "version": "0.2.1", "description": "CLI validator for HDP (Human Delegation Provenance Protocol) tokens", "type": "module", "bin": { diff --git a/packages/hdp-mcp/package.json b/packages/hdp-mcp/package.json index e9e8353..5b7134c 100644 --- a/packages/hdp-mcp/package.json +++ b/packages/hdp-mcp/package.json @@ -1,6 +1,6 @@ { "name": "@helixar_ai/hdp-mcp", - "version": "0.2.0", + "version": "0.2.1", "description": "HDP middleware for MCP (Model Context Protocol) servers", "type": "module", "main": "dist/index.cjs",