@exagent/agent 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/dist/chunk-EJHDRG5Y.mjs +5305 -0
- package/dist/chunk-NENK6U55.mjs +5305 -0
- package/dist/chunk-QSKHZYR2.mjs +5305 -0
- package/dist/cli.js +224 -61
- package/dist/cli.mjs +87 -3
- package/dist/index.d.mts +27 -5
- package/dist/index.d.ts +27 -5
- package/dist/index.js +138 -59
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1659,7 +1659,7 @@ function classifyTradeError(message) {
|
|
|
1659
1659
|
if (lower.includes("notauthorizedforagent") || lower.includes("not authorized")) {
|
|
1660
1660
|
return {
|
|
1661
1661
|
category: "not_authorized",
|
|
1662
|
-
userMessage:
|
|
1662
|
+
userMessage: 'Wallet not authorized for this agent. This wallet is not linked to your agent on-chain, so the router rejected the trade. To fix: (1) Open your command center at exagent.io, (2) Use the Wallet Management panel to check linked wallets, (3) If you lost your old wallet, unlink it first then re-run the agent to link the new one. Run "npx @exagent/agent export-key" to verify which wallet this agent is using.'
|
|
1663
1663
|
};
|
|
1664
1664
|
}
|
|
1665
1665
|
if (lower.includes("aggregatornotwhitelisted")) {
|
|
@@ -3702,7 +3702,7 @@ function loadSecureEnv(basePath, passphrase) {
|
|
|
3702
3702
|
}
|
|
3703
3703
|
|
|
3704
3704
|
// src/index.ts
|
|
3705
|
-
var AGENT_VERSION = "0.1.
|
|
3705
|
+
var AGENT_VERSION = "0.1.23";
|
|
3706
3706
|
|
|
3707
3707
|
// src/relay.ts
|
|
3708
3708
|
var RelayClient = class {
|
|
@@ -3984,6 +3984,9 @@ var AgentRuntime = class {
|
|
|
3984
3984
|
isRunning = false;
|
|
3985
3985
|
mode = "idle";
|
|
3986
3986
|
configHash;
|
|
3987
|
+
pendingConfigHash = null;
|
|
3988
|
+
lastConfigCheckAt = 0;
|
|
3989
|
+
// Timestamp of last pending config RPC check
|
|
3987
3990
|
cycleCount = 0;
|
|
3988
3991
|
lastCycleAt = 0;
|
|
3989
3992
|
lastPortfolioValue = 0;
|
|
@@ -4010,6 +4013,12 @@ var AgentRuntime = class {
|
|
|
4010
4013
|
// When perpConnected && perpTradingActive: dedicated runPerpCycle() runs every interval
|
|
4011
4014
|
perpConnected = false;
|
|
4012
4015
|
perpTradingActive = false;
|
|
4016
|
+
// Cached perp account data for synchronous heartbeat inclusion (refreshed async)
|
|
4017
|
+
cachedPerpEquity = 0;
|
|
4018
|
+
cachedPerpUnrealizedPnl = 0;
|
|
4019
|
+
cachedPerpMarginUsed = 0;
|
|
4020
|
+
cachedPerpLeverage = 0;
|
|
4021
|
+
cachedPerpOpenPositions = 0;
|
|
4013
4022
|
constructor(config) {
|
|
4014
4023
|
this.config = config;
|
|
4015
4024
|
}
|
|
@@ -4320,8 +4329,14 @@ var AgentRuntime = class {
|
|
|
4320
4329
|
}
|
|
4321
4330
|
/**
|
|
4322
4331
|
* Sync the LLM config hash to chain for epoch tracking.
|
|
4323
|
-
*
|
|
4324
|
-
*
|
|
4332
|
+
*
|
|
4333
|
+
* If the trading wallet is NOT the agent owner, the on-chain setConfig
|
|
4334
|
+
* call would revert with AgentNotOwner. Instead, we set a pending state
|
|
4335
|
+
* and send a message to the command center so the owner can approve it
|
|
4336
|
+
* from the website with one click.
|
|
4337
|
+
*
|
|
4338
|
+
* Until the config is verified on-chain, the agent won't appear on the
|
|
4339
|
+
* leaderboard (trades still execute normally).
|
|
4325
4340
|
*/
|
|
4326
4341
|
async syncConfigHash() {
|
|
4327
4342
|
const agentId = BigInt(this.config.agentId);
|
|
@@ -4329,53 +4344,89 @@ var AgentRuntime = class {
|
|
|
4329
4344
|
this.configHash = import_sdk.ExagentRegistry.calculateConfigHash(llmMeta.provider, llmMeta.model);
|
|
4330
4345
|
console.log(`Config hash: ${this.configHash}`);
|
|
4331
4346
|
const onChainHash = await this.client.registry.getConfigHash(agentId);
|
|
4332
|
-
if (onChainHash
|
|
4333
|
-
console.log("Config
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4347
|
+
if (onChainHash === this.configHash) {
|
|
4348
|
+
console.log("Config hash matches on-chain");
|
|
4349
|
+
this.pendingConfigHash = null;
|
|
4350
|
+
return;
|
|
4351
|
+
}
|
|
4352
|
+
console.log("Config changed, updating on-chain...");
|
|
4353
|
+
const agent = await this.client.registry.getAgent(agentId);
|
|
4354
|
+
const isOwner = agent?.owner.toLowerCase() === this.client.address.toLowerCase();
|
|
4355
|
+
if (!isOwner) {
|
|
4356
|
+
this.pendingConfigHash = this.configHash;
|
|
4357
|
+
this.configHash = onChainHash;
|
|
4358
|
+
console.log("");
|
|
4359
|
+
console.log("=== CONFIG VERIFICATION NEEDED ===");
|
|
4360
|
+
console.log("");
|
|
4361
|
+
console.log(" Your trading wallet cannot update the LLM config on-chain.");
|
|
4362
|
+
console.log(" The owner must approve this from the command center.");
|
|
4363
|
+
console.log("");
|
|
4364
|
+
console.log(` LLM: ${llmMeta.provider} / ${llmMeta.model}`);
|
|
4365
|
+
console.log(` Hash: ${this.pendingConfigHash}`);
|
|
4366
|
+
console.log("");
|
|
4367
|
+
console.log(" Until approved:");
|
|
4368
|
+
console.log(" - New agents will not appear on the leaderboard");
|
|
4369
|
+
console.log(" - Trades will still execute normally");
|
|
4370
|
+
console.log("");
|
|
4371
|
+
this.relay?.sendMessage(
|
|
4372
|
+
"system",
|
|
4373
|
+
"warning",
|
|
4374
|
+
"Config Verification Needed",
|
|
4375
|
+
`Your agent is using ${llmMeta.provider}/${llmMeta.model} but this hasn't been recorded on-chain. Open the command center and click "Approve Config" to verify. Until then, your agent won't appear on the leaderboard.`,
|
|
4376
|
+
{ configHash: this.pendingConfigHash, provider: llmMeta.provider, model: llmMeta.model }
|
|
4377
|
+
);
|
|
4378
|
+
return;
|
|
4379
|
+
}
|
|
4380
|
+
try {
|
|
4381
|
+
await this.client.registry.updateConfig(agentId, this.configHash);
|
|
4382
|
+
console.log(`Config updated on-chain`);
|
|
4383
|
+
this.pendingConfigHash = null;
|
|
4384
|
+
} catch (error) {
|
|
4385
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
4386
|
+
if (message.includes("insufficient funds") || message.includes("intrinsic gas too low") || message.includes("exceeds the balance")) {
|
|
4387
|
+
const ccUrl = `https://exagent.io/agents/${encodeURIComponent(this.config.name)}/command-center`;
|
|
4388
|
+
const publicClientInstance = (0, import_viem6.createPublicClient)({
|
|
4389
|
+
chain: import_chains4.base,
|
|
4390
|
+
transport: (0, import_viem6.http)(this.getRpcUrl())
|
|
4391
|
+
});
|
|
4392
|
+
console.log("");
|
|
4393
|
+
console.log("=== ETH NEEDED FOR GAS ===");
|
|
4394
|
+
console.log("");
|
|
4395
|
+
console.log(` Wallet: ${this.client.address}`);
|
|
4396
|
+
console.log(" Your wallet needs ETH to pay for transaction gas.");
|
|
4397
|
+
console.log(" Opening the command center to fund your wallet...");
|
|
4398
|
+
console.log(` ${ccUrl}`);
|
|
4399
|
+
console.log("");
|
|
4400
|
+
openBrowser(ccUrl);
|
|
4401
|
+
console.log(" Waiting for ETH... (checking every 15s)");
|
|
4402
|
+
console.log(" Press Ctrl+C to exit.");
|
|
4403
|
+
console.log("");
|
|
4404
|
+
while (true) {
|
|
4405
|
+
await this.sleep(15e3);
|
|
4406
|
+
const balance = await publicClientInstance.getBalance({
|
|
4407
|
+
address: this.client.address
|
|
4345
4408
|
});
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
console.log(" Your wallet needs ETH to pay for transaction gas.");
|
|
4351
|
-
console.log(" Opening the command center to fund your wallet...");
|
|
4352
|
-
console.log(` ${ccUrl}`);
|
|
4353
|
-
console.log("");
|
|
4354
|
-
openBrowser(ccUrl);
|
|
4355
|
-
console.log(" Waiting for ETH... (checking every 15s)");
|
|
4356
|
-
console.log(" Press Ctrl+C to exit.");
|
|
4357
|
-
console.log("");
|
|
4358
|
-
while (true) {
|
|
4359
|
-
await this.sleep(15e3);
|
|
4360
|
-
const balance = await publicClientInstance.getBalance({
|
|
4361
|
-
address: this.client.address
|
|
4362
|
-
});
|
|
4363
|
-
if (balance > BigInt(0)) {
|
|
4364
|
-
console.log(" ETH detected! Retrying config update...");
|
|
4365
|
-
console.log("");
|
|
4409
|
+
if (balance > BigInt(0)) {
|
|
4410
|
+
console.log(" ETH detected! Retrying config update...");
|
|
4411
|
+
console.log("");
|
|
4412
|
+
try {
|
|
4366
4413
|
await this.client.registry.updateConfig(agentId, this.configHash);
|
|
4367
4414
|
console.log(`Config updated on-chain`);
|
|
4368
|
-
|
|
4415
|
+
this.pendingConfigHash = null;
|
|
4416
|
+
} catch (retryError) {
|
|
4417
|
+
const retryMsg = retryError instanceof Error ? retryError.message : String(retryError);
|
|
4418
|
+
console.warn(`Config update failed after funding: ${retryMsg}`);
|
|
4419
|
+
console.warn("Continuing with on-chain config.");
|
|
4420
|
+
this.configHash = onChainHash;
|
|
4369
4421
|
}
|
|
4370
|
-
|
|
4422
|
+
return;
|
|
4371
4423
|
}
|
|
4372
|
-
|
|
4373
|
-
console.warn(`Config update skipped (continuing with on-chain config): ${message}`);
|
|
4374
|
-
this.configHash = onChainHash;
|
|
4424
|
+
process.stdout.write(".");
|
|
4375
4425
|
}
|
|
4426
|
+
} else {
|
|
4427
|
+
console.warn(`Config update skipped (continuing with on-chain config): ${message}`);
|
|
4428
|
+
this.configHash = onChainHash;
|
|
4376
4429
|
}
|
|
4377
|
-
} else {
|
|
4378
|
-
console.log("Config hash matches on-chain");
|
|
4379
4430
|
}
|
|
4380
4431
|
}
|
|
4381
4432
|
/**
|
|
@@ -4706,11 +4757,38 @@ var AgentRuntime = class {
|
|
|
4706
4757
|
this.relay?.sendCommandResult(cmd.id, false, message);
|
|
4707
4758
|
}
|
|
4708
4759
|
}
|
|
4760
|
+
/**
|
|
4761
|
+
* Periodically check if the owner has approved the pending config hash.
|
|
4762
|
+
* Called from sendRelayStatus at most every 2.5 minutes (timestamp-throttled).
|
|
4763
|
+
*/
|
|
4764
|
+
async checkPendingConfigApproval() {
|
|
4765
|
+
if (!this.pendingConfigHash) return;
|
|
4766
|
+
try {
|
|
4767
|
+
const onChain = await this.client.registry.getConfigHash(BigInt(this.config.agentId));
|
|
4768
|
+
if (onChain === this.pendingConfigHash) {
|
|
4769
|
+
this.configHash = this.pendingConfigHash;
|
|
4770
|
+
this.pendingConfigHash = null;
|
|
4771
|
+
console.log("Config verified on-chain! Your agent will now appear on the leaderboard.");
|
|
4772
|
+
this.relay?.sendMessage(
|
|
4773
|
+
"config_updated",
|
|
4774
|
+
"success",
|
|
4775
|
+
"Config Verified",
|
|
4776
|
+
"Your LLM config has been verified on-chain. Your agent will now appear on the leaderboard."
|
|
4777
|
+
);
|
|
4778
|
+
}
|
|
4779
|
+
} catch {
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4709
4782
|
/**
|
|
4710
4783
|
* Send current status to the relay
|
|
4711
4784
|
*/
|
|
4712
4785
|
sendRelayStatus() {
|
|
4713
4786
|
if (!this.relay) return;
|
|
4787
|
+
const CONFIG_CHECK_INTERVAL_MS = 15e4;
|
|
4788
|
+
if (this.pendingConfigHash && Date.now() - this.lastConfigCheckAt >= CONFIG_CHECK_INTERVAL_MS) {
|
|
4789
|
+
this.lastConfigCheckAt = Date.now();
|
|
4790
|
+
this.checkPendingConfigApproval();
|
|
4791
|
+
}
|
|
4714
4792
|
const vaultConfig = this.config.vault || { policy: "disabled" };
|
|
4715
4793
|
const status = {
|
|
4716
4794
|
mode: this.mode,
|
|
@@ -4739,31 +4817,32 @@ var AgentRuntime = class {
|
|
|
4739
4817
|
perp: this.perpConnected ? {
|
|
4740
4818
|
enabled: true,
|
|
4741
4819
|
trading: this.perpTradingActive,
|
|
4742
|
-
equity:
|
|
4743
|
-
unrealizedPnl:
|
|
4744
|
-
marginUsed:
|
|
4745
|
-
openPositions:
|
|
4746
|
-
effectiveLeverage:
|
|
4820
|
+
equity: this.cachedPerpEquity,
|
|
4821
|
+
unrealizedPnl: this.cachedPerpUnrealizedPnl,
|
|
4822
|
+
marginUsed: this.cachedPerpMarginUsed,
|
|
4823
|
+
openPositions: this.cachedPerpOpenPositions,
|
|
4824
|
+
effectiveLeverage: this.cachedPerpLeverage,
|
|
4747
4825
|
pendingRecords: this.perpRecorder?.pendingRetries ?? 0
|
|
4748
4826
|
} : void 0,
|
|
4749
|
-
positions: this.positionTracker ? this.positionTracker.getPositionSummary(this.lastPrices) : void 0
|
|
4827
|
+
positions: this.positionTracker ? this.positionTracker.getPositionSummary(this.lastPrices) : void 0,
|
|
4828
|
+
configHash: this.configHash || void 0,
|
|
4829
|
+
pendingConfigHash: this.pendingConfigHash
|
|
4830
|
+
// null preserved by JSON.stringify for clearing
|
|
4750
4831
|
};
|
|
4751
|
-
|
|
4832
|
+
this.relay.sendHeartbeat(status);
|
|
4833
|
+
if (this.perpConnected && this.perpPositions) {
|
|
4752
4834
|
this.perpPositions.getAccountSummary().then((account) => {
|
|
4753
|
-
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
status.perp.effectiveLeverage = account.effectiveLeverage;
|
|
4758
|
-
}
|
|
4835
|
+
this.cachedPerpEquity = account.totalEquity;
|
|
4836
|
+
this.cachedPerpUnrealizedPnl = account.totalUnrealizedPnl;
|
|
4837
|
+
this.cachedPerpMarginUsed = account.totalMarginUsed;
|
|
4838
|
+
this.cachedPerpLeverage = account.effectiveLeverage;
|
|
4759
4839
|
}).catch(() => {
|
|
4760
4840
|
});
|
|
4761
4841
|
this.perpPositions.getPositionCount().then((count) => {
|
|
4762
|
-
|
|
4842
|
+
this.cachedPerpOpenPositions = count;
|
|
4763
4843
|
}).catch(() => {
|
|
4764
4844
|
});
|
|
4765
4845
|
}
|
|
4766
|
-
this.relay.sendHeartbeat(status);
|
|
4767
4846
|
}
|
|
4768
4847
|
/**
|
|
4769
4848
|
* Run a single trading cycle
|
|
@@ -5227,6 +5306,37 @@ async function checkFirstRunSetup(configPath) {
|
|
|
5227
5306
|
let privateKey;
|
|
5228
5307
|
let walletAddress;
|
|
5229
5308
|
if (walletSetup === "generate") {
|
|
5309
|
+
console.log("");
|
|
5310
|
+
console.log("!".repeat(60));
|
|
5311
|
+
console.log(" WALLET BACKUP \u2014 READ BEFORE CONTINUING");
|
|
5312
|
+
console.log("!".repeat(60));
|
|
5313
|
+
console.log("");
|
|
5314
|
+
console.log(" WHY THIS MATTERS:");
|
|
5315
|
+
console.log(" Exagent is non-custodial. Your trading wallet key is");
|
|
5316
|
+
console.log(" generated here on your machine and never leaves it.");
|
|
5317
|
+
console.log(" We do not store it. No one else has a copy.");
|
|
5318
|
+
console.log("");
|
|
5319
|
+
console.log(" WHAT THIS MEANS:");
|
|
5320
|
+
console.log(" The private key will live ONLY in the .env file");
|
|
5321
|
+
console.log(" in this folder. If you delete this folder, your");
|
|
5322
|
+
console.log(" wallet and ALL FUNDS in it are permanently lost.");
|
|
5323
|
+
console.log(" There is NO recovery \u2014 Exagent cannot help.");
|
|
5324
|
+
console.log("");
|
|
5325
|
+
console.log(" BEFORE CONTINUING:");
|
|
5326
|
+
console.log(" - Know where this folder is on your computer");
|
|
5327
|
+
console.log(" - Plan to back up .env (or .env.enc) after setup");
|
|
5328
|
+
console.log(" - Store your passphrase in a password manager");
|
|
5329
|
+
console.log(" - View your key anytime: npx @exagent/agent export-key");
|
|
5330
|
+
console.log("");
|
|
5331
|
+
console.log("!".repeat(60));
|
|
5332
|
+
console.log("");
|
|
5333
|
+
const ack = await prompt(' Type "I understand" to continue: ');
|
|
5334
|
+
if (ack.trim().toLowerCase() !== "i understand") {
|
|
5335
|
+
console.log("");
|
|
5336
|
+
console.log(" Setup cancelled. Run the agent again when ready.");
|
|
5337
|
+
process.exit(0);
|
|
5338
|
+
}
|
|
5339
|
+
console.log("");
|
|
5230
5340
|
console.log("[WALLET] Generating a new wallet for your agent...");
|
|
5231
5341
|
console.log("");
|
|
5232
5342
|
const generatedKey = (0, import_accounts6.generatePrivateKey)();
|
|
@@ -5240,8 +5350,9 @@ async function checkFirstRunSetup(configPath) {
|
|
|
5240
5350
|
console.log(" | " + walletAddress.padEnd(56) + " |");
|
|
5241
5351
|
console.log(" +" + "-".repeat(58) + "+");
|
|
5242
5352
|
console.log("");
|
|
5243
|
-
console.log("
|
|
5244
|
-
console.log("
|
|
5353
|
+
console.log(" CRITICAL: Back up your .env file now.");
|
|
5354
|
+
console.log(" Export your key anytime: npx @exagent/agent export-key");
|
|
5355
|
+
console.log(" If you lose .env AND your backup, funds are unrecoverable.");
|
|
5245
5356
|
console.log("");
|
|
5246
5357
|
const confirmed = await prompt(" Press Enter to continue, or Ctrl+C to cancel...");
|
|
5247
5358
|
} else {
|
|
@@ -5570,4 +5681,56 @@ program.command("encrypt").description("Encrypt .env file to .env.enc for secure
|
|
|
5570
5681
|
process.exit(1);
|
|
5571
5682
|
}
|
|
5572
5683
|
});
|
|
5684
|
+
program.command("export-key").description("Display your trading wallet private key for backup").option("-d, --dir <path>", "Directory containing .env or .env.enc file", ".").option("-p, --passphrase <passphrase>", "Passphrase to decrypt .env.enc").action(async (options) => {
|
|
5685
|
+
try {
|
|
5686
|
+
const dir = options.dir.startsWith("/") ? options.dir : path2.join(process.cwd(), options.dir);
|
|
5687
|
+
let passphrase = options.passphrase || process.env.EXAGENT_PASSPHRASE;
|
|
5688
|
+
const encPath = path2.join(dir, ".env.enc");
|
|
5689
|
+
const envPath = path2.join(dir, ".env");
|
|
5690
|
+
if (fs2.existsSync(encPath) && !passphrase) {
|
|
5691
|
+
console.log("");
|
|
5692
|
+
console.log(" Encrypted config found (.env.enc)");
|
|
5693
|
+
console.log("");
|
|
5694
|
+
passphrase = await prompt(" Enter passphrase: ", true);
|
|
5695
|
+
console.log("");
|
|
5696
|
+
}
|
|
5697
|
+
const usedEncrypted = loadSecureEnv(dir, passphrase);
|
|
5698
|
+
if (!usedEncrypted && fs2.existsSync(envPath)) {
|
|
5699
|
+
const { config: loadDotenv } = await import("dotenv");
|
|
5700
|
+
loadDotenv({ path: envPath, override: true });
|
|
5701
|
+
}
|
|
5702
|
+
const privateKey = process.env.EXAGENT_PRIVATE_KEY;
|
|
5703
|
+
if (!privateKey) {
|
|
5704
|
+
console.error("");
|
|
5705
|
+
console.error(" No private key found. Make sure .env or .env.enc exists in this directory.");
|
|
5706
|
+
console.error("");
|
|
5707
|
+
process.exit(1);
|
|
5708
|
+
}
|
|
5709
|
+
const { privateKeyToAccount: privateKeyToAccount7 } = await import("viem/accounts");
|
|
5710
|
+
const account = privateKeyToAccount7(privateKey);
|
|
5711
|
+
console.log("");
|
|
5712
|
+
console.log("=".repeat(60));
|
|
5713
|
+
console.log(" WALLET PRIVATE KEY EXPORT");
|
|
5714
|
+
console.log("=".repeat(60));
|
|
5715
|
+
console.log("");
|
|
5716
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
5717
|
+
console.log(" | WALLET ADDRESS: |");
|
|
5718
|
+
console.log(" | " + account.address.padEnd(56) + " |");
|
|
5719
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
5720
|
+
console.log(" | PRIVATE KEY: |");
|
|
5721
|
+
console.log(" | " + privateKey.padEnd(56) + " |");
|
|
5722
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
5723
|
+
console.log("");
|
|
5724
|
+
console.log(" WARNING: Anyone with this key controls your wallet.");
|
|
5725
|
+
console.log(" Store it in a password manager. Never share it.");
|
|
5726
|
+
console.log(" Never paste it in a browser, email, or chat.");
|
|
5727
|
+
console.log("");
|
|
5728
|
+
console.log("=".repeat(60));
|
|
5729
|
+
console.log("");
|
|
5730
|
+
process.exit(0);
|
|
5731
|
+
} catch (error) {
|
|
5732
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
5733
|
+
process.exit(1);
|
|
5734
|
+
}
|
|
5735
|
+
});
|
|
5573
5736
|
program.parse();
|
package/dist/cli.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
loadConfig,
|
|
7
7
|
loadSecureEnv,
|
|
8
8
|
validateConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-NENK6U55.mjs";
|
|
10
10
|
|
|
11
11
|
// src/cli.ts
|
|
12
12
|
import { Command } from "commander";
|
|
@@ -89,6 +89,37 @@ async function checkFirstRunSetup(configPath) {
|
|
|
89
89
|
let privateKey;
|
|
90
90
|
let walletAddress;
|
|
91
91
|
if (walletSetup === "generate") {
|
|
92
|
+
console.log("");
|
|
93
|
+
console.log("!".repeat(60));
|
|
94
|
+
console.log(" WALLET BACKUP \u2014 READ BEFORE CONTINUING");
|
|
95
|
+
console.log("!".repeat(60));
|
|
96
|
+
console.log("");
|
|
97
|
+
console.log(" WHY THIS MATTERS:");
|
|
98
|
+
console.log(" Exagent is non-custodial. Your trading wallet key is");
|
|
99
|
+
console.log(" generated here on your machine and never leaves it.");
|
|
100
|
+
console.log(" We do not store it. No one else has a copy.");
|
|
101
|
+
console.log("");
|
|
102
|
+
console.log(" WHAT THIS MEANS:");
|
|
103
|
+
console.log(" The private key will live ONLY in the .env file");
|
|
104
|
+
console.log(" in this folder. If you delete this folder, your");
|
|
105
|
+
console.log(" wallet and ALL FUNDS in it are permanently lost.");
|
|
106
|
+
console.log(" There is NO recovery \u2014 Exagent cannot help.");
|
|
107
|
+
console.log("");
|
|
108
|
+
console.log(" BEFORE CONTINUING:");
|
|
109
|
+
console.log(" - Know where this folder is on your computer");
|
|
110
|
+
console.log(" - Plan to back up .env (or .env.enc) after setup");
|
|
111
|
+
console.log(" - Store your passphrase in a password manager");
|
|
112
|
+
console.log(" - View your key anytime: npx @exagent/agent export-key");
|
|
113
|
+
console.log("");
|
|
114
|
+
console.log("!".repeat(60));
|
|
115
|
+
console.log("");
|
|
116
|
+
const ack = await prompt(' Type "I understand" to continue: ');
|
|
117
|
+
if (ack.trim().toLowerCase() !== "i understand") {
|
|
118
|
+
console.log("");
|
|
119
|
+
console.log(" Setup cancelled. Run the agent again when ready.");
|
|
120
|
+
process.exit(0);
|
|
121
|
+
}
|
|
122
|
+
console.log("");
|
|
92
123
|
console.log("[WALLET] Generating a new wallet for your agent...");
|
|
93
124
|
console.log("");
|
|
94
125
|
const generatedKey = generatePrivateKey();
|
|
@@ -102,8 +133,9 @@ async function checkFirstRunSetup(configPath) {
|
|
|
102
133
|
console.log(" | " + walletAddress.padEnd(56) + " |");
|
|
103
134
|
console.log(" +" + "-".repeat(58) + "+");
|
|
104
135
|
console.log("");
|
|
105
|
-
console.log("
|
|
106
|
-
console.log("
|
|
136
|
+
console.log(" CRITICAL: Back up your .env file now.");
|
|
137
|
+
console.log(" Export your key anytime: npx @exagent/agent export-key");
|
|
138
|
+
console.log(" If you lose .env AND your backup, funds are unrecoverable.");
|
|
107
139
|
console.log("");
|
|
108
140
|
const confirmed = await prompt(" Press Enter to continue, or Ctrl+C to cancel...");
|
|
109
141
|
} else {
|
|
@@ -432,4 +464,56 @@ program.command("encrypt").description("Encrypt .env file to .env.enc for secure
|
|
|
432
464
|
process.exit(1);
|
|
433
465
|
}
|
|
434
466
|
});
|
|
467
|
+
program.command("export-key").description("Display your trading wallet private key for backup").option("-d, --dir <path>", "Directory containing .env or .env.enc file", ".").option("-p, --passphrase <passphrase>", "Passphrase to decrypt .env.enc").action(async (options) => {
|
|
468
|
+
try {
|
|
469
|
+
const dir = options.dir.startsWith("/") ? options.dir : path.join(process.cwd(), options.dir);
|
|
470
|
+
let passphrase = options.passphrase || process.env.EXAGENT_PASSPHRASE;
|
|
471
|
+
const encPath = path.join(dir, ".env.enc");
|
|
472
|
+
const envPath = path.join(dir, ".env");
|
|
473
|
+
if (fs.existsSync(encPath) && !passphrase) {
|
|
474
|
+
console.log("");
|
|
475
|
+
console.log(" Encrypted config found (.env.enc)");
|
|
476
|
+
console.log("");
|
|
477
|
+
passphrase = await prompt(" Enter passphrase: ", true);
|
|
478
|
+
console.log("");
|
|
479
|
+
}
|
|
480
|
+
const usedEncrypted = loadSecureEnv(dir, passphrase);
|
|
481
|
+
if (!usedEncrypted && fs.existsSync(envPath)) {
|
|
482
|
+
const { config: loadDotenv } = await import("dotenv");
|
|
483
|
+
loadDotenv({ path: envPath, override: true });
|
|
484
|
+
}
|
|
485
|
+
const privateKey = process.env.EXAGENT_PRIVATE_KEY;
|
|
486
|
+
if (!privateKey) {
|
|
487
|
+
console.error("");
|
|
488
|
+
console.error(" No private key found. Make sure .env or .env.enc exists in this directory.");
|
|
489
|
+
console.error("");
|
|
490
|
+
process.exit(1);
|
|
491
|
+
}
|
|
492
|
+
const { privateKeyToAccount: privateKeyToAccount2 } = await import("viem/accounts");
|
|
493
|
+
const account = privateKeyToAccount2(privateKey);
|
|
494
|
+
console.log("");
|
|
495
|
+
console.log("=".repeat(60));
|
|
496
|
+
console.log(" WALLET PRIVATE KEY EXPORT");
|
|
497
|
+
console.log("=".repeat(60));
|
|
498
|
+
console.log("");
|
|
499
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
500
|
+
console.log(" | WALLET ADDRESS: |");
|
|
501
|
+
console.log(" | " + account.address.padEnd(56) + " |");
|
|
502
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
503
|
+
console.log(" | PRIVATE KEY: |");
|
|
504
|
+
console.log(" | " + privateKey.padEnd(56) + " |");
|
|
505
|
+
console.log(" +" + "-".repeat(58) + "+");
|
|
506
|
+
console.log("");
|
|
507
|
+
console.log(" WARNING: Anyone with this key controls your wallet.");
|
|
508
|
+
console.log(" Store it in a password manager. Never share it.");
|
|
509
|
+
console.log(" Never paste it in a browser, email, or chat.");
|
|
510
|
+
console.log("");
|
|
511
|
+
console.log("=".repeat(60));
|
|
512
|
+
console.log("");
|
|
513
|
+
process.exit(0);
|
|
514
|
+
} catch (error) {
|
|
515
|
+
console.error("Error:", error instanceof Error ? error.message : error);
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
|
518
|
+
});
|
|
435
519
|
program.parse();
|
package/dist/index.d.mts
CHANGED
|
@@ -339,9 +339,9 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
339
339
|
}>>;
|
|
340
340
|
allowedTokens: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
341
341
|
}, "strip", z.ZodTypeAny, {
|
|
342
|
+
agentId: string | number;
|
|
342
343
|
name: string;
|
|
343
344
|
network: "mainnet";
|
|
344
|
-
agentId: string | number;
|
|
345
345
|
llm: {
|
|
346
346
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
347
347
|
temperature: number;
|
|
@@ -388,8 +388,8 @@ declare const AgentConfigSchema: z.ZodObject<{
|
|
|
388
388
|
} | undefined;
|
|
389
389
|
allowedTokens?: string[] | undefined;
|
|
390
390
|
}, {
|
|
391
|
-
name: string;
|
|
392
391
|
agentId: string | number;
|
|
392
|
+
name: string;
|
|
393
393
|
llm: {
|
|
394
394
|
provider: "custom" | "openai" | "anthropic" | "google" | "deepseek" | "mistral" | "groq" | "together" | "ollama";
|
|
395
395
|
model?: string | undefined;
|
|
@@ -739,6 +739,10 @@ interface AgentStatusPayload {
|
|
|
739
739
|
recentTrades: number;
|
|
740
740
|
totalRealizedPnL: number;
|
|
741
741
|
};
|
|
742
|
+
/** Current on-chain config hash (for epoch tracking) */
|
|
743
|
+
configHash?: string;
|
|
744
|
+
/** Config hash awaiting owner approval — null/undefined means no pending verification */
|
|
745
|
+
pendingConfigHash?: string | null;
|
|
742
746
|
}
|
|
743
747
|
interface RelayConfig {
|
|
744
748
|
enabled: boolean;
|
|
@@ -770,6 +774,8 @@ declare class AgentRuntime {
|
|
|
770
774
|
private isRunning;
|
|
771
775
|
private mode;
|
|
772
776
|
private configHash;
|
|
777
|
+
private pendingConfigHash;
|
|
778
|
+
private lastConfigCheckAt;
|
|
773
779
|
private cycleCount;
|
|
774
780
|
private lastCycleAt;
|
|
775
781
|
private lastPortfolioValue;
|
|
@@ -790,6 +796,11 @@ declare class AgentRuntime {
|
|
|
790
796
|
private perpStrategy;
|
|
791
797
|
private perpConnected;
|
|
792
798
|
private perpTradingActive;
|
|
799
|
+
private cachedPerpEquity;
|
|
800
|
+
private cachedPerpUnrealizedPnl;
|
|
801
|
+
private cachedPerpMarginUsed;
|
|
802
|
+
private cachedPerpLeverage;
|
|
803
|
+
private cachedPerpOpenPositions;
|
|
793
804
|
constructor(config: RuntimeConfig);
|
|
794
805
|
/**
|
|
795
806
|
* Initialize the agent runtime
|
|
@@ -821,8 +832,14 @@ declare class AgentRuntime {
|
|
|
821
832
|
private loadTradingRestrictions;
|
|
822
833
|
/**
|
|
823
834
|
* Sync the LLM config hash to chain for epoch tracking.
|
|
824
|
-
*
|
|
825
|
-
*
|
|
835
|
+
*
|
|
836
|
+
* If the trading wallet is NOT the agent owner, the on-chain setConfig
|
|
837
|
+
* call would revert with AgentNotOwner. Instead, we set a pending state
|
|
838
|
+
* and send a message to the command center so the owner can approve it
|
|
839
|
+
* from the website with one click.
|
|
840
|
+
*
|
|
841
|
+
* Until the config is verified on-chain, the agent won't appear on the
|
|
842
|
+
* leaderboard (trades still execute normally).
|
|
826
843
|
*/
|
|
827
844
|
private syncConfigHash;
|
|
828
845
|
/**
|
|
@@ -841,6 +858,11 @@ declare class AgentRuntime {
|
|
|
841
858
|
* Handle a command from the command center
|
|
842
859
|
*/
|
|
843
860
|
private handleCommand;
|
|
861
|
+
/**
|
|
862
|
+
* Periodically check if the owner has approved the pending config hash.
|
|
863
|
+
* Called from sendRelayStatus at most every 2.5 minutes (timestamp-throttled).
|
|
864
|
+
*/
|
|
865
|
+
private checkPendingConfigApproval;
|
|
844
866
|
/**
|
|
845
867
|
* Send current status to the relay
|
|
846
868
|
*/
|
|
@@ -2081,6 +2103,6 @@ declare function decryptEnvFile(encPath: string, passphrase: string): Record<str
|
|
|
2081
2103
|
declare function loadSecureEnv(basePath: string, passphrase?: string): boolean;
|
|
2082
2104
|
|
|
2083
2105
|
/** @exagent/agent package version — update alongside package.json */
|
|
2084
|
-
declare const AGENT_VERSION = "0.1.
|
|
2106
|
+
declare const AGENT_VERSION = "0.1.23";
|
|
2085
2107
|
|
|
2086
2108
|
export { AGENT_VERSION, type AccountSummary, type AgentConfig, AgentConfigSchema, type AgentMode, AgentRuntime, type AgentStatusPayload, AnthropicAdapter, BaseLLMAdapter, type CommandType, DeepSeekAdapter, FileStore, type FillCallback, type FundingCallback, type FundingPayment, GoogleAdapter, GroqAdapter, HYPERLIQUID_DOMAIN, HyperliquidClient, HyperliquidSigner, HyperliquidWebSocket, type LLMAdapter, type LLMConfig, LLMConfigSchema, type LLMMessage, type LLMMetadata, type LLMProvider, LLMProviderSchema, type LLMResponse, type LiquidationCallback, type MarketData, MarketDataService, type MessageLevel, type MessageType, MistralAdapter, OllamaAdapter, type OnboardingStatus, OpenAIAdapter, OrderManager, type OrderResult, type PerpAction, type PerpConfig$1 as PerpConfig, PerpConfigSchema, type PerpFill, type PerpMarketData, PerpOnboarding, type PerpPosition, type PerpStrategyFunction, PerpTradeRecorder, type PerpTradeSignal, type PerpConfig as PerpTradingConfig, PositionManager, type PositionSummary, PositionTracker, type RecordPerpTradeParams, RelayClient, type RelayCommand, type RelayConfig$1 as RelayConfig, RelayConfigSchema, RiskManager, type RiskState, type RiskUniverse, RiskUniverseSchema, type RuntimeConfig, STRATEGY_TEMPLATES, type StrategyContext, type StrategyFunction, type StrategyStore, type StrategyTemplate, TogetherAdapter, type TrackedPosition, TradeExecutor, type TradeRecord, type TradeSignal, type TradingConfig, TradingConfigSchema, type VaultConfig, VaultConfigSchema, VaultManager, type VaultManagerConfig, type VaultPolicy, VaultPolicySchema, type VaultStatus, createLLMAdapter, createSampleConfig, decryptEnvFile, encryptEnvFile, fillHashToBytes32, fillOidToBytes32, getAllStrategyTemplates, getNextNonce, getStrategyTemplate, loadConfig, loadSecureEnv, loadStrategy, validateConfig, validateStrategy };
|