Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changeset/script-free-install.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@bloxwap/agent-cli': patch
---

Ship license, changelog and repository metadata with the CLI. Verify script-free
global npm installs and installed bunx execution on macOS/Linux and Node 22.12/24.
36 changes: 33 additions & 3 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ on:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: dedicated-testnet-account
cancel-in-progress: false
jobs:
testnet:
runs-on: ubuntu-latest
timeout-minutes: 15
environment: testnet
env:
BLOXWAP_E2E: '1'
# This wallet and Privy app belong to disposable company CI, never users.
BLOXWAP_TEST_ACCOUNT_ONLY: '1'
BLOXWAP_TEST_MASTER_KEY: ${{ secrets.BLOXWAP_TEST_MASTER_KEY }}
BLOXWAP_PRIVY_APP_ID: ${{ secrets.BLOXWAP_PRIVY_APP_ID }}
BLOXWAP_PRIVY_APP_SECRET: ${{ secrets.BLOXWAP_PRIVY_APP_SECRET }}
Expand All @@ -23,9 +28,34 @@ jobs:
cache: npm
- run: npm ci
- run: npm run build
- run: npm run test:e2e
- name: Verify the live testnet lifecycle (Relay mocked)
run: npm run test:e2e
- name: Record testnet coverage and outcome
if: always()
run: |
node --input-type=module <<'NODE'
import { readFileSync, appendFileSync, existsSync } from 'node:fs';
const path = 'packages/agent-cli/artifacts/lifecycle-report.json';
if (!existsSync(path)) {
appendFileSync(process.env.GITHUB_STEP_SUMMARY, 'No lifecycle report was produced. Live coverage is unproven.\n');
process.exit(1);
}
const report = JSON.parse(readFileSync(path));
const stages = report.stages.filter(stage => stage.status !== 'running');
appendFileSync(process.env.GITHUB_STEP_SUMMARY,
`Testnet lifecycle: **${report.status}**. Cleanup: ${report.cleanup}.\n\n` +
'Hyperliquid testnet and dedicated Privy app are live; Relay is a zero-value mock using pre-funded test collateral. This script is not an AI-agent session.\n\n' +
stages.map(stage => `- ${stage.name}: ${stage.status}\n`).join(''));
NODE
- uses: actions/upload-artifact@v4
if: always()
with:
name: testnet-journals
path: packages/agent-cli/artifacts/
name: testnet-journals-${{ github.run_id }}
retention-days: 7
if-no-files-found: error
path: |
packages/agent-cli/artifacts/lifecycle-report.json
packages/agent-cli/artifacts/events.jsonl
packages/agent-cli/artifacts/events-follow.jsonl
packages/agent-cli/artifacts/audit.jsonl
packages/agent-cli/artifacts/runner*.jsonl
9 changes: 8 additions & 1 deletion .github/workflows/install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ jobs:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
node: ['22.12.0', '24']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
Expand All @@ -16,8 +17,14 @@ jobs:
node-version: 24
cache: npm
- uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.10'
- run: npm ci
- run: npm run build
- run: npm run test:package
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- name: Install the packed artifact with lifecycle scripts disabled
run: npm run test:package
env:
BLOXWAP_SMOKE_BUN: '1'
130 changes: 111 additions & 19 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,39 +4,131 @@ on:
tags: ['v*']
workflow_dispatch:
permissions:
contents: write
id-token: write
contents: read
concurrency:
group: agent-cli-release-${{ github.ref }}
cancel-in-progress: false
jobs:
release:
if: vars.BLOXWAP_PUBLISH == '1'
runs-on: ubuntu-latest
environment: npm-release
build:
name: Candidate (${{ matrix.platform }})
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
platform: linux-x64
target: bun-linux-x64-baseline
package: true
- os: ubuntu-24.04-arm
platform: linux-arm64
target: bun-linux-arm64
- os: macos-15-intel
platform: darwin-x64
target: bun-darwin-x64
- os: macos-latest
platform: darwin-arm64
target: bun-darwin-arm64
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 24
cache: npm
registry-url: https://registry.npmjs.org
- uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.10'
- name: Verify version, skill, release notes and tagged main ancestry
run: node packages/agent-cli/scripts/verify-release.mjs
- run: npm ci
- name: Verify tag and package version
if: startsWith(github.ref, 'refs/tags/')
run: node -e 'const p=require("./packages/agent-cli/package.json");if(process.env.GITHUB_REF_NAME!==`v${p.version}`)throw Error("Tag/version mismatch")'
- run: npm run build
- run: npm run lint
- run: npm run typecheck
- run: npm test
- run: npm run test:package
- run: npm run build:binaries
- run: npm publish --workspace @bloxwap/agent-cli --provenance --access public
- name: Verify installed npm and bunx package
run: npm run test:package
env:
BLOXWAP_SMOKE_BUN: '1'
- name: Compile and run the native executable
run: |
npm run build:binaries -- ${{ matrix.target }}
node packages/agent-cli/scripts/binary-smoke.mjs packages/agent-cli/binaries/agent-cli-${{ matrix.platform }}
- name: Ensure generated tracked files match the release commit
run: git diff --exit-code HEAD
- uses: actions/upload-artifact@v4
with:
name: native-${{ matrix.platform }}
path: packages/agent-cli/binaries/agent-cli-${{ matrix.platform }}
if-no-files-found: error
- name: Pack the tested npm release artifact
if: matrix.package
run: |
mkdir -p packages/agent-cli/artifacts
npm pack --workspace @bloxwap/agent-cli --ignore-scripts --pack-destination packages/agent-cli/artifacts
cp packages/agent-cli/SKILL.md packages/agent-cli/CHANGELOG.md packages/agent-cli/LICENSE packages/agent-cli/artifacts/
- name: Verify the exact release tarball
if: matrix.package
run: |
for release_tarball in "$PWD"/packages/agent-cli/artifacts/*.tgz; do
BLOXWAP_SMOKE_TARBALL="$release_tarball" npm run test:package
done
env:
BLOXWAP_SMOKE_BUN: '1'
- uses: actions/upload-artifact@v4
if: matrix.package
with:
name: npm-package
path: packages/agent-cli/artifacts/*
if-no-files-found: error
publish:
needs: build
if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') && vars.BLOXWAP_PUBLISH == '1'
runs-on: ubuntu-latest
environment: npm-release
concurrency:
group: agent-cli-npm-publish
cancel-in-progress: false
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 24
registry-url: https://registry.npmjs.org
- uses: oven-sh/setup-bun@v2
with:
bun-version: '1.3.10'
- name: Recheck tagged main ancestry before publishing
run: node packages/agent-cli/scripts/verify-release.mjs
- uses: actions/download-artifact@v4
with:
pattern: native-*
merge-multiple: true
path: release
- uses: actions/download-artifact@v4
with:
name: npm-package
path: release
- name: Prepare release checksums
run: node packages/agent-cli/scripts/release-checksums.mjs release
- name: Publish the tested tarball with provenance
run: node packages/agent-cli/scripts/publish-artifact.mjs release
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Verify published integrity and provenance
run: node packages/agent-cli/scripts/verify-publication.mjs release
- name: Verify public npm install and bunx
run: npm run test:package
env:
BLOXWAP_SMOKE_REGISTRY: '1'
BLOXWAP_SMOKE_BUN: '1'
- uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
generate_release_notes: true
files: |
packages/agent-cli/binaries/*
packages/agent-cli/SKILL.md
packages/agent-cli/CHANGELOG.md
fail_on_unmatched_files: true
files: release/*
25 changes: 24 additions & 1 deletion .github/workflows/version.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
name: Version packages
on:
workflow_dispatch:
inputs:
create_pr:
type: boolean
default: false
description: Open a Changesets PR (requires organization permission)
permissions:
contents: write
pull-requests: write
concurrency:
group: agent-cli-version-main
cancel-in-progress: false
jobs:
version:
if: github.ref == 'refs/heads/main'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -14,8 +23,22 @@ jobs:
node-version: 24
cache: npm
- run: npm ci
- name: Prepare and validate a version patch
if: ${{ !inputs.create_pr }}
run: |
npm run version:candidate
git diff --binary HEAD > version.patch
- uses: actions/upload-artifact@v4
if: ${{ !inputs.create_pr }}
with:
name: agent-cli-version-patch
path: version.patch
if-no-files-found: error
- uses: changesets/action@v1
if: inputs.create_pr
with:
version: npm run version:packages
version: npm run version:candidate
title: 'chore: version agent-cli for release'
commit: 'chore: version agent-cli for release'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,18 @@ or current Bun. No postinstall script. Publishing is release-gated.

## Testnet quickstart

Create your own [Privy account and app](https://dashboard.privy.io/) first.
Use your app ID and secret on your machine or infrastructure you control.
Bloxwap does not provide a shared Privy app, receive these credentials, or operate
a hosted signing service. Keep the master wallet separate from the Privy agent.

```sh
npm ci
npm run build
node packages/agent-cli/dist/cli.js --help
node packages/agent-cli/dist/cli.js config set privyAppId YOUR_APP_ID
node packages/agent-cli/dist/cli.js config set privyAppSecretRef env:BLOXWAP_PRIVY_APP_SECRET
# Set BLOXWAP_PRIVY_APP_SECRET securely outside the CLI/conversation.
# Set your own app's BLOXWAP_PRIVY_APP_SECRET locally, outside the conversation.
node packages/agent-cli/dist/cli.js init --network testnet --master-address 0xYOUR_MASTER_ADDRESS
# Sign returned EIP-712 approval externally, then submit its 65-byte signature:
node packages/agent-cli/dist/cli.js init --network testnet --signature 0xYOUR_SIGNATURE
Expand All @@ -40,17 +45,21 @@ with addresses/signatures from your test environment. Never paste a private key.
```mermaid
flowchart LR
Agent[Agent / CLI] -->|private JSON-RPC| Runner[Persistent runner]
Runner -->|P-256 authorization| Privy[Privy managed agent]
Runner -->|P-256 authorization| Privy[Agent in user's Privy app]
Privy -->|EIP-712 signature| HL[Hyperliquid exchange]
Agent --> Relay[Relay funding quote]
Master[External master wallet] -->|one-time approvals| HL
Runner --> Journal[Events / audit / logs]
```

Master custody stays external. Privy owns the separate agent key; the CLI holds
only an authorization key. Hyperliquid agent permissions deny withdrawal.
Privy policies restrict signing domains; local checks enforce configured risk
limits. Read [custody limits](docs/custody.md) before using a funded account.
You own the Privy account/app. Privy manages the separate agent wallet key in
that app; its P-256 authorization key stays on your machine or infrastructure.
Your master key stays in your external wallet. Bloxwap never receives or stores
these keys, your Privy app secret, or your authorization key on Bloxwap servers.
The CLI talks directly to Privy, Hyperliquid, and Relay. Hyperliquid agent
permissions prevent withdrawals from the master account. Privy policies restrict
the visible signing envelope; local checks enforce configured risk limits.
Read [custody limits](docs/custody.md) before using a funded account.

State: `~/.bloxwap`; config: `~/.bloxwap/config.json`; IPC:
`~/.bloxwap/run.sock`; env prefix: `BLOXWAP_`. All local state is private to the OS
Expand All @@ -62,7 +71,10 @@ Override via `config set builder.address` / `config set builder.fee` or
## Development and docs

`npm run build`, `npm run lint`, `npm run typecheck`, `npm test` must pass before
committing. Unit tests mock services. Credential-dependent tests are gated: `npm run test:sandbox` and `npm run test:e2e` skip without the required environment. The master-key testnet harness is CI-only; unit tests never access the network.
committing. Unit tests mock services. `npm run test:sandbox` requires an explicit
opt-in and credentials for your own test app; missing prerequisites fail before
any request. `npm run test:e2e` is separately credential-gated. The master-key
testnet harness is CI-only; unit tests never access the network.

The npm workspace keeps the publishable CLI in `packages/agent-cli` and the
Fumadocs app in `apps/docs`. Use Node.js **24+** for repository development.
Expand Down
Loading
Loading