@thirdfy/agent-cli 0.2.72 → 0.2.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,16 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.73] - 2026-09-21
8
+
9
+ ### Added
10
+
11
+ - Hyperliquid Circle CCTP ids: `quote_hyperliquid_cctp_deposit` (read) and `deposit_hyperliquid_cctp` (write, 180s timeout). Managed execute signs those on `params.sourceChainId` and fails closed without it. Provider hints follow API `setupHints` and `get_hyperliquid_funding_status` `nextAction` instead of hardcoded Arbitrum / Li.Fi. Pin: `test/walletExecuteChainId.test.cjs`, `test/read-only-action-classifier.test.cjs`. Pairs with `thirdfy-mcp` **0.0.123**.
12
+
13
+ ### Fixed
14
+
15
+ - Managed execute signs `execute_bridge` / `get_bridge_quote` on `params.fromChain` even when `--chain-id` defaulted to Base. Preflight uses the same chain resolver as the execute payload. `execute_bridge`, `get_bridge_quote`, and `swap` use the 180s timeout. Pin: `test/walletExecuteChainId.test.cjs`, `test/actionTimeouts.test.cjs`. Pairs with `thirdfy-mcp` **0.0.123**.
16
+
7
17
  ## [0.2.72] - 2026-09-17
8
18
 
9
19
  ### Added
package/README.md CHANGED
@@ -40,9 +40,10 @@ Run without global install:
40
40
  npx @thirdfy/agent-cli --help
41
41
  ```
42
42
 
43
- ## What's new in v0.2.72
43
+ ## What's new in v0.2.73
44
44
 
45
- - Hyperliquid `place_hyperliquid_tp_sl` is a write. Lighter `place_lighter_perps_order` accepts stop-loss and take-profit `orderType` values with `triggerPrice`.
45
+ - Hyperliquid Circle CCTP ids `quote_hyperliquid_cctp_deposit` and `deposit_hyperliquid_cctp`. Managed execute signs those on `params.sourceChainId` with no default chain.
46
+ - Provider hints follow API `setupHints` and `get_hyperliquid_funding_status` `nextAction` instead of hardcoded Arbitrum / Li.Fi.
46
47
  - See [CHANGELOG.md](./CHANGELOG.md) and GitHub Releases for older versions.
47
48
 
48
49
  ## Quick start
@@ -197,7 +198,7 @@ Auth expectations by mode:
197
198
  - `hybrid`: requires execution identity and governed mirror semantics (`--hybrid-wallet-mode self|agent_wallet`, default `self`).
198
199
  - `thirdfy`: requires execution identity and delegated governance path.
199
200
  - `agent_wallet`: requires execution identity and owner `userDid`, but does not require subscriber delegation when the owner identity matches the agent wallet/creator. Thirdfy credits/free quota still gate execution; Privy gas sponsorship only covers network gas when enabled.
200
- - Hyperliquid setup uses `complete_hyperliquid_onboarding` for runtime-owned funding/setup. It can submit Li.Fi and Bridge2 steps automatically, then return `bridge2_submitted` while Hyperliquid credits the deposit. Bridge2 setup is the Arbitrum exception to the Base-focused `agent_wallet` rule: Bridge2 credits the transaction sender. Pass **`--estimated-amount-usd`** as a top-level flag (not inside `--params`). The normal solo `agent_wallet` path uses the managed execution wallet as the Hyperliquid main wallet. If margin already sits on a different Hyperliquid main wallet, pass that wallet as `mainWalletAddress` / order `userAddress`, and pass the approved execution/API wallet as `apiWalletAddress`. When USDC sits on your linked email-login wallet (`primaryEvmWallet`) instead of the managed execution wallet, Thirdfy API returns **`FUND_AGENT_EXECUTION_WALLET`** / **`MANUAL_BRIDGE2_DEPOSIT_REQUIRED`** with `fundedWallet` and `executionWalletAddress`; move native Arbitrum USDC to `executionWalletAddress` and retry.
201
+ - Hyperliquid setup uses `complete_hyperliquid_onboarding` for runtime-owned funding/setup. Call `get_hyperliquid_funding_status` and follow `nextAction` plus `nextActionParams`. Do not invent a funding chain. Pass **`--estimated-amount-usd`** as a top-level flag (not inside `--params`). The normal solo `agent_wallet` path uses the managed execution wallet as the Hyperliquid main wallet. If margin already sits on a different Hyperliquid main wallet, pass that wallet as `mainWalletAddress` / order `userAddress`, and pass the approved execution/API wallet as `apiWalletAddress`. When USDC sits on your linked email-login wallet (`primaryEvmWallet`) instead of the managed execution wallet, Thirdfy API returns **`FUND_AGENT_EXECUTION_WALLET`** with `fundedWallet` and `executionWalletAddress`; move USDC to `executionWalletAddress` on the chain named by `nextActionParams.sourceChainId` and retry.
201
202
  - custody mode defaults are profile-aware:
202
203
  - `managed` default for `thirdfy`
203
204
  - `external` default for `self` and `hybrid`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.2.72",
3
+ "version": "0.2.73",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,6 +16,11 @@ const LONG_RUNNING_ACTIONS = new Set([
16
16
  'get_cmc_perp_contract_analysis',
17
17
  'get_cmc_market_regime',
18
18
  'get_cmc_derivatives_crowding',
19
+ 'execute_bridge',
20
+ 'get_bridge_quote',
21
+ 'swap',
22
+ 'execute_optimal_swap',
23
+ 'deposit_hyperliquid_cctp',
19
24
  ]);
20
25
 
21
26
  function normalizeActionId(action) {
@@ -20,6 +20,7 @@ const READ_ONLY_EXACT = new Set([
20
20
  'get_condor_policy_status',
21
21
  'get_hummingbot_gateway_networks',
22
22
  'get_hummingbot_gateway_connectors',
23
+ 'quote_hyperliquid_cctp_deposit',
23
24
  ]);
24
25
 
25
26
  export function normalizeActionKey(actionKey) {
@@ -0,0 +1,49 @@
1
+ const DEFAULT_CHAIN_ID = 8453;
2
+
3
+ function normalizeActionId(action) {
4
+ return String(action || '')
5
+ .trim()
6
+ .replace(/-/g, '_')
7
+ .toLowerCase();
8
+ }
9
+
10
+ function positiveChainId(value) {
11
+ const n = Number(value);
12
+ if (!Number.isFinite(n) || n <= 0) return undefined;
13
+ return Math.trunc(n);
14
+ }
15
+
16
+ function isBridgeAction(action) {
17
+ const key = normalizeActionId(action);
18
+ return key === 'execute_bridge' || key === 'get_bridge_quote' || key === 'check_bridge_status';
19
+ }
20
+
21
+ function isHyperliquidCctpAction(action) {
22
+ const key = normalizeActionId(action);
23
+ return key === 'deposit_hyperliquid_cctp' || key === 'quote_hyperliquid_cctp_deposit';
24
+ }
25
+
26
+ /**
27
+ * Signing / wallet-preflight chain for managed execute.
28
+ * Bridge writes sign on fromChain. CCTP burns sign on sourceChainId. Do not default Base.
29
+ */
30
+ export function resolveWalletExecuteChainId({ action, chainId, params } = {}) {
31
+ const record = params && typeof params === 'object' ? params : {};
32
+ if (isHyperliquidCctpAction(action)) {
33
+ const sourceChainId = positiveChainId(record.sourceChainId);
34
+ if (!sourceChainId) {
35
+ throw new Error('HYPERLIQUID_CCTP_SOURCE_CHAIN_REQUIRED');
36
+ }
37
+ return sourceChainId;
38
+ }
39
+ if (isBridgeAction(action)) {
40
+ return (
41
+ positiveChainId(record.fromChain) ||
42
+ positiveChainId(record.fromChainId) ||
43
+ positiveChainId(chainId) ||
44
+ positiveChainId(record.chainId) ||
45
+ DEFAULT_CHAIN_ID
46
+ );
47
+ }
48
+ return positiveChainId(chainId) || positiveChainId(record.chainId) || DEFAULT_CHAIN_ID;
49
+ }
@@ -93,6 +93,8 @@ function inferActionProvider(action) {
93
93
  'get-hyperliquid-referral-status': 'hyperliquid',
94
94
  'deposit-hyperliquid-staking': 'hyperliquid',
95
95
  'deposit-hyperliquid-bridge': 'hyperliquid',
96
+ 'deposit-hyperliquid-cctp': 'hyperliquid',
97
+ 'quote-hyperliquid-cctp-deposit': 'hyperliquid',
96
98
  'place-hyperliquid-perps-order': 'hyperliquid',
97
99
  'cancel-hyperliquid-perps-order': 'hyperliquid',
98
100
  'update-hyperliquid-leverage': 'hyperliquid',
@@ -7,6 +7,7 @@ import { createCliError } from '../../core/envelope.mjs';
7
7
  import { normalizeRunMode, normalizeManagedRunMode, normalizeHybridWalletMode } from '../../core/runMode.mjs';
8
8
  import { assertHostedRuntimePolymarketWriteIdempotency } from './hostedRuntimeWriteGate.mjs';
9
9
  import { resolveTokenInForFunding } from '../../core/fundingTokenIn.mjs';
10
+ import { resolveWalletExecuteChainId } from '../../core/walletExecuteChainId.mjs';
10
11
 
11
12
  function isTruthyFlag(value) {
12
13
  return value === true || String(value || '').trim().toLowerCase() === 'true';
@@ -129,16 +130,21 @@ function buildManagedExecutePayload(flags, options) {
129
130
  delete managedParams.tokenInDecimals;
130
131
  managedParams.amountIn = flags.__swapInput.amountInHuman;
131
132
  }
133
+ const action = String(options.resolvedAction || requireFlag(flags, 'action', 'Missing --action')).trim();
132
134
  const payload = {
133
135
  agentApiKey: resolveAgentApiKey(flags, runMode),
134
- action: String(options.resolvedAction || requireFlag(flags, 'action', 'Missing --action')).trim(),
136
+ action,
135
137
  userDid: resolveEffectiveUserDid(flags, {
136
138
  runMode,
137
139
  hybridWalletMode: options.hybridWalletMode,
138
140
  preferDelegationIdentity: options.preferDelegationIdentity,
139
141
  }),
140
142
  params: managedParams,
141
- chainId: Number(flags.chainId || 8453),
143
+ chainId: resolveWalletExecuteChainId({
144
+ action,
145
+ chainId: flags.chainId,
146
+ params: managedParams,
147
+ }),
142
148
  executionStrategy: {
143
149
  runMode,
144
150
  mirrorOnly: false,
@@ -12,6 +12,7 @@ import {
12
12
  import { apiGet, apiPost } from '../../core/http.mjs';
13
13
  import { withActionTimeout } from '../../core/actionTimeouts.mjs';
14
14
  import { isReadOnlyResolvedAction } from '../../core/readOnlyActions.mjs';
15
+ import { resolveWalletExecuteChainId } from '../../core/walletExecuteChainId.mjs';
15
16
  import { isEmptyQueuedExecuteIntent, shouldFallbackManagedReadToExecuteIntent } from './managedReadExecuteRail.mjs';
16
17
  import { createRequire } from 'module';
17
18
 
@@ -637,7 +638,13 @@ async function executeHybridRun(ctx, flags, resolved, options) {
637
638
  }
638
639
 
639
640
  async function resolveManagedExecutionPreflight(ctx, flags, resolved, options = {}) {
640
- const chainId = Number(flags.chainId || 8453);
641
+ const action = String(resolved?.resolvedAction || flags.action || '').trim();
642
+ const params = getPreparedParams(flags);
643
+ const chainId = resolveWalletExecuteChainId({
644
+ action,
645
+ chainId: flags.chainId,
646
+ params,
647
+ });
641
648
  const runMode = String(options.runMode || 'agent_wallet').trim().toLowerCase();
642
649
  const agentApiKey = resolveAgentApiKey(flags, runMode);
643
650
  const userDid = resolveEffectiveUserDid(flags, {
@@ -657,10 +664,7 @@ async function resolveManagedExecutionPreflight(ctx, flags, resolved, options =
657
664
  signerMethod: 'managed_wallet_server',
658
665
  };
659
666
  }
660
- const tokenIn = resolveTokenInForFunding(
661
- getPreparedParams(flags),
662
- resolved?.resolvedAction || flags.action
663
- );
667
+ const tokenIn = resolveTokenInForFunding(params, action);
664
668
  const query = new URLSearchParams({
665
669
  userDid,
666
670
  chainId: String(chainId),
@@ -5,18 +5,8 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
5
5
  function getTradingProviderHint(providerId) {
6
6
  const provider = String(providerId || '').trim().toLowerCase();
7
7
  const manifestHint = getCachedProviderHintFromCapabilities(provider);
8
- if (manifestHint) return manifestHint;
9
- if (provider === 'trading') {
10
- return {
11
- provider,
12
- category: 'onchain_spot',
13
- canonicalWriteAction: 'swap',
14
- supportedChains: [1, 10, 130, 137, 8453, 84532, 42161, 4663],
15
- laneCompatibility:
16
- 'Kyber quote/build is live on Ethereum, Optimism, Unichain, Polygon, Base, and Arbitrum; sponsored Kyber execution is validated on Base only. Robinhood Chain (4663) uses Li.Fi Intents for spot swaps with user-pays gas. Gnosis FX uses the fx provider via CoW.',
17
- credentialUx: 'Use normal Thirdfy login/delegation; do not use this provider for Hyperliquid, Lighter, or Polymarket.',
18
- };
19
- }
8
+ const setupHints =
9
+ manifestHint?.setupHints && typeof manifestHint.setupHints === 'object' ? manifestHint.setupHints : {};
20
10
  if (provider === 'hyperliquid') {
21
11
  return {
22
12
  provider,
@@ -34,6 +24,7 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
34
24
  'get_hyperliquid_onboarding_plan',
35
25
  'get_hyperliquid_referral_status',
36
26
  'get_hyperliquid_builder_fee_status',
27
+ 'quote_hyperliquid_cctp_deposit',
37
28
  ],
38
29
  orderManagementActions: [
39
30
  'place_hyperliquid_perps_order',
@@ -48,13 +39,16 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
48
39
  'get_hyperliquid_onboarding_plan',
49
40
  'prepare_hyperliquid_onboarding',
50
41
  'complete_hyperliquid_onboarding',
42
+ 'quote_hyperliquid_cctp_deposit',
43
+ 'deposit_hyperliquid_cctp',
44
+ 'deposit_hyperliquid_bridge',
45
+ 'transfer_hyperliquid_spot_to_perps',
51
46
  'get_bridge_quote',
52
47
  'execute_bridge',
53
48
  'approve_hyperliquid_agent',
54
49
  'get_hyperliquid_builder_fee_status',
55
50
  'approve_hyperliquid_builder_fee',
56
51
  'set_hyperliquid_referrer',
57
- 'deposit_hyperliquid_bridge',
58
52
  'deposit_hyperliquid_staking',
59
53
  'claim_hyperliquid_testnet_faucet',
60
54
  ],
@@ -73,17 +67,14 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
73
67
  credentialType: 'hyperliquid_api_wallet',
74
68
  credentialUx:
75
69
  'Thirdfy manages Hyperliquid API-wallet setup for normal users. Delegated writes require encrypted privateKey-backed hyperliquid_api_wallet credentials; walletAddress-only records are rejected until Privy walletId-backed Hyperliquid signing ships.',
76
- recommendedFundingChainId: 42161,
77
70
  supportedFundingSourceChains: [
78
- { chainId: 42161, name: 'Arbitrum One', path: 'native USDC -> Bridge2' },
79
- { chainId: 8453, name: 'Base', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
80
- { chainId: 1, name: 'Ethereum', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
81
- { chainId: 137, name: 'Polygon', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
71
+ { chainId: 8453, name: 'Base' },
72
+ { chainId: 42161, name: 'Arbitrum One' },
73
+ { chainId: 137, name: 'Polygon' },
74
+ { chainId: 1, name: 'Ethereum' },
82
75
  ],
83
76
  setupBlockers: [
84
77
  'HYPERLIQUID_SOURCE_FUNDS_REQUIRED',
85
- 'HYPERLIQUID_ARBITRUM_USDC_REQUIRED',
86
- 'HYPERLIQUID_BRIDGE2_DEPOSIT_REQUIRED',
87
78
  'HYPERLIQUID_API_WALLET_APPROVAL_REQUIRED',
88
79
  'HYPERLIQUID_BUILDER_APPROVAL_REQUIRED',
89
80
  'HYPERLIQUID_POLICY_REQUIRED',
@@ -94,17 +85,32 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
94
85
  'HYPERLIQUID_BUILDER_WALLET_UNFUNDED',
95
86
  'HYPERLIQUID_API_WALLET_NOT_PROVIDED',
96
87
  ],
97
- sourceBridgeProvider: 'lifi',
98
88
  funding:
99
- 'Best path: Base/Ethereum/Polygon USDC -> Li.Fi bridge to native Arbitrum USDC -> Hyperliquid Bridge2. If the user already has native Circle USDC on Arbitrum One (42161), skip Li.Fi and call deposit_hyperliquid_bridge. Minimum 5 USDC; Bridge2 credits the sender/source wallet.',
89
+ 'Follow nextAction and nextActionParams from get_hyperliquid_funding_status. Do not invent a funding chain.',
100
90
  laneCompatibility:
101
- 'Use self/BYOW only for setup signatures or Arbitrum funding transactions. Perps order placement is an offchain venue write and should use thirdfy, hybrid, or agent_wallet. The default solo agent_wallet path uses the managed execution wallet as the Hyperliquid master address. If margin already sits on a distinct Hyperliquid main wallet, pass that as userAddress/mainWalletAddress and pass the approved execution/API wallet as apiWalletAddress.',
91
+ 'Use self/BYOW only for setup signatures or source-chain funding transactions. Perps order placement is an offchain venue write and should use thirdfy, hybrid, or agent_wallet. The default solo agent_wallet path uses the managed execution wallet as the Hyperliquid master address. If margin already sits on a distinct Hyperliquid main wallet, pass that as userAddress/mainWalletAddress and pass the approved execution/API wallet as apiWalletAddress.',
102
92
  setupExample:
103
- 'actions --provider hyperliquid -> get_hyperliquid_funding_status -> complete_hyperliquid_onboarding for runtime-owned setup, or get_hyperliquid_onboarding_plan/prepare_hyperliquid_onboarding for operator previews -> get_bridge_quote/execute_bridge if source is Base/Ethereum/Polygon -> deposit_hyperliquid_bridge on 42161 -> approve_hyperliquid_agent -> approve_hyperliquid_builder_fee only when get_hyperliquid_setup_status shows builder.enabled=true -> get_hyperliquid_setup_status before place_hyperliquid_perps_order',
93
+ 'actions --provider hyperliquid -> get_hyperliquid_funding_status -> complete_hyperliquid_onboarding for runtime-owned setup, or get_hyperliquid_onboarding_plan/prepare_hyperliquid_onboarding for operator previews -> follow nextAction with nextActionParams -> get_hyperliquid_setup_status before place_hyperliquid_perps_order',
104
94
  monetization:
105
95
  'Builder monetization is active only when the API operator configured a builder address and the builder treasury has Hyperliquid margin. When active, the main wallet signs approve_hyperliquid_builder_fee once and orders attach builder fees. When the treasury is unfunded, get_hyperliquid_setup_status can return ready=true with warning HYPERLIQUID_BUILDER_WALLET_UNFUNDED, get_hyperliquid_builder_fee_status returns monetizationEnabled=false with reason BUILDER_WALLET_UNFUNDED, and place_hyperliquid_perps_order does not require builder approval.',
106
96
  example:
107
97
  'thirdfy-agent actions --provider hyperliquid && thirdfy-agent preflight --action place_hyperliquid_perps_order --params \'{"coin":"ETH","isBuy":true,"size":0.01,"limitPx":3500,"orderType":"market"}\'',
98
+ ...(manifestHint || {}),
99
+ ...setupHints,
100
+ provider,
101
+ source: manifestHint ? 'cli_capabilities_manifest' : 'static_provider_hint',
102
+ };
103
+ }
104
+ if (manifestHint) return manifestHint;
105
+ if (provider === 'trading') {
106
+ return {
107
+ provider,
108
+ category: 'onchain_spot',
109
+ canonicalWriteAction: 'swap',
110
+ supportedChains: [1, 10, 130, 137, 8453, 84532, 42161, 4663],
111
+ laneCompatibility:
112
+ 'Kyber quote/build is live on Ethereum, Optimism, Unichain, Polygon, Base, and Arbitrum; sponsored Kyber execution is validated on Base only. Robinhood Chain (4663) uses Li.Fi Intents for spot swaps with user-pays gas. Gnosis FX uses the fx provider via CoW.',
113
+ credentialUx: 'Use normal Thirdfy login/delegation; do not use this provider for Hyperliquid, Lighter, or Polymarket.',
108
114
  };
109
115
  }
110
116
  if (provider === 'lighter') {
@@ -952,6 +958,7 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
952
958
  custodyMode: match.custodyMode || null,
953
959
  description: match.description || null,
954
960
  source: 'cli_capabilities_manifest',
961
+ ...(match.setupHints && typeof match.setupHints === 'object' ? { setupHints: match.setupHints } : {}),
955
962
  };
956
963
  }
957
964