@net-protocol/cli 0.1.41 → 0.1.43
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/README.md +131 -0
- package/dist/cli/index.mjs +855 -7
- package/dist/cli/index.mjs.map +1 -1
- package/dist/profile/index.mjs +7 -1
- package/dist/profile/index.mjs.map +1 -1
- package/package.json +2 -1
package/dist/cli/index.mjs
CHANGED
|
@@ -7,15 +7,15 @@ import chalk4 from 'chalk';
|
|
|
7
7
|
import * as fs6 from 'fs';
|
|
8
8
|
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
9
9
|
import { OPTIMAL_CHUNK_SIZE, StorageClient, detectFileTypeFromBase64, base64ToDataUri, shouldSuggestXmlStorage, getStorageKeyBytes, encodeStorageKeyForUrl, chunkDataForStorage, CHUNKED_STORAGE_CONTRACT, STORAGE_CONTRACT as STORAGE_CONTRACT$1 } from '@net-protocol/storage';
|
|
10
|
-
import {
|
|
10
|
+
import { createPublicClient, http, createWalletClient, stringToHex, hexToString, parseEther, encodeFunctionData, publicActions, concat, defineChain, decodeEventLog, formatEther, isAddress } from 'viem';
|
|
11
11
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
12
|
-
import { getNetContract, getChainName,
|
|
13
|
-
import {
|
|
12
|
+
import { getNetContract, getChainName, getChainRpcUrls, getPublicClient, getBaseDataSuffix, NetClient, toBytes32, NULL_ADDRESS } from '@net-protocol/core';
|
|
13
|
+
import { fundBackendWallet, checkBackendWalletBalance, createRelayX402Client, createRelaySession, batchTransactions, submitTransactionsViaRelay, waitForConfirmations, retryFailedTransactions as retryFailedTransactions$1 } from '@net-protocol/relay';
|
|
14
14
|
import { isCommentTopic, parseCommentData, FeedRegistryClient, FeedClient, AgentRegistryClient, COMMENT_TOPIC_SUFFIX, FEED_TOPIC_PREFIX } from '@net-protocol/feeds';
|
|
15
15
|
import '@net-protocol/chats';
|
|
16
16
|
import { isNetrSupportedChain, NetrClient } from '@net-protocol/netr';
|
|
17
17
|
import { PROFILE_PICTURE_STORAGE_KEY, PROFILE_METADATA_STORAGE_KEY, parseProfileMetadata, PROFILE_CANVAS_STORAGE_KEY, PROFILE_CSS_STORAGE_KEY, isValidUrl, getProfilePictureStorageArgs, STORAGE_CONTRACT, isValidXUsername, getProfileMetadataStorageArgs, isValidBio, isValidDisplayName, isValidTokenAddress, DEMO_THEMES, MAX_CSS_SIZE, isValidCSS, getProfileCSSStorageArgs, buildCSSPrompt } from '@net-protocol/profiles';
|
|
18
|
-
import { base } from 'viem/chains';
|
|
18
|
+
import { baseSepolia, base } from 'viem/chains';
|
|
19
19
|
import * as path from 'path';
|
|
20
20
|
import { join } from 'path';
|
|
21
21
|
import { BazaarClient } from '@net-protocol/bazaar';
|
|
@@ -23,6 +23,7 @@ import * as os from 'os';
|
|
|
23
23
|
import { homedir } from 'os';
|
|
24
24
|
import * as readline from 'readline';
|
|
25
25
|
import { discoverTokenPool, PURE_ALPHA_STRATEGY, UNIV234_POOLS_STRATEGY, encodePoolKey, DYNAMIC_SPLIT_STRATEGY, getTokenScoreKey, UPVOTE_PRICE_ETH, UPVOTE_APP, ScoreClient, ALL_STRATEGY_ADDRESSES, NULL_ADDRESS as NULL_ADDRESS$1, UserUpvoteClient, calculateUpvoteCost, USER_UPVOTE_CONTRACT } from '@net-protocol/score';
|
|
26
|
+
import { RELAY_ACCESS_KEY, generateAgentChatTopic, AgentClient, isAgentChatTopic, parseAgentAddressFromTopic, buildSessionTypedData, NET_API_URL, exchangeSessionSignature, buildConversationAuthTypedData, NET_TESTNET_API_URL } from '@net-protocol/agents';
|
|
26
27
|
|
|
27
28
|
var DEFAULT_CHAIN_ID = 8453;
|
|
28
29
|
function getRequiredChainId(optionValue) {
|
|
@@ -1566,8 +1567,8 @@ function registerStorageCommand(program2) {
|
|
|
1566
1567
|
console.log(chalk4.blue(`\u{1F4C1} Reading file: ${options.file}`));
|
|
1567
1568
|
console.log(chalk4.blue(`\u{1F517} Using relay API: ${options.apiUrl}`));
|
|
1568
1569
|
const result = await uploadFileWithRelay(uploadRelayOptions);
|
|
1569
|
-
const { privateKeyToAccount:
|
|
1570
|
-
const userAccount =
|
|
1570
|
+
const { privateKeyToAccount: privateKeyToAccount28 } = await import('viem/accounts');
|
|
1571
|
+
const userAccount = privateKeyToAccount28(commonOptions.privateKey);
|
|
1571
1572
|
const storageUrl = generateStorageUrl(
|
|
1572
1573
|
userAccount.address,
|
|
1573
1574
|
commonOptions.chainId,
|
|
@@ -2369,6 +2370,7 @@ async function executeProfileGet(options) {
|
|
|
2369
2370
|
}
|
|
2370
2371
|
let xUsername;
|
|
2371
2372
|
let bio;
|
|
2373
|
+
let displayName;
|
|
2372
2374
|
let tokenAddress;
|
|
2373
2375
|
try {
|
|
2374
2376
|
const metadataResult = await client.readStorageData({
|
|
@@ -2379,6 +2381,7 @@ async function executeProfileGet(options) {
|
|
|
2379
2381
|
const metadata = parseProfileMetadata(metadataResult.data);
|
|
2380
2382
|
xUsername = metadata?.x_username;
|
|
2381
2383
|
bio = metadata?.bio;
|
|
2384
|
+
displayName = metadata?.display_name;
|
|
2382
2385
|
tokenAddress = metadata?.token_address;
|
|
2383
2386
|
}
|
|
2384
2387
|
} catch (error) {
|
|
@@ -2419,12 +2422,13 @@ async function executeProfileGet(options) {
|
|
|
2419
2422
|
throw error;
|
|
2420
2423
|
}
|
|
2421
2424
|
}
|
|
2422
|
-
const hasProfile = profilePicture || xUsername || bio || tokenAddress || canvasSize || cssSize;
|
|
2425
|
+
const hasProfile = profilePicture || xUsername || bio || displayName || tokenAddress || canvasSize || cssSize;
|
|
2423
2426
|
if (options.json) {
|
|
2424
2427
|
const output = {
|
|
2425
2428
|
address: options.address,
|
|
2426
2429
|
chainId: readOnlyOptions.chainId,
|
|
2427
2430
|
profilePicture: profilePicture || null,
|
|
2431
|
+
displayName: displayName || null,
|
|
2428
2432
|
xUsername: xUsername || null,
|
|
2429
2433
|
bio: bio || null,
|
|
2430
2434
|
tokenAddress: tokenAddress || null,
|
|
@@ -2438,6 +2442,9 @@ async function executeProfileGet(options) {
|
|
|
2438
2442
|
console.log(chalk4.white.bold("\nProfile:\n"));
|
|
2439
2443
|
console.log(` ${chalk4.cyan("Address:")} ${options.address}`);
|
|
2440
2444
|
console.log(` ${chalk4.cyan("Chain ID:")} ${readOnlyOptions.chainId}`);
|
|
2445
|
+
console.log(
|
|
2446
|
+
` ${chalk4.cyan("Display Name:")} ${displayName || chalk4.gray("(not set)")}`
|
|
2447
|
+
);
|
|
2441
2448
|
console.log(
|
|
2442
2449
|
` ${chalk4.cyan("Profile Picture:")} ${profilePicture || chalk4.gray("(not set)")}`
|
|
2443
2450
|
);
|
|
@@ -7534,6 +7541,845 @@ function registerUpvoteCommand(program2) {
|
|
|
7534
7541
|
registerUpvoteUserCommand(upvoteCommand);
|
|
7535
7542
|
registerGetUserUpvotesCommand(upvoteCommand);
|
|
7536
7543
|
}
|
|
7544
|
+
var VALID_RUN_MODES = ["auto", "feeds", "chats"];
|
|
7545
|
+
function addAuthOptions(cmd) {
|
|
7546
|
+
return addCommonOptions(cmd).option("--private-key <key>", "Private key (0x-prefixed)").option(
|
|
7547
|
+
"--session-token <token>",
|
|
7548
|
+
"Pre-existing session token (alternative to --private-key)"
|
|
7549
|
+
).option(
|
|
7550
|
+
"--operator <address>",
|
|
7551
|
+
"Operator address (required with --session-token)"
|
|
7552
|
+
);
|
|
7553
|
+
}
|
|
7554
|
+
function addCommonOptions(cmd) {
|
|
7555
|
+
return cmd.option("--chain-id <id>", "Chain ID (default: 8453)", (v) => parseInt(v, 10)).option("--rpc-url <url>", "Custom RPC URL").option("--api-url <url>", "Net Protocol API URL");
|
|
7556
|
+
}
|
|
7557
|
+
function addFilterOptions(cmd) {
|
|
7558
|
+
return cmd.option("--include-feed <pattern...>", "Only engage with matching feeds").option("--exclude-feed <pattern...>", "Never engage with matching feeds").option("--preferred-feed <pattern...>", "Prioritize matching feeds").option("--chat-topic <topic...>", "Chat topics to participate in");
|
|
7559
|
+
}
|
|
7560
|
+
function addProfileOptions(cmd) {
|
|
7561
|
+
return cmd.option("--display-name <name>", "Agent display name").option("--bio <text>", "Agent bio");
|
|
7562
|
+
}
|
|
7563
|
+
function buildFilters(options) {
|
|
7564
|
+
const filters = {};
|
|
7565
|
+
if (options.includeFeed?.length) filters.includeFeedPatterns = options.includeFeed;
|
|
7566
|
+
if (options.excludeFeed?.length) filters.excludeFeedPatterns = options.excludeFeed;
|
|
7567
|
+
if (options.preferredFeed?.length) filters.preferredFeedPatterns = options.preferredFeed;
|
|
7568
|
+
if (options.chatTopic?.length) filters.preferredChatTopics = options.chatTopic;
|
|
7569
|
+
return Object.keys(filters).length > 0 ? filters : void 0;
|
|
7570
|
+
}
|
|
7571
|
+
function buildProfile(options) {
|
|
7572
|
+
const profile = {};
|
|
7573
|
+
if (options.displayName) profile.displayName = options.displayName;
|
|
7574
|
+
if (options.bio) profile.bio = options.bio;
|
|
7575
|
+
return Object.keys(profile).length > 0 ? profile : void 0;
|
|
7576
|
+
}
|
|
7577
|
+
function parseRunMode(raw) {
|
|
7578
|
+
const mode = raw ?? "auto";
|
|
7579
|
+
if (!VALID_RUN_MODES.includes(mode)) {
|
|
7580
|
+
exitWithError(`Invalid mode "${mode}". Must be one of: ${VALID_RUN_MODES.join(", ")}`);
|
|
7581
|
+
}
|
|
7582
|
+
return mode;
|
|
7583
|
+
}
|
|
7584
|
+
function resolveReadOnly(options) {
|
|
7585
|
+
const readOnly = parseReadOnlyOptionsWithDefault({
|
|
7586
|
+
chainId: options.chainId,
|
|
7587
|
+
rpcUrl: options.rpcUrl
|
|
7588
|
+
});
|
|
7589
|
+
const apiUrl = options.apiUrl || process.env.NET_API_URL || NET_API_URL;
|
|
7590
|
+
let operator;
|
|
7591
|
+
if (options.operator) {
|
|
7592
|
+
if (!isAddress(options.operator)) {
|
|
7593
|
+
exitWithError(`Invalid operator address: ${options.operator}`);
|
|
7594
|
+
}
|
|
7595
|
+
operator = options.operator;
|
|
7596
|
+
}
|
|
7597
|
+
return { chainId: readOnly.chainId, apiUrl, operator };
|
|
7598
|
+
}
|
|
7599
|
+
async function resolveAuth(options) {
|
|
7600
|
+
const sessionToken = options.sessionToken || process.env.NET_SESSION_TOKEN;
|
|
7601
|
+
const privateKey = options.privateKey || process.env.NET_PRIVATE_KEY || process.env.PRIVATE_KEY;
|
|
7602
|
+
if (sessionToken && options.privateKey) {
|
|
7603
|
+
exitWithError("Cannot use both --session-token and --private-key. Pick one.");
|
|
7604
|
+
}
|
|
7605
|
+
const apiUrl = options.apiUrl || process.env.NET_API_URL || NET_API_URL;
|
|
7606
|
+
if (sessionToken) {
|
|
7607
|
+
if (!options.operator) {
|
|
7608
|
+
exitWithError(
|
|
7609
|
+
"--operator <address> is required when using --session-token. It must match the address that signed the session."
|
|
7610
|
+
);
|
|
7611
|
+
}
|
|
7612
|
+
if (!isAddress(options.operator)) {
|
|
7613
|
+
exitWithError(`Invalid operator address: ${options.operator}`);
|
|
7614
|
+
}
|
|
7615
|
+
const readOnly = parseReadOnlyOptionsWithDefault({
|
|
7616
|
+
chainId: options.chainId,
|
|
7617
|
+
rpcUrl: options.rpcUrl
|
|
7618
|
+
});
|
|
7619
|
+
const client2 = new AgentClient({ apiUrl, chainId: readOnly.chainId });
|
|
7620
|
+
return {
|
|
7621
|
+
client: client2,
|
|
7622
|
+
sessionToken,
|
|
7623
|
+
operatorAddress: options.operator,
|
|
7624
|
+
chainId: readOnly.chainId,
|
|
7625
|
+
apiUrl
|
|
7626
|
+
};
|
|
7627
|
+
}
|
|
7628
|
+
if (!privateKey) {
|
|
7629
|
+
exitWithError(
|
|
7630
|
+
"No auth provided. Use one of:\n --private-key <key> (or NET_PRIVATE_KEY env var)\n --session-token <token> + --operator <address> (for Bankr or other external signers)"
|
|
7631
|
+
);
|
|
7632
|
+
}
|
|
7633
|
+
const commonOptions = parseCommonOptionsWithDefault({
|
|
7634
|
+
privateKey,
|
|
7635
|
+
chainId: options.chainId,
|
|
7636
|
+
rpcUrl: options.rpcUrl
|
|
7637
|
+
});
|
|
7638
|
+
const account = privateKeyToAccount(commonOptions.privateKey);
|
|
7639
|
+
console.log(chalk4.blue("Creating session..."));
|
|
7640
|
+
const { sessionToken: token } = await createRelaySession({
|
|
7641
|
+
apiUrl,
|
|
7642
|
+
chainId: commonOptions.chainId,
|
|
7643
|
+
operatorAddress: account.address,
|
|
7644
|
+
secretKey: RELAY_ACCESS_KEY,
|
|
7645
|
+
account
|
|
7646
|
+
});
|
|
7647
|
+
const client = new AgentClient({ apiUrl, chainId: commonOptions.chainId });
|
|
7648
|
+
return {
|
|
7649
|
+
client,
|
|
7650
|
+
sessionToken: token,
|
|
7651
|
+
account,
|
|
7652
|
+
operatorAddress: account.address,
|
|
7653
|
+
chainId: commonOptions.chainId,
|
|
7654
|
+
apiUrl
|
|
7655
|
+
};
|
|
7656
|
+
}
|
|
7657
|
+
function bigintReplacer5(_key, value) {
|
|
7658
|
+
return typeof value === "bigint" ? value.toString() : value;
|
|
7659
|
+
}
|
|
7660
|
+
function jsonStringify(obj, indent = 2) {
|
|
7661
|
+
return JSON.stringify(obj, bigintReplacer5, indent);
|
|
7662
|
+
}
|
|
7663
|
+
|
|
7664
|
+
// src/commands/agent/create.ts
|
|
7665
|
+
async function executeCreate(name, options) {
|
|
7666
|
+
try {
|
|
7667
|
+
const auth = await resolveAuth(options);
|
|
7668
|
+
const config = {
|
|
7669
|
+
name,
|
|
7670
|
+
systemPrompt: options.systemPrompt
|
|
7671
|
+
};
|
|
7672
|
+
if (options.schedule) config.runIntervalMinutes = options.schedule;
|
|
7673
|
+
const filters = buildFilters(options);
|
|
7674
|
+
if (filters) config.filters = filters;
|
|
7675
|
+
const profile = buildProfile(options);
|
|
7676
|
+
console.log(chalk4.blue(`Creating agent "${name}"...`));
|
|
7677
|
+
const result = await auth.client.createAgent({
|
|
7678
|
+
sessionToken: auth.sessionToken,
|
|
7679
|
+
config,
|
|
7680
|
+
profile
|
|
7681
|
+
});
|
|
7682
|
+
if (!result.success) {
|
|
7683
|
+
exitWithError(result.error || "Failed to create agent");
|
|
7684
|
+
}
|
|
7685
|
+
if (options.json) {
|
|
7686
|
+
console.log(jsonStringify(result));
|
|
7687
|
+
return;
|
|
7688
|
+
}
|
|
7689
|
+
console.log(chalk4.green("Agent created successfully!"));
|
|
7690
|
+
console.log(` Agent ID: ${result.agentId}`);
|
|
7691
|
+
console.log(` Wallet: ${result.agentWalletAddress}`);
|
|
7692
|
+
if (result.scheduleError) {
|
|
7693
|
+
console.log(chalk4.yellow(` Schedule warning: ${result.scheduleError}`));
|
|
7694
|
+
}
|
|
7695
|
+
} catch (error) {
|
|
7696
|
+
exitWithError(
|
|
7697
|
+
`Failed to create agent: ${error instanceof Error ? error.message : String(error)}`
|
|
7698
|
+
);
|
|
7699
|
+
}
|
|
7700
|
+
}
|
|
7701
|
+
function registerAgentCreateCommand(parent) {
|
|
7702
|
+
const cmd = parent.command("create <name>").description("Create a new onchain agent").requiredOption("--system-prompt <prompt>", "Agent system prompt (personality)").option("--schedule <minutes>", "Auto-run interval in minutes", (v) => parseInt(v, 10)).option("--json", "Output as JSON");
|
|
7703
|
+
addAuthOptions(cmd);
|
|
7704
|
+
addFilterOptions(cmd);
|
|
7705
|
+
addProfileOptions(cmd);
|
|
7706
|
+
cmd.action(async (name, options) => {
|
|
7707
|
+
await executeCreate(name, options);
|
|
7708
|
+
});
|
|
7709
|
+
}
|
|
7710
|
+
async function executeList(options) {
|
|
7711
|
+
try {
|
|
7712
|
+
const auth = await resolveAuth(options);
|
|
7713
|
+
const result = await auth.client.listAgents({ sessionToken: auth.sessionToken });
|
|
7714
|
+
if (!result.success) {
|
|
7715
|
+
exitWithError(result.error || "Failed to list agents");
|
|
7716
|
+
}
|
|
7717
|
+
const agents = result.agents || [];
|
|
7718
|
+
const visible = options.showHidden ? agents : agents.filter((a) => !a.config.hidden);
|
|
7719
|
+
if (options.json) {
|
|
7720
|
+
console.log(jsonStringify(visible));
|
|
7721
|
+
return;
|
|
7722
|
+
}
|
|
7723
|
+
if (visible.length === 0) {
|
|
7724
|
+
console.log(chalk4.yellow("No agents found."));
|
|
7725
|
+
return;
|
|
7726
|
+
}
|
|
7727
|
+
console.log(chalk4.bold(`Agents (${visible.length}):
|
|
7728
|
+
`));
|
|
7729
|
+
for (const agent of visible) {
|
|
7730
|
+
const { config, walletAddress } = agent;
|
|
7731
|
+
const schedule = config.runIntervalMinutes ? `every ${config.runIntervalMinutes}m` : "manual";
|
|
7732
|
+
const hidden = config.hidden ? chalk4.gray(" [hidden]") : "";
|
|
7733
|
+
const promptPreview = config.systemPrompt.length > 80 ? `${config.systemPrompt.slice(0, 80)}...` : config.systemPrompt;
|
|
7734
|
+
console.log(` ${chalk4.cyan(config.name)}${hidden}`);
|
|
7735
|
+
console.log(` ID: ${config.id}`);
|
|
7736
|
+
console.log(` Wallet: ${walletAddress}`);
|
|
7737
|
+
console.log(` Schedule: ${schedule}`);
|
|
7738
|
+
console.log(` Prompt: ${promptPreview}`);
|
|
7739
|
+
console.log();
|
|
7740
|
+
}
|
|
7741
|
+
} catch (error) {
|
|
7742
|
+
exitWithError(
|
|
7743
|
+
`Failed to list agents: ${error instanceof Error ? error.message : String(error)}`
|
|
7744
|
+
);
|
|
7745
|
+
}
|
|
7746
|
+
}
|
|
7747
|
+
function registerAgentListCommand(parent) {
|
|
7748
|
+
const cmd = parent.command("list").description("List your onchain agents").option("--json", "Output as JSON").option("--show-hidden", "Include hidden agents");
|
|
7749
|
+
addAuthOptions(cmd);
|
|
7750
|
+
cmd.action(async (options) => {
|
|
7751
|
+
await executeList(options);
|
|
7752
|
+
});
|
|
7753
|
+
}
|
|
7754
|
+
async function executeUpdate(agentId, options) {
|
|
7755
|
+
try {
|
|
7756
|
+
const auth = await resolveAuth(options);
|
|
7757
|
+
const config = {};
|
|
7758
|
+
let hasConfigChanges = false;
|
|
7759
|
+
if (options.name) {
|
|
7760
|
+
config.name = options.name;
|
|
7761
|
+
hasConfigChanges = true;
|
|
7762
|
+
}
|
|
7763
|
+
if (options.systemPrompt) {
|
|
7764
|
+
config.systemPrompt = options.systemPrompt;
|
|
7765
|
+
hasConfigChanges = true;
|
|
7766
|
+
}
|
|
7767
|
+
if (options.schedule) {
|
|
7768
|
+
config.runIntervalMinutes = options.schedule;
|
|
7769
|
+
hasConfigChanges = true;
|
|
7770
|
+
}
|
|
7771
|
+
if (options.disableSchedule) {
|
|
7772
|
+
config.runIntervalMinutes = 0;
|
|
7773
|
+
hasConfigChanges = true;
|
|
7774
|
+
}
|
|
7775
|
+
const filters = buildFilters(options);
|
|
7776
|
+
if (filters) {
|
|
7777
|
+
config.filters = filters;
|
|
7778
|
+
hasConfigChanges = true;
|
|
7779
|
+
}
|
|
7780
|
+
const profile = buildProfile(options);
|
|
7781
|
+
if (!hasConfigChanges && !profile) {
|
|
7782
|
+
exitWithError(
|
|
7783
|
+
"No changes specified. Use --name, --system-prompt, --schedule, --display-name, --bio, or filter options."
|
|
7784
|
+
);
|
|
7785
|
+
}
|
|
7786
|
+
console.log(chalk4.blue(`Updating agent ${agentId}...`));
|
|
7787
|
+
const result = await auth.client.updateAgent({
|
|
7788
|
+
sessionToken: auth.sessionToken,
|
|
7789
|
+
agentId,
|
|
7790
|
+
config: hasConfigChanges ? config : void 0,
|
|
7791
|
+
profile
|
|
7792
|
+
});
|
|
7793
|
+
if (!result.success) {
|
|
7794
|
+
exitWithError(result.error || "Failed to update agent");
|
|
7795
|
+
}
|
|
7796
|
+
if (options.json) {
|
|
7797
|
+
console.log(jsonStringify(result));
|
|
7798
|
+
return;
|
|
7799
|
+
}
|
|
7800
|
+
console.log(chalk4.green("Agent updated successfully!"));
|
|
7801
|
+
if (result.profileError) {
|
|
7802
|
+
console.log(chalk4.yellow(` Profile warning: ${result.profileError}`));
|
|
7803
|
+
}
|
|
7804
|
+
} catch (error) {
|
|
7805
|
+
exitWithError(
|
|
7806
|
+
`Failed to update agent: ${error instanceof Error ? error.message : String(error)}`
|
|
7807
|
+
);
|
|
7808
|
+
}
|
|
7809
|
+
}
|
|
7810
|
+
function registerAgentUpdateCommand(parent) {
|
|
7811
|
+
const cmd = parent.command("update <agentId>").description("Update an existing agent").option("--name <name>", "New agent name").option("--system-prompt <prompt>", "New system prompt").option("--schedule <minutes>", "Auto-run interval in minutes", (v) => parseInt(v, 10)).option("--disable-schedule", "Disable automatic scheduling").option("--json", "Output as JSON");
|
|
7812
|
+
addAuthOptions(cmd);
|
|
7813
|
+
addFilterOptions(cmd);
|
|
7814
|
+
addProfileOptions(cmd);
|
|
7815
|
+
cmd.action(async (agentId, options) => {
|
|
7816
|
+
await executeUpdate(agentId, options);
|
|
7817
|
+
});
|
|
7818
|
+
}
|
|
7819
|
+
async function executeToggleHidden(agentId, options, hide) {
|
|
7820
|
+
const verb = hide ? "Hiding" : "Unhiding";
|
|
7821
|
+
const past = hide ? "hidden" : "unhidden";
|
|
7822
|
+
try {
|
|
7823
|
+
const auth = await resolveAuth(options);
|
|
7824
|
+
console.log(chalk4.blue(`${verb} agent ${agentId}...`));
|
|
7825
|
+
const result = hide ? await auth.client.hideAgent(auth.sessionToken, agentId) : await auth.client.unhideAgent(auth.sessionToken, agentId);
|
|
7826
|
+
if (!result.success) {
|
|
7827
|
+
exitWithError(result.error || `Failed to ${hide ? "hide" : "unhide"} agent`);
|
|
7828
|
+
}
|
|
7829
|
+
console.log(chalk4.green(`Agent ${past} successfully.`));
|
|
7830
|
+
} catch (error) {
|
|
7831
|
+
exitWithError(
|
|
7832
|
+
`Failed to ${hide ? "hide" : "unhide"} agent: ${error instanceof Error ? error.message : String(error)}`
|
|
7833
|
+
);
|
|
7834
|
+
}
|
|
7835
|
+
}
|
|
7836
|
+
function registerAgentHideCommand(parent) {
|
|
7837
|
+
const cmd = parent.command("hide <agentId>").description("Hide an agent (soft-delete)");
|
|
7838
|
+
addAuthOptions(cmd).action(async (agentId, options) => {
|
|
7839
|
+
await executeToggleHidden(agentId, options, true);
|
|
7840
|
+
});
|
|
7841
|
+
}
|
|
7842
|
+
function registerAgentUnhideCommand(parent) {
|
|
7843
|
+
const cmd = parent.command("unhide <agentId>").description("Unhide a previously hidden agent");
|
|
7844
|
+
addAuthOptions(cmd).action(async (agentId, options) => {
|
|
7845
|
+
await executeToggleHidden(agentId, options, false);
|
|
7846
|
+
});
|
|
7847
|
+
}
|
|
7848
|
+
async function executeRun(agentId, options) {
|
|
7849
|
+
try {
|
|
7850
|
+
const auth = await resolveAuth(options);
|
|
7851
|
+
const mode = parseRunMode(options.mode);
|
|
7852
|
+
console.log(chalk4.blue(`Running agent ${agentId} (mode: ${mode})...`));
|
|
7853
|
+
const result = await auth.client.runAgent({
|
|
7854
|
+
sessionToken: auth.sessionToken,
|
|
7855
|
+
agentId,
|
|
7856
|
+
mode
|
|
7857
|
+
});
|
|
7858
|
+
if (options.json) {
|
|
7859
|
+
console.log(jsonStringify(result));
|
|
7860
|
+
return;
|
|
7861
|
+
}
|
|
7862
|
+
if (!result.success) {
|
|
7863
|
+
exitWithError(result.error || "Agent run failed");
|
|
7864
|
+
}
|
|
7865
|
+
console.log(chalk4.green(`Agent run complete: ${result.action}`));
|
|
7866
|
+
if (result.summary) {
|
|
7867
|
+
console.log(` Summary: ${result.summary}`);
|
|
7868
|
+
}
|
|
7869
|
+
if (result.actions.length > 0) {
|
|
7870
|
+
console.log(" Actions:");
|
|
7871
|
+
for (const action of result.actions) {
|
|
7872
|
+
const textPreview = action.text.length > 60 ? `${action.text.slice(0, 60)}...` : action.text;
|
|
7873
|
+
console.log(` - ${action.type} in ${action.topic}: "${textPreview}"`);
|
|
7874
|
+
console.log(` tx: ${action.transactionHash}`);
|
|
7875
|
+
}
|
|
7876
|
+
}
|
|
7877
|
+
if (result.autoFunded) {
|
|
7878
|
+
console.log(
|
|
7879
|
+
chalk4.blue(
|
|
7880
|
+
` Auto-funded: $${result.autoFunded.amountUsd.toFixed(4)} (${result.autoFunded.amountEth} ETH)`
|
|
7881
|
+
)
|
|
7882
|
+
);
|
|
7883
|
+
}
|
|
7884
|
+
if (result.agentBalanceUsd !== void 0) {
|
|
7885
|
+
console.log(` Agent balance: $${result.agentBalanceUsd.toFixed(4)}`);
|
|
7886
|
+
}
|
|
7887
|
+
if (result.mainBalanceUsd !== void 0) {
|
|
7888
|
+
console.log(` Credits balance: $${result.mainBalanceUsd.toFixed(4)}`);
|
|
7889
|
+
}
|
|
7890
|
+
} catch (error) {
|
|
7891
|
+
exitWithError(
|
|
7892
|
+
`Failed to run agent: ${error instanceof Error ? error.message : String(error)}`
|
|
7893
|
+
);
|
|
7894
|
+
}
|
|
7895
|
+
}
|
|
7896
|
+
function registerAgentRunCommand(parent) {
|
|
7897
|
+
const cmd = parent.command("run <agentId>").description("Execute one agent cycle").option("--mode <mode>", "Run mode: auto, feeds, or chats (default: auto)").option("--json", "Output as JSON");
|
|
7898
|
+
addAuthOptions(cmd).action(async (agentId, options) => {
|
|
7899
|
+
await executeRun(agentId, options);
|
|
7900
|
+
});
|
|
7901
|
+
}
|
|
7902
|
+
async function executeInfo(agentId, options) {
|
|
7903
|
+
try {
|
|
7904
|
+
const auth = await resolveAuth(options);
|
|
7905
|
+
const agent = await auth.client.getAgent(auth.sessionToken, agentId);
|
|
7906
|
+
if (!agent) {
|
|
7907
|
+
exitWithError(`Agent not found: ${agentId}`);
|
|
7908
|
+
return;
|
|
7909
|
+
}
|
|
7910
|
+
if (options.json) {
|
|
7911
|
+
console.log(jsonStringify(agent));
|
|
7912
|
+
return;
|
|
7913
|
+
}
|
|
7914
|
+
const { config, walletAddress } = agent;
|
|
7915
|
+
const schedule = config.runIntervalMinutes ? `every ${config.runIntervalMinutes} minutes` : "manual only";
|
|
7916
|
+
console.log(
|
|
7917
|
+
chalk4.bold(config.name) + (config.hidden ? chalk4.gray(" [hidden]") : "")
|
|
7918
|
+
);
|
|
7919
|
+
console.log();
|
|
7920
|
+
console.log(` ID: ${config.id}`);
|
|
7921
|
+
console.log(` Wallet: ${walletAddress}`);
|
|
7922
|
+
console.log(` Owner: ${config.ownerAddress}`);
|
|
7923
|
+
console.log(` Schedule: ${schedule}`);
|
|
7924
|
+
console.log(` Created: ${new Date(config.createdAt).toLocaleString()}`);
|
|
7925
|
+
console.log(` Updated: ${new Date(config.updatedAt).toLocaleString()}`);
|
|
7926
|
+
console.log();
|
|
7927
|
+
console.log(" System Prompt:");
|
|
7928
|
+
console.log(` ${config.systemPrompt}`);
|
|
7929
|
+
if (config.filters) {
|
|
7930
|
+
console.log();
|
|
7931
|
+
console.log(" Filters:");
|
|
7932
|
+
if (config.filters.includeFeedPatterns?.length) {
|
|
7933
|
+
console.log(` Include feeds: ${config.filters.includeFeedPatterns.join(", ")}`);
|
|
7934
|
+
}
|
|
7935
|
+
if (config.filters.excludeFeedPatterns?.length) {
|
|
7936
|
+
console.log(` Exclude feeds: ${config.filters.excludeFeedPatterns.join(", ")}`);
|
|
7937
|
+
}
|
|
7938
|
+
if (config.filters.preferredFeedPatterns?.length) {
|
|
7939
|
+
console.log(
|
|
7940
|
+
` Preferred feeds: ${config.filters.preferredFeedPatterns.join(", ")}`
|
|
7941
|
+
);
|
|
7942
|
+
}
|
|
7943
|
+
if (config.filters.preferredChatTopics?.length) {
|
|
7944
|
+
console.log(` Chat topics: ${config.filters.preferredChatTopics.join(", ")}`);
|
|
7945
|
+
}
|
|
7946
|
+
}
|
|
7947
|
+
} catch (error) {
|
|
7948
|
+
exitWithError(
|
|
7949
|
+
`Failed to get agent info: ${error instanceof Error ? error.message : String(error)}`
|
|
7950
|
+
);
|
|
7951
|
+
}
|
|
7952
|
+
}
|
|
7953
|
+
function registerAgentInfoCommand(parent) {
|
|
7954
|
+
const cmd = parent.command("info <agentId>").description("Show detailed agent information").option("--json", "Output as JSON");
|
|
7955
|
+
addAuthOptions(cmd).action(async (agentId, options) => {
|
|
7956
|
+
await executeInfo(agentId, options);
|
|
7957
|
+
});
|
|
7958
|
+
}
|
|
7959
|
+
async function executeDm(agentAddress, message, options) {
|
|
7960
|
+
try {
|
|
7961
|
+
if (!isAddress(agentAddress)) {
|
|
7962
|
+
exitWithError(`Invalid agent address: ${agentAddress}`);
|
|
7963
|
+
}
|
|
7964
|
+
if (options.topicSignature && !options.topic) {
|
|
7965
|
+
exitWithError(
|
|
7966
|
+
"--topic-signature requires --topic (the topic the signature authorizes)"
|
|
7967
|
+
);
|
|
7968
|
+
}
|
|
7969
|
+
const usingSessionToken = !!(options.sessionToken || process.env.NET_SESSION_TOKEN);
|
|
7970
|
+
if (usingSessionToken && (!options.topic || !options.topicSignature)) {
|
|
7971
|
+
exitWithError(
|
|
7972
|
+
"When using --session-token, you must also provide --topic and --topic-signature.\n Obtain the signature with:\n netp agent dm-auth-encode --agent-address <addr> \u2192 produces { typedData, topic }\n [sign .typedData with your external signer, e.g. Bankr /agent/sign]\n Then:\n netp agent dm <addr> <message> --session-token <token> --operator <addr> \\\n --topic <topic> --topic-signature <sig>"
|
|
7973
|
+
);
|
|
7974
|
+
}
|
|
7975
|
+
const auth = await resolveAuth(options);
|
|
7976
|
+
const topic = options.topic ?? generateAgentChatTopic(agentAddress);
|
|
7977
|
+
const isNewConversation = !options.topic;
|
|
7978
|
+
console.log(
|
|
7979
|
+
chalk4.blue(
|
|
7980
|
+
isNewConversation ? `Starting new conversation with ${agentAddress}...` : `Continuing conversation ${topic}...`
|
|
7981
|
+
)
|
|
7982
|
+
);
|
|
7983
|
+
const result = await auth.client.sendMessage(
|
|
7984
|
+
{
|
|
7985
|
+
sessionToken: auth.sessionToken,
|
|
7986
|
+
agentAddress,
|
|
7987
|
+
topic,
|
|
7988
|
+
message,
|
|
7989
|
+
userSignature: options.topicSignature
|
|
7990
|
+
},
|
|
7991
|
+
auth.account
|
|
7992
|
+
);
|
|
7993
|
+
if (options.json) {
|
|
7994
|
+
console.log(jsonStringify(result));
|
|
7995
|
+
return;
|
|
7996
|
+
}
|
|
7997
|
+
console.log();
|
|
7998
|
+
console.log(chalk4.cyan("You: ") + message);
|
|
7999
|
+
console.log(chalk4.green("Agent: ") + result.aiMessage);
|
|
8000
|
+
console.log();
|
|
8001
|
+
console.log(chalk4.gray(` Topic: ${result.topic}`));
|
|
8002
|
+
console.log(chalk4.gray(` TX: ${result.transactionHash}`));
|
|
8003
|
+
if (isNewConversation) {
|
|
8004
|
+
console.log(
|
|
8005
|
+
chalk4.gray(` (Use --topic ${result.topic} to continue this conversation)`)
|
|
8006
|
+
);
|
|
8007
|
+
}
|
|
8008
|
+
} catch (error) {
|
|
8009
|
+
exitWithError(
|
|
8010
|
+
`Failed to send DM: ${error instanceof Error ? error.message : String(error)}`
|
|
8011
|
+
);
|
|
8012
|
+
}
|
|
8013
|
+
}
|
|
8014
|
+
function registerAgentDmCommand(parent) {
|
|
8015
|
+
const cmd = parent.command("dm <agentAddress> <message>").description("Send a DM to an onchain agent").option("--topic <topic>", "Continue an existing conversation").option(
|
|
8016
|
+
"--topic-signature <hex>",
|
|
8017
|
+
"Pre-signed ConversationAuth signature (requires --topic). Obtain via `agent dm-auth-encode` + external signer."
|
|
8018
|
+
).option("--json", "Output as JSON");
|
|
8019
|
+
addAuthOptions(cmd).action(async (agentAddress, message, options) => {
|
|
8020
|
+
await executeDm(agentAddress, message, options);
|
|
8021
|
+
});
|
|
8022
|
+
}
|
|
8023
|
+
async function executeDmList(options) {
|
|
8024
|
+
try {
|
|
8025
|
+
const { chainId, apiUrl, operator } = resolveReadOnly(options);
|
|
8026
|
+
if (!operator) {
|
|
8027
|
+
exitWithError(
|
|
8028
|
+
"--operator <address> is required (user wallet address to list conversations for)"
|
|
8029
|
+
);
|
|
8030
|
+
}
|
|
8031
|
+
const client = new AgentClient({ apiUrl, chainId });
|
|
8032
|
+
console.log(chalk4.blue("Loading conversations..."));
|
|
8033
|
+
const conversations = await client.listConversations(operator, {
|
|
8034
|
+
limit: options.limit
|
|
8035
|
+
});
|
|
8036
|
+
const agentConversations = conversations.filter((c) => isAgentChatTopic(c.topic));
|
|
8037
|
+
if (options.json) {
|
|
8038
|
+
console.log(jsonStringify(agentConversations));
|
|
8039
|
+
return;
|
|
8040
|
+
}
|
|
8041
|
+
if (agentConversations.length === 0) {
|
|
8042
|
+
console.log(chalk4.yellow("No agent conversations found."));
|
|
8043
|
+
return;
|
|
8044
|
+
}
|
|
8045
|
+
console.log(chalk4.bold(`Agent Conversations (${agentConversations.length}):
|
|
8046
|
+
`));
|
|
8047
|
+
for (const conv of agentConversations) {
|
|
8048
|
+
const agentAddr = parseAgentAddressFromTopic(conv.topic);
|
|
8049
|
+
const encrypted = conv.isEncrypted ? chalk4.yellow(" [encrypted]") : "";
|
|
8050
|
+
const date = new Date(conv.lastMessageTimestamp * 1e3).toLocaleString();
|
|
8051
|
+
const preview = conv.lastMessage ? conv.lastMessage.length > 60 ? `${conv.lastMessage.slice(0, 60)}...` : conv.lastMessage : null;
|
|
8052
|
+
console.log(` ${chalk4.cyan(agentAddr || "unknown")}${encrypted}`);
|
|
8053
|
+
console.log(` Topic: ${conv.topic}`);
|
|
8054
|
+
console.log(` Messages: ${conv.messageCount}`);
|
|
8055
|
+
console.log(` Last: ${date}`);
|
|
8056
|
+
if (preview) console.log(` Preview: ${preview}`);
|
|
8057
|
+
console.log();
|
|
8058
|
+
}
|
|
8059
|
+
} catch (error) {
|
|
8060
|
+
exitWithError(
|
|
8061
|
+
`Failed to list conversations: ${error instanceof Error ? error.message : String(error)}`
|
|
8062
|
+
);
|
|
8063
|
+
}
|
|
8064
|
+
}
|
|
8065
|
+
function registerAgentDmListCommand(parent) {
|
|
8066
|
+
const cmd = parent.command("dm-list").description("List your DM conversations with agents (pure chain read)").requiredOption("--operator <address>", "User wallet address").option("--limit <n>", "Max conversations to fetch", (v) => parseInt(v, 10)).option("--json", "Output as JSON");
|
|
8067
|
+
addCommonOptions(cmd).action(async (options) => {
|
|
8068
|
+
await executeDmList(options);
|
|
8069
|
+
});
|
|
8070
|
+
}
|
|
8071
|
+
async function executeDmHistory(topic, options) {
|
|
8072
|
+
try {
|
|
8073
|
+
const { chainId, apiUrl, operator } = resolveReadOnly(options);
|
|
8074
|
+
if (!operator) {
|
|
8075
|
+
exitWithError(
|
|
8076
|
+
"--operator <address> is required (user wallet address for this conversation)"
|
|
8077
|
+
);
|
|
8078
|
+
}
|
|
8079
|
+
const client = new AgentClient({ apiUrl, chainId });
|
|
8080
|
+
console.log(chalk4.blue("Loading conversation history..."));
|
|
8081
|
+
const messages = await client.getConversationHistory(operator, topic, {
|
|
8082
|
+
limit: options.limit
|
|
8083
|
+
});
|
|
8084
|
+
if (options.json) {
|
|
8085
|
+
console.log(jsonStringify(messages));
|
|
8086
|
+
return;
|
|
8087
|
+
}
|
|
8088
|
+
if (messages.length === 0) {
|
|
8089
|
+
console.log(chalk4.yellow("No messages found."));
|
|
8090
|
+
return;
|
|
8091
|
+
}
|
|
8092
|
+
const agentAddr = parseAgentAddressFromTopic(topic);
|
|
8093
|
+
console.log(
|
|
8094
|
+
chalk4.bold(
|
|
8095
|
+
`Conversation with ${agentAddr || topic} (${messages.length} messages):
|
|
8096
|
+
`
|
|
8097
|
+
)
|
|
8098
|
+
);
|
|
8099
|
+
for (const msg of messages) {
|
|
8100
|
+
const date = new Date(msg.timestamp * 1e3).toLocaleString();
|
|
8101
|
+
const prefix = msg.sender === "user" ? chalk4.cyan("You") : chalk4.green("Agent");
|
|
8102
|
+
const encrypted = msg.encrypted ? chalk4.yellow(" [encrypted]") : "";
|
|
8103
|
+
console.log(` ${prefix}${encrypted} (${chalk4.gray(date)}):`);
|
|
8104
|
+
console.log(` ${msg.text}`);
|
|
8105
|
+
console.log();
|
|
8106
|
+
}
|
|
8107
|
+
} catch (error) {
|
|
8108
|
+
exitWithError(
|
|
8109
|
+
`Failed to load history: ${error instanceof Error ? error.message : String(error)}`
|
|
8110
|
+
);
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
function registerAgentDmHistoryCommand(parent) {
|
|
8114
|
+
const cmd = parent.command("dm-history <topic>").description("Read DM conversation history (pure chain read)").requiredOption(
|
|
8115
|
+
"--operator <address>",
|
|
8116
|
+
"User wallet address for this conversation"
|
|
8117
|
+
).option("--limit <n>", "Max recent messages to fetch", (v) => parseInt(v, 10)).option("--json", "Output as JSON");
|
|
8118
|
+
addCommonOptions(cmd).action(async (topic, options) => {
|
|
8119
|
+
await executeDmHistory(topic, options);
|
|
8120
|
+
});
|
|
8121
|
+
}
|
|
8122
|
+
async function executeDmAuthEncode(options) {
|
|
8123
|
+
try {
|
|
8124
|
+
const { chainId } = parseReadOnlyOptionsWithDefault({
|
|
8125
|
+
chainId: options.chainId
|
|
8126
|
+
});
|
|
8127
|
+
let topic = options.topic;
|
|
8128
|
+
if (!topic) {
|
|
8129
|
+
if (!options.agentAddress) {
|
|
8130
|
+
exitWithError(
|
|
8131
|
+
"Must provide either --topic or --agent-address to generate a topic"
|
|
8132
|
+
);
|
|
8133
|
+
}
|
|
8134
|
+
if (!isAddress(options.agentAddress)) {
|
|
8135
|
+
exitWithError(`Invalid agent address: ${options.agentAddress}`);
|
|
8136
|
+
}
|
|
8137
|
+
topic = generateAgentChatTopic(options.agentAddress);
|
|
8138
|
+
}
|
|
8139
|
+
const result = buildConversationAuthTypedData({ topic, chainId });
|
|
8140
|
+
console.log(jsonStringify(result));
|
|
8141
|
+
} catch (error) {
|
|
8142
|
+
exitWithError(
|
|
8143
|
+
`dm-auth-encode failed: ${error instanceof Error ? error.message : String(error)}`
|
|
8144
|
+
);
|
|
8145
|
+
}
|
|
8146
|
+
}
|
|
8147
|
+
function registerAgentDmAuthEncodeCommand(parent) {
|
|
8148
|
+
parent.command("dm-auth-encode").description(
|
|
8149
|
+
"Emit { typedData, topic } for external signing. Pipe .typedData to your signer, pass .topic + the resulting signature to `agent dm --topic ... --topic-signature ...`."
|
|
8150
|
+
).option(
|
|
8151
|
+
"--topic <topic>",
|
|
8152
|
+
"Existing topic to authorize (e.g. agent-chat-0x...-nanoid). If omitted, a new topic is generated from --agent-address."
|
|
8153
|
+
).option(
|
|
8154
|
+
"--agent-address <address>",
|
|
8155
|
+
"Agent address \u2014 used to generate a new topic when --topic is omitted"
|
|
8156
|
+
).option("--chain-id <id>", "Chain ID (default: 8453)", (v) => parseInt(v, 10)).action(async (options) => {
|
|
8157
|
+
await executeDmAuthEncode(options);
|
|
8158
|
+
});
|
|
8159
|
+
}
|
|
8160
|
+
async function executeSessionEncode(options) {
|
|
8161
|
+
try {
|
|
8162
|
+
if (!isAddress(options.operator)) {
|
|
8163
|
+
exitWithError(`Invalid operator address: ${options.operator}`);
|
|
8164
|
+
}
|
|
8165
|
+
const { chainId } = parseReadOnlyOptionsWithDefault({
|
|
8166
|
+
chainId: options.chainId
|
|
8167
|
+
});
|
|
8168
|
+
const result = buildSessionTypedData({
|
|
8169
|
+
operatorAddress: options.operator,
|
|
8170
|
+
chainId,
|
|
8171
|
+
expiresIn: options.expiresIn
|
|
8172
|
+
});
|
|
8173
|
+
console.log(jsonStringify(result));
|
|
8174
|
+
} catch (error) {
|
|
8175
|
+
exitWithError(
|
|
8176
|
+
`session-encode failed: ${error instanceof Error ? error.message : String(error)}`
|
|
8177
|
+
);
|
|
8178
|
+
}
|
|
8179
|
+
}
|
|
8180
|
+
function registerAgentSessionEncodeCommand(parent) {
|
|
8181
|
+
parent.command("session-encode").description(
|
|
8182
|
+
"Emit { typedData, expiresAt } for external signing (e.g., Bankr). Pipe .typedData to your signer, pass .expiresAt + the resulting signature to `agent session-create`."
|
|
8183
|
+
).requiredOption(
|
|
8184
|
+
"--operator <address>",
|
|
8185
|
+
"Address that will sign the session (must match signer)"
|
|
8186
|
+
).option("--chain-id <id>", "Chain ID (default: 8453)", (v) => parseInt(v, 10)).option(
|
|
8187
|
+
"--expires-in <seconds>",
|
|
8188
|
+
"Session lifetime in seconds (default: 3600, max: 86400)",
|
|
8189
|
+
(v) => parseInt(v, 10)
|
|
8190
|
+
).action(async (options) => {
|
|
8191
|
+
await executeSessionEncode(options);
|
|
8192
|
+
});
|
|
8193
|
+
}
|
|
8194
|
+
async function executeSessionCreate(options) {
|
|
8195
|
+
try {
|
|
8196
|
+
if (!isAddress(options.operator)) {
|
|
8197
|
+
exitWithError(`Invalid operator address: ${options.operator}`);
|
|
8198
|
+
}
|
|
8199
|
+
if (!options.signature.startsWith("0x")) {
|
|
8200
|
+
exitWithError("--signature must be a 0x-prefixed hex string");
|
|
8201
|
+
}
|
|
8202
|
+
if (!options.expiresAt || !Number.isFinite(options.expiresAt)) {
|
|
8203
|
+
exitWithError("--expires-at must be a unix timestamp (seconds)");
|
|
8204
|
+
}
|
|
8205
|
+
const { chainId } = parseReadOnlyOptionsWithDefault({
|
|
8206
|
+
chainId: options.chainId
|
|
8207
|
+
});
|
|
8208
|
+
const apiUrl = options.apiUrl || process.env.NET_API_URL || NET_API_URL;
|
|
8209
|
+
const result = await exchangeSessionSignature({
|
|
8210
|
+
apiUrl,
|
|
8211
|
+
chainId,
|
|
8212
|
+
operatorAddress: options.operator,
|
|
8213
|
+
signature: options.signature,
|
|
8214
|
+
expiresAt: options.expiresAt
|
|
8215
|
+
});
|
|
8216
|
+
console.log(jsonStringify(result));
|
|
8217
|
+
} catch (error) {
|
|
8218
|
+
exitWithError(
|
|
8219
|
+
`session-create failed: ${error instanceof Error ? error.message : String(error)}`
|
|
8220
|
+
);
|
|
8221
|
+
}
|
|
8222
|
+
}
|
|
8223
|
+
function registerAgentSessionCreateCommand(parent) {
|
|
8224
|
+
parent.command("session-create").description(
|
|
8225
|
+
"Exchange an externally-produced signature for a session token. Pair with `agent session-encode`."
|
|
8226
|
+
).requiredOption(
|
|
8227
|
+
"--operator <address>",
|
|
8228
|
+
"Address that produced the signature (must match the ecrecover result)"
|
|
8229
|
+
).requiredOption("--signature <hex>", "EIP-712 signature over the session typed data").requiredOption(
|
|
8230
|
+
"--expires-at <timestamp>",
|
|
8231
|
+
"expiresAt value from session-encode (unix seconds)",
|
|
8232
|
+
(v) => parseInt(v, 10)
|
|
8233
|
+
).option("--chain-id <id>", "Chain ID (default: 8453)", (v) => parseInt(v, 10)).option("--api-url <url>", "Net Protocol API URL").action(async (options) => {
|
|
8234
|
+
await executeSessionCreate(options);
|
|
8235
|
+
});
|
|
8236
|
+
}
|
|
8237
|
+
|
|
8238
|
+
// src/commands/agent/index.ts
|
|
8239
|
+
function registerAgentCommand(program2) {
|
|
8240
|
+
const agentCommand = program2.command("agent").description("Onchain agent operations (create, manage, run, DM)");
|
|
8241
|
+
registerAgentCreateCommand(agentCommand);
|
|
8242
|
+
registerAgentListCommand(agentCommand);
|
|
8243
|
+
registerAgentUpdateCommand(agentCommand);
|
|
8244
|
+
registerAgentHideCommand(agentCommand);
|
|
8245
|
+
registerAgentUnhideCommand(agentCommand);
|
|
8246
|
+
registerAgentRunCommand(agentCommand);
|
|
8247
|
+
registerAgentInfoCommand(agentCommand);
|
|
8248
|
+
registerAgentDmCommand(agentCommand);
|
|
8249
|
+
registerAgentDmListCommand(agentCommand);
|
|
8250
|
+
registerAgentDmHistoryCommand(agentCommand);
|
|
8251
|
+
registerAgentSessionEncodeCommand(agentCommand);
|
|
8252
|
+
registerAgentSessionCreateCommand(agentCommand);
|
|
8253
|
+
registerAgentDmAuthEncodeCommand(agentCommand);
|
|
8254
|
+
}
|
|
8255
|
+
var CHAINS = {
|
|
8256
|
+
8453: base,
|
|
8257
|
+
84532: baseSepolia
|
|
8258
|
+
};
|
|
8259
|
+
function getApiUrl(chainId) {
|
|
8260
|
+
return chainId === 84532 ? NET_TESTNET_API_URL : NET_API_URL;
|
|
8261
|
+
}
|
|
8262
|
+
function registerRelayCommand(program2) {
|
|
8263
|
+
const relayCommand = program2.command("relay").description("Relay operations (fund credits, check balance)");
|
|
8264
|
+
relayCommand.command("fund").description("Add Net credits via x402 USDC payment").option("--amount <usd>", "Amount in USD to fund (default: 0.10)", "0.10").option("--chain-id <id>", "Chain ID (default: 8453)").option("--rpc-url <url>", "Custom RPC URL").option("--private-key <key>", "Private key (0x-prefixed)").option("--json", "Output as JSON").action(async (options) => {
|
|
8265
|
+
const { privateKey, chainId, rpcUrl } = parseCommonOptionsWithDefault({
|
|
8266
|
+
privateKey: options.privateKey,
|
|
8267
|
+
chainId: options.chainId ? parseInt(options.chainId, 10) : void 0,
|
|
8268
|
+
rpcUrl: options.rpcUrl
|
|
8269
|
+
});
|
|
8270
|
+
const amount = parseFloat(options.amount);
|
|
8271
|
+
if (isNaN(amount) || amount <= 0) {
|
|
8272
|
+
exitWithError("Invalid amount. Must be a positive number.");
|
|
8273
|
+
}
|
|
8274
|
+
const chain = CHAINS[chainId];
|
|
8275
|
+
if (!chain) {
|
|
8276
|
+
exitWithError(
|
|
8277
|
+
`Chain ${chainId} not supported for relay funding. Use Base (8453) or Base Sepolia (84532).`
|
|
8278
|
+
);
|
|
8279
|
+
}
|
|
8280
|
+
const account = privateKeyToAccount(privateKey);
|
|
8281
|
+
const rpcUrls = getChainRpcUrls({ chainId, rpcUrl });
|
|
8282
|
+
const publicClient = createPublicClient({
|
|
8283
|
+
chain,
|
|
8284
|
+
transport: http(rpcUrls[0])
|
|
8285
|
+
});
|
|
8286
|
+
const walletClient = createWalletClient({
|
|
8287
|
+
account,
|
|
8288
|
+
chain,
|
|
8289
|
+
transport: http(rpcUrls[0])
|
|
8290
|
+
});
|
|
8291
|
+
const signer = {
|
|
8292
|
+
address: account.address,
|
|
8293
|
+
signTypedData: (msg) => walletClient.signTypedData(msg),
|
|
8294
|
+
readContract: (args) => publicClient.readContract(args),
|
|
8295
|
+
sendTransaction: (args) => walletClient.sendTransaction(args)
|
|
8296
|
+
};
|
|
8297
|
+
const { x402Client, wrapFetchWithPayment, x402HTTPClient } = await import('@x402/fetch');
|
|
8298
|
+
const { registerExactEvmScheme } = await import('@x402/evm/exact/client');
|
|
8299
|
+
const client = new x402Client();
|
|
8300
|
+
registerExactEvmScheme(client, { signer });
|
|
8301
|
+
const fetchWithPayment = wrapFetchWithPayment(fetch, client);
|
|
8302
|
+
const httpClient = new x402HTTPClient(client);
|
|
8303
|
+
const apiUrl = getApiUrl(chainId);
|
|
8304
|
+
if (!options.json) {
|
|
8305
|
+
console.log(
|
|
8306
|
+
`Funding $${amount.toFixed(2)} USDC to relay on chain ${chainId}...`
|
|
8307
|
+
);
|
|
8308
|
+
}
|
|
8309
|
+
try {
|
|
8310
|
+
const result = await fundBackendWallet({
|
|
8311
|
+
apiUrl,
|
|
8312
|
+
chainId,
|
|
8313
|
+
operatorAddress: account.address,
|
|
8314
|
+
secretKey: RELAY_ACCESS_KEY,
|
|
8315
|
+
fetchWithPayment,
|
|
8316
|
+
httpClient,
|
|
8317
|
+
amount
|
|
8318
|
+
});
|
|
8319
|
+
if (options.json) {
|
|
8320
|
+
console.log(
|
|
8321
|
+
JSON.stringify(
|
|
8322
|
+
{
|
|
8323
|
+
success: true,
|
|
8324
|
+
paymentTxHash: result.paymentTxHash,
|
|
8325
|
+
backendWalletAddress: result.backendWalletAddress,
|
|
8326
|
+
amountUsd: amount
|
|
8327
|
+
},
|
|
8328
|
+
null,
|
|
8329
|
+
2
|
|
8330
|
+
)
|
|
8331
|
+
);
|
|
8332
|
+
} else {
|
|
8333
|
+
console.log(chalk4.green(`
|
|
8334
|
+
\u2713 Funded $${amount.toFixed(2)} successfully`));
|
|
8335
|
+
console.log(` Payment tx: ${result.paymentTxHash}`);
|
|
8336
|
+
console.log(
|
|
8337
|
+
` Backend wallet: ${result.backendWalletAddress}`
|
|
8338
|
+
);
|
|
8339
|
+
}
|
|
8340
|
+
} catch (error) {
|
|
8341
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
8342
|
+
if (options.json) {
|
|
8343
|
+
console.log(JSON.stringify({ success: false, error: msg }, null, 2));
|
|
8344
|
+
process.exit(1);
|
|
8345
|
+
}
|
|
8346
|
+
exitWithError(`Funding failed: ${msg}`);
|
|
8347
|
+
}
|
|
8348
|
+
});
|
|
8349
|
+
relayCommand.command("balance").description("Check relay backend wallet balance").option("--chain-id <id>", "Chain ID (default: 8453)").option("--private-key <key>", "Private key (0x-prefixed)").option("--json", "Output as JSON").action(async (options) => {
|
|
8350
|
+
const { privateKey, chainId } = parseCommonOptionsWithDefault({
|
|
8351
|
+
privateKey: options.privateKey,
|
|
8352
|
+
chainId: options.chainId ? parseInt(options.chainId, 10) : void 0
|
|
8353
|
+
});
|
|
8354
|
+
const account = privateKeyToAccount(privateKey);
|
|
8355
|
+
const apiUrl = getApiUrl(chainId);
|
|
8356
|
+
try {
|
|
8357
|
+
const result = await checkBackendWalletBalance({
|
|
8358
|
+
apiUrl,
|
|
8359
|
+
chainId,
|
|
8360
|
+
operatorAddress: account.address,
|
|
8361
|
+
secretKey: RELAY_ACCESS_KEY
|
|
8362
|
+
});
|
|
8363
|
+
if (options.json) {
|
|
8364
|
+
console.log(JSON.stringify(result, null, 2));
|
|
8365
|
+
} else {
|
|
8366
|
+
console.log(`Relay Balance`);
|
|
8367
|
+
console.log(` Backend wallet: ${result.backendWalletAddress}`);
|
|
8368
|
+
console.log(` Balance: ${result.balanceEth} ETH`);
|
|
8369
|
+
console.log(
|
|
8370
|
+
` Sufficient: ${result.sufficientBalance ? chalk4.green("Yes") : chalk4.red("No")} (min: ${result.minRequiredEth} ETH)`
|
|
8371
|
+
);
|
|
8372
|
+
}
|
|
8373
|
+
} catch (error) {
|
|
8374
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
8375
|
+
if (options.json) {
|
|
8376
|
+
console.log(JSON.stringify({ success: false, error: msg }, null, 2));
|
|
8377
|
+
process.exit(1);
|
|
8378
|
+
}
|
|
8379
|
+
exitWithError(`Balance check failed: ${msg}`);
|
|
8380
|
+
}
|
|
8381
|
+
});
|
|
8382
|
+
}
|
|
7537
8383
|
var CACHE_DIR = join(homedir(), ".netp");
|
|
7538
8384
|
var CACHE_FILE = join(CACHE_DIR, "update-check.json");
|
|
7539
8385
|
var CHECK_INTERVAL_MS = 4 * 60 * 60 * 1e3;
|
|
@@ -7634,6 +8480,8 @@ registerProfileCommand(program);
|
|
|
7634
8480
|
registerBazaarCommand(program);
|
|
7635
8481
|
registerFeedCommand(program);
|
|
7636
8482
|
registerUpvoteCommand(program);
|
|
8483
|
+
registerAgentCommand(program);
|
|
8484
|
+
registerRelayCommand(program);
|
|
7637
8485
|
program.command("update").description("Update netp to the latest version").action(async () => {
|
|
7638
8486
|
const { execSync } = await import('child_process');
|
|
7639
8487
|
console.log("Updating @net-protocol/cli...");
|