@thirdfy/agent-cli 0.1.46 → 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 +64 -0
- package/README.md +16 -1
- package/bin/thirdfy-agent.mjs +3 -5037
- 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,181 @@
|
|
|
1
|
+
import { negotiateCapabilities } from '../core/http.mjs';
|
|
2
|
+
import { createPolymarketCommands } from '../commands/polymarket.mjs';
|
|
3
|
+
import { createHyperliquidHelpers } from '../commands/hyperliquid.mjs';
|
|
4
|
+
import { createExecuteCommands } from '../commands/execute.mjs';
|
|
5
|
+
import { createWalletCommands } from '../commands/wallet.mjs';
|
|
6
|
+
import { createDelegationCommands } from '../commands/delegation.mjs';
|
|
7
|
+
import { createBootstrapCommands } from '../commands/bootstrap.mjs';
|
|
8
|
+
import { createDiscoveryCommands } from '../commands/discovery.mjs';
|
|
9
|
+
import { createTelemetryCommands } from '../commands/telemetry.mjs';
|
|
10
|
+
import { createCredentialsCommands } from '../commands/credentials.mjs';
|
|
11
|
+
import { createAgentCommands } from '../commands/agent.mjs';
|
|
12
|
+
import { createDoctorCommands } from '../commands/doctor.mjs';
|
|
13
|
+
import { createPromptCommands } from '../commands/prompt.mjs';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Wire command-module factories and local handlers for Commander manifest registration.
|
|
17
|
+
*/
|
|
18
|
+
export function createRuntimeHandlers(deps) {
|
|
19
|
+
const {
|
|
20
|
+
printEnvelope,
|
|
21
|
+
negotiateCapabilitiesForCli,
|
|
22
|
+
extractAgentApiKey,
|
|
23
|
+
extractAgentKey,
|
|
24
|
+
maskSecret,
|
|
25
|
+
getAuthToken,
|
|
26
|
+
buildOwnerAuthHeaders,
|
|
27
|
+
probeBitfinexPermissions,
|
|
28
|
+
applyActionFilters,
|
|
29
|
+
getTradingProviderHint,
|
|
30
|
+
resolveChainSupport,
|
|
31
|
+
resolveAgentApiKey,
|
|
32
|
+
getPreparedParams,
|
|
33
|
+
resolveActionSelection,
|
|
34
|
+
prepareActionParamsForFlags,
|
|
35
|
+
enforceOffchainVenueLaneCompatibility,
|
|
36
|
+
enforceChainCompatibility,
|
|
37
|
+
executeManagedWalletRun,
|
|
38
|
+
executeSelfRun,
|
|
39
|
+
submitSignedTx,
|
|
40
|
+
runPreflightByMode,
|
|
41
|
+
runExecutionByMode,
|
|
42
|
+
applyExecutionFallbackHints,
|
|
43
|
+
performSelfBroadcast,
|
|
44
|
+
resolveManagedExecutionPreflight,
|
|
45
|
+
resolveEffectiveUserDid,
|
|
46
|
+
} = deps;
|
|
47
|
+
|
|
48
|
+
const __discovery = createDiscoveryCommands({
|
|
49
|
+
printEnvelope,
|
|
50
|
+
applyActionFilters,
|
|
51
|
+
getTradingProviderHint,
|
|
52
|
+
resolveChainSupport,
|
|
53
|
+
getAuthToken,
|
|
54
|
+
resolveAgentApiKey,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const __telemetry = createTelemetryCommands({
|
|
58
|
+
printEnvelope,
|
|
59
|
+
resolveAgentApiKey,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const __credentials = createCredentialsCommands({
|
|
63
|
+
printEnvelope,
|
|
64
|
+
getAuthToken,
|
|
65
|
+
buildOwnerAuthHeaders,
|
|
66
|
+
probeBitfinexPermissions,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const __agent = createAgentCommands({
|
|
70
|
+
printEnvelope,
|
|
71
|
+
extractAgentApiKey,
|
|
72
|
+
extractAgentKey,
|
|
73
|
+
buildOwnerAuthHeaders,
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
const __doctor = createDoctorCommands({
|
|
77
|
+
printEnvelope,
|
|
78
|
+
extractAgentApiKey,
|
|
79
|
+
extractAgentKey,
|
|
80
|
+
maskSecret,
|
|
81
|
+
resolveAgentApiKey,
|
|
82
|
+
buildOwnerAuthHeaders,
|
|
83
|
+
resolveEffectiveUserDid,
|
|
84
|
+
loadEthers: deps.loadEthers,
|
|
85
|
+
resolveOwsBinary: deps.resolveOwsBinary,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const __prompt = createPromptCommands({ printEnvelope });
|
|
89
|
+
|
|
90
|
+
const __hyperliquid = createHyperliquidHelpers({
|
|
91
|
+
getPreparedParams,
|
|
92
|
+
resolveManagedExecutionPreflight,
|
|
93
|
+
});
|
|
94
|
+
const { applyHyperliquidAgentWalletAddressDefault } = __hyperliquid;
|
|
95
|
+
|
|
96
|
+
const __wallet = createWalletCommands({
|
|
97
|
+
resolveActionSelection,
|
|
98
|
+
prepareActionParamsForFlags,
|
|
99
|
+
enforceOffchainVenueLaneCompatibility,
|
|
100
|
+
enforceChainCompatibility,
|
|
101
|
+
applyHyperliquidAgentWalletAddressDefault,
|
|
102
|
+
executeManagedWalletRun,
|
|
103
|
+
executeSelfRun,
|
|
104
|
+
submitSignedTx,
|
|
105
|
+
printEnvelope,
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const __execute = createExecuteCommands({
|
|
109
|
+
resolveActionSelection,
|
|
110
|
+
prepareActionParamsForFlags,
|
|
111
|
+
enforceOffchainVenueLaneCompatibility,
|
|
112
|
+
enforceChainCompatibility,
|
|
113
|
+
applyHyperliquidAgentWalletAddressDefault,
|
|
114
|
+
runPreflightByMode,
|
|
115
|
+
runExecutionByMode,
|
|
116
|
+
applyExecutionFallbackHints,
|
|
117
|
+
performSelfBroadcast,
|
|
118
|
+
executeManagedWalletRun,
|
|
119
|
+
executeSelfRun,
|
|
120
|
+
printEnvelope,
|
|
121
|
+
commandWalletSign: __wallet.commandWalletSign,
|
|
122
|
+
commandWalletExecute: __wallet.commandWalletExecute,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const __delegation = createDelegationCommands({
|
|
126
|
+
buildOwnerAuthHeaders,
|
|
127
|
+
printEnvelope,
|
|
128
|
+
commandRun: __execute.commandRun,
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
const __polymarket = createPolymarketCommands({
|
|
132
|
+
commandPreflight: __execute.commandPreflight,
|
|
133
|
+
printEnvelope,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const __bootstrap = createBootstrapCommands({
|
|
137
|
+
printEnvelope,
|
|
138
|
+
extractAgentApiKey,
|
|
139
|
+
extractAgentKey,
|
|
140
|
+
buildOnboardingHelp: __doctor.buildOnboardingHelp,
|
|
141
|
+
buildWalletChallengePayload: __agent.buildWalletChallengePayload,
|
|
142
|
+
issueBootstrapToken: __agent.issueBootstrapToken,
|
|
143
|
+
verifyOwnerWalletChallenge: __agent.verifyOwnerWalletChallenge,
|
|
144
|
+
resolveEffectiveUserDid,
|
|
145
|
+
negotiateCapabilities,
|
|
146
|
+
commandAgentRegister: __agent.commandAgentRegister,
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
...__execute,
|
|
151
|
+
...__wallet,
|
|
152
|
+
...__delegation,
|
|
153
|
+
...__polymarket,
|
|
154
|
+
...__bootstrap,
|
|
155
|
+
...__discovery,
|
|
156
|
+
...__telemetry,
|
|
157
|
+
...__credentials,
|
|
158
|
+
...__agent,
|
|
159
|
+
...__doctor,
|
|
160
|
+
...__prompt,
|
|
161
|
+
commandDoctorSelf: __doctor.commandDoctorSelf,
|
|
162
|
+
commandDoctorAuth: __doctor.commandDoctorAuth,
|
|
163
|
+
commandManagedSetup: __doctor.commandManagedSetup,
|
|
164
|
+
commandCatalogsList: __discovery.commandCatalogsList,
|
|
165
|
+
commandActions: __discovery.commandActions,
|
|
166
|
+
commandCreditsBalance: __discovery.commandCreditsBalance,
|
|
167
|
+
commandDataSummary: __telemetry.commandDataSummary,
|
|
168
|
+
commandTrackList: __telemetry.commandTrackList,
|
|
169
|
+
commandTrackAction: __telemetry.commandTrackAction,
|
|
170
|
+
commandCredentialsUpsert: __credentials.commandCredentialsUpsert,
|
|
171
|
+
commandCredentialsStatus: __credentials.commandCredentialsStatus,
|
|
172
|
+
commandAgentRegister: __agent.commandAgentRegister,
|
|
173
|
+
commandAgentKeyRotate: __agent.commandAgentKeyRotate,
|
|
174
|
+
commandAgentKeyRevoke: __agent.commandAgentKeyRevoke,
|
|
175
|
+
commandAgentAuthChallenge: __agent.commandAgentAuthChallenge,
|
|
176
|
+
commandAgentAuthVerify: __agent.commandAgentAuthVerify,
|
|
177
|
+
commandAnalyticsPortfolio: __telemetry.commandAnalyticsPortfolio,
|
|
178
|
+
commandAnalyticsLeaderboard: __telemetry.commandAnalyticsLeaderboard,
|
|
179
|
+
commandPrompt: __prompt.commandPrompt,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { createRequire } from 'module';
|
|
2
|
+
import { printEnvelope as corePrintEnvelope } from '../core/envelope.mjs';
|
|
3
|
+
import { negotiateCapabilities } from '../core/http.mjs';
|
|
4
|
+
import {
|
|
5
|
+
buildCliProgram,
|
|
6
|
+
collectRootFlags,
|
|
7
|
+
handleRootOnlyFlows,
|
|
8
|
+
collectVersionFlagsFromArgv,
|
|
9
|
+
} from '../cli/program.mjs';
|
|
10
|
+
import { createInitialRuntimeContext, applyFlagsToRuntimeContext } from './context.mjs';
|
|
11
|
+
import { createProviderHints } from './providerHints.mjs';
|
|
12
|
+
import { createRuntimeHandlers } from './handlers.mjs';
|
|
13
|
+
import { isCommanderCliError } from './errors.mjs';
|
|
14
|
+
import { createOnboardingHints } from './onboardingHints.mjs';
|
|
15
|
+
import { createAgentExtract } from './agentExtract.mjs';
|
|
16
|
+
import { createAuthHelpers } from './authHelpers.mjs';
|
|
17
|
+
import { createExecutionAmounts } from './execution/amounts.mjs';
|
|
18
|
+
import { createExecutionLanes } from './execution/lanes.mjs';
|
|
19
|
+
import { createExecutionPayloads } from './execution/payloads.mjs';
|
|
20
|
+
import { createExecutionRunners } from './execution/runners.mjs';
|
|
21
|
+
import { createActionSelection } from './actions/selection.mjs';
|
|
22
|
+
import { createBitfinexProbe } from './bitfinexProbe.mjs';
|
|
23
|
+
import { createOwsSigning } from './owsSigning.mjs';
|
|
24
|
+
|
|
25
|
+
const require = createRequire(import.meta.url);
|
|
26
|
+
const { version: CLI_VERSION } = require('../../package.json');
|
|
27
|
+
|
|
28
|
+
export function createThirdfyAgentRuntime() {
|
|
29
|
+
const context = createInitialRuntimeContext();
|
|
30
|
+
let cliProgram = null;
|
|
31
|
+
|
|
32
|
+
function printEnvelope(payload, options = {}) {
|
|
33
|
+
const jsonMode = Boolean(
|
|
34
|
+
options.jsonMode ||
|
|
35
|
+
context.jsonMode ||
|
|
36
|
+
process.argv.includes('--json') ||
|
|
37
|
+
(cliProgram ? cliProgram.opts()?.json : false)
|
|
38
|
+
);
|
|
39
|
+
corePrintEnvelope(payload, { jsonMode });
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function prepareContextFromFlags(flags) {
|
|
43
|
+
return applyFlagsToRuntimeContext(context, flags);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
async function negotiateCapabilitiesForCli(ctx) {
|
|
47
|
+
if (ctx.negotiatedCapabilitiesCache) return ctx.negotiatedCapabilitiesCache;
|
|
48
|
+
const capabilities = await negotiateCapabilities(ctx);
|
|
49
|
+
ctx.negotiatedCapabilitiesCache = capabilities;
|
|
50
|
+
return capabilities;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const providerHints = createProviderHints({
|
|
54
|
+
getNegotiatedCapabilitiesCache: () => context.negotiatedCapabilitiesCache,
|
|
55
|
+
});
|
|
56
|
+
const { getTradingProviderHint, formatProviderAmbiguousActionHint, formatProviderUnknownActionHint } =
|
|
57
|
+
providerHints;
|
|
58
|
+
|
|
59
|
+
const { extractAgentApiKey, extractAgentKey, maskSecret } = createAgentExtract();
|
|
60
|
+
const onboarding = createOnboardingHints();
|
|
61
|
+
const amounts = createExecutionAmounts();
|
|
62
|
+
const lanes = createExecutionLanes();
|
|
63
|
+
const auth = createAuthHelpers();
|
|
64
|
+
const payloads = createExecutionPayloads({
|
|
65
|
+
getPreparedParams: amounts.getPreparedParams,
|
|
66
|
+
rawUnitsToDecimalString: amounts.rawUnitsToDecimalString,
|
|
67
|
+
});
|
|
68
|
+
const actions = createActionSelection({
|
|
69
|
+
getTradingProviderHint,
|
|
70
|
+
formatProviderAmbiguousActionHint,
|
|
71
|
+
formatProviderUnknownActionHint,
|
|
72
|
+
});
|
|
73
|
+
const ows = createOwsSigning();
|
|
74
|
+
const bitfinex = createBitfinexProbe();
|
|
75
|
+
const runners = createExecutionRunners({
|
|
76
|
+
buildIntentPayload: payloads.buildIntentPayload,
|
|
77
|
+
buildBuildTxPayload: payloads.buildBuildTxPayload,
|
|
78
|
+
buildManagedExecutePayload: payloads.buildManagedExecutePayload,
|
|
79
|
+
getPreparedParams: amounts.getPreparedParams,
|
|
80
|
+
resolveEffectiveUserDid: payloads.resolveEffectiveUserDid,
|
|
81
|
+
resolveTokenInForFunding: payloads.resolveTokenInForFunding,
|
|
82
|
+
shouldUseBuildTxPreflight: lanes.shouldUseBuildTxPreflight,
|
|
83
|
+
shouldUseBuildTxExecution: lanes.shouldUseBuildTxExecution,
|
|
84
|
+
buildBitfinexOnboardingCommand: onboarding.buildBitfinexOnboardingCommand,
|
|
85
|
+
inferBitfinexPermissionProfileFromAction: onboarding.inferBitfinexPermissionProfileFromAction,
|
|
86
|
+
resolveAgentApiKey: payloads.resolveAgentApiKey,
|
|
87
|
+
loadEthers: ows.loadEthers,
|
|
88
|
+
signAndBroadcastWithOws: ows.signAndBroadcastWithOws,
|
|
89
|
+
readEffectBalances: ows.readEffectBalances,
|
|
90
|
+
resolveUnsignedTx: auth.resolveUnsignedTx,
|
|
91
|
+
sleepMs: auth.sleepMs,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
const cliHandlers = createRuntimeHandlers({
|
|
95
|
+
printEnvelope,
|
|
96
|
+
negotiateCapabilitiesForCli,
|
|
97
|
+
extractAgentApiKey,
|
|
98
|
+
extractAgentKey,
|
|
99
|
+
maskSecret,
|
|
100
|
+
getAuthToken: auth.getAuthToken,
|
|
101
|
+
buildOwnerAuthHeaders: auth.buildOwnerAuthHeaders,
|
|
102
|
+
probeBitfinexPermissions: bitfinex.probeBitfinexPermissions,
|
|
103
|
+
applyActionFilters: actions.applyActionFilters,
|
|
104
|
+
getTradingProviderHint,
|
|
105
|
+
resolveChainSupport: lanes.resolveChainSupport,
|
|
106
|
+
resolveAgentApiKey: payloads.resolveAgentApiKey,
|
|
107
|
+
getPreparedParams: amounts.getPreparedParams,
|
|
108
|
+
resolveActionSelection: actions.resolveActionSelection,
|
|
109
|
+
prepareActionParamsForFlags: amounts.prepareActionParamsForFlags,
|
|
110
|
+
enforceOffchainVenueLaneCompatibility: lanes.enforceOffchainVenueLaneCompatibility,
|
|
111
|
+
enforceChainCompatibility: lanes.enforceChainCompatibility,
|
|
112
|
+
executeManagedWalletRun: runners.executeManagedWalletRun,
|
|
113
|
+
executeSelfRun: runners.executeSelfRun,
|
|
114
|
+
submitSignedTx: runners.submitSignedTx,
|
|
115
|
+
runPreflightByMode: runners.runPreflightByMode,
|
|
116
|
+
runExecutionByMode: runners.runExecutionByMode,
|
|
117
|
+
applyExecutionFallbackHints: runners.applyExecutionFallbackHints,
|
|
118
|
+
performSelfBroadcast: runners.performSelfBroadcast,
|
|
119
|
+
resolveManagedExecutionPreflight: runners.resolveManagedExecutionPreflight,
|
|
120
|
+
resolveEffectiveUserDid: payloads.resolveEffectiveUserDid,
|
|
121
|
+
loadEthers: ows.loadEthers,
|
|
122
|
+
resolveOwsBinary: ows.resolveOwsBinary,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
cliProgram = buildCliProgram({
|
|
126
|
+
CLI_VERSION,
|
|
127
|
+
handlers: cliHandlers,
|
|
128
|
+
getContext: () => context,
|
|
129
|
+
getJsonMode: () => context.jsonMode,
|
|
130
|
+
printEnvelope,
|
|
131
|
+
prepareContextFromFlags,
|
|
132
|
+
negotiateCapabilities: negotiateCapabilitiesForCli,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
async function runMain() {
|
|
136
|
+
const rootFlowDeps = {
|
|
137
|
+
collectRootFlags,
|
|
138
|
+
prepareContextFromFlags,
|
|
139
|
+
printEnvelope,
|
|
140
|
+
CLI_VERSION,
|
|
141
|
+
getApiBase: () => context.apiBase,
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
const earlyVersionFlags = collectVersionFlagsFromArgv(process.argv);
|
|
145
|
+
if (earlyVersionFlags.version) {
|
|
146
|
+
prepareContextFromFlags(earlyVersionFlags);
|
|
147
|
+
await handleRootOnlyFlows(cliProgram, rootFlowDeps, earlyVersionFlags);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
await cliProgram.parseAsync(process.argv, { from: 'node' });
|
|
153
|
+
const versionHandled = await handleRootOnlyFlows(cliProgram, rootFlowDeps);
|
|
154
|
+
if (versionHandled) return;
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (isCommanderCliError(error)) {
|
|
157
|
+
const flags = collectRootFlags(cliProgram);
|
|
158
|
+
if (
|
|
159
|
+
flags.version &&
|
|
160
|
+
(error.code === 'commander.help' || error.code === 'commander.helpDisplayed')
|
|
161
|
+
) {
|
|
162
|
+
prepareContextFromFlags(flags);
|
|
163
|
+
await handleRootOnlyFlows(cliProgram, rootFlowDeps);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (error.code === 'commander.help' || error.code === 'commander.helpDisplayed') {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const exitCode = Number(error.exitCode ?? 1);
|
|
170
|
+
process.exit(exitCode);
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function handleCliEntryError(error) {
|
|
177
|
+
const statusCode = Number(error?.statusCode || 0) || undefined;
|
|
178
|
+
const payload = error?.payload && typeof error.payload === 'object' ? error.payload : {};
|
|
179
|
+
const blockedReason = String(payload.blockedReason || payload.error || '').trim() || undefined;
|
|
180
|
+
const blockedStage = String(payload.blockedStage || '').trim() || undefined;
|
|
181
|
+
const onboardingHint = onboarding.buildTopLevelOnboardingHint(payload);
|
|
182
|
+
printEnvelope({
|
|
183
|
+
success: false,
|
|
184
|
+
code: statusCode ? 'API_REQUEST_FAILED' : 'CLI_UNHANDLED_ERROR',
|
|
185
|
+
message: error?.message || 'Unhandled CLI error',
|
|
186
|
+
data: {
|
|
187
|
+
statusCode,
|
|
188
|
+
blockedReason,
|
|
189
|
+
blockedStage,
|
|
190
|
+
onboardingHint,
|
|
191
|
+
payload,
|
|
192
|
+
},
|
|
193
|
+
meta: { version: CLI_VERSION, apiBase: context.apiBase },
|
|
194
|
+
});
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
return {
|
|
199
|
+
runMain,
|
|
200
|
+
handleCliEntryError,
|
|
201
|
+
getContext: () => context,
|
|
202
|
+
getCliProgram: () => cliProgram,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BITFINEX_PERMISSION_PROFILES } from '../core/constants.mjs';
|
|
2
|
+
export function createOnboardingHints() {
|
|
3
|
+
function buildBitfinexOnboardingCommand(permissionProfile = 'funding') {
|
|
4
|
+
const profile = BITFINEX_PERMISSION_PROFILES[permissionProfile] || BITFINEX_PERMISSION_PROFILES.funding;
|
|
5
|
+
return [
|
|
6
|
+
'thirdfy-agent credentials upsert',
|
|
7
|
+
'--auth-token "$THIRDFY_AUTH_TOKEN"',
|
|
8
|
+
'--venue bitfinex',
|
|
9
|
+
`--permission-profile ${profile.id}`,
|
|
10
|
+
`--credential-ref ${profile.credentialRef}`,
|
|
11
|
+
'--api-key "<BITFINEX_API_KEY>"',
|
|
12
|
+
'--api-secret "<BITFINEX_API_SECRET>"',
|
|
13
|
+
'--verify-permissions',
|
|
14
|
+
'--json',
|
|
15
|
+
].join(' ');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function inferBitfinexPermissionProfileFromAction(actionName) {
|
|
19
|
+
const action = String(actionName || '')
|
|
20
|
+
.trim()
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/[_\s]+/g, '-');
|
|
23
|
+
if (!action.includes('bitfinex')) return 'funding';
|
|
24
|
+
return action.includes('bitfinex-order') ? 'spot' : 'funding';
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function buildTopLevelOnboardingHint(payload) {
|
|
28
|
+
const reason = String(payload?.blockedReason || payload?.error || '').trim();
|
|
29
|
+
const permissionProfile = inferBitfinexPermissionProfileFromAction(
|
|
30
|
+
payload?.resolvedAction || payload?.action || payload?.requestedAction
|
|
31
|
+
);
|
|
32
|
+
if (!reason) return null;
|
|
33
|
+
if (
|
|
34
|
+
[
|
|
35
|
+
'CEX_CREDENTIAL_NOT_FOUND',
|
|
36
|
+
'BITFINEX_CREDENTIALS_NOT_IN_CONTEXT',
|
|
37
|
+
'BITFINEX_CREDENTIALS_NOT_IN_THIRDFY_DELEGATION_CONTEXT',
|
|
38
|
+
'BITFINEX_ENV_CREDENTIALS_NOT_CONFIGURED',
|
|
39
|
+
].includes(reason)
|
|
40
|
+
) {
|
|
41
|
+
return {
|
|
42
|
+
type: 'bitfinex_credentials',
|
|
43
|
+
command: buildBitfinexOnboardingCommand(permissionProfile),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
buildBitfinexOnboardingCommand,
|
|
51
|
+
inferBitfinexPermissionProfileFromAction,
|
|
52
|
+
buildTopLevelOnboardingHint,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { spawnSync } from 'child_process';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import { createCliError } from '../core/envelope.mjs';
|
|
6
|
+
export function createOwsSigning() {
|
|
7
|
+
async function loadEthers() {
|
|
8
|
+
const candidates = ['ethers', path.join(process.cwd(), 'node_modules', 'ethers')];
|
|
9
|
+
for (const candidate of candidates) {
|
|
10
|
+
try {
|
|
11
|
+
return require(candidate);
|
|
12
|
+
} catch {
|
|
13
|
+
// continue
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
throw new Error('Could not load ethers dependency for self-exec');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function resolveOwsBinary() {
|
|
20
|
+
const explicit = String(process.env.OWS_CLI_PATH || '').trim();
|
|
21
|
+
if (explicit && fs.existsSync(explicit)) return explicit;
|
|
22
|
+
const localBin = path.join(process.cwd(), 'node_modules', '.bin', 'ows');
|
|
23
|
+
if (fs.existsSync(localBin)) return localBin;
|
|
24
|
+
const which = spawnSync('which', ['ows'], { encoding: 'utf-8' });
|
|
25
|
+
const discovered = String(which.stdout || '').trim();
|
|
26
|
+
if (discovered) return discovered;
|
|
27
|
+
throw new Error('ows CLI not found. Install it or set OWS_CLI_PATH.');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function signUnsignedTxWithOws(unsignedHex, walletName, chainId) {
|
|
31
|
+
const passphrase = String(process.env.OWS_PASSPHRASE || process.env.OWS_API_KEY || '').trim();
|
|
32
|
+
if (!passphrase) {
|
|
33
|
+
throw new Error('Set OWS_PASSPHRASE (or OWS_API_KEY) for self-exec signing.');
|
|
34
|
+
}
|
|
35
|
+
const ows = resolveOwsBinary();
|
|
36
|
+
const txHex = String(unsignedHex).startsWith('0x') ? String(unsignedHex).slice(2) : String(unsignedHex);
|
|
37
|
+
const res = spawnSync(
|
|
38
|
+
ows,
|
|
39
|
+
['sign', 'tx', '--wallet', walletName, '--chain', `eip155:${chainId}`, '--tx', txHex, '--json'],
|
|
40
|
+
{ env: { ...process.env, OWS_PASSPHRASE: passphrase }, encoding: 'utf-8' }
|
|
41
|
+
);
|
|
42
|
+
const out = String(res.stdout || '').trim();
|
|
43
|
+
if (res.status !== 0 || !out) {
|
|
44
|
+
throw new Error(`ows sign tx failed: ${String(res.stderr || out || res.status).slice(0, 300)}`);
|
|
45
|
+
}
|
|
46
|
+
let parsed;
|
|
47
|
+
try {
|
|
48
|
+
parsed = JSON.parse(out);
|
|
49
|
+
} catch {
|
|
50
|
+
throw new Error(`ows sign tx returned non-json payload: ${out.slice(0, 200)}`);
|
|
51
|
+
}
|
|
52
|
+
const signature = String(parsed.signature || '').replace(/^0x/i, '');
|
|
53
|
+
if (signature.length < 128) {
|
|
54
|
+
throw new Error('Invalid OWS signature payload');
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
recoveryId: Number(parsed.recovery_id),
|
|
58
|
+
r: `0x${signature.slice(0, 64)}`,
|
|
59
|
+
s: `0x${signature.slice(64, 128)}`,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function signAndBroadcastWithOws({ txd, chainId, walletAddress, owsWalletName, rpcUrl }) {
|
|
64
|
+
const ethers = await loadEthers();
|
|
65
|
+
const { JsonRpcProvider, Transaction, Signature } = ethers;
|
|
66
|
+
const provider = new JsonRpcProvider(rpcUrl, chainId);
|
|
67
|
+
const nonce = await provider.getTransactionCount(walletAddress, 'pending');
|
|
68
|
+
const fee = await provider.getFeeData();
|
|
69
|
+
const txFields = {
|
|
70
|
+
type: 2,
|
|
71
|
+
chainId,
|
|
72
|
+
nonce,
|
|
73
|
+
to: String(txd.to).toLowerCase(),
|
|
74
|
+
data: txd.data,
|
|
75
|
+
value: txd.value ? BigInt(txd.value) : 0n,
|
|
76
|
+
gasLimit: txd.gas ? BigInt(txd.gas) : txd.gasLimit ? BigInt(txd.gasLimit) : 500000n,
|
|
77
|
+
maxFeePerGas: fee.maxFeePerGas ?? fee.gasPrice ?? 2_000_000_000n,
|
|
78
|
+
maxPriorityFeePerGas: fee.maxPriorityFeePerGas ?? 1_000_000_000n,
|
|
79
|
+
};
|
|
80
|
+
const unsigned = Transaction.from(txFields);
|
|
81
|
+
const sigParts = signUnsignedTxWithOws(unsigned.unsignedSerialized, owsWalletName, chainId);
|
|
82
|
+
const sig = Signature.from({ r: sigParts.r, s: sigParts.s, yParity: sigParts.recoveryId });
|
|
83
|
+
const tx = Transaction.from(unsigned.unsignedSerialized);
|
|
84
|
+
tx.signature = sig;
|
|
85
|
+
const sent = await provider.broadcastTransaction(tx.serialized);
|
|
86
|
+
return { sent };
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function readTokenBalanceRaw(rpcUrl, walletAddress, tokenAddress) {
|
|
90
|
+
const ethers = await loadEthers();
|
|
91
|
+
const { JsonRpcProvider, Interface } = ethers;
|
|
92
|
+
const provider = new JsonRpcProvider(rpcUrl);
|
|
93
|
+
const erc20 = new Interface(['function balanceOf(address owner) view returns (uint256)']);
|
|
94
|
+
const response = await provider.call({
|
|
95
|
+
to: tokenAddress,
|
|
96
|
+
data: erc20.encodeFunctionData('balanceOf', [walletAddress]),
|
|
97
|
+
});
|
|
98
|
+
const decoded = erc20.decodeFunctionResult('balanceOf', response);
|
|
99
|
+
return BigInt(decoded[0].toString()).toString();
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
async function readEffectBalances(rpcUrl, walletAddress, tokenIn, tokenOut) {
|
|
103
|
+
const [inBal, outBal] = await Promise.all([
|
|
104
|
+
readTokenBalanceRaw(rpcUrl, walletAddress, tokenIn),
|
|
105
|
+
readTokenBalanceRaw(rpcUrl, walletAddress, tokenOut),
|
|
106
|
+
]);
|
|
107
|
+
return { tokenIn: inBal, tokenOut: outBal };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
loadEthers,
|
|
112
|
+
resolveOwsBinary,
|
|
113
|
+
signUnsignedTxWithOws,
|
|
114
|
+
signAndBroadcastWithOws,
|
|
115
|
+
readTokenBalanceRaw,
|
|
116
|
+
readEffectBalances,
|
|
117
|
+
};
|
|
118
|
+
}
|