@thirdfy/agent-cli 0.1.48 → 0.2.1
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 +51 -0
- package/README.md +16 -1
- package/bin/thirdfy-agent.mjs +3 -5106
- package/package.json +17 -4
- package/scripts/validate-npm-pack.mjs +43 -0
- package/src/cli/errors.mjs +103 -0
- package/src/cli/flags.mjs +66 -0
- package/src/cli/help.mjs +89 -0
- package/src/cli/manifest.mjs +422 -0
- package/src/cli/options/agent.mjs +9 -0
- package/src/cli/options/analytics.mjs +5 -0
- package/src/cli/options/auth.mjs +10 -0
- package/src/cli/options/bootstrap.mjs +19 -0
- package/src/cli/options/chains.mjs +3 -0
- package/src/cli/options/credentials.mjs +15 -0
- package/src/cli/options/delegation.mjs +22 -0
- package/src/cli/options/execution.mjs +24 -0
- package/src/cli/options/global.mjs +16 -0
- package/src/cli/options/index.mjs +37 -0
- package/src/cli/options/polymarket.mjs +3 -0
- package/src/cli/options/tracking.mjs +18 -0
- package/src/cli/options/wallet.mjs +7 -0
- package/src/cli/program.mjs +5 -0
- package/src/cli/register.mjs +118 -0
- package/src/commands/agent.mjs +194 -0
- package/src/commands/bootstrap.mjs +762 -0
- package/src/commands/credentials.mjs +102 -0
- package/src/commands/delegation.mjs +355 -0
- package/src/commands/discovery.mjs +77 -0
- package/src/commands/doctor.mjs +320 -0
- package/src/commands/execute.mjs +255 -0
- package/src/commands/hyperliquid.mjs +51 -0
- package/src/commands/index.mjs +6 -0
- package/src/commands/polymarket.mjs +89 -0
- package/src/commands/prompt.mjs +33 -0
- package/src/commands/telemetry.mjs +146 -0
- package/src/commands/wallet.mjs +129 -0
- package/src/core/args.mjs +68 -0
- package/src/core/constants.mjs +31 -0
- package/src/core/context.mjs +145 -0
- package/src/core/envelope.mjs +20 -0
- package/src/core/http.mjs +77 -0
- package/src/core/index.mjs +6 -0
- package/src/core/runMode.mjs +72 -0
- package/src/runtime/actions/selection.mjs +339 -0
- package/src/runtime/agentExtract.mjs +52 -0
- package/src/runtime/authHelpers.mjs +53 -0
- package/src/runtime/bitfinexProbe.mjs +121 -0
- package/src/runtime/context.mjs +28 -0
- package/src/runtime/createThirdfyAgentRuntime.mjs +2 -0
- package/src/runtime/errors.mjs +3 -0
- package/src/runtime/execution/amounts.mjs +193 -0
- package/src/runtime/execution/lanes.mjs +75 -0
- package/src/runtime/execution/payloads.mjs +148 -0
- package/src/runtime/execution/runners.mjs +702 -0
- package/src/runtime/handlers.mjs +181 -0
- package/src/runtime/index.mjs +4 -0
- package/src/runtime/main.mjs +204 -0
- package/src/runtime/onboardingHints.mjs +54 -0
- package/src/runtime/owsSigning.mjs +118 -0
- package/src/runtime/providerHints.mjs +414 -0
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { requireFlag, parseJsonFlag } from '../core/args.mjs';
|
|
3
|
+
import { requestWithRouteFallback } from '../core/http.mjs';
|
|
4
|
+
import { createCliError } from '../core/envelope.mjs';
|
|
5
|
+
import { BITFINEX_PERMISSION_PROFILES, DEFAULT_BITFINEX_BASE_URL } from '../core/constants.mjs';
|
|
6
|
+
import { parseBooleanFlag } from '../core/runMode.mjs';
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const { normalizeCredentialStatus } = require('../utils/cli/delegationNormalization.cjs');
|
|
10
|
+
export function createCredentialsCommands({ printEnvelope, getAuthToken, buildOwnerAuthHeaders, probeBitfinexPermissions }) {
|
|
11
|
+
async function commandCredentialsUpsert(ctx, flags, capabilities) {
|
|
12
|
+
const authToken = getAuthToken(flags, 'Missing --auth-token (or THIRDFY_AUTH_TOKEN) for credentials upsert');
|
|
13
|
+
const venue = requireFlag(flags, 'venue', 'Missing --venue');
|
|
14
|
+
const permissionProfile = String(flags.permissionProfile || 'funding').trim().toLowerCase();
|
|
15
|
+
const bitfinexProfile =
|
|
16
|
+
String(venue).trim().toLowerCase() === 'bitfinex'
|
|
17
|
+
? BITFINEX_PERMISSION_PROFILES[permissionProfile] || BITFINEX_PERMISSION_PROFILES.funding
|
|
18
|
+
: null;
|
|
19
|
+
const payload = {
|
|
20
|
+
venue,
|
|
21
|
+
apiKey: requireFlag(flags, 'apiKey', 'Missing --api-key'),
|
|
22
|
+
apiSecret: requireFlag(flags, 'apiSecret', 'Missing --api-secret'),
|
|
23
|
+
credentialType: String(flags.credentialType || 'api_key'),
|
|
24
|
+
credentialRef: String(flags.credentialRef || bitfinexProfile?.credentialRef || ''),
|
|
25
|
+
};
|
|
26
|
+
if (flags.passphrase) payload.passphrase = String(flags.passphrase);
|
|
27
|
+
if (flags.metadata) payload.metadata = parseJsonFlag(flags, 'metadata');
|
|
28
|
+
if (flags.policy) payload.policy = parseJsonFlag(flags, 'policy');
|
|
29
|
+
if (flags.agentKey) payload.agentKey = String(flags.agentKey).trim();
|
|
30
|
+
if (flags.chainId) payload.chainId = Number(flags.chainId);
|
|
31
|
+
const probeEnabled =
|
|
32
|
+
String(venue).trim().toLowerCase() === 'bitfinex' &&
|
|
33
|
+
!parseBooleanFlag(flags.skipPermissionsProbe, false) &&
|
|
34
|
+
parseBooleanFlag(flags.verifyPermissions, true);
|
|
35
|
+
let permissionProbe = null;
|
|
36
|
+
if (probeEnabled) {
|
|
37
|
+
permissionProbe = await probeBitfinexPermissions({
|
|
38
|
+
apiKey: payload.apiKey,
|
|
39
|
+
apiSecret: payload.apiSecret,
|
|
40
|
+
permissionProfile: bitfinexProfile?.id || 'funding',
|
|
41
|
+
timeoutMs: ctx.timeoutMs,
|
|
42
|
+
baseUrl: String(flags.bitfinexBaseUrl || process.env.BITFINEX_BASE_URL || DEFAULT_BITFINEX_BASE_URL),
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const response = await requestWithRouteFallback(ctx, {
|
|
47
|
+
method: 'POST',
|
|
48
|
+
routes: ['/api/v1/agent/delegation/credentials/upsert', '/api/v1/agent/agent/delegation/credentials/upsert'],
|
|
49
|
+
body: payload,
|
|
50
|
+
headers: {
|
|
51
|
+
Authorization: `Bearer ${authToken}`,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
printEnvelope({
|
|
55
|
+
success: Boolean(response?.success !== false),
|
|
56
|
+
code: 'CREDENTIALS_UPSERTED',
|
|
57
|
+
message: 'Delegation credential upsert completed',
|
|
58
|
+
data: response,
|
|
59
|
+
meta: {
|
|
60
|
+
apiBase: ctx.apiBase,
|
|
61
|
+
permissionProbe,
|
|
62
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async function commandCredentialsStatus(ctx, flags, capabilities) {
|
|
68
|
+
const authToken = getAuthToken(flags, 'Missing --auth-token (or THIRDFY_AUTH_TOKEN) for credentials status');
|
|
69
|
+
const query = new URLSearchParams();
|
|
70
|
+
if (flags.venue) query.set('venue', String(flags.venue));
|
|
71
|
+
if (flags.credentialType) query.set('credentialType', String(flags.credentialType));
|
|
72
|
+
if (flags.credentialRef) query.set('credentialRef', String(flags.credentialRef));
|
|
73
|
+
const suffix = query.toString() ? `?${query.toString()}` : '';
|
|
74
|
+
const response = await requestWithRouteFallback(ctx, {
|
|
75
|
+
method: 'GET',
|
|
76
|
+
routes: [
|
|
77
|
+
`/api/v1/agent/delegation/credentials/status${suffix}`,
|
|
78
|
+
`/api/v1/agent/agent/delegation/credentials/status${suffix}`,
|
|
79
|
+
],
|
|
80
|
+
headers: {
|
|
81
|
+
Authorization: `Bearer ${authToken}`,
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
const normalized = normalizeCredentialStatus(response);
|
|
85
|
+
printEnvelope({
|
|
86
|
+
success: true,
|
|
87
|
+
code: 'CREDENTIALS_STATUS_OK',
|
|
88
|
+
message: 'Delegation credential status loaded',
|
|
89
|
+
data: normalized,
|
|
90
|
+
meta: {
|
|
91
|
+
apiBase: ctx.apiBase,
|
|
92
|
+
governanceState: normalized.state || null,
|
|
93
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
commandCredentialsUpsert,
|
|
100
|
+
commandCredentialsStatus,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import { requireFlag, parseJsonFlag } from '../core/args.mjs';
|
|
2
|
+
import { createCliError } from '../core/envelope.mjs';
|
|
3
|
+
import { getEffectiveRunMode } from '../core/runMode.mjs';
|
|
4
|
+
import { apiGet, apiPost, requestWithRouteFallback } from '../core/http.mjs';
|
|
5
|
+
import { createRequire } from 'module';
|
|
6
|
+
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
const { normalizeDelegationStatus } = require('../utils/cli/delegationNormalization.cjs');
|
|
9
|
+
|
|
10
|
+
export function createDelegationCommands(deps) {
|
|
11
|
+
const {
|
|
12
|
+
buildOwnerAuthHeaders,
|
|
13
|
+
printEnvelope,
|
|
14
|
+
commandRun,
|
|
15
|
+
} = deps;
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
async function commandDelegationCreate(ctx, flags, capabilities) {
|
|
19
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
20
|
+
flags,
|
|
21
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation create'
|
|
22
|
+
);
|
|
23
|
+
let sessionAccountAddress = String(flags.sessionAccountAddress || '').trim();
|
|
24
|
+
if (!sessionAccountAddress) {
|
|
25
|
+
try {
|
|
26
|
+
const executorAddressResponse = await apiGet(ctx, '/api/v1/agent/delegation/executor-address', {
|
|
27
|
+
...authHeaders,
|
|
28
|
+
});
|
|
29
|
+
sessionAccountAddress = String(executorAddressResponse?.data?.executorAddress || '').trim();
|
|
30
|
+
} catch (error) {
|
|
31
|
+
if (ctx.verbose) {
|
|
32
|
+
process.stderr.write(
|
|
33
|
+
`delegation create: executor-address discovery failed, falling back to --session-account-address (${error?.message || 'unknown error'})\n`
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const payload = {
|
|
39
|
+
agentKey: requireFlag(flags, 'agentKey', 'Missing --agent-key'),
|
|
40
|
+
ownerAddress: String(flags.ownerAddress || flags.walletAddress || '').trim() || requireFlag(flags, 'ownerAddress', 'Missing --owner-address'),
|
|
41
|
+
sessionAccountAddress: sessionAccountAddress || requireFlag(flags, 'sessionAccountAddress', 'Missing --session-account-address'),
|
|
42
|
+
chainId: Number(flags.chainId || 8453),
|
|
43
|
+
tokenAddress: requireFlag(flags, 'tokenAddress', 'Missing --token-address'),
|
|
44
|
+
maxUsdPerDay: Number(requireFlag(flags, 'maxUsdPerDay', 'Missing --max-usd-per-day')),
|
|
45
|
+
periodDuration: Number(flags.periodDuration || 86_400),
|
|
46
|
+
expirySeconds: Number(flags.expirySeconds || 86_400),
|
|
47
|
+
};
|
|
48
|
+
const response = await apiPost(ctx, '/api/v1/agent/delegation/create', payload, {
|
|
49
|
+
...authHeaders,
|
|
50
|
+
});
|
|
51
|
+
const success = Boolean(response?.success !== false);
|
|
52
|
+
printEnvelope({
|
|
53
|
+
success,
|
|
54
|
+
code: success ? 'DELEGATION_CREATED' : 'DELEGATION_CREATE_FAILED',
|
|
55
|
+
message: response?.message || (success ? 'Delegation payload created' : 'Delegation create failed'),
|
|
56
|
+
data: {
|
|
57
|
+
...response,
|
|
58
|
+
delegationModel: 'gator_erc7710',
|
|
59
|
+
nextSteps: success
|
|
60
|
+
? [
|
|
61
|
+
'Sign data.delegation with the external wallet or OWS account that owns --owner-address.',
|
|
62
|
+
'Run `thirdfy-agent delegation activate --agent-key <key> --wallet-address <owner> --session-account-address <delegate> --delegation-manager <manager> --delegation <json> --signature <hex>`.',
|
|
63
|
+
'Verify with `thirdfy-agent delegation inspect --agent-key <key> --verify`, then use `delegation redeem` or run with --run-mode hybrid|thirdfy for delegated execution.',
|
|
64
|
+
]
|
|
65
|
+
: [],
|
|
66
|
+
},
|
|
67
|
+
meta: {
|
|
68
|
+
apiBase: ctx.apiBase,
|
|
69
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async function commandDelegationInitCustodial(ctx, flags, capabilities) {
|
|
76
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
77
|
+
flags,
|
|
78
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation init-custodial'
|
|
79
|
+
);
|
|
80
|
+
const payload = {
|
|
81
|
+
chainId: Number(flags.chainId || 8453),
|
|
82
|
+
};
|
|
83
|
+
const response = await requestWithRouteFallback(ctx, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
routes: ['/api/v1/agent/delegation/init-custodial'],
|
|
86
|
+
body: payload,
|
|
87
|
+
headers: {
|
|
88
|
+
...authHeaders,
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
const success = Boolean(response?.success !== false);
|
|
92
|
+
printEnvelope({
|
|
93
|
+
success,
|
|
94
|
+
code: success ? 'DELEGATION_CUSTODIAL_INITIALIZED' : 'DELEGATION_CUSTODIAL_INIT_FAILED',
|
|
95
|
+
message: response?.message || (success ? 'Custodial wallet initialized' : 'Custodial wallet init failed'),
|
|
96
|
+
data: response,
|
|
97
|
+
meta: {
|
|
98
|
+
apiBase: ctx.apiBase,
|
|
99
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
async function commandDelegationCustodialGrant(ctx, flags, capabilities) {
|
|
106
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
107
|
+
flags,
|
|
108
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation custodial-grant'
|
|
109
|
+
);
|
|
110
|
+
const payload = {
|
|
111
|
+
chainId: Number(flags.chainId || 8453),
|
|
112
|
+
agentKey: requireFlag(flags, 'agentKey', 'Missing --agent-key'),
|
|
113
|
+
tokenAddress: requireFlag(flags, 'tokenAddress', 'Missing --token-address'),
|
|
114
|
+
maxUsdPerDay: Number(requireFlag(flags, 'maxUsdPerDay', 'Missing --max-usd-per-day')),
|
|
115
|
+
periodDuration: Number(flags.periodDuration || 86_400),
|
|
116
|
+
expirySeconds: Number(flags.expirySeconds || 86_400),
|
|
117
|
+
};
|
|
118
|
+
const response = await requestWithRouteFallback(ctx, {
|
|
119
|
+
method: 'POST',
|
|
120
|
+
routes: ['/api/v1/agent/delegation/custodial-grant'],
|
|
121
|
+
body: payload,
|
|
122
|
+
headers: {
|
|
123
|
+
...authHeaders,
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
const success = Boolean(response?.success !== false);
|
|
127
|
+
printEnvelope({
|
|
128
|
+
success,
|
|
129
|
+
code: success ? 'DELEGATION_CUSTODIAL_GRANTED' : 'DELEGATION_CUSTODIAL_GRANT_FAILED',
|
|
130
|
+
message: response?.message || (success ? 'Custodial delegation granted' : 'Custodial delegation grant failed'),
|
|
131
|
+
data: response,
|
|
132
|
+
meta: {
|
|
133
|
+
apiBase: ctx.apiBase,
|
|
134
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
async function commandDelegationActivate(ctx, flags, capabilities) {
|
|
141
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
142
|
+
flags,
|
|
143
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation activate'
|
|
144
|
+
);
|
|
145
|
+
const payload = {
|
|
146
|
+
agentKey: requireFlag(flags, 'agentKey', 'Missing --agent-key'),
|
|
147
|
+
walletAddress: requireFlag(flags, 'walletAddress', 'Missing --wallet-address'),
|
|
148
|
+
sessionAccountAddress: requireFlag(flags, 'sessionAccountAddress', 'Missing --session-account-address'),
|
|
149
|
+
sessionAccountType: String(flags.sessionAccountType || 'smart').trim(),
|
|
150
|
+
chainId: Number(flags.chainId || 8453),
|
|
151
|
+
delegationManager: requireFlag(flags, 'delegationManager', 'Missing --delegation-manager'),
|
|
152
|
+
signature: requireFlag(flags, 'signature', 'Missing --signature'),
|
|
153
|
+
};
|
|
154
|
+
const delegation = parseJsonFlag(flags, 'delegation');
|
|
155
|
+
payload.delegation = delegation;
|
|
156
|
+
if (flags.permissionsExpiry) payload.permissionsExpiry = String(flags.permissionsExpiry).trim();
|
|
157
|
+
if (flags.permissionsContext) payload.permissionsContext = String(flags.permissionsContext).trim();
|
|
158
|
+
if (flags.permission) payload.permission = parseJsonFlag(flags, 'permission');
|
|
159
|
+
if (flags.permissionType) payload.permissionType = String(flags.permissionType).trim();
|
|
160
|
+
if (flags.permissionData) payload.permissionData = parseJsonFlag(flags, 'permissionData');
|
|
161
|
+
if (flags.modelAConstraints) payload.modelAConstraints = parseJsonFlag(flags, 'modelAConstraints');
|
|
162
|
+
const response = await apiPost(ctx, '/api/v1/agent/delegation/activate', payload, {
|
|
163
|
+
...authHeaders,
|
|
164
|
+
});
|
|
165
|
+
const success = Boolean(response?.success !== false);
|
|
166
|
+
printEnvelope({
|
|
167
|
+
success,
|
|
168
|
+
code: success ? 'DELEGATION_ACTIVATED' : 'DELEGATION_ACTIVATE_FAILED',
|
|
169
|
+
message: response?.message || (success ? 'Delegation activated' : 'Delegation activate failed'),
|
|
170
|
+
data: {
|
|
171
|
+
...response,
|
|
172
|
+
delegationModel: 'gator_erc7710',
|
|
173
|
+
nextSteps: success
|
|
174
|
+
? [
|
|
175
|
+
'Run `thirdfy-agent delegation inspect --agent-key <key> --verify` to confirm period allowance and revocation state.',
|
|
176
|
+
'Use `thirdfy-agent delegation redeem --run-mode hybrid|thirdfy ...` when Thirdfy/session executor should act under this external-wallet delegation.',
|
|
177
|
+
]
|
|
178
|
+
: [],
|
|
179
|
+
},
|
|
180
|
+
meta: {
|
|
181
|
+
apiBase: ctx.apiBase,
|
|
182
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
async function commandDelegationStatus(ctx, flags, capabilities) {
|
|
189
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
190
|
+
flags,
|
|
191
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation status'
|
|
192
|
+
);
|
|
193
|
+
const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
|
|
194
|
+
const chainId = Number(flags.chainId || 8453);
|
|
195
|
+
const verify = Boolean(flags.verify);
|
|
196
|
+
const route = verify
|
|
197
|
+
? `/api/v1/agent/delegation/verify?agentKey=${encodeURIComponent(agentKey)}&chainId=${encodeURIComponent(String(chainId))}`
|
|
198
|
+
: `/api/v1/agent/delegation/check?agentKey=${encodeURIComponent(agentKey)}&chainId=${encodeURIComponent(String(chainId))}`;
|
|
199
|
+
const response = await apiGet(ctx, route, {
|
|
200
|
+
...authHeaders,
|
|
201
|
+
});
|
|
202
|
+
const normalized = normalizeDelegationStatus(response);
|
|
203
|
+
printEnvelope({
|
|
204
|
+
success: true,
|
|
205
|
+
code: 'DELEGATION_STATUS_OK',
|
|
206
|
+
message: 'Delegation status loaded',
|
|
207
|
+
data: normalized,
|
|
208
|
+
meta: {
|
|
209
|
+
apiBase: ctx.apiBase,
|
|
210
|
+
verify,
|
|
211
|
+
governanceState: normalized.state || null,
|
|
212
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
213
|
+
},
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
async function commandDelegationInspect(ctx, flags, capabilities) {
|
|
219
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
220
|
+
flags,
|
|
221
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation inspect'
|
|
222
|
+
);
|
|
223
|
+
const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
|
|
224
|
+
const chainId = Number(flags.chainId || 8453);
|
|
225
|
+
const includeOnchain = Boolean(flags.verify || flags.includeOnchain || flags.onchain);
|
|
226
|
+
const checkRoute = `/api/v1/agent/delegation/check?agentKey=${encodeURIComponent(agentKey)}&chainId=${encodeURIComponent(String(chainId))}`;
|
|
227
|
+
const checkResponse = await apiGet(ctx, checkRoute, {
|
|
228
|
+
...authHeaders,
|
|
229
|
+
});
|
|
230
|
+
const checkNormalized = normalizeDelegationStatus(checkResponse);
|
|
231
|
+
|
|
232
|
+
let verifyNormalized = null;
|
|
233
|
+
if (includeOnchain) {
|
|
234
|
+
const verifyRoute = `/api/v1/agent/delegation/verify?agentKey=${encodeURIComponent(agentKey)}&chainId=${encodeURIComponent(String(chainId))}`;
|
|
235
|
+
const verifyResponse = await apiGet(ctx, verifyRoute, {
|
|
236
|
+
...authHeaders,
|
|
237
|
+
});
|
|
238
|
+
verifyNormalized = normalizeDelegationStatus(verifyResponse);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
printEnvelope({
|
|
242
|
+
success: true,
|
|
243
|
+
code: 'DELEGATION_INSPECT_OK',
|
|
244
|
+
message: includeOnchain ? 'Delegation inspect loaded (with onchain verification)' : 'Delegation inspect loaded',
|
|
245
|
+
data: {
|
|
246
|
+
check: checkNormalized,
|
|
247
|
+
verify: verifyNormalized,
|
|
248
|
+
state: verifyNormalized?.state || checkNormalized.state,
|
|
249
|
+
rawStatus: verifyNormalized?.rawStatus || checkNormalized.rawStatus,
|
|
250
|
+
},
|
|
251
|
+
meta: {
|
|
252
|
+
apiBase: ctx.apiBase,
|
|
253
|
+
includeOnchain,
|
|
254
|
+
governanceState: verifyNormalized?.state || checkNormalized.state || null,
|
|
255
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
256
|
+
},
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
async function commandDelegationRevoke(ctx, flags, capabilities) {
|
|
262
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
263
|
+
flags,
|
|
264
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation revoke'
|
|
265
|
+
);
|
|
266
|
+
const payload = {
|
|
267
|
+
agentKey: requireFlag(flags, 'agentKey', 'Missing --agent-key'),
|
|
268
|
+
reason: String(flags.reason || 'user_revoked').trim(),
|
|
269
|
+
chainId: Number(flags.chainId || 8453),
|
|
270
|
+
};
|
|
271
|
+
const response = await requestWithRouteFallback(ctx, {
|
|
272
|
+
method: 'POST',
|
|
273
|
+
routes: ['/api/v1/agent/delegation/revoke'],
|
|
274
|
+
body: payload,
|
|
275
|
+
headers: {
|
|
276
|
+
...authHeaders,
|
|
277
|
+
},
|
|
278
|
+
});
|
|
279
|
+
const success = Boolean(response?.success !== false);
|
|
280
|
+
printEnvelope({
|
|
281
|
+
success,
|
|
282
|
+
code: success ? 'DELEGATION_REVOKED' : 'DELEGATION_REVOKE_FAILED',
|
|
283
|
+
message: response?.message || (success ? 'Delegation revoked' : 'Delegation revoke failed'),
|
|
284
|
+
data: response,
|
|
285
|
+
meta: {
|
|
286
|
+
apiBase: ctx.apiBase,
|
|
287
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
async function commandDelegationBalance(ctx, flags, capabilities) {
|
|
294
|
+
const authHeaders = buildOwnerAuthHeaders(
|
|
295
|
+
flags,
|
|
296
|
+
'Missing --auth-token/--owner-session-token (or THIRDFY_AUTH_TOKEN/THIRDFY_OWNER_SESSION_TOKEN) for delegation balance'
|
|
297
|
+
);
|
|
298
|
+
const agentKey = requireFlag(flags, 'agentKey', 'Missing --agent-key');
|
|
299
|
+
const chainId = Number(flags.chainId || 8453);
|
|
300
|
+
const route = `/api/v1/agent/delegation/verify?agentKey=${encodeURIComponent(agentKey)}&chainId=${encodeURIComponent(String(chainId))}`;
|
|
301
|
+
const response = await apiGet(ctx, route, {
|
|
302
|
+
...authHeaders,
|
|
303
|
+
});
|
|
304
|
+
const normalized = normalizeDelegationStatus(response);
|
|
305
|
+
const verifyData = normalized?.data?.onChainVerification || {};
|
|
306
|
+
printEnvelope({
|
|
307
|
+
success: true,
|
|
308
|
+
code: 'DELEGATION_BALANCE_OK',
|
|
309
|
+
message: 'Delegation allowance balance loaded',
|
|
310
|
+
data: {
|
|
311
|
+
state: normalized.state,
|
|
312
|
+
rawStatus: normalized.rawStatus,
|
|
313
|
+
delegatedWalletAddress: normalized?.data?.delegatedWalletAddress || null,
|
|
314
|
+
periodAvailableUsd: verifyData?.periodAvailableUsd ?? null,
|
|
315
|
+
periodAvailableBaseUnits: verifyData?.periodAvailableBaseUnits ?? null,
|
|
316
|
+
verified: verifyData?.verified ?? null,
|
|
317
|
+
isRevoked: verifyData?.isRevoked ?? null,
|
|
318
|
+
onChainVerification: verifyData || null,
|
|
319
|
+
},
|
|
320
|
+
meta: {
|
|
321
|
+
apiBase: ctx.apiBase,
|
|
322
|
+
governanceState: normalized.state || null,
|
|
323
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
324
|
+
},
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
|
|
329
|
+
async function commandDelegationRedeem(ctx, flags, capabilities) {
|
|
330
|
+
const selectedRunMode = getEffectiveRunMode(ctx, flags);
|
|
331
|
+
if (!['thirdfy', 'hybrid', 'agent_wallet'].includes(selectedRunMode)) {
|
|
332
|
+
throw createCliError('DELEGATION_REDEEM_MODE_INVALID', 'delegation redeem supports only --run-mode thirdfy|hybrid|agent_wallet');
|
|
333
|
+
}
|
|
334
|
+
const delegatedFlags = {
|
|
335
|
+
...flags,
|
|
336
|
+
runMode: selectedRunMode,
|
|
337
|
+
};
|
|
338
|
+
if (!delegatedFlags.estimatedAmountUsd) {
|
|
339
|
+
delegatedFlags.estimatedAmountUsd = '5';
|
|
340
|
+
}
|
|
341
|
+
await commandRun(ctx, delegatedFlags, capabilities);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
return {
|
|
345
|
+
commandDelegationCreate,
|
|
346
|
+
commandDelegationInitCustodial,
|
|
347
|
+
commandDelegationCustodialGrant,
|
|
348
|
+
commandDelegationActivate,
|
|
349
|
+
commandDelegationStatus,
|
|
350
|
+
commandDelegationInspect,
|
|
351
|
+
commandDelegationRevoke,
|
|
352
|
+
commandDelegationBalance,
|
|
353
|
+
commandDelegationRedeem,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { requireFlag, parseJsonFlag } from '../core/args.mjs';
|
|
2
|
+
import { apiGet, apiPost } from '../core/http.mjs';
|
|
3
|
+
import { extractActions, getCachedActionsCatalog } from '../core/context.mjs';
|
|
4
|
+
import { getEffectiveRunMode } from '../core/runMode.mjs';
|
|
5
|
+
export function createDiscoveryCommands({ printEnvelope, applyActionFilters, getTradingProviderHint, resolveChainSupport, getAuthToken, resolveAgentApiKey }) {
|
|
6
|
+
async function commandCatalogsList(ctx, flags, capabilities) {
|
|
7
|
+
const response = await apiGet(ctx, '/api/v1/agent/actions/catalog');
|
|
8
|
+
const actions = extractActions(response);
|
|
9
|
+
const catalogs = [];
|
|
10
|
+
const seen = new Set();
|
|
11
|
+
for (const action of actions) {
|
|
12
|
+
const catalog = String(action.catalog || action.catalogId || action.provider || 'default').trim();
|
|
13
|
+
if (!catalog || seen.has(catalog)) continue;
|
|
14
|
+
seen.add(catalog);
|
|
15
|
+
catalogs.push({
|
|
16
|
+
id: catalog,
|
|
17
|
+
provider: String(action.provider || '').trim() || undefined,
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
printEnvelope({
|
|
21
|
+
success: true,
|
|
22
|
+
code: 'OK',
|
|
23
|
+
message: 'Catalogs loaded',
|
|
24
|
+
data: { catalogs },
|
|
25
|
+
meta: {
|
|
26
|
+
apiBase: ctx.apiBase,
|
|
27
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
28
|
+
},
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function commandActions(ctx, flags, capabilities) {
|
|
33
|
+
const policyAware = Boolean(flags.agentApiKey);
|
|
34
|
+
const actions = applyActionFilters(await getCachedActionsCatalog(ctx, flags), flags);
|
|
35
|
+
const providerHint = getTradingProviderHint(flags.provider);
|
|
36
|
+
const effectiveRunMode = getEffectiveRunMode(ctx, flags);
|
|
37
|
+
const chainIdFilter = Number(flags.chainId || 0) || undefined;
|
|
38
|
+
const chainSupport = resolveChainSupport(capabilities, chainIdFilter, effectiveRunMode);
|
|
39
|
+
printEnvelope({
|
|
40
|
+
success: true,
|
|
41
|
+
code: 'OK',
|
|
42
|
+
message: 'Actions loaded',
|
|
43
|
+
data: { actions, ...(providerHint ? { providerHint } : {}) },
|
|
44
|
+
meta: {
|
|
45
|
+
apiBase: ctx.apiBase,
|
|
46
|
+
policyAware,
|
|
47
|
+
runMode: effectiveRunMode,
|
|
48
|
+
profile: ctx.profile || null,
|
|
49
|
+
chainCompatibility: chainSupport,
|
|
50
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
async function commandCreditsBalance(ctx, flags, capabilities) {
|
|
56
|
+
const authToken = getAuthToken(flags, 'Missing --auth-token (or THIRDFY_AUTH_TOKEN) for credits balance');
|
|
57
|
+
const response = await apiGet(ctx, '/api/v1/credits/balance', {
|
|
58
|
+
Authorization: `Bearer ${authToken}`,
|
|
59
|
+
});
|
|
60
|
+
printEnvelope({
|
|
61
|
+
success: true,
|
|
62
|
+
code: 'OK',
|
|
63
|
+
message: 'Credits balance loaded',
|
|
64
|
+
data: response,
|
|
65
|
+
meta: {
|
|
66
|
+
apiBase: ctx.apiBase,
|
|
67
|
+
capabilitiesVersion: capabilities?.contractVersion || null,
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
commandCatalogsList,
|
|
74
|
+
commandActions,
|
|
75
|
+
commandCreditsBalance,
|
|
76
|
+
};
|
|
77
|
+
}
|