From 44b32b2884f1eaba2217c29aeab04690a555f9ba Mon Sep 17 00:00:00 2001 From: Joe Blau Date: Fri, 16 Oct 2026 11:41:40 -0700 Subject: [PATCH] chore: prepare agent-cli 0.2.0 (#41) --- .changeset/first-release.md | 6 ------ .changeset/script-free-install.md | 6 ------ apps/docs/content/docs/skill.mdx | 2 +- docs/PROGRESS.md | 4 ++++ docs/releases.md | 5 ++--- package-lock.json | 2 +- packages/agent-cli/CHANGELOG.md | 12 ++++++++++++ packages/agent-cli/SKILL.md | 4 ++-- packages/agent-cli/package.json | 2 +- packages/agent-cli/scripts/sync-skill-version.mjs | 4 +++- packages/agent-cli/src/core/skill-content.ts | 4 ++-- packages/agent-cli/test/skill.test.ts | 1 + 12 files changed, 29 insertions(+), 23 deletions(-) delete mode 100644 .changeset/first-release.md delete mode 100644 .changeset/script-free-install.md diff --git a/.changeset/first-release.md b/.changeset/first-release.md deleted file mode 100644 index a27363b..0000000 --- a/.changeset/first-release.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@bloxwap/agent-cli": minor ---- - -Add managed Hyperliquid agents, Relay funding, JSON commands, a persistent runner, -risk checks, durable events/audit journals, and the packaged trading skill. diff --git a/.changeset/script-free-install.md b/.changeset/script-free-install.md deleted file mode 100644 index 00ee147..0000000 --- a/.changeset/script-free-install.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@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. diff --git a/apps/docs/content/docs/skill.mdx b/apps/docs/content/docs/skill.mdx index e2e5f90..a11116d 100644 --- a/apps/docs/content/docs/skill.mdx +++ b/apps/docs/content/docs/skill.mdx @@ -112,7 +112,7 @@ Full inputs/outputs are discoverable with `schema`; amounts/prices are strings. | `revoke --cancel-orders` | `{"ok":true,"data":{"locallyRevoked":true,"exchangeRevoked":false,"requiresSignature":true,"approval":{}}}` | | `revoke --signature 0x...` | `{"ok":true,"data":{"locallyRevoked":true,"exchangeRevoked":true}}` | | `audit --intent ID` | `{"ok":true,"data":[{"intentId":"ID","stage":"decision","data":{"allowed":true},"previousHash":"...","hash":"..."}]}` | -| `skill install --target codex` | `{"ok":true,"data":{"target":"codex","path":".../agent-cli/SKILL.md","version":"0.1.0"}}` | +| `skill install --target codex` | `{"ok":true,"data":{"target":"codex","path":".../agent-cli/SKILL.md","version":"0.2.0"}}` | Before an order, query `market --coin BTC` for `mid`, `szDecimals`, asset and market leverage ceiling. Compute size/notional with decimal strings/bigints, diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index cfdf660..9a590d4 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -71,3 +71,7 @@ configured. GitHub also rejected the repository's Actions PR setting with an organization-policy 409; version dispatch therefore defaults to an uploaded reviewable patch. No production user credentials, package publication or live account trading were used for this review. + +The validated version-patch workflow prepared 0.2.0, consuming the pending +changesets and synchronizing package/lock/skill versions and generated docs. +This is release preparation; public npm installation/provenance is still pending. diff --git a/docs/releases.md b/docs/releases.md index a457c52..b845a0a 100644 --- a/docs/releases.md +++ b/docs/releases.md @@ -8,9 +8,8 @@ and synchronize the packaged skill version. By default it regenerates the docs, validates build, lint, typecheck, tests and docs checks, then uploads a reviewable `version.patch` artifact. Apply that patch on a fresh branch at the run's revision and open the version PR yourself; -alternatively run `npm run version:packages` locally and create the PR. With the -current pending first-release changeset, the next stable version is **0.2.0**, -not 0.1.0. +alternatively run `npm run version:packages` locally and create the PR. Read the +resulting CLI package version and changelog to select the matching release tag. The optional `create_pr=true` input uses Changesets to create the version PR after the same validation. This needs GitHub Actions' permission to create pull requests. diff --git a/package-lock.json b/package-lock.json index d087444..a96c829 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11250,7 +11250,7 @@ }, "packages/agent-cli": { "name": "@bloxwap/agent-cli", - "version": "0.1.0", + "version": "0.2.0", "license": "MIT", "dependencies": { "@bloxwap/hyperliquid": "^0.6.0", diff --git a/packages/agent-cli/CHANGELOG.md b/packages/agent-cli/CHANGELOG.md index 8c8e460..c8b508b 100644 --- a/packages/agent-cli/CHANGELOG.md +++ b/packages/agent-cli/CHANGELOG.md @@ -1,5 +1,17 @@ # @bloxwap/agent-cli +## 0.2.0 + +### Minor Changes + +- a04a6c7: Add managed Hyperliquid agents, Relay funding, JSON commands, a persistent runner, + risk checks, durable events/audit journals, and the packaged trading skill. + +### Patch Changes + +- db928e2: 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. + ## 0.1.0 Initial implementation of managed-agent trading, funding and persistent runner. diff --git a/packages/agent-cli/SKILL.md b/packages/agent-cli/SKILL.md index e425012..f608c5b 100644 --- a/packages/agent-cli/SKILL.md +++ b/packages/agent-cli/SKILL.md @@ -2,7 +2,7 @@ name: agent-cli description: Operate the agent-cli Hyperliquid trading CLI, including managed-agent onboarding, funding, orders, event monitoring, rotation, and normalized error recovery. metadata: - version: "0.1.0" + version: "0.2.0" --- Use `agent-cli` for the user's authorized Hyperliquid account operations. Obtain @@ -102,7 +102,7 @@ Full inputs/outputs are discoverable with `schema`; amounts/prices are strings. | `revoke --cancel-orders` | `{"ok":true,"data":{"locallyRevoked":true,"exchangeRevoked":false,"requiresSignature":true,"approval":{}}}` | | `revoke --signature 0x...` | `{"ok":true,"data":{"locallyRevoked":true,"exchangeRevoked":true}}` | | `audit --intent ID` | `{"ok":true,"data":[{"intentId":"ID","stage":"decision","data":{"allowed":true},"previousHash":"...","hash":"..."}]}` | -| `skill install --target codex` | `{"ok":true,"data":{"target":"codex","path":".../agent-cli/SKILL.md","version":"0.1.0"}}` | +| `skill install --target codex` | `{"ok":true,"data":{"target":"codex","path":".../agent-cli/SKILL.md","version":"0.2.0"}}` | Before an order, query `market --coin BTC` for `mid`, `szDecimals`, asset and market leverage ceiling. Compute size/notional with decimal strings/bigints, diff --git a/packages/agent-cli/package.json b/packages/agent-cli/package.json index 7701306..a3f7686 100644 --- a/packages/agent-cli/package.json +++ b/packages/agent-cli/package.json @@ -1,6 +1,6 @@ { "name": "@bloxwap/agent-cli", - "version": "0.1.0", + "version": "0.2.0", "type": "module", "bin": { "agent-cli": "dist/cli.js" diff --git a/packages/agent-cli/scripts/sync-skill-version.mjs b/packages/agent-cli/scripts/sync-skill-version.mjs index 6442d96..8c1d7b9 100644 --- a/packages/agent-cli/scripts/sync-skill-version.mjs +++ b/packages/agent-cli/scripts/sync-skill-version.mjs @@ -3,5 +3,7 @@ const { version } = JSON.parse(readFileSync('package.json', 'utf8')); const skill = readFileSync('SKILL.md', 'utf8'); writeFileSync( 'SKILL.md', - skill.replace(/(metadata:\n version: )"[^"]+"/, `$1"${version}"`), + skill + .replace(/(metadata:\n version: )"[^"]+"/, `$1"${version}"`) + .replace(/("version":")\d+\.\d+\.\d+(")/g, `$1${version}$2`), ); diff --git a/packages/agent-cli/src/core/skill-content.ts b/packages/agent-cli/src/core/skill-content.ts index 47d8e02..9d3ec33 100644 --- a/packages/agent-cli/src/core/skill-content.ts +++ b/packages/agent-cli/src/core/skill-content.ts @@ -1,3 +1,3 @@ // Generated from SKILL.md and package.json. -export const cliVersion="0.1.0"; -export const skillContent="---\nname: agent-cli\ndescription: Operate the agent-cli Hyperliquid trading CLI, including managed-agent onboarding, funding, orders, event monitoring, rotation, and normalized error recovery.\nmetadata:\n version: \"0.1.0\"\n---\n\nUse `agent-cli` for the user's authorized Hyperliquid account operations. Obtain\ncommand schemas with `agent-cli schema COMMAND`; arguments can be flags or\n`--json '{...}'`, or a JSON object on stdin. Ordinary commands print exactly one\nJSON object: `{ok:true,data}` or `{ok:false,code,message,retryable,details}`.\nLogs/QR appear on stderr. `events --follow` and `logs` explicitly stream JSON lines.\nUse `--network testnet` during testing; never silently change to mainnet.\n\n## Onboarding sequence\n\n1. The user creates and owns their own Privy account and app. Configure that\n app ID and a local secret reference, e.g. `config set privyAppId APP` and\n `config set privyAppSecretRef env:BLOXWAP_PRIVY_APP_SECRET`. The user sets the\n environment secret outside the conversation on their own machine or runner.\n Bloxwap does not host the app, receive credentials, or custody user keys.\n Privy manages the trading-agent key in the user's app; master-wallet approval\n always remains in the user's external wallet. The default Bloxwap builder is\n `0x71b09A08257078A4d642F7Dd7315e656c837329a`, with `f=10` (1 bp = 0.01%).\n Override with `config set builder.address` / `config set builder.fee` or\n `BLOXWAP_BUILDER_ADDRESS` / `BLOXWAP_BUILDER_FEE`.\n2. Run `init --master-address 0x... --network testnet`. Show the returned approval\n payload/deeplink/QR. The user signs in their master wallet; submit only the\n resulting signature with `init --signature 0x...`. Submit builder approval\n separately with `init --builder-signature 0x...` for the configured 0.01% default. Continue only after `approved:true`.\n3. Run `fund --amount 10 --origin-chain 42161`. Show `qrAscii`/deposit address,\n origin chain/token, minimum, fees, expected received amount and expiry. On\n testnet, do not treat the default Arbitrum mainnet chain/token as a test route:\n use an explicitly supported test chain/token and `originDecimals`, or the\n credential-gated CI harness with mocked Relay and pre-funded test collateral.\n If no test route is known, stop funding and report the missing route. The user\n transfers the quoted origin token. If `signatureSteps` require signatures,\n show the exact payload and submit each via `deposit` in returned order.\n4. Poll `status` until each active deposit is `settled`, for at most 12 polls\n or 5 minutes, whichever comes first. Start with 1-second delays, double to a\n 15-second cap, and stop with an explicit pending report if the budget expires.\n Settlement requires Relay success and Hyperliquid balance receipt. Stop on\n failed/refunded deposits and explain their status. Do not place orders while\n any deposit is awaiting funds or pending.\n5. Run `run --detach`, then monitor `events --follow --since SEQ`. Persist the\n last handled sequence; replay after reconnect. An unfilled or rejected order\n remains incomplete: do not claim the requested trade succeeded. A fill updates the trading\n plan, an error follows the catalog below, and expiry warnings prompt rotation\n using external master-wallet approval.\n\n## Completion and approval boundaries\n\nRead this skill and query schemas before acting. Keep a progress record with the\nnetwork, current stage, deposit IDs, last event sequence and order cloid/oid;\nrecord public IDs only. A missing user-owned Privy app, wallet signature, funding\nroute or settled balance is a blocked stage. Report the exact next action without\nrequesting any secret in chat or moving to the next stage. Repeat `init` to resume\npersisted approvals rather than creating another agent. An `ok:true` transport\nenvelope does not imply exchange acceptance: inspect `data.result` and reconcile\n`orders`/`events` after uncertain mutations. Never retry an order with a new cloid\nuntil the original intent has been reconciled.\n\nFor rotation, verify `swapped:true` before asking the external wallet to sign old\nagent revocation. Require `oldRevoked:true` before claiming rotation complete.\n`revoke` immediately disables local signing; only `exchangeRevoked:true` confirms\nthat the signed exchange revocation was submitted. Inspect `status` to verify the\nagent is absent from exchange approvals. Cancel outstanding orders before final\nrevocation, and report any cancellation or cleanup failure explicitly.\n\n## Commands and example envelopes\n\nExamples show representative `data`, not live balances or service promises.\nFull inputs/outputs are discoverable with `schema`; amounts/prices are strings.\n\n| Input | Example output |\n| --- | --- |\n| `--help` | `{\"ok\":true,\"data\":{\"commands\":[{\"name\":\"status\",\"description\":\"Read account status\"}],\"globalFlags\":[\"--json\",\"--config\",\"--network\",\"--pretty\"]}}` |\n| `schema order` | `{\"ok\":true,\"data\":{\"input\":{\"type\":\"object\"},\"output\":{\"oneOf\":[]}}}` (actual schemas include properties) |\n| `config get network` | `{\"ok\":true,\"data\":\"testnet\"}` |\n| `config set limits.maxLeverage 5` | `{\"ok\":true,\"data\":{\"version\":1,\"limits\":{\"maxLeverage\":5}}}` |\n| `config validate` | `{\"ok\":true,\"data\":{\"valid\":true,\"version\":1}}` |\n| `init --master-address 0x...` | `{\"ok\":true,\"data\":{\"approved\":false,\"requiresSignature\":true,\"approvals\":{\"agent\":{\"typedData\":{}}},\"qrAscii\":\"...\"}}` |\n| `fund --amount 10 --no-qr` | `{\"ok\":true,\"data\":{\"depositId\":\"...\",\"depositAddress\":\"0x...\",\"expectedReceived\":\"100000000\",\"builderFeeRate\":\"0.01%\",\"builderAddress\":\"0x71b09A08257078A4d642F7Dd7315e656c837329a\",\"state\":\"awaiting_funds\",\"qrAscii\":null}}` |\n| `deposit --deposit-id ID` | `{\"ok\":true,\"data\":{\"depositId\":\"ID\",\"steps\":[{\"id\":\"step:0\",\"requiresSignature\":true,\"payload\":{}}]}}` |\n| `deposit --deposit-id ID --step-id step:0 --signature 0x...` | `{\"ok\":true,\"data\":{\"depositId\":\"ID\",\"steps\":[]}}` |\n| `status` | `{\"ok\":true,\"data\":{\"balance\":{\"accountValue\":\"100\"},\"agent\":{\"approved\":true,\"daysRemaining\":\"179\"},\"deposits\":[],\"policy\":{\"id\":\"...\",\"version\":\"2\"},\"runner\":{\"pid\":\"123\"}}}` |\n| `balance` | `{\"ok\":true,\"data\":{\"accountValue\":\"100\",\"accountValueUnits\":\"10000000000\",\"withdrawable\":\"96\",\"marginUsed\":\"4\"}}` |\n| `market --coin BTC` | `{\"ok\":true,\"data\":{\"coin\":\"BTC\",\"asset\":\"0\",\"szDecimals\":\"5\",\"maxLeverage\":\"40\",\"mid\":\"20000\"}}` |\n| `positions` | `{\"ok\":true,\"data\":[{\"coin\":\"BTC\",\"size\":\"0.001\",\"entryPrice\":\"20000\",\"leverage\":\"5\",\"marginMode\":\"cross\"}]}` |\n| `orders` | `{\"ok\":true,\"data\":[{\"coin\":\"BTC\",\"oid\":\"123\",\"sz\":\"0.001\",\"limitPx\":\"20000\",\"side\":\"B\"}]}` |\n| `order --json '{\"coin\":\"BTC\",\"side\":\"buy\",\"size\":\"0.001\",\"price\":\"20000\",\"tif\":\"Gtc\",\"cloid\":\"0x11111111111111111111111111111111\"}'` | `{\"ok\":true,\"data\":{\"result\":{\"status\":\"ok\",\"response\":{\"data\":{\"statuses\":[{\"resting\":{\"oid\":123}}]}}},\"builderFeeRate\":\"0.01%\",\"builderAddress\":\"0x71b09A08257078A4d642F7Dd7315e656c837329a\",\"cloid\":\"0x...\"}}` |\n| `order --json '{\"coin\":\"BTC\",\"side\":\"sell\",\"size\":\"0.001\",\"type\":\"market\",\"slippage\":0.01,\"reduceOnly\":true}'` | `{\"ok\":true,\"data\":{\"result\":{\"status\":\"ok\",\"response\":{\"data\":{\"statuses\":[{\"filled\":{\"oid\":123}}]}}}}}` |\n| `cancel --oid 123` or `cancel --all` | `{\"ok\":true,\"data\":{\"cancelled\":[\"123\"],\"result\":{\"status\":\"ok\"}}}` |\n| `modify --json '{\"modifications\":[{\"oid\":123,\"price\":\"20100\",\"size\":\"0.001\"}]}'` | `{\"ok\":true,\"data\":{\"status\":\"ok\"}}` |\n| `leverage --coin BTC --leverage 5 --mode isolated` | `{\"ok\":true,\"data\":{\"status\":\"ok\"}}` |\n| `run --detach` | `{\"ok\":true,\"data\":{\"pid\":123,\"startedAt\":1700000000000,\"network\":\"testnet\"}}` |\n| `events --since 12 --types '[\"fill\"]'` | `{\"ok\":true,\"data\":[{\"seq\":13,\"timestamp\":\"2026-01-01T00:00:00.000Z\",\"type\":\"fill\",\"data\":{\"tid\":1}}]}` |\n| `events --follow` | `{\"seq\":13,\"timestamp\":\"2026-01-01T00:00:00.000Z\",\"type\":\"fill\",\"data\":{\"tid\":1}}` (one line per event) |\n| `logs --follow --level warn` | `{\"level\":\"warn\",\"requestId\":\"...\",\"message\":\"Risk rejected\",\"time\":\"...\"}` (JSON lines) |\n| `rotate` then `rotate --signature 0x...` | `{\"ok\":true,\"data\":{\"oldAgent\":\"0x...\",\"newAgent\":\"0x...\",\"swapped\":true,\"oldRevoked\":false,\"revokeApproval\":{}}}` |\n| `rotate --revoke-signature 0x...` | `{\"ok\":true,\"data\":{\"swapped\":true,\"oldRevoked\":true}}` |\n| `revoke --cancel-orders` | `{\"ok\":true,\"data\":{\"locallyRevoked\":true,\"exchangeRevoked\":false,\"requiresSignature\":true,\"approval\":{}}}` |\n| `revoke --signature 0x...` | `{\"ok\":true,\"data\":{\"locallyRevoked\":true,\"exchangeRevoked\":true}}` |\n| `audit --intent ID` | `{\"ok\":true,\"data\":[{\"intentId\":\"ID\",\"stage\":\"decision\",\"data\":{\"allowed\":true},\"previousHash\":\"...\",\"hash\":\"...\"}]}` |\n| `skill install --target codex` | `{\"ok\":true,\"data\":{\"target\":\"codex\",\"path\":\".../agent-cli/SKILL.md\",\"version\":\"0.1.0\"}}` |\n\nBefore an order, query `market --coin BTC` for `mid`, `szDecimals`, asset and\nmarket leverage ceiling. Compute size/notional with decimal strings/bigints,\nusing the user-approved limit or the bounded IOC execution price. A valid schema\nalone does not establish that an order is tradable or within the budget.\n\nUse `--intent-id ID --intent \"reason\"` on trading actions to connect the user's\nreasoning to the audit. Keep cloid stable when retrying a known order intent.\nFor TP/SL use `type:\"tp\"|\"sl\"` and `triggerPrice` with size/price/reduceOnly;\nmarket orders use an explicit slippage-bounded IOC, not an unbounded market order.\n\n## Error recovery\n\n| Code | Action |\n| --- | --- |\n| RATE_LIMIT, NETWORK_ERROR | At most 3 read retries with exponential backoff; for uncertain mutations, reconcile order state/cloid before retrying. Stop and report unresolved results |\n| NONCE_COLLISION | Retry using a newly issued nonce; inspect a stale lock if persistent |\n| DEPOSIT_PENDING | Poll status until settled; stop on terminal funding failure |\n| RUNNER_NOT_RUNNING | Start runner or use configured direct fallback |\n| INSUFFICIENT_MARGIN | Reduce exposure or request authorized funding |\n| POLICY_REJECTED | Stop and revise intent within limits; do not bypass policy |\n| AGENT_EXPIRED | Rotate with master-wallet approval |\n| AGENT_NOT_APPROVED | Complete init/approval or explain revocation |\n| INVALID_SIZE, INVALID_PRICE | Correct input using market precision |\n| UNKNOWN_MARKET | Refresh metadata; use an allowed market |\n| ORDER_NOT_FOUND | Refresh orders before changing intent |\n| CONFIG_INVALID | Correct configuration/input; never insert secrets |\n| UPSTREAM_ERROR, INTERNAL | Stop, inspect redacted details/logs and report failure |\n\n## Gotchas\n\nHyperCore perps USDC uses **8 decimals**; EVM USDC uses **6**. Preserve strings and\nbigints. Some deposits require **two distinct signatures**; resume stored steps\nrather than restarting the route. Agent expiry is at most **180 days**. Never\nask for, paste, log or import a master private key or seed. The managed agent is\ntrade-only; local limits include markets, size/notional, leverage, daily loss and\nopen orders. Privy sees an L1 action hash, so it cannot independently inspect\nnotional/action contents; Hyperliquid agent permissions and local checks enforce\nthose boundaries. State is always `~/.bloxwap`, env prefix `BLOXWAP_`.\n\n\n## Verification boundaries\n\nOffline skill tests validate the documented command examples against CLI schemas.\nMocked lifecycle tests exercise resumable approvals, pending funding, events\nand failure handling. These checks do **not** prove a live agent or\nexchange run. The nightly testnet lifecycle uses only a company-owned disposable\nCI master account and separate test Privy app, real Hyperliquid testnet and Privy,\nand an explicitly mocked Relay route backed by already funded test collateral.\nIt never transfers real funds. Missing CI credentials fail the job; a skipped or\nmocked test must never be reported as live validation. Record the workflow run,\ncommit, lifecycle report, event and audit artifacts before claiming a testnet pass.\nSee `docs/agent-workflow.md` and `docs/testnet.md` in the repository for setup.\n"; +export const cliVersion="0.2.0"; +export const skillContent="---\nname: agent-cli\ndescription: Operate the agent-cli Hyperliquid trading CLI, including managed-agent onboarding, funding, orders, event monitoring, rotation, and normalized error recovery.\nmetadata:\n version: \"0.2.0\"\n---\n\nUse `agent-cli` for the user's authorized Hyperliquid account operations. Obtain\ncommand schemas with `agent-cli schema COMMAND`; arguments can be flags or\n`--json '{...}'`, or a JSON object on stdin. Ordinary commands print exactly one\nJSON object: `{ok:true,data}` or `{ok:false,code,message,retryable,details}`.\nLogs/QR appear on stderr. `events --follow` and `logs` explicitly stream JSON lines.\nUse `--network testnet` during testing; never silently change to mainnet.\n\n## Onboarding sequence\n\n1. The user creates and owns their own Privy account and app. Configure that\n app ID and a local secret reference, e.g. `config set privyAppId APP` and\n `config set privyAppSecretRef env:BLOXWAP_PRIVY_APP_SECRET`. The user sets the\n environment secret outside the conversation on their own machine or runner.\n Bloxwap does not host the app, receive credentials, or custody user keys.\n Privy manages the trading-agent key in the user's app; master-wallet approval\n always remains in the user's external wallet. The default Bloxwap builder is\n `0x71b09A08257078A4d642F7Dd7315e656c837329a`, with `f=10` (1 bp = 0.01%).\n Override with `config set builder.address` / `config set builder.fee` or\n `BLOXWAP_BUILDER_ADDRESS` / `BLOXWAP_BUILDER_FEE`.\n2. Run `init --master-address 0x... --network testnet`. Show the returned approval\n payload/deeplink/QR. The user signs in their master wallet; submit only the\n resulting signature with `init --signature 0x...`. Submit builder approval\n separately with `init --builder-signature 0x...` for the configured 0.01% default. Continue only after `approved:true`.\n3. Run `fund --amount 10 --origin-chain 42161`. Show `qrAscii`/deposit address,\n origin chain/token, minimum, fees, expected received amount and expiry. On\n testnet, do not treat the default Arbitrum mainnet chain/token as a test route:\n use an explicitly supported test chain/token and `originDecimals`, or the\n credential-gated CI harness with mocked Relay and pre-funded test collateral.\n If no test route is known, stop funding and report the missing route. The user\n transfers the quoted origin token. If `signatureSteps` require signatures,\n show the exact payload and submit each via `deposit` in returned order.\n4. Poll `status` until each active deposit is `settled`, for at most 12 polls\n or 5 minutes, whichever comes first. Start with 1-second delays, double to a\n 15-second cap, and stop with an explicit pending report if the budget expires.\n Settlement requires Relay success and Hyperliquid balance receipt. Stop on\n failed/refunded deposits and explain their status. Do not place orders while\n any deposit is awaiting funds or pending.\n5. Run `run --detach`, then monitor `events --follow --since SEQ`. Persist the\n last handled sequence; replay after reconnect. An unfilled or rejected order\n remains incomplete: do not claim the requested trade succeeded. A fill updates the trading\n plan, an error follows the catalog below, and expiry warnings prompt rotation\n using external master-wallet approval.\n\n## Completion and approval boundaries\n\nRead this skill and query schemas before acting. Keep a progress record with the\nnetwork, current stage, deposit IDs, last event sequence and order cloid/oid;\nrecord public IDs only. A missing user-owned Privy app, wallet signature, funding\nroute or settled balance is a blocked stage. Report the exact next action without\nrequesting any secret in chat or moving to the next stage. Repeat `init` to resume\npersisted approvals rather than creating another agent. An `ok:true` transport\nenvelope does not imply exchange acceptance: inspect `data.result` and reconcile\n`orders`/`events` after uncertain mutations. Never retry an order with a new cloid\nuntil the original intent has been reconciled.\n\nFor rotation, verify `swapped:true` before asking the external wallet to sign old\nagent revocation. Require `oldRevoked:true` before claiming rotation complete.\n`revoke` immediately disables local signing; only `exchangeRevoked:true` confirms\nthat the signed exchange revocation was submitted. Inspect `status` to verify the\nagent is absent from exchange approvals. Cancel outstanding orders before final\nrevocation, and report any cancellation or cleanup failure explicitly.\n\n## Commands and example envelopes\n\nExamples show representative `data`, not live balances or service promises.\nFull inputs/outputs are discoverable with `schema`; amounts/prices are strings.\n\n| Input | Example output |\n| --- | --- |\n| `--help` | `{\"ok\":true,\"data\":{\"commands\":[{\"name\":\"status\",\"description\":\"Read account status\"}],\"globalFlags\":[\"--json\",\"--config\",\"--network\",\"--pretty\"]}}` |\n| `schema order` | `{\"ok\":true,\"data\":{\"input\":{\"type\":\"object\"},\"output\":{\"oneOf\":[]}}}` (actual schemas include properties) |\n| `config get network` | `{\"ok\":true,\"data\":\"testnet\"}` |\n| `config set limits.maxLeverage 5` | `{\"ok\":true,\"data\":{\"version\":1,\"limits\":{\"maxLeverage\":5}}}` |\n| `config validate` | `{\"ok\":true,\"data\":{\"valid\":true,\"version\":1}}` |\n| `init --master-address 0x...` | `{\"ok\":true,\"data\":{\"approved\":false,\"requiresSignature\":true,\"approvals\":{\"agent\":{\"typedData\":{}}},\"qrAscii\":\"...\"}}` |\n| `fund --amount 10 --no-qr` | `{\"ok\":true,\"data\":{\"depositId\":\"...\",\"depositAddress\":\"0x...\",\"expectedReceived\":\"100000000\",\"builderFeeRate\":\"0.01%\",\"builderAddress\":\"0x71b09A08257078A4d642F7Dd7315e656c837329a\",\"state\":\"awaiting_funds\",\"qrAscii\":null}}` |\n| `deposit --deposit-id ID` | `{\"ok\":true,\"data\":{\"depositId\":\"ID\",\"steps\":[{\"id\":\"step:0\",\"requiresSignature\":true,\"payload\":{}}]}}` |\n| `deposit --deposit-id ID --step-id step:0 --signature 0x...` | `{\"ok\":true,\"data\":{\"depositId\":\"ID\",\"steps\":[]}}` |\n| `status` | `{\"ok\":true,\"data\":{\"balance\":{\"accountValue\":\"100\"},\"agent\":{\"approved\":true,\"daysRemaining\":\"179\"},\"deposits\":[],\"policy\":{\"id\":\"...\",\"version\":\"2\"},\"runner\":{\"pid\":\"123\"}}}` |\n| `balance` | `{\"ok\":true,\"data\":{\"accountValue\":\"100\",\"accountValueUnits\":\"10000000000\",\"withdrawable\":\"96\",\"marginUsed\":\"4\"}}` |\n| `market --coin BTC` | `{\"ok\":true,\"data\":{\"coin\":\"BTC\",\"asset\":\"0\",\"szDecimals\":\"5\",\"maxLeverage\":\"40\",\"mid\":\"20000\"}}` |\n| `positions` | `{\"ok\":true,\"data\":[{\"coin\":\"BTC\",\"size\":\"0.001\",\"entryPrice\":\"20000\",\"leverage\":\"5\",\"marginMode\":\"cross\"}]}` |\n| `orders` | `{\"ok\":true,\"data\":[{\"coin\":\"BTC\",\"oid\":\"123\",\"sz\":\"0.001\",\"limitPx\":\"20000\",\"side\":\"B\"}]}` |\n| `order --json '{\"coin\":\"BTC\",\"side\":\"buy\",\"size\":\"0.001\",\"price\":\"20000\",\"tif\":\"Gtc\",\"cloid\":\"0x11111111111111111111111111111111\"}'` | `{\"ok\":true,\"data\":{\"result\":{\"status\":\"ok\",\"response\":{\"data\":{\"statuses\":[{\"resting\":{\"oid\":123}}]}}},\"builderFeeRate\":\"0.01%\",\"builderAddress\":\"0x71b09A08257078A4d642F7Dd7315e656c837329a\",\"cloid\":\"0x...\"}}` |\n| `order --json '{\"coin\":\"BTC\",\"side\":\"sell\",\"size\":\"0.001\",\"type\":\"market\",\"slippage\":0.01,\"reduceOnly\":true}'` | `{\"ok\":true,\"data\":{\"result\":{\"status\":\"ok\",\"response\":{\"data\":{\"statuses\":[{\"filled\":{\"oid\":123}}]}}}}}` |\n| `cancel --oid 123` or `cancel --all` | `{\"ok\":true,\"data\":{\"cancelled\":[\"123\"],\"result\":{\"status\":\"ok\"}}}` |\n| `modify --json '{\"modifications\":[{\"oid\":123,\"price\":\"20100\",\"size\":\"0.001\"}]}'` | `{\"ok\":true,\"data\":{\"status\":\"ok\"}}` |\n| `leverage --coin BTC --leverage 5 --mode isolated` | `{\"ok\":true,\"data\":{\"status\":\"ok\"}}` |\n| `run --detach` | `{\"ok\":true,\"data\":{\"pid\":123,\"startedAt\":1700000000000,\"network\":\"testnet\"}}` |\n| `events --since 12 --types '[\"fill\"]'` | `{\"ok\":true,\"data\":[{\"seq\":13,\"timestamp\":\"2026-01-01T00:00:00.000Z\",\"type\":\"fill\",\"data\":{\"tid\":1}}]}` |\n| `events --follow` | `{\"seq\":13,\"timestamp\":\"2026-01-01T00:00:00.000Z\",\"type\":\"fill\",\"data\":{\"tid\":1}}` (one line per event) |\n| `logs --follow --level warn` | `{\"level\":\"warn\",\"requestId\":\"...\",\"message\":\"Risk rejected\",\"time\":\"...\"}` (JSON lines) |\n| `rotate` then `rotate --signature 0x...` | `{\"ok\":true,\"data\":{\"oldAgent\":\"0x...\",\"newAgent\":\"0x...\",\"swapped\":true,\"oldRevoked\":false,\"revokeApproval\":{}}}` |\n| `rotate --revoke-signature 0x...` | `{\"ok\":true,\"data\":{\"swapped\":true,\"oldRevoked\":true}}` |\n| `revoke --cancel-orders` | `{\"ok\":true,\"data\":{\"locallyRevoked\":true,\"exchangeRevoked\":false,\"requiresSignature\":true,\"approval\":{}}}` |\n| `revoke --signature 0x...` | `{\"ok\":true,\"data\":{\"locallyRevoked\":true,\"exchangeRevoked\":true}}` |\n| `audit --intent ID` | `{\"ok\":true,\"data\":[{\"intentId\":\"ID\",\"stage\":\"decision\",\"data\":{\"allowed\":true},\"previousHash\":\"...\",\"hash\":\"...\"}]}` |\n| `skill install --target codex` | `{\"ok\":true,\"data\":{\"target\":\"codex\",\"path\":\".../agent-cli/SKILL.md\",\"version\":\"0.2.0\"}}` |\n\nBefore an order, query `market --coin BTC` for `mid`, `szDecimals`, asset and\nmarket leverage ceiling. Compute size/notional with decimal strings/bigints,\nusing the user-approved limit or the bounded IOC execution price. A valid schema\nalone does not establish that an order is tradable or within the budget.\n\nUse `--intent-id ID --intent \"reason\"` on trading actions to connect the user's\nreasoning to the audit. Keep cloid stable when retrying a known order intent.\nFor TP/SL use `type:\"tp\"|\"sl\"` and `triggerPrice` with size/price/reduceOnly;\nmarket orders use an explicit slippage-bounded IOC, not an unbounded market order.\n\n## Error recovery\n\n| Code | Action |\n| --- | --- |\n| RATE_LIMIT, NETWORK_ERROR | At most 3 read retries with exponential backoff; for uncertain mutations, reconcile order state/cloid before retrying. Stop and report unresolved results |\n| NONCE_COLLISION | Retry using a newly issued nonce; inspect a stale lock if persistent |\n| DEPOSIT_PENDING | Poll status until settled; stop on terminal funding failure |\n| RUNNER_NOT_RUNNING | Start runner or use configured direct fallback |\n| INSUFFICIENT_MARGIN | Reduce exposure or request authorized funding |\n| POLICY_REJECTED | Stop and revise intent within limits; do not bypass policy |\n| AGENT_EXPIRED | Rotate with master-wallet approval |\n| AGENT_NOT_APPROVED | Complete init/approval or explain revocation |\n| INVALID_SIZE, INVALID_PRICE | Correct input using market precision |\n| UNKNOWN_MARKET | Refresh metadata; use an allowed market |\n| ORDER_NOT_FOUND | Refresh orders before changing intent |\n| CONFIG_INVALID | Correct configuration/input; never insert secrets |\n| UPSTREAM_ERROR, INTERNAL | Stop, inspect redacted details/logs and report failure |\n\n## Gotchas\n\nHyperCore perps USDC uses **8 decimals**; EVM USDC uses **6**. Preserve strings and\nbigints. Some deposits require **two distinct signatures**; resume stored steps\nrather than restarting the route. Agent expiry is at most **180 days**. Never\nask for, paste, log or import a master private key or seed. The managed agent is\ntrade-only; local limits include markets, size/notional, leverage, daily loss and\nopen orders. Privy sees an L1 action hash, so it cannot independently inspect\nnotional/action contents; Hyperliquid agent permissions and local checks enforce\nthose boundaries. State is always `~/.bloxwap`, env prefix `BLOXWAP_`.\n\n\n## Verification boundaries\n\nOffline skill tests validate the documented command examples against CLI schemas.\nMocked lifecycle tests exercise resumable approvals, pending funding, events\nand failure handling. These checks do **not** prove a live agent or\nexchange run. The nightly testnet lifecycle uses only a company-owned disposable\nCI master account and separate test Privy app, real Hyperliquid testnet and Privy,\nand an explicitly mocked Relay route backed by already funded test collateral.\nIt never transfers real funds. Missing CI credentials fail the job; a skipped or\nmocked test must never be reported as live validation. Record the workflow run,\ncommit, lifecycle report, event and audit artifacts before claiming a testnet pass.\nSee `docs/agent-workflow.md` and `docs/testnet.md` in the repository for setup.\n"; diff --git a/packages/agent-cli/test/skill.test.ts b/packages/agent-cli/test/skill.test.ts index 45670da..7d781e2 100644 --- a/packages/agent-cli/test/skill.test.ts +++ b/packages/agent-cli/test/skill.test.ts @@ -33,6 +33,7 @@ test('skill frontmatter and embedded source match the published skill', async () expect(frontmatter![1]).toMatch(/^name: agent-cli$/m); expect(frontmatter![1]).toMatch(/^description: [^\n:]+$/m); expect(frontmatter![1]).toContain(` version: "${packageInfo.version}"`); + expect(source).toContain(`"version":"${packageInfo.version}"`); for (const code of Object.keys(errorDefaults)) expect(source).toContain(code); for (const required of [ '8 decimals', '6', 'two distinct signatures', '180 days',