@thirdfy/agent-cli 0.1.32 → 0.1.34
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 +16 -0
- package/bin/thirdfy-agent.mjs +59 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.1.34] - 2026-05-14
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Public docs: aligned Earn provider action inventory and provider index with current catalog coverage (`vaults-fyi`, `yield-xyz`).
|
|
12
|
+
|
|
13
|
+
## [0.1.33] - 2026-05-12
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **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.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- **DogeOS provider discovery:** Tests and docs aligned with catalog-driven provider hints.
|
|
22
|
+
|
|
7
23
|
## [0.1.32] - 2026-05-08
|
|
8
24
|
|
|
9
25
|
### Added
|
package/bin/thirdfy-agent.mjs
CHANGED
|
@@ -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
|
|
23
|
-
funding: {
|
|
24
|
-
|
|
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
|
-
[
|
|
85
|
-
|
|
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(
|
|
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
|
|
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]
|