@thirdfy/agent-cli 0.1.21 → 0.1.23

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,10 +4,35 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.1.23] - 2026-05-02
8
+
9
+ **npm:** [`@thirdfy/agent-cli@0.1.23`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.23)
10
+ **Git tag:** `v0.1.23`
11
+
12
+ ### Added
13
+
14
+ - Provider discovery hints for `earn`, `morpho`, `curve`, and generic `prediction` so agents can filter action catalogs by domain without hard-coded protocol-specific flows.
15
+ - Curve/Base 4pool write hints surfaced through the actions provider filter for earn flows.
16
+
17
+ ### Fixed
18
+
19
+ - **Provider filter:** Case-insensitive matching for earn-related action keys when filtering catalogs by provider.
20
+ - **Self custody:** `preflight` and self-exec paths reject offchain venue order actions before `build-tx`, aligned with venue execution guardrails.
21
+
22
+ ## [0.1.22] - 2026-04-28
23
+
24
+ **npm:** [`@thirdfy/agent-cli@0.1.22`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.22)
25
+ **Git tag:** `v0.1.22`
26
+
27
+ ### Added
28
+
29
+ - **Agent tracking/data commands:** Added `data summary`, `track actions`, `track events`, and `track action` so operators and agents can read Thirdfy-owned analytics and report actions without raw telemetry HTTP calls.
30
+ - **Permissive custom tracking:** `track action` now supports unknown/custom action names with optional `--source`, `--provider`, `--protocol`, `--namespace`, and `--action-type` metadata.
31
+
7
32
  ## [0.1.21] - 2026-04-26
8
33
 
9
- **npm:** [`@thirdfy/agent-cli@0.1.21`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.21) (after publish)
10
- **Git tag:** `v0.1.21`
34
+ **npm:** [`@thirdfy/agent-cli@0.1.21`](https://www.npmjs.com/package/@thirdfy/agent-cli/v/0.1.21)
35
+ **Git tag:** [`v0.1.21`](https://github.com/thirdfy/agent-cli/releases/tag/v0.1.21)
11
36
 
12
37
  ### Fixed
13
38
 
@@ -176,6 +176,18 @@ async function main() {
176
176
  case 'credits balance':
177
177
  await commandCreditsBalance(context, subFlags, capabilities);
178
178
  return;
179
+ case 'data summary':
180
+ await commandDataSummary(context, subFlags, capabilities);
181
+ return;
182
+ case 'track actions':
183
+ await commandTrackList(context, subFlags, capabilities, 'actions');
184
+ return;
185
+ case 'track events':
186
+ await commandTrackList(context, subFlags, capabilities, 'events');
187
+ return;
188
+ case 'track action':
189
+ await commandTrackAction(context, subFlags, capabilities);
190
+ return;
179
191
  case 'delegation create':
180
192
  await commandDelegationCreate(context, subFlags, capabilities);
181
193
  return;
@@ -362,6 +374,212 @@ function shouldApplySwapAmountContract(actionName) {
362
374
  return action === 'swap' || /(^|:|-)swap$/.test(action);
363
375
  }
364
376
 
377
+ function getTradingProviderHint(providerId) {
378
+ const provider = String(providerId || '').trim().toLowerCase();
379
+ const manifestHint = getCachedProviderHintFromCapabilities(provider);
380
+ if (manifestHint) return manifestHint;
381
+ if (provider === 'trading') {
382
+ return {
383
+ provider,
384
+ category: 'onchain_spot',
385
+ canonicalWriteAction: 'swap',
386
+ credentialUx: 'Use normal Thirdfy login/delegation; do not use this provider for Hyperliquid or Polymarket.',
387
+ };
388
+ }
389
+ if (provider === 'hyperliquid') {
390
+ return {
391
+ provider,
392
+ category: 'leveraged_perps',
393
+ canonicalWriteAction: 'place_hyperliquid_perps_order',
394
+ readActions: [
395
+ 'get_hyperliquid_perps_meta',
396
+ 'get_hyperliquid_all_mids',
397
+ 'get_hyperliquid_l2_book',
398
+ 'get_hyperliquid_candles',
399
+ 'get_hyperliquid_user_state',
400
+ 'get_hyperliquid_open_orders',
401
+ 'get_hyperliquid_onboarding_plan',
402
+ 'get_hyperliquid_referral_status',
403
+ 'get_hyperliquid_builder_fee_status',
404
+ ],
405
+ orderManagementActions: [
406
+ 'place_hyperliquid_perps_order',
407
+ 'get_hyperliquid_open_orders',
408
+ ],
409
+ setupActions: [
410
+ 'get_hyperliquid_setup_status',
411
+ 'get_hyperliquid_onboarding_plan',
412
+ 'prepare_hyperliquid_onboarding',
413
+ 'get_bridge_quote',
414
+ 'execute_bridge',
415
+ 'approve_hyperliquid_agent',
416
+ 'get_hyperliquid_builder_fee_status',
417
+ 'approve_hyperliquid_builder_fee',
418
+ 'set_hyperliquid_referrer',
419
+ 'deposit_hyperliquid_bridge',
420
+ 'deposit_hyperliquid_staking',
421
+ 'claim_hyperliquid_testnet_faucet',
422
+ ],
423
+ statusActions: ['get_hyperliquid_setup_status', 'get_hyperliquid_builder_fee_status', 'get_hyperliquid_referral_status'],
424
+ credentialType: 'hyperliquid_api_wallet',
425
+ credentialUx:
426
+ '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.',
427
+ recommendedFundingChainId: 42161,
428
+ supportedFundingSourceChains: [
429
+ { chainId: 42161, name: 'Arbitrum One', path: 'native USDC -> Bridge2' },
430
+ { chainId: 8453, name: 'Base', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
431
+ { chainId: 1, name: 'Ethereum', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
432
+ { chainId: 137, name: 'Polygon', path: 'Li.Fi -> Arbitrum native USDC -> Bridge2' },
433
+ ],
434
+ setupBlockers: [
435
+ 'HYPERLIQUID_SOURCE_FUNDS_REQUIRED',
436
+ 'HYPERLIQUID_ARBITRUM_USDC_REQUIRED',
437
+ 'HYPERLIQUID_BRIDGE2_DEPOSIT_REQUIRED',
438
+ 'HYPERLIQUID_API_WALLET_APPROVAL_REQUIRED',
439
+ 'HYPERLIQUID_BUILDER_APPROVAL_REQUIRED',
440
+ 'HYPERLIQUID_POLICY_REQUIRED',
441
+ 'HYPERLIQUID_CREDITS_REQUIRED',
442
+ 'HYPERLIQUID_API_WALLET_SIGNER_REQUIRED',
443
+ ],
444
+ sourceBridgeProvider: 'lifi',
445
+ funding:
446
+ '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.',
447
+ laneCompatibility:
448
+ 'Use self only for setup signatures or Arbitrum funding transactions. Perps orders should use thirdfy, hybrid, or agent_wallet.',
449
+ setupExample:
450
+ 'actions --provider hyperliquid -> get_hyperliquid_onboarding_plan -> prepare_hyperliquid_onboarding -> get_bridge_quote/execute_bridge if source is Base -> deposit_hyperliquid_bridge on 42161 -> approve_hyperliquid_agent -> approve_hyperliquid_builder_fee if required -> get_hyperliquid_setup_status',
451
+ example:
452
+ '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"}\'',
453
+ };
454
+ }
455
+ if (provider === 'polymarket') {
456
+ return {
457
+ provider,
458
+ category: 'prediction_market',
459
+ canonicalWriteAction: 'place_polymarket_order',
460
+ readActions: [
461
+ 'get_polymarket_markets',
462
+ 'get_polymarket_market',
463
+ 'get_polymarket_order_book',
464
+ 'get_polymarket_prices',
465
+ 'get_polymarket_price_history',
466
+ 'get_polymarket_setup_status',
467
+ 'get_polymarket_order',
468
+ 'get_polymarket_user_orders',
469
+ ],
470
+ orderManagementActions: [
471
+ 'place_polymarket_order',
472
+ 'get_polymarket_order',
473
+ 'get_polymarket_user_orders',
474
+ 'cancel_polymarket_order',
475
+ ],
476
+ setupActions: [
477
+ 'get_polymarket_setup_status',
478
+ 'agent_wallet_setup:ensure_agent_wallet_safe',
479
+ 'agent_wallet_setup:deploy_safe_and_set_approvals',
480
+ 'agent_wallet_setup:create_or_derive_clob_credentials',
481
+ 'browser_setup:add_privy_signer',
482
+ 'browser_setup:create_or_derive_clob_credentials',
483
+ 'browser_setup:deploy_safe_and_set_approvals',
484
+ ],
485
+ statusActions: ['get_polymarket_setup_status'],
486
+ credentialType: 'polymarket_clob',
487
+ credentialUx:
488
+ 'Autonomous agents use an agent-owned Privy wallet/Safe first: Thirdfy creates the agent wallet, deploys/approves the Safe, and stores encrypted CLOB credentials once Polymarket key creation is available. User-owned browser setup remains optional for interactive capital.',
489
+ funding:
490
+ 'Fund the agent-owned Polymarket Safe with Polygon USDC/pUSD collateral after Safe deployment and approvals.',
491
+ laneCompatibility:
492
+ 'Use agent_wallet as the preferred autonomous-agent path. Use self only for user-owned setup/funding signatures. CLOB orders should use thirdfy, hybrid, or agent_wallet after polymarket_clob credentials are stored.',
493
+ setupBlockers: [
494
+ 'POLYMARKET_AGENT_WALLET_SAFE_REQUIRED',
495
+ 'POLYMARKET_CLOB_CREDENTIALS_REQUIRED',
496
+ 'POLYMARKET_SAFE_DEPLOYMENT_REQUIRED',
497
+ 'POLYMARKET_SAFE_APPROVALS_REQUIRED',
498
+ 'POLYMARKET_USDC_REQUIRED',
499
+ 'POLYMARKET_CREDITS_REQUIRED',
500
+ 'POLYMARKET_RELAYER_UNAVAILABLE',
501
+ 'POLYMARKET_CLOB_KEY_CREATION_BLOCKED_UNTIL_POLYMARKET_FIX',
502
+ ],
503
+ example:
504
+ 'thirdfy-agent actions --provider polymarket && thirdfy-agent preflight --action place_polymarket_order --params \'{"tokenID":"...","price":0.42,"size":10,"side":"BUY"}\'',
505
+ };
506
+ }
507
+ if (provider === 'prediction') {
508
+ return {
509
+ provider,
510
+ category: 'prediction',
511
+ canonicalWriteAction: 'place_prediction_order',
512
+ readActions: ['get_prediction_markets', 'get_prediction_market', 'get_prediction_order_book'],
513
+ orderManagementActions: ['place_prediction_order', 'cancel_prediction_order'],
514
+ compatibilityProvider: 'polymarket',
515
+ };
516
+ }
517
+ if (provider === 'earn') {
518
+ return {
519
+ provider,
520
+ category: 'earn',
521
+ canonicalReadAction: 'get_earn_opportunities',
522
+ canonicalWriteAction: 'deposit_earn_position',
523
+ readActions: ['get_earn_opportunities', 'get_earn_provider', 'get_earn_position'],
524
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
525
+ laneCompatibility:
526
+ 'Generic earn writes use deposit_earn_position / withdraw_earn_position on normal Thirdfy policy/delegation rails; routing selects Morpho vault calldata or the validated Curve Base 4pool adapter on Base (8453) per opportunity.',
527
+ };
528
+ }
529
+ if (provider === 'morpho') {
530
+ return {
531
+ provider,
532
+ category: 'earn',
533
+ canonicalReadAction: 'get_morpho_vaults',
534
+ canonicalWriteAction: 'deposit_earn_position',
535
+ readActions: ['get_morpho_vaults', 'get_earn_provider', 'get_earn_position'],
536
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
537
+ supportedChains: [8453, 84532],
538
+ laneCompatibility: 'Morpho deposits require ERC-20 approvals to the vault/market routes surfaced by the catalog before deposit_earn_position.',
539
+ example:
540
+ 'thirdfy-agent actions --provider morpho && thirdfy-agent run --action deposit_earn_position --params \'{"providerId":"morpho","vaultAddress":"0x...","tokenAddress":"0x...","amount":"10","chainId":8453}\'',
541
+ };
542
+ }
543
+ if (provider === 'curve') {
544
+ return {
545
+ provider,
546
+ category: 'earn',
547
+ canonicalReadAction: 'get_curve_pools',
548
+ canonicalWriteAction: 'deposit_earn_position',
549
+ readActions: ['get_curve_pools', 'get_earn_opportunities', 'get_earn_provider', 'get_earn_position'],
550
+ orderManagementActions: ['deposit_earn_position', 'withdraw_earn_position'],
551
+ supportedChains: [8453],
552
+ laneCompatibility:
553
+ 'Curve EVM writes are limited to the validated Base mainnet 4pool adapter; other pools remain discovery-only until per-pool calldata is validated.',
554
+ };
555
+ }
556
+ return null;
557
+ }
558
+
559
+ function getCachedProviderHintFromCapabilities(_provider) {
560
+ return null;
561
+ }
562
+
563
+ const OFFCHAIN_VENUE_ORDER_ACTIONS = new Set([
564
+ 'place_hyperliquid_perps_order',
565
+ 'place-hyperliquid-perps-order',
566
+ 'place_polymarket_order',
567
+ 'place-polymarket-order',
568
+ ]);
569
+
570
+ function enforceOffchainVenueLaneCompatibility(action, runMode) {
571
+ const normalizedAction = String(action || '').trim().toLowerCase();
572
+ if (runMode !== 'self' || !OFFCHAIN_VENUE_ORDER_ACTIONS.has(normalizedAction)) return;
573
+ throw createCliError(
574
+ 'OFFCHAIN_VENUE_ORDER_SELF_UNSUPPORTED',
575
+ 'Polymarket CLOB and Hyperliquid perps orders are offchain signed API actions, not EVM build-tx actions. Use self for setup/funding signatures, then run venue orders with --run-mode thirdfy, --run-mode hybrid, or --run-mode agent_wallet.',
576
+ {
577
+ recommendedRunModes: ['thirdfy', 'hybrid', 'agent_wallet'],
578
+ setupOnlyRunMode: 'self',
579
+ }
580
+ );
581
+ }
582
+
365
583
  function createCliError(code, message, payload = {}) {
366
584
  const error = new Error(message);
367
585
  error.payload = {
@@ -539,9 +757,86 @@ async function commandCatalogsList(ctx, flags, capabilities) {
539
757
  });
540
758
  }
541
759
 
760
+ async function commandDataSummary(ctx, flags, capabilities) {
761
+ const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
762
+ const query = new URLSearchParams({ agentKey });
763
+ if (flags.chainId) query.set('chainId', String(flags.chainId));
764
+ if (flags.limit) query.set('limit', String(flags.limit));
765
+ const response = await apiGet(ctx, `/api/v1/agent/telemetry/summary?${query.toString()}`);
766
+ printEnvelope({
767
+ success: true,
768
+ code: 'DATA_SUMMARY_OK',
769
+ message: 'Agent data summary loaded',
770
+ data: response,
771
+ meta: {
772
+ apiBase: ctx.apiBase,
773
+ agentKey,
774
+ chainId: flags.chainId ? Number(flags.chainId) : null,
775
+ },
776
+ });
777
+ }
778
+
779
+ async function commandTrackList(ctx, flags, capabilities, kind) {
780
+ const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
781
+ const query = new URLSearchParams({ agentKey });
782
+ if (flags.limit) query.set('limit', String(flags.limit));
783
+ const response = await apiGet(ctx, `/api/v1/agent/telemetry/${kind}?${query.toString()}`);
784
+ printEnvelope({
785
+ success: true,
786
+ code: kind === 'events' ? 'TRACK_EVENTS_OK' : 'TRACK_ACTIONS_OK',
787
+ message: kind === 'events' ? 'Tracked agent events loaded' : 'Tracked agent actions loaded',
788
+ data: response,
789
+ meta: {
790
+ apiBase: ctx.apiBase,
791
+ agentKey,
792
+ kind,
793
+ },
794
+ });
795
+ }
796
+
797
+ async function commandTrackAction(ctx, flags, capabilities) {
798
+ const agentApiKey = resolveAgentApiKey(flags, 'thirdfy');
799
+ const action = requireFlag(flags, 'action', 'Missing --action');
800
+ const payload = {
801
+ agentApiKey,
802
+ action,
803
+ status: String(flags.status || 'observed'),
804
+ };
805
+ if (flags.agentKey) payload.agentKey = String(flags.agentKey);
806
+ if (flags.eventId) payload.eventId = String(flags.eventId);
807
+ if (flags.idempotencyKey) payload.idempotencyKey = String(flags.idempotencyKey);
808
+ if (flags.category) payload.category = String(flags.category);
809
+ if (flags.source) payload.source = String(flags.source);
810
+ if (flags.provider) payload.provider = String(flags.provider);
811
+ if (flags.protocol) payload.protocol = String(flags.protocol);
812
+ if (flags.namespace) payload.namespace = String(flags.namespace);
813
+ if (flags.actionType) payload.actionType = String(flags.actionType);
814
+ if (flags.chainId) payload.chainId = Number(flags.chainId);
815
+ if (flags.amountUsd) payload.amountUsd = Number(flags.amountUsd);
816
+ if (flags.txHash) payload.txHash = String(flags.txHash);
817
+ if (flags.userDid) payload.userDid = String(flags.userDid);
818
+ if (flags.params) payload.params = parseJsonFlag(flags, 'params');
819
+ if (flags.decision) payload.decision = parseJsonFlag(flags, 'decision');
820
+ if (flags.proof) payload.proof = parseJsonFlag(flags, 'proof');
821
+
822
+ const response = await apiPost(ctx, '/api/v1/agent/telemetry/actions', payload);
823
+ printEnvelope({
824
+ success: Boolean(response?.success !== false),
825
+ code: response?.success === false ? 'TRACK_ACTION_FAILED' : 'TRACK_ACTION_OK',
826
+ message: response?.success === false ? 'Agent action tracking failed' : 'Agent action tracked',
827
+ data: response,
828
+ meta: {
829
+ apiBase: ctx.apiBase,
830
+ action,
831
+ chainId: payload.chainId || null,
832
+ },
833
+ });
834
+ }
835
+
542
836
  async function commandActions(ctx, flags, capabilities) {
543
837
  const policyAware = Boolean(flags.agentApiKey);
544
838
  const actions = applyActionFilters(await getCachedActionsCatalog(ctx, flags), flags);
839
+ const providerHint = getTradingProviderHint(flags.provider);
545
840
  const effectiveRunMode = getEffectiveRunMode(ctx, flags);
546
841
  const chainIdFilter = Number(flags.chainId || 0) || undefined;
547
842
  const chainSupport = resolveChainSupport(capabilities, chainIdFilter, effectiveRunMode);
@@ -549,7 +844,7 @@ async function commandActions(ctx, flags, capabilities) {
549
844
  success: true,
550
845
  code: 'OK',
551
846
  message: 'Actions loaded',
552
- data: { actions },
847
+ data: { actions, ...(providerHint ? { providerHint } : {}) },
553
848
  meta: {
554
849
  apiBase: ctx.apiBase,
555
850
  policyAware,
@@ -565,6 +860,7 @@ async function commandPreflight(ctx, flags, capabilities) {
565
860
  const resolved = await resolveActionSelection(ctx, flags);
566
861
  prepareActionParamsForFlags(flags, resolved.resolvedAction);
567
862
  const runMode = getEffectiveRunMode(ctx, flags);
863
+ enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, runMode);
568
864
  const hybridWalletMode = runMode === 'hybrid' ? normalizeHybridWalletMode(flags.hybridWalletMode) : null;
569
865
  enforceChainCompatibility(capabilities, flags, runMode);
570
866
  const backendResult = await runPreflightByMode(runMode, ctx, flags, resolved, { hybridWalletMode });
@@ -599,6 +895,7 @@ async function commandRun(ctx, flags, capabilities) {
599
895
  const resolved = await resolveActionSelection(ctx, flags);
600
896
  prepareActionParamsForFlags(flags, resolved.resolvedAction);
601
897
  const runMode = getEffectiveRunMode(ctx, flags);
898
+ enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, runMode);
602
899
  const hybridWalletMode = runMode === 'hybrid' ? normalizeHybridWalletMode(flags.hybridWalletMode) : null;
603
900
  enforceChainCompatibility(capabilities, flags, runMode);
604
901
  const skipPreflight = Boolean(flags.skipPreflight);
@@ -724,6 +1021,7 @@ async function commandWalletSign(ctx, flags, capabilities) {
724
1021
  const normalizedFlags = { ...flags, runMode: 'self' };
725
1022
  const resolved = await resolveActionSelection(ctx, normalizedFlags);
726
1023
  prepareActionParamsForFlags(normalizedFlags, resolved.resolvedAction);
1024
+ enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, 'self');
727
1025
  enforceChainCompatibility(capabilities, normalizedFlags, 'self');
728
1026
  const selfResult = await executeSelfRun(ctx, normalizedFlags, resolved, {
729
1027
  skipPreflight: Boolean(normalizedFlags.skipPreflight),
@@ -1594,6 +1892,7 @@ async function commandPrompt(ctx, flags, capabilities, promptTokens) {
1594
1892
  async function commandSelfExec(ctx, flags, capabilities) {
1595
1893
  const resolved = await resolveActionSelection(ctx, flags);
1596
1894
  prepareActionParamsForFlags(flags, resolved.resolvedAction);
1895
+ enforceOffchainVenueLaneCompatibility(resolved.resolvedAction, 'self');
1597
1896
  enforceChainCompatibility(capabilities, flags, 'self');
1598
1897
  const selfResult = await executeSelfRun(ctx, flags, resolved, {
1599
1898
  skipPreflight: Boolean(flags.skipPreflight),
@@ -2881,11 +3180,22 @@ function applyActionFilters(actions, flags) {
2881
3180
  }
2882
3181
  if (flags.provider) {
2883
3182
  const expectedProvider = String(flags.provider).trim().toLowerCase();
2884
- filtered = filtered.filter((a) => String(a.provider || '').trim().toLowerCase() === expectedProvider);
3183
+ filtered = filtered.filter((a) => {
3184
+ const provider = getActionProvider(a);
3185
+ const actionKey = getActionKey(a).replace(/-/g, '_').toLowerCase();
3186
+ if (provider === expectedProvider) return true;
3187
+ if (expectedProvider === 'earn') return provider === 'morpho' || provider === 'curve' || actionKey.includes('_earn_');
3188
+ if (expectedProvider === 'prediction') return provider === 'polymarket' || actionKey.includes('_prediction_');
3189
+ return false;
3190
+ });
2885
3191
  }
2886
3192
  return filtered;
2887
3193
  }
2888
3194
 
3195
+ function getActionProvider(action) {
3196
+ return String(action?.provider || action?.providerId || action?.provider_id || action?.catalog || '').trim().toLowerCase();
3197
+ }
3198
+
2889
3199
  async function resolveActionSelection(ctx, flags) {
2890
3200
  const requestedAction = requireFlag(flags, 'action', 'Missing --action');
2891
3201
  const requestedLower = requestedAction.toLowerCase();
@@ -2921,10 +3231,11 @@ async function resolveActionSelection(ctx, flags) {
2921
3231
  return { requestedAction, resolvedAction: exactAlias[0].key, resolvedActionMeta: exactAlias[0].action || null };
2922
3232
  }
2923
3233
  if (exactAlias.length > 1) {
3234
+ const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
2924
3235
  throw new Error(
2925
3236
  `Ambiguous --action "${requestedAction}". Alias matches multiple actions: ${formatActionList(
2926
3237
  exactAlias.map((v) => v.key)
2927
- )}.`
3238
+ )}.${providerHint ? ` Provider ${providerHint.provider} expects ${providerHint.canonicalWriteAction}.` : ''}`
2928
3239
  );
2929
3240
  }
2930
3241
 
@@ -2937,14 +3248,18 @@ async function resolveActionSelection(ctx, flags) {
2937
3248
  return { requestedAction, resolvedAction: fuzzy[0].key, resolvedActionMeta: fuzzy[0].action || null };
2938
3249
  }
2939
3250
  if (fuzzy.length > 1) {
3251
+ const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
2940
3252
  throw new Error(
2941
3253
  `Ambiguous --action "${requestedAction}". Did you mean one of: ${formatActionList(
2942
3254
  fuzzy.slice(0, 10).map((v) => v.key)
2943
- )}?`
3255
+ )}?${providerHint ? ` Provider ${providerHint.provider} expects ${providerHint.canonicalWriteAction}.` : ''}`
2944
3256
  );
2945
3257
  }
3258
+ const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
2946
3259
  throw new Error(
2947
- `Unknown --action "${requestedAction}". No compatible action found in current catalog/provider scope.`
3260
+ `Unknown --action "${requestedAction}". No compatible action found in current catalog/provider scope.${
3261
+ providerHint ? ` Provider ${providerHint.provider} expects ${providerHint.canonicalWriteAction}; run actions --provider ${providerHint.provider} first.` : ''
3262
+ }`
2948
3263
  );
2949
3264
  }
2950
3265
 
@@ -3479,6 +3794,10 @@ Core commands:
3479
3794
  thirdfy-agent whoami [--json]
3480
3795
  thirdfy-agent catalogs list [--json]
3481
3796
  thirdfy-agent actions [--catalog <id>] [--provider <id>] [--agent-api-key <key>] [--chain-id <id>] [--run-mode <mode>] [--json]
3797
+ thirdfy-agent data summary --agent-key <key> [--chain-id <id>] [--limit <n>] [--json]
3798
+ thirdfy-agent track actions --agent-key <key> [--limit <n>] [--json]
3799
+ thirdfy-agent track events --agent-key <key> [--limit <n>] [--json]
3800
+ thirdfy-agent track action --agent-api-key <key> --action <name> [--category <name>] [--source agent|external_mcp|operator|thirdfy|custom] [--provider <id>] [--protocol <id>] [--namespace <name>] [--action-type supported|custom] [--status observed|planned|skipped|submitted|confirmed|failed|blocked] [--chain-id <id>] [--params <json>] [--json]
3482
3801
  thirdfy-agent delegation create [--auth-token <token> | --owner-session-token <token>] --agent-key <key> --owner-address <addr> --token-address <addr> --max-usd-per-day <usd> [--session-account-address <addr>] [--json]
3483
3802
  thirdfy-agent delegation init-custodial [--auth-token <token> | --owner-session-token <token>] [--chain-id <id>] [--json]
3484
3803
  thirdfy-agent delegation custodial-grant [--auth-token <token> | --owner-session-token <token>] --agent-key <key> --token-address <addr> --max-usd-per-day <usd> [--chain-id <id>] [--period-duration <sec>] [--expiry-seconds <sec>] [--json]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.1.21",
3
+ "version": "0.1.23",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {