@thirdfy/agent-cli 0.1.32 → 0.1.33

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.1.33] - 2026-05-12
8
+
9
+ ### Added
10
+
11
+ - **Bitfinex CEX delegation:** Permission profiles for funding vs spot, `--permission-profile` on credential upsert, onboarding hints when credentials are missing from Thirdfy delegation context, and `get-bitfinex-ledgers-hist` read-check documentation.
12
+
13
+ ### Changed
14
+
15
+ - **DogeOS provider discovery:** Tests and docs aligned with catalog-driven provider hints.
16
+
7
17
  ## [0.1.32] - 2026-05-08
8
18
 
9
19
  ### Added
@@ -19,9 +19,23 @@ const DEFAULT_API_BASE = 'https://api.thirdfy.com';
19
19
  const DEFAULT_TIMEOUT_MS = 30000;
20
20
  const DEFAULT_CATALOG_CACHE_TTL_MS = 60_000;
21
21
  const DEFAULT_BITFINEX_BASE_URL = 'https://api.bitfinex.com';
22
- const BITFINEX_REQUIRED_SCOPE_PERMISSIONS = {
23
- funding: { read: 1, write: 1 },
24
- wallets: { read: 1, write: 1 },
22
+ const BITFINEX_PERMISSION_PROFILES = {
23
+ funding: {
24
+ id: 'funding',
25
+ credentialRef: 'bitfinex:funding-primary',
26
+ required: {
27
+ funding: { read: 1, write: 1 },
28
+ wallets: { read: 1, write: 0 },
29
+ },
30
+ },
31
+ spot: {
32
+ id: 'spot',
33
+ credentialRef: 'bitfinex:spot-primary',
34
+ required: {
35
+ orders: { read: 1, write: 1 },
36
+ wallets: { read: 1, write: 0 },
37
+ },
38
+ },
25
39
  };
26
40
  const RUN_MODES = ['thirdfy', 'self', 'hybrid', 'agent_wallet'];
27
41
  const HYBRID_WALLET_MODES = ['self', 'agent_wallet'];
@@ -79,15 +93,21 @@ main().catch((error) => {
79
93
 
80
94
  function buildTopLevelOnboardingHint(payload) {
81
95
  const reason = String(payload?.blockedReason || payload?.error || '').trim();
96
+ const permissionProfile = inferBitfinexPermissionProfileFromAction(
97
+ payload?.resolvedAction || payload?.action || payload?.requestedAction
98
+ );
82
99
  if (!reason) return null;
83
100
  if (
84
- ['CEX_CREDENTIAL_NOT_FOUND', 'BITFINEX_CREDENTIALS_NOT_IN_CONTEXT', 'BITFINEX_ENV_CREDENTIALS_NOT_CONFIGURED'].includes(
85
- reason
86
- )
101
+ [
102
+ 'CEX_CREDENTIAL_NOT_FOUND',
103
+ 'BITFINEX_CREDENTIALS_NOT_IN_CONTEXT',
104
+ 'BITFINEX_CREDENTIALS_NOT_IN_THIRDFY_DELEGATION_CONTEXT',
105
+ 'BITFINEX_ENV_CREDENTIALS_NOT_CONFIGURED',
106
+ ].includes(reason)
87
107
  ) {
88
108
  return {
89
109
  type: 'bitfinex_credentials',
90
- command: buildBitfinexOnboardingCommand(),
110
+ command: buildBitfinexOnboardingCommand(permissionProfile),
91
111
  };
92
112
  }
93
113
  return null;
@@ -1605,12 +1625,17 @@ async function commandDelegationRedeem(ctx, flags, capabilities) {
1605
1625
  async function commandCredentialsUpsert(ctx, flags, capabilities) {
1606
1626
  const authToken = getAuthToken(flags, 'Missing --auth-token (or THIRDFY_AUTH_TOKEN) for credentials upsert');
1607
1627
  const venue = requireFlag(flags, 'venue', 'Missing --venue');
1628
+ const permissionProfile = String(flags.permissionProfile || 'funding').trim().toLowerCase();
1629
+ const bitfinexProfile =
1630
+ String(venue).trim().toLowerCase() === 'bitfinex'
1631
+ ? BITFINEX_PERMISSION_PROFILES[permissionProfile] || BITFINEX_PERMISSION_PROFILES.funding
1632
+ : null;
1608
1633
  const payload = {
1609
1634
  venue,
1610
1635
  apiKey: requireFlag(flags, 'apiKey', 'Missing --api-key'),
1611
1636
  apiSecret: requireFlag(flags, 'apiSecret', 'Missing --api-secret'),
1612
1637
  credentialType: String(flags.credentialType || 'api_key'),
1613
- credentialRef: String(flags.credentialRef || ''),
1638
+ credentialRef: String(flags.credentialRef || bitfinexProfile?.credentialRef || ''),
1614
1639
  };
1615
1640
  if (flags.passphrase) payload.passphrase = String(flags.passphrase);
1616
1641
  if (flags.metadata) payload.metadata = parseJsonFlag(flags, 'metadata');
@@ -1626,6 +1651,7 @@ async function commandCredentialsUpsert(ctx, flags, capabilities) {
1626
1651
  permissionProbe = await probeBitfinexPermissions({
1627
1652
  apiKey: payload.apiKey,
1628
1653
  apiSecret: payload.apiSecret,
1654
+ permissionProfile: bitfinexProfile?.id || 'funding',
1629
1655
  timeoutMs: ctx.timeoutMs,
1630
1656
  baseUrl: String(flags.bitfinexBaseUrl || process.env.BITFINEX_BASE_URL || DEFAULT_BITFINEX_BASE_URL),
1631
1657
  });
@@ -2721,11 +2747,14 @@ function shouldUseBuildTxExecution(runMode, resolved) {
2721
2747
  return true;
2722
2748
  }
2723
2749
 
2724
- function buildBitfinexOnboardingCommand() {
2750
+ function buildBitfinexOnboardingCommand(permissionProfile = 'funding') {
2751
+ const profile = BITFINEX_PERMISSION_PROFILES[permissionProfile] || BITFINEX_PERMISSION_PROFILES.funding;
2725
2752
  return [
2726
2753
  'thirdfy-agent credentials upsert',
2727
2754
  '--auth-token "$THIRDFY_AUTH_TOKEN"',
2728
2755
  '--venue bitfinex',
2756
+ `--permission-profile ${profile.id}`,
2757
+ `--credential-ref ${profile.credentialRef}`,
2729
2758
  '--api-key "<BITFINEX_API_KEY>"',
2730
2759
  '--api-secret "<BITFINEX_API_SECRET>"',
2731
2760
  '--verify-permissions',
@@ -2733,6 +2762,15 @@ function buildBitfinexOnboardingCommand() {
2733
2762
  ].join(' ');
2734
2763
  }
2735
2764
 
2765
+ function inferBitfinexPermissionProfileFromAction(actionName) {
2766
+ const action = String(actionName || '')
2767
+ .trim()
2768
+ .toLowerCase()
2769
+ .replace(/[_\s]+/g, '-');
2770
+ if (!action.includes('bitfinex')) return 'funding';
2771
+ return action.includes('bitfinex-order') ? 'spot' : 'funding';
2772
+ }
2773
+
2736
2774
  function applyExecutionFallbackHints(normalized, { flags, runMode, resolvedAction }) {
2737
2775
  if (!normalized || typeof normalized !== 'object') return normalized;
2738
2776
  const next = { ...normalized };
@@ -2745,9 +2783,11 @@ function applyExecutionFallbackHints(normalized, { flags, runMode, resolvedActio
2745
2783
  }
2746
2784
  const resolvedActionLower = String(resolvedAction || '').trim().toLowerCase();
2747
2785
  const looksBitfinexAction = resolvedActionLower.includes('bitfinex');
2786
+ const permissionProfile = inferBitfinexPermissionProfileFromAction(resolvedActionLower);
2748
2787
  const cexCredentialMissingSignals = new Set([
2749
2788
  'CEX_CREDENTIAL_NOT_FOUND',
2750
2789
  'BITFINEX_CREDENTIALS_NOT_IN_CONTEXT',
2790
+ 'BITFINEX_CREDENTIALS_NOT_IN_THIRDFY_DELEGATION_CONTEXT',
2751
2791
  'BITFINEX_ENV_CREDENTIALS_NOT_CONFIGURED',
2752
2792
  ]);
2753
2793
  const hasMissingCredentialSignal = Array.from(reasons).some((code) => cexCredentialMissingSignals.has(code));
@@ -2756,7 +2796,7 @@ function applyExecutionFallbackHints(normalized, { flags, runMode, resolvedActio
2756
2796
  type: 'bitfinex_credentials',
2757
2797
  message:
2758
2798
  'Bitfinex credentials are missing for this delegated account. Onboard credentials first, then retry the same command.',
2759
- command: buildBitfinexOnboardingCommand(),
2799
+ command: buildBitfinexOnboardingCommand(permissionProfile),
2760
2800
  };
2761
2801
  }
2762
2802
  if (
@@ -4060,9 +4100,10 @@ function parseBitfinexPermissionRows(rawData) {
4060
4100
  return parsed;
4061
4101
  }
4062
4102
 
4063
- function getMissingBitfinexScopes(scopePermissions) {
4103
+ function getMissingBitfinexScopes(scopePermissions, permissionProfile = 'funding') {
4104
+ const profile = BITFINEX_PERMISSION_PROFILES[permissionProfile] || BITFINEX_PERMISSION_PROFILES.funding;
4064
4105
  const missing = [];
4065
- for (const [scope, required] of Object.entries(BITFINEX_REQUIRED_SCOPE_PERMISSIONS)) {
4106
+ for (const [scope, required] of Object.entries(profile.required)) {
4066
4107
  const actual = scopePermissions[scope] || { read: 0, write: 0 };
4067
4108
  if (actual.read < required.read || actual.write < required.write) {
4068
4109
  missing.push({
@@ -4075,7 +4116,7 @@ function getMissingBitfinexScopes(scopePermissions) {
4075
4116
  return missing;
4076
4117
  }
4077
4118
 
4078
- async function probeBitfinexPermissions({ apiKey, apiSecret, timeoutMs, baseUrl }) {
4119
+ async function probeBitfinexPermissions({ apiKey, apiSecret, permissionProfile = 'funding', timeoutMs, baseUrl }) {
4079
4120
  const normalizedBaseUrl = String(baseUrl || DEFAULT_BITFINEX_BASE_URL).trim().replace(/\/+$/, '');
4080
4121
  const apiPath = '/v2/auth/r/permissions';
4081
4122
  const nonce = Date.now().toString();
@@ -4126,18 +4167,19 @@ async function probeBitfinexPermissions({ apiKey, apiSecret, timeoutMs, baseUrl
4126
4167
  );
4127
4168
  }
4128
4169
  const scopePermissions = parseBitfinexPermissionRows(parsed);
4129
- const missingScopes = getMissingBitfinexScopes(scopePermissions);
4170
+ const missingScopes = getMissingBitfinexScopes(scopePermissions, permissionProfile);
4130
4171
  if (missingScopes.length > 0) {
4131
4172
  throw createCliError(
4132
4173
  'BITFINEX_PERMISSION_SCOPE_MISSING',
4133
4174
  `Bitfinex key is missing required scopes (${missingScopes
4134
4175
  .map((entry) => entry.scope)
4135
- .join(', ')}). Enable funding+wallets read/write and retry onboarding.`,
4136
- { missingScopes, scopePermissions }
4176
+ .join(', ')}). Enable the ${permissionProfile} profile scopes and retry onboarding.`,
4177
+ { missingScopes, scopePermissions, permissionProfile }
4137
4178
  );
4138
4179
  }
4139
4180
  return {
4140
4181
  venue: 'bitfinex',
4182
+ permissionProfile,
4141
4183
  checked: true,
4142
4184
  scopes: scopePermissions,
4143
4185
  missingScopes: [],
@@ -4201,7 +4243,7 @@ Core commands:
4201
4243
  thirdfy-agent wallet sign --agent-api-key <key> --action <id> --params <json> [--chain-id <id>] [--json]
4202
4244
  thirdfy-agent wallet submit --signed-tx-hex <hex> [--chain-id <id>] [--rpc-url <url>] [--json]
4203
4245
  thirdfy-agent agent run --agent-api-key <key> --action <id> --params <json> [--signer-method managed_wallet_server|byow|fanout_intent] [--strategy-intent single_wallet|fanout] [--run-mode <mode>] [--user-did <did>] [--json]
4204
- thirdfy-agent credentials upsert --auth-token <token> --venue <id> --api-key <key> --api-secret <secret> [--verify-permissions] [--skip-permissions-probe] [--bitfinex-base-url <url>] [--json]
4246
+ thirdfy-agent credentials upsert --auth-token <token> --venue <id> --api-key <key> --api-secret <secret> [--permission-profile funding|spot] [--credential-ref <ref>] [--verify-permissions] [--skip-permissions-probe] [--bitfinex-base-url <url>] [--json]
4205
4247
  thirdfy-agent credentials status --auth-token <token> [--venue <id>] [--json]
4206
4248
  thirdfy-agent agent auth challenge --agent-key <key> [--wallet-address <addr>] [--chain-id <id>] [--json]
4207
4249
  thirdfy-agent agent auth verify --challenge-id <id> --signature <hex> --agent-key <key> [--wallet-address <addr>] [--json]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thirdfy/agent-cli",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "description": "Thirdfy Agent CLI for onboarding, governance preflight, execute-intent, and status polling.",
5
5
  "type": "module",
6
6
  "bin": {