@thirdfy/agent-cli 0.2.22 → 0.2.28

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,50 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.2.28] - 2026-07-11
8
+
9
+ ### Fixed
10
+
11
+ - `e2e:base:simulate` Robinhood tier uses `--run-mode agent_wallet` so chain 4663 compatibility passes (Robinhood advertises `self` + `agent_wallet` only).
12
+
13
+ ## [0.2.27] - 2026-07-11
14
+
15
+ ### Changed
16
+
17
+ - Robinhood partner validator moved to `scripts/e2e/chains/robinhood/delegated-preflight.mjs` with shared `delegation-lane` helper and Robinhood constants.
18
+ - `e2e:base:simulate` includes `actions --chain-id 4663` tier; `docs/partners/robinhood-validation.md` documents CLI vs API validation split.
19
+ - npm alias `validate:robinhood:delegated-preflight`; legacy `validate:robinhood-agent-wallet-preflight` preserved.
20
+
21
+ ## [0.2.26] - 2026-07-11
22
+
23
+ ### Changed
24
+
25
+ - Robinhood live validator uses Privy subscriber delegation (`THIRDFY_USER_DID` + `managed_wallet_server`) and Robinhood-native WETH/USDG addresses instead of solo `did:wallet:<agentKey>`.
26
+ - Validator requires explicit `THIRDFY_USER_DID` or `ROBINHOOD_SMOKE_USER_DID` (no `~/.thirdfy/config.json` fallback) so partner checks always exercise the delegation lane.
27
+ - Validator probes `GET /api/v1/agent/execution-wallet` and rejects agent-owner bypass when `canonicalUserDid` rewrites to `did:wallet:<agentKey>`.
28
+
29
+ ## [0.2.25] - 2026-07-11
30
+
31
+ ### Fixed
32
+
33
+ - Solo `agent_wallet` still uses `did:wallet:<agentKey>`, but hybrid `agent_wallet` and `--signer-method managed_wallet_server` keep saved Privy delegation identity.
34
+
35
+ ## [0.2.24] - 2026-07-11
36
+
37
+ ### Fixed
38
+
39
+ - `agent_wallet` execute-intent read-only fallback now passes `runMode: agent_wallet` into identity resolution so solo `did:wallet:<agentKey>` is used consistently.
40
+
41
+ ## [0.2.23] - 2026-07-11
42
+
43
+ ### Fixed
44
+
45
+ - 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).
46
+
47
+ ### Added
48
+
49
+ - `npm run validate:robinhood-agent-wallet-preflight` for live API delegated agent_wallet preflight on chain 4663 (requires `THIRDFY_USER_DID` + active delegation on 4663).
50
+
7
51
  ## [0.2.22] - 2026-07-10
8
52
 
9
53
  ### Added
package/README.md CHANGED
@@ -40,12 +40,9 @@ Run without global install:
40
40
  npx @thirdfy/agent-cli --help
41
41
  ```
42
42
 
43
- ## What's new in v0.2.22
43
+ ## What's new in v0.2.28
44
44
 
45
- - **Robinhood Chain (4663):** Provider hints for `trading`, `bridge`, `yield-xyz`, and `market-data`; `robinhood-mainnet` chat alias.
46
- - Live capabilities validation asserts chain 4663 when `THIRDFY_API_BASE` is set. Pairs with Thirdfy API **v3.10.7+**.
47
-
48
- Older versions: see [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
45
+ - `e2e:base:simulate` Robinhood tier passes chain 4663 compatibility by using `--run-mode agent_wallet`.
49
46
 
50
47
  Older versions: see [CHANGELOG.md](./CHANGELOG.md) and [GitHub Releases](https://github.com/thirdfy/agent-cli/releases).
51
48
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.2.22",
3
+ "version": "0.2.28",
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:delegated-preflight": "node ./scripts/e2e/chains/robinhood/delegated-preflight.mjs",
51
+ "validate:robinhood-agent-wallet-preflight": "node ./scripts/e2e/chains/robinhood/delegated-preflight.mjs",
50
52
  "prepublishOnly": "npm run validate:release-preflight"
51
53
  },
52
54
  "keywords": [
@@ -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
  }