@thirdfy/agent-cli 0.2.21 → 0.2.25

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,39 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.25] - 2026-07-11
8
+
9
+ ### Fixed
10
+
11
+ - Solo `agent_wallet` still uses `did:wallet:<agentKey>`, but hybrid `agent_wallet` and `--signer-method managed_wallet_server` keep saved Privy delegation identity.
12
+
13
+ ## [0.2.24] - 2026-07-11
14
+
15
+ ### Fixed
16
+
17
+ - `agent_wallet` execute-intent read-only fallback now passes `runMode: agent_wallet` into identity resolution so solo `did:wallet:<agentKey>` is used consistently.
18
+
19
+ ## [0.2.23] - 2026-07-11
20
+
21
+ ### Fixed
22
+
23
+ - Solo `agent_wallet` preflight now resolves `did:wallet:<agentKey>` from `--agent-key`, `THIRDFY_AGENT_KEY`, or `config.agent.agentKey` instead of falling back to subscriber Privy `userDid` (fixes `SUBSCRIPTION_NOT_FOUND` on Robinhood and other direct agent lanes).
24
+
25
+ ### Added
26
+
27
+ - `npm run validate:robinhood-agent-wallet-preflight` for live API solo agent_wallet preflight on chain 4663.
28
+
29
+ ## [0.2.22] - 2026-07-10
30
+
31
+ ### Added
32
+
33
+ - Robinhood Chain (4663) provider hints for trading, bridge, yield-xyz, and market-data; `robinhood-mainnet` chat alias; live capabilities validation for 4663.
34
+
35
+ ### Fixed
36
+
37
+ - Capabilities-derived hints no longer set a write action for read-only `market-data`.
38
+ - Live API validation also asserts `yield-xyz` includes chain 4663.
39
+
7
40
  ## [0.2.21] - 2026-07-05
8
41
 
9
42
  ### Added
package/README.md CHANGED
@@ -40,11 +40,18 @@ Run without global install:
40
40
  npx @thirdfy/agent-cli --help
41
41
  ```
42
42
 
43
- ## What's new in v0.2.21
43
+ ## What's new in v0.2.25
44
44
 
45
- - **Console mandate:** `thirdfy-agent console-mandate status|draft|activate|revoke` for Console delegated execution with daily cap and expiry.
46
- - Uses the same `/api/v1/console/delegation/*` routes as Console and Account. Separate from certified-agent `delegation *` commands.
47
- - Pairs with Thirdfy API **v3.10.2+**. See [`docs/command-reference.md`](./docs/command-reference.md).
45
+ - Hybrid and `managed_wallet_server` agent_wallet paths keep Privy delegation identity; solo Robinhood lane still uses `did:wallet:<agentKey>`.
46
+
47
+ ## What's new in v0.2.24
48
+
49
+ - `agent_wallet` read-only execute-intent fallback keeps solo `did:wallet:<agentKey>` identity (matches preflight and primary execute path).
50
+
51
+ ## What's new in v0.2.23
52
+
53
+ - Solo `agent_wallet` preflight uses `did:wallet:<agentKey>` so Robinhood and direct agent lanes skip subscriber delegation (`SUBSCRIPTION_NOT_FOUND` fix).
54
+ - `npm run validate:robinhood-agent-wallet-preflight` for live chain 4663 execution-wallet checks.
48
55
 
49
56
  Older versions: see [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
50
57
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.2.21",
3
+ "version": "0.2.25",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -47,6 +47,8 @@
47
47
  "smoke:cli": "node ./bin/thirdfy-agent.mjs --help && node ./bin/thirdfy-agent.mjs -V && node ./bin/thirdfy-agent.mjs --version --json",
48
48
  "validate:release-preflight": "npm run lint && npm run validate:public-docs && npm run validate:cli-contract-schemas && npm run validate:provider-parity && npm run validate:cli-manifest-handlers && npm run validate:runtime-boundaries && npm run test && npm run validate:npm-pack && npm run smoke:cli",
49
49
  "validate:live-api-capabilities": "node ./scripts/validate-live-api-capabilities.mjs",
50
+ "validate:robinhood-agent-wallet-preflight": "node ./scripts/validate-robinhood-agent-wallet-preflight.mjs",
51
+ "validate:robinhood-agent-wallet-preflight": "node ./scripts/validate-robinhood-agent-wallet-preflight.mjs",
50
52
  "prepublishOnly": "npm run validate:release-preflight"
51
53
  },
52
54
  "keywords": [
@@ -5,6 +5,7 @@ import { apiGet, safeJsonParse } from '../core/http.mjs';
5
5
  const NETWORK_CHAIN_IDS = {
6
6
  'base-mainnet': 8453,
7
7
  'base-sepolia': 84532,
8
+ 'robinhood-mainnet': 4663,
8
9
  };
9
10
 
10
11
  const DEFAULT_CHAT_CHAIN_ID = 8453;
@@ -16,13 +16,57 @@ function buildBuildTxPayload(flags, resolvedAction) {
16
16
  return payload;
17
17
  }
18
18
 
19
- function resolveEffectiveUserDid(flags) {
19
+ function resolveAgentKey(flags) {
20
+ const explicit = String(flags.agentKey || '').trim();
21
+ if (explicit) return explicit.toLowerCase();
22
+ const envKey = String(process.env.THIRDFY_AGENT_KEY || process.env.AGENT_KEY || '').trim();
23
+ if (envKey) return envKey.toLowerCase();
24
+ const config = loadProfileConfig();
25
+ const configKey = String(config?.agent?.agentKey || '').trim();
26
+ if (configKey) return configKey.toLowerCase();
27
+ return '';
28
+ }
29
+
30
+ function buildSoloAgentWalletUserDid(agentKey) {
31
+ const normalized = String(agentKey || '').trim().toLowerCase();
32
+ if (!normalized) return '';
33
+ return `did:wallet:${normalized}`;
34
+ }
35
+
36
+ function isWalletScopedUserDid(value) {
37
+ return String(value || '').trim().toLowerCase().startsWith('did:wallet:');
38
+ }
39
+
40
+ function preferDelegationAgentWalletIdentity(flags, options = {}) {
41
+ if (options.preferDelegationIdentity === true) return true;
42
+ if (String(flags.runMode || '').trim().toLowerCase() === 'hybrid') return true;
43
+ if (options.hybridWalletMode) return true;
44
+ const signerMethod = String(flags.signerMethod || '').trim().toLowerCase();
45
+ if (signerMethod === 'managed_wallet_server') return true;
46
+ const scope = String(flags.executionScope || '').trim();
47
+ if (scope && scope !== 'solo_owner_mirror') return true;
48
+ return false;
49
+ }
50
+
51
+ function resolveEffectiveUserDid(flags, options = {}) {
20
52
  const explicit = String(flags.userDid || '').trim();
21
53
  if (explicit) return explicit;
54
+ const runMode = String(options.runMode || flags.runMode || '').trim().toLowerCase();
22
55
  const envUserDid = String(process.env.THIRDFY_USER_DID || '').trim();
23
- if (envUserDid) return envUserDid;
24
56
  const config = loadProfileConfig();
25
- return String(config?.wallets?.userDid || config?.identity?.userDid || '').trim();
57
+ const configUserDid = String(config?.wallets?.userDid || config?.identity?.userDid || '').trim();
58
+
59
+ // Solo agent_wallet uses did:wallet:<agentKey>. Hybrid and managed_wallet_server keep Privy delegation.
60
+ if (runMode === 'agent_wallet' && !preferDelegationAgentWalletIdentity(flags, options)) {
61
+ const soloDid = buildSoloAgentWalletUserDid(resolveAgentKey(flags));
62
+ if (soloDid) return soloDid;
63
+ if (isWalletScopedUserDid(envUserDid)) return envUserDid;
64
+ if (isWalletScopedUserDid(configUserDid)) return configUserDid;
65
+ return '';
66
+ }
67
+
68
+ if (envUserDid) return envUserDid;
69
+ return configUserDid;
26
70
  }
27
71
 
28
72
  function buildManagedExecutePayload(flags, options) {
@@ -55,7 +99,11 @@ function buildManagedExecutePayload(flags, options) {
55
99
  const payload = {
56
100
  agentApiKey: resolveAgentApiKey(flags, runMode),
57
101
  action: String(options.resolvedAction || requireFlag(flags, 'action', 'Missing --action')).trim(),
58
- userDid: resolveEffectiveUserDid(flags),
102
+ userDid: resolveEffectiveUserDid(flags, {
103
+ runMode,
104
+ hybridWalletMode: options.hybridWalletMode,
105
+ preferDelegationIdentity: options.preferDelegationIdentity,
106
+ }),
59
107
  params: managedParams,
60
108
  chainId: Number(flags.chainId || 8453),
61
109
  executionStrategy: {
@@ -66,7 +114,7 @@ function buildManagedExecutePayload(flags, options) {
66
114
  if (!payload.userDid) {
67
115
  throw createCliError(
68
116
  'MISSING_USER_DID',
69
- 'Managed wallet execution requires --user-did, THIRDFY_USER_DID, or a saved userDid from `thirdfy-agent login email`.'
117
+ 'Managed wallet execution requires --user-did, --agent-key (solo did:wallet identity), THIRDFY_USER_DID, or a saved userDid from `thirdfy-agent login email`.'
70
118
  );
71
119
  }
72
120
  if (flags.estimatedAmountUsd) payload.estimatedAmountUsd = Number(flags.estimatedAmountUsd);
@@ -96,7 +144,12 @@ function buildIntentPayload(flags, options) {
96
144
  if (flags.catalog) payload.catalog = String(flags.catalog).trim();
97
145
  if (flags.chainId) payload.chainId = Number(flags.chainId);
98
146
  if (flags.estimatedAmountUsd) payload.estimatedAmountUsd = Number(flags.estimatedAmountUsd);
99
- const userDid = resolveEffectiveUserDid(flags);
147
+ const intentRunMode = String(options.runMode || flags.runMode || '').trim().toLowerCase();
148
+ const userDid = resolveEffectiveUserDid(flags, {
149
+ runMode: intentRunMode,
150
+ hybridWalletMode: options.hybridWalletMode,
151
+ preferDelegationIdentity: options.preferDelegationIdentity,
152
+ });
100
153
  if (flags.userDid || (options.validationOnly && (runMode === 'agent_wallet' || (runMode === 'hybrid' && options.mirrorOnly)))) {
101
154
  if (userDid) payload.userDid = userDid;
102
155
  }
@@ -139,6 +192,8 @@ function resolveAgentApiKey(flags, runMode) {
139
192
 
140
193
  return {
141
194
  buildBuildTxPayload,
195
+ resolveAgentKey,
196
+ buildSoloAgentWalletUserDid,
142
197
  resolveEffectiveUserDid,
143
198
  buildManagedExecutePayload,
144
199
  resolveTokenInForFunding,
@@ -338,7 +338,11 @@ async function executeManagedWalletRun(ctx, flags, resolved, options) {
338
338
  const actionCtx = withActionTimeout(ctx, resolved.resolvedAction);
339
339
  const response = await apiPost(actionCtx, '/api/v1/agent/execute', payload);
340
340
  if (shouldFallbackAgentWalletToExecuteIntent(resolved, response)) {
341
- const userDid = resolveEffectiveUserDid(flags);
341
+ const userDid = resolveEffectiveUserDid(flags, {
342
+ runMode: 'agent_wallet',
343
+ hybridWalletMode: options.hybridWalletMode,
344
+ preferDelegationIdentity: options.preferDelegationIdentity,
345
+ });
342
346
  const chainId = Number(flags.chainId || 8453);
343
347
  const intentResult = await executeThirdfyRun(
344
348
  ctx,
@@ -493,13 +497,20 @@ async function resolveManagedExecutionPreflight(ctx, flags, resolved, options =
493
497
  const chainId = Number(flags.chainId || 8453);
494
498
  const runMode = String(options.runMode || 'agent_wallet').trim().toLowerCase();
495
499
  const agentApiKey = resolveAgentApiKey(flags, runMode);
496
- const userDid = resolveEffectiveUserDid(flags);
500
+ const userDid = resolveEffectiveUserDid(flags, {
501
+ runMode,
502
+ hybridWalletMode: options.hybridWalletMode,
503
+ preferDelegationIdentity: options.preferDelegationIdentity,
504
+ });
497
505
  if (!userDid) {
498
506
  return {
499
507
  success: false,
500
508
  blockedReason: 'MISSING_USER_DID',
501
509
  blockedStage: 'routing',
502
- error: 'Managed wallet execution requires --user-did, THIRDFY_USER_DID, or a saved userDid from `thirdfy-agent login email`.',
510
+ error:
511
+ runMode === 'agent_wallet'
512
+ ? 'Solo agent_wallet requires --agent-key, THIRDFY_AGENT_KEY, config.agent.agentKey, or --user-did did:wallet:<agentKey>. Subscriber Privy DIDs require delegation; use did:wallet for direct agent execution.'
513
+ : 'Managed wallet execution requires --user-did, THIRDFY_USER_DID, or a saved userDid from `thirdfy-agent login email`.',
503
514
  signerMethod: 'managed_wallet_server',
504
515
  };
505
516
  }
@@ -11,9 +11,9 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
11
11
  provider,
12
12
  category: 'onchain_spot',
13
13
  canonicalWriteAction: 'swap',
14
- supportedChains: [1, 10, 130, 137, 8453, 84532, 42161],
14
+ supportedChains: [1, 10, 130, 137, 8453, 84532, 42161, 4663],
15
15
  laneCompatibility:
16
- 'Kyber quote/build is live on Ethereum, Optimism, Unichain, Polygon, Base, and Arbitrum; sponsored Kyber execution is validated on Base only. Gnosis FX uses the fx provider via CoW.',
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
17
  credentialUx: 'Use normal Thirdfy login/delegation; do not use this provider for Hyperliquid, Lighter, or Polymarket.',
18
18
  };
19
19
  }
@@ -329,7 +329,7 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
329
329
  canonicalWriteAction: 'execute_bridge',
330
330
  readActions: ['get_bridge_quote', 'get_supported_bridge_chains', 'check_bridge_status'],
331
331
  orderManagementActions: ['execute_bridge'],
332
- supportedChains: [1, 8453, 42161, 10, 137, 56, 43114, 250, 100, 1284, 1285, 25, 288, 1088, 42220, 122, 324, 59144, 534352, 5000, 81457, 169],
332
+ supportedChains: [1, 8453, 42161, 10, 137, 56, 43114, 250, 100, 1284, 1285, 25, 288, 1088, 42220, 122, 324, 59144, 534352, 5000, 81457, 169, 4663],
333
333
  laneCompatibility: 'Li.Fi bridge supports mainnet value movement only; testnets are not auto-mapped to mainnet.',
334
334
  };
335
335
  }
@@ -455,6 +455,22 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
455
455
  'Yield.xyz writes are transaction-prep first. Thirdfy calls Yield.xyz directly and validates returned unsigned transactions with @yieldxyz/shield before signing or returning prepared calls.',
456
456
  example:
457
457
  'thirdfy-agent actions --provider yield-xyz && thirdfy-agent preflight --action deposit_earn_position --params \'{"providerId":"yield-xyz","opportunityId":"ethereum-eth-lido-staking","tokenAddress":"0x...","amount":"0.01","chainId":1}\'',
458
+ supportedChains: [1, 10, 100, 130, 137, 42220, 8453, 42161, 4663],
459
+ };
460
+ }
461
+ if (provider === 'market-data') {
462
+ return {
463
+ provider,
464
+ category: 'market_data',
465
+ canonicalReadAction: 'get_trending_tokens',
466
+ readActions: [
467
+ 'get_trending_tokens',
468
+ 'get_new_token_launches',
469
+ 'get_token_market_data',
470
+ 'get_chain_market_overview',
471
+ ],
472
+ supportedChains: [8453, 84532, 4663],
473
+ laneCompatibility: 'Read-only market data via API-owned actions. Robinhood Chain uses CoinGecko Onchain network id robinhood.',
458
474
  };
459
475
  }
460
476
  return null;
@@ -488,6 +504,7 @@ export function createProviderHints({ getNegotiatedCapabilitiesCache }) {
488
504
  curve: 'get_curve_pools',
489
505
  'vaults-fyi': 'get-vaults-fyi-vaults',
490
506
  'yield-xyz': 'get_yield_xyz_opportunities',
507
+ 'market-data': 'get_trending_tokens',
491
508
  prediction: 'get_prediction_markets',
492
509
  };
493
510
  return {