@pod-protocol/cli
Version:
Command-line interface for PoD Protocol (Prompt or Die) AI Agent Communication Protocol
229 lines (228 loc) • 9.16 kB
JavaScript
import chalk from "chalk";
import inquirer from "inquirer";
import { table } from "table";
import { PublicKey } from "@solana/web3.js";
import { AGENT_CAPABILITIES, getCapabilityNames, } from "@pod-protocol/sdk";
import { createCommandHandler, handleDryRun, createSpinner, showSuccess, } from "../utils/shared.js";
import { createClient, getWallet, getKeypair } from "../utils/client.js";
import ora from "ora";
export class AgentCommands {
register(program) {
const agent = program
.command("agent")
.description("Manage AI agents on POD-COM");
this.setupRegisterCommand(agent);
this.setupInfoCommand(agent);
this.setupUpdateCommand(agent);
this.setupListCommand(agent);
}
setupRegisterCommand(agent) {
agent
.command("register")
.description("Register a new AI agent")
.option("-c, --capabilities <value>", "Agent capabilities as number")
.option("-m, --metadata <uri>", "Metadata URI")
.option("-i, --interactive", "Interactive registration")
.action(createCommandHandler("register agent", async (client, wallet, globalOpts, options) => {
const { capabilities, metadataUri } = await this.prepareRegistrationData(options);
const spinner = createSpinner("Registering agent...");
if (handleDryRun(globalOpts, spinner, "Agent registration", {
Capabilities: getCapabilityNames(capabilities).join(", "),
"Metadata URI": metadataUri,
})) {
return;
}
const signature = await client.agents.registerAgent(wallet, {
capabilities,
metadataUri,
});
showSuccess(spinner, "Agent registered successfully!", {
Transaction: signature,
Capabilities: getCapabilityNames(capabilities).join(", "),
"Metadata URI": metadataUri,
});
}));
}
setupInfoCommand(agent) {
agent
.command("info [address]")
.description("Show agent information")
.action(async (address, cmd) => {
const globalOpts = cmd.parent?.opts() || {};
try {
const spinner = ora("Fetching agent information...").start();
const client = await createClient(globalOpts.network);
const walletAddress = this.resolveWalletAddress(address, globalOpts);
const agentData = await client.agents.getAgent(walletAddress);
if (!agentData) {
spinner.fail("Agent not found");
return;
}
spinner.succeed("Agent information retrieved");
this.displayAgentInfo(agentData);
}
catch (error) {
console.error(chalk.red("Failed to fetch agent info:"), error.message);
process.exit(1);
}
});
}
setupUpdateCommand(agent) {
agent
.command("update")
.description("Update agent information")
.option("-c, --capabilities <value>", "New capabilities")
.option("-m, --metadata <uri>", "New metadata URI")
.action(async (options, cmd) => {
const globalOpts = cmd.parent?.opts() || {};
try {
const spinner = ora("Updating agent...").start();
const wallet = getWallet(globalOpts.keypair);
const keypair = getKeypair(globalOpts.keypair);
const client = await createClient(globalOpts.network, wallet);
const updateOptions = this.prepareUpdateOptions(options);
if (Object.keys(updateOptions).length === 0) {
spinner.fail("No updates specified");
return;
}
if (globalOpts.dryRun) {
spinner.succeed("Dry run: Agent update prepared");
console.log(chalk.cyan("Updates:"), JSON.stringify(updateOptions, null, 2));
return;
}
const signature = await client.agents.updateAgent(keypair, updateOptions);
spinner.succeed("Agent updated successfully!");
console.log(chalk.green("Transaction:"), signature);
}
catch (error) {
console.error(chalk.red("Failed to update agent:"), error.message);
process.exit(1);
}
});
}
setupListCommand(agent) {
agent
.command("list")
.description("List all registered agents")
.option("-l, --limit <number>", "Maximum number of agents to show", "10")
.action(async (options, cmd) => {
const globalOpts = cmd.parent?.opts() || {};
try {
const spinner = ora("Fetching agents...").start();
const client = await createClient(globalOpts.network);
const agents = await client.agents.getAllAgents(parseInt(options.limit, 10));
if (agents.length === 0) {
spinner.succeed("No agents found");
return;
}
spinner.succeed(`Found ${agents.length} agents`);
this.displayAgentsList(agents);
}
catch (error) {
console.error(chalk.red("Failed to list agents:"), error.message);
process.exit(1);
}
});
}
async prepareRegistrationData(options) {
let capabilities = options.capabilities
? parseInt(options.capabilities, 10)
: 0;
let metadataUri = options.metadata || "";
if (options.interactive) {
const answers = await this.promptForRegistrationData();
capabilities = answers.capabilities.reduce((acc, cap) => acc | cap, 0);
metadataUri = answers.metadataUri;
}
if (!metadataUri) {
metadataUri = `https://pod-com.org/agents/${Date.now()}`;
}
return { capabilities, metadataUri };
}
async promptForRegistrationData() {
return await inquirer.prompt([
{
type: "checkbox",
name: "capabilities",
message: "Select agent capabilities:",
choices: [
{ name: "Trading", value: AGENT_CAPABILITIES.TRADING },
{ name: "Analysis", value: AGENT_CAPABILITIES.ANALYSIS },
{
name: "Data Processing",
value: AGENT_CAPABILITIES.DATA_PROCESSING,
},
{
name: "Content Generation",
value: AGENT_CAPABILITIES.CONTENT_GENERATION,
},
],
},
{
type: "input",
name: "metadataUri",
message: "Metadata URI (optional):",
default: "",
},
]);
}
resolveWalletAddress(address, globalOpts) {
if (address) {
return new PublicKey(address);
}
else {
const wallet = getWallet(globalOpts.keypair);
return wallet.publicKey;
}
}
displayAgentInfo(agentData) {
const data = [
["Public Key", agentData.pubkey.toBase58()],
[
"Capabilities",
getCapabilityNames(agentData.capabilities).join(", "),
],
["Reputation", agentData.reputation.toString()],
["Metadata URI", agentData.metadataUri],
[
"Last Updated",
new Date(agentData.lastUpdated * 1000).toLocaleString(),
],
];
console.log("\n" +
table(data, {
header: {
alignment: "center",
content: chalk.blue.bold("Agent Information"),
},
}));
}
prepareUpdateOptions(options) {
const updateOptions = {};
if (options.capabilities) {
updateOptions.capabilities = parseInt(options.capabilities, 10);
}
if (options.metadata) {
updateOptions.metadataUri = options.metadata;
}
return updateOptions;
}
displayAgentsList(agents) {
const data = agents.map((agent) => [
agent.pubkey.toBase58().slice(0, 8) + "...",
getCapabilityNames(agent.capabilities).join(", "),
agent.reputation.toString(),
new Date(agent.lastUpdated * 1000).toLocaleDateString(),
]);
console.log("\n" +
table([
["Address", "Capabilities", "Reputation", "Last Updated"],
...data,
], {
header: {
alignment: "center",
content: chalk.blue.bold("Registered Agents"),
},
}));
}
}