@paylobster/cli 4.0.0

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.
Files changed (89) hide show
  1. package/BUILD_SUMMARY.md +429 -0
  2. package/CHANGELOG.md +78 -0
  3. package/CONTRIBUTING.md +368 -0
  4. package/EXAMPLES.md +432 -0
  5. package/LICENSE +21 -0
  6. package/QUICKSTART.md +189 -0
  7. package/README.md +377 -0
  8. package/TEST_REPORT.md +191 -0
  9. package/bin/plob.js +9 -0
  10. package/bin/plob.ts +9 -0
  11. package/demo.sh +154 -0
  12. package/dist/bin/plob.d.ts +7 -0
  13. package/dist/bin/plob.d.ts.map +1 -0
  14. package/dist/bin/plob.js +10 -0
  15. package/dist/bin/plob.js.map +1 -0
  16. package/dist/src/commands/auth.d.ts +3 -0
  17. package/dist/src/commands/auth.d.ts.map +1 -0
  18. package/dist/src/commands/auth.js +75 -0
  19. package/dist/src/commands/auth.js.map +1 -0
  20. package/dist/src/commands/config.d.ts +3 -0
  21. package/dist/src/commands/config.d.ts.map +1 -0
  22. package/dist/src/commands/config.js +79 -0
  23. package/dist/src/commands/config.js.map +1 -0
  24. package/dist/src/commands/escrow.d.ts +3 -0
  25. package/dist/src/commands/escrow.d.ts.map +1 -0
  26. package/dist/src/commands/escrow.js +193 -0
  27. package/dist/src/commands/escrow.js.map +1 -0
  28. package/dist/src/commands/mandate.d.ts +8 -0
  29. package/dist/src/commands/mandate.d.ts.map +1 -0
  30. package/dist/src/commands/mandate.js +54 -0
  31. package/dist/src/commands/mandate.js.map +1 -0
  32. package/dist/src/commands/pay.d.ts +6 -0
  33. package/dist/src/commands/pay.d.ts.map +1 -0
  34. package/dist/src/commands/pay.js +77 -0
  35. package/dist/src/commands/pay.js.map +1 -0
  36. package/dist/src/commands/register.d.ts +3 -0
  37. package/dist/src/commands/register.d.ts.map +1 -0
  38. package/dist/src/commands/register.js +51 -0
  39. package/dist/src/commands/register.js.map +1 -0
  40. package/dist/src/commands/reputation.d.ts +3 -0
  41. package/dist/src/commands/reputation.d.ts.map +1 -0
  42. package/dist/src/commands/reputation.js +116 -0
  43. package/dist/src/commands/reputation.js.map +1 -0
  44. package/dist/src/commands/status.d.ts +3 -0
  45. package/dist/src/commands/status.d.ts.map +1 -0
  46. package/dist/src/commands/status.js +82 -0
  47. package/dist/src/commands/status.js.map +1 -0
  48. package/dist/src/index.d.ts +3 -0
  49. package/dist/src/index.d.ts.map +1 -0
  50. package/dist/src/index.js +59 -0
  51. package/dist/src/index.js.map +1 -0
  52. package/dist/src/lib/config.d.ts +26 -0
  53. package/dist/src/lib/config.d.ts.map +1 -0
  54. package/dist/src/lib/config.js +91 -0
  55. package/dist/src/lib/config.js.map +1 -0
  56. package/dist/src/lib/contracts.d.ts +18798 -0
  57. package/dist/src/lib/contracts.d.ts.map +1 -0
  58. package/dist/src/lib/contracts.js +361 -0
  59. package/dist/src/lib/contracts.js.map +1 -0
  60. package/dist/src/lib/display.d.ts +83 -0
  61. package/dist/src/lib/display.d.ts.map +1 -0
  62. package/dist/src/lib/display.js +293 -0
  63. package/dist/src/lib/display.js.map +1 -0
  64. package/dist/src/lib/types.d.ts +49 -0
  65. package/dist/src/lib/types.d.ts.map +1 -0
  66. package/dist/src/lib/types.js +3 -0
  67. package/dist/src/lib/types.js.map +1 -0
  68. package/dist/src/lib/wallet.d.ts +30 -0
  69. package/dist/src/lib/wallet.d.ts.map +1 -0
  70. package/dist/src/lib/wallet.js +143 -0
  71. package/dist/src/lib/wallet.js.map +1 -0
  72. package/jest.config.js +15 -0
  73. package/package.json +55 -0
  74. package/src/__tests__/cli.test.ts +38 -0
  75. package/src/commands/auth.ts +75 -0
  76. package/src/commands/config.ts +84 -0
  77. package/src/commands/escrow.ts +222 -0
  78. package/src/commands/mandate.ts +56 -0
  79. package/src/commands/pay.ts +96 -0
  80. package/src/commands/register.ts +57 -0
  81. package/src/commands/reputation.ts +84 -0
  82. package/src/commands/status.ts +91 -0
  83. package/src/index.ts +63 -0
  84. package/src/lib/config.ts +90 -0
  85. package/src/lib/contracts.ts +392 -0
  86. package/src/lib/display.ts +265 -0
  87. package/src/lib/types.ts +57 -0
  88. package/src/lib/wallet.ts +146 -0
  89. package/tsconfig.json +21 -0
@@ -0,0 +1,75 @@
1
+ import { Command } from 'commander';
2
+ import { saveToKeystore, loadWallet, getWalletAddress } from '../lib/wallet';
3
+ import { saveConfig } from '../lib/config';
4
+ import { success, error, warning, info } from '../lib/display';
5
+
6
+ export function createAuthCommand(): Command {
7
+ const cmd = new Command('auth')
8
+ .description('Set up wallet authentication');
9
+
10
+ cmd
11
+ .option('--private-key <key>', 'Set private key directly')
12
+ .option('--env <var>', 'Use environment variable (PRIVATE_KEY or custom)')
13
+ .option('--keystore <file>', 'Save to keystore file')
14
+ .action(async (options) => {
15
+ try {
16
+ if (options.privateKey) {
17
+ // Validate private key format
18
+ if (!options.privateKey.startsWith('0x') || options.privateKey.length !== 66) {
19
+ error('Invalid private key format. Must be 0x-prefixed 64-character hex string');
20
+ process.exit(1);
21
+ }
22
+
23
+ // Save to keystore
24
+ const keystorePath = saveToKeystore(options.privateKey, options.keystore || 'default.key');
25
+
26
+ // Update config
27
+ saveConfig({
28
+ wallet: {
29
+ type: 'keystore',
30
+ path: options.keystore || 'default.key',
31
+ },
32
+ });
33
+
34
+ success('Wallet configured successfully');
35
+ info(`Private key saved to keystore: ${keystorePath}`);
36
+ warning('Keep your keystore file secure!');
37
+
38
+ // Show address
39
+ const address = getWalletAddress();
40
+ info(`Wallet address: ${address}`);
41
+ } else if (options.env) {
42
+ // Use environment variable
43
+ saveConfig({
44
+ wallet: {
45
+ type: 'env',
46
+ },
47
+ });
48
+
49
+ success(`Configured to use environment variable: ${options.env}`);
50
+ info('Set the environment variable before running commands:');
51
+ console.log(` export ${options.env}="0x..."`);
52
+ } else {
53
+ // Default: check if wallet is already configured
54
+ try {
55
+ const address = getWalletAddress();
56
+ success('Wallet is already configured');
57
+ info(`Address: ${address}`);
58
+ } catch (err) {
59
+ error('No wallet configured');
60
+ console.log();
61
+ console.log('Usage:');
62
+ console.log(' plob auth --private-key 0x...');
63
+ console.log(' plob auth --env PRIVATE_KEY');
64
+ console.log();
65
+ process.exit(1);
66
+ }
67
+ }
68
+ } catch (err) {
69
+ error(`Failed to configure wallet: ${err}`);
70
+ process.exit(1);
71
+ }
72
+ });
73
+
74
+ return cmd;
75
+ }
@@ -0,0 +1,84 @@
1
+ import { Command } from 'commander';
2
+ import { loadConfig, saveConfig, clearConfig } from '../lib/config';
3
+ import { success, error, outputJSON, printConfig, formatNetwork } from '../lib/display';
4
+ import type { OutputOptions } from '../lib/types';
5
+
6
+ export function createConfigCommand(): Command {
7
+ const cmd = new Command('config')
8
+ .description('Manage CLI configuration');
9
+
10
+ // plob config show
11
+ cmd
12
+ .command('show')
13
+ .description('Show current configuration')
14
+ .option('--json', 'Output as JSON')
15
+ .action(async (options: OutputOptions) => {
16
+ try {
17
+ const config = loadConfig();
18
+
19
+ if (outputJSON(config, options)) {
20
+ return;
21
+ }
22
+
23
+ console.log();
24
+ printConfig({
25
+ network: formatNetwork(config.network),
26
+ rpcUrl: config.rpcUrl || 'default',
27
+ indexerUrl: config.indexerUrl || 'default',
28
+ wallet: config.wallet?.type || 'env',
29
+ });
30
+ console.log();
31
+ } catch (err) {
32
+ error(`Failed to load config: ${err}`);
33
+ process.exit(1);
34
+ }
35
+ });
36
+
37
+ // plob config set <key> <value>
38
+ cmd
39
+ .command('set')
40
+ .description('Set a configuration value')
41
+ .argument('<key>', 'Configuration key (network, rpcUrl, indexerUrl)')
42
+ .argument('<value>', 'Configuration value')
43
+ .action(async (key: string, value: string) => {
44
+ try {
45
+ const validKeys = ['network', 'rpcUrl', 'indexerUrl'];
46
+
47
+ if (!validKeys.includes(key)) {
48
+ error(`Invalid config key: ${key}`);
49
+ console.log(`Valid keys: ${validKeys.join(', ')}`);
50
+ process.exit(1);
51
+ }
52
+
53
+ if (key === 'network' && !['mainnet', 'sepolia'].includes(value)) {
54
+ error('Network must be "mainnet" or "sepolia"');
55
+ process.exit(1);
56
+ }
57
+
58
+ const config = loadConfig();
59
+ (config as any)[key] = value;
60
+ saveConfig(config);
61
+
62
+ success(`Set ${key} = ${value}`);
63
+ } catch (err) {
64
+ error(`Failed to set config: ${err}`);
65
+ process.exit(1);
66
+ }
67
+ });
68
+
69
+ // plob config reset
70
+ cmd
71
+ .command('reset')
72
+ .description('Reset configuration to defaults')
73
+ .action(async () => {
74
+ try {
75
+ clearConfig();
76
+ success('Configuration reset to defaults');
77
+ } catch (err) {
78
+ error(`Failed to reset config: ${err}`);
79
+ process.exit(1);
80
+ }
81
+ });
82
+
83
+ return cmd;
84
+ }
@@ -0,0 +1,222 @@
1
+ import { Command } from 'commander';
2
+ import { createEscrow, releaseEscrow, getEscrow, formatUSDC, getUserEscrowCount } from '../lib/contracts';
3
+ import { getWalletAddress } from '../lib/wallet';
4
+ import { success, error, info, withSpinner, outputJSON, formatAddress, formatStatus, printEscrowTable, confirm } from '../lib/display';
5
+ import type { OutputOptions } from '../lib/types';
6
+
7
+ export function createEscrowCommand(): Command {
8
+ const cmd = new Command('escrow')
9
+ .description('Manage escrows');
10
+
11
+ // plob escrow create
12
+ cmd
13
+ .command('create')
14
+ .description('Create a new escrow')
15
+ .requiredOption('--to <address>', 'Recipient address')
16
+ .requiredOption('--amount <amount>', 'Amount in USDC')
17
+ .option('--description <desc>', 'Escrow description', 'Payment via PayLobster CLI')
18
+ .option('--json', 'Output as JSON')
19
+ .action(async (options: { to: string; amount: string; description: string } & OutputOptions) => {
20
+ try {
21
+ // Validate address format
22
+ if (!options.to.startsWith('0x') || options.to.length !== 42) {
23
+ error('Invalid recipient address format');
24
+ process.exit(1);
25
+ }
26
+
27
+ // Validate amount
28
+ const amount = parseFloat(options.amount);
29
+ if (isNaN(amount) || amount <= 0) {
30
+ error('Invalid amount. Must be a positive number');
31
+ process.exit(1);
32
+ }
33
+
34
+ info(`Creating escrow for ${options.amount} USDC to ${formatAddress(options.to)}`);
35
+
36
+ const txHash = await withSpinner(
37
+ 'Creating escrow (approving USDC + creating escrow)...',
38
+ async () => {
39
+ return await createEscrow(
40
+ options.to as `0x${string}`,
41
+ options.amount,
42
+ options.description
43
+ );
44
+ }
45
+ );
46
+
47
+ if (outputJSON({
48
+ txHash: txHash.toString(),
49
+ to: options.to,
50
+ amount: options.amount,
51
+ description: options.description,
52
+ }, options)) {
53
+ return;
54
+ }
55
+
56
+ success('Escrow created successfully!');
57
+ info(`Transaction: ${txHash.toString()}`);
58
+ info(`Recipient: ${options.to}`);
59
+ info(`Amount: ${options.amount} USDC`);
60
+ } catch (err) {
61
+ error(`Failed to create escrow: ${err}`);
62
+ process.exit(1);
63
+ }
64
+ });
65
+
66
+ // plob escrow list
67
+ cmd
68
+ .command('list')
69
+ .description('List your escrows')
70
+ .option('--json', 'Output as JSON')
71
+ .action(async (options: OutputOptions) => {
72
+ try {
73
+ const address = getWalletAddress() as `0x${string}`;
74
+ const count = await getUserEscrowCount(address);
75
+
76
+ if (count === 0) {
77
+ info('No escrows found');
78
+ return;
79
+ }
80
+
81
+ info(`Total escrows: ${count}`);
82
+
83
+ // Fetch details for each escrow
84
+ // Note: This is a simplified implementation. In production, you'd want pagination
85
+ // or fetch from an indexer
86
+ const escrows = [];
87
+ for (let i = 0; i < Math.min(count, 10); i++) {
88
+ try {
89
+ const escrowData = await getEscrow(BigInt(i));
90
+ escrows.push({
91
+ id: i,
92
+ from: escrowData.sender,
93
+ to: escrowData.recipient,
94
+ amount: formatUSDC(escrowData.amount) + ' USDC',
95
+ status: escrowData.status,
96
+ });
97
+ } catch (err) {
98
+ // Skip if can't fetch
99
+ }
100
+ }
101
+
102
+ if (outputJSON(escrows, options)) {
103
+ return;
104
+ }
105
+
106
+ printEscrowTable(escrows);
107
+
108
+ if (count > 10) {
109
+ info(`Showing first 10 of ${count} escrows`);
110
+ }
111
+ } catch (err) {
112
+ error(`Failed to list escrows: ${err}`);
113
+ process.exit(1);
114
+ }
115
+ });
116
+
117
+ // plob escrow get
118
+ cmd
119
+ .command('get')
120
+ .description('Get escrow details')
121
+ .argument('<id>', 'Escrow ID')
122
+ .option('--json', 'Output as JSON')
123
+ .action(async (id: string, options: OutputOptions) => {
124
+ try {
125
+ const escrowId = BigInt(id);
126
+ const escrow = await getEscrow(escrowId);
127
+
128
+ if (outputJSON({
129
+ id: id,
130
+ sender: escrow.sender,
131
+ recipient: escrow.recipient,
132
+ amount: formatUSDC(escrow.amount),
133
+ token: escrow.token,
134
+ status: escrow.status,
135
+ }, options)) {
136
+ return;
137
+ }
138
+
139
+ console.log();
140
+ console.log('Escrow ID: ', id);
141
+ console.log('From: ', escrow.sender);
142
+ console.log('To: ', escrow.recipient);
143
+ console.log('Amount: ', formatUSDC(escrow.amount), 'USDC');
144
+ console.log('Token: ', escrow.token);
145
+ console.log('Status: ', formatStatus(escrow.status));
146
+ console.log();
147
+ } catch (err) {
148
+ error(`Failed to get escrow: ${err}`);
149
+ process.exit(1);
150
+ }
151
+ });
152
+
153
+ // plob escrow release
154
+ cmd
155
+ .command('release')
156
+ .description('Release an escrow')
157
+ .argument('<id>', 'Escrow ID')
158
+ .option('--yes', 'Skip confirmation')
159
+ .option('--json', 'Output as JSON')
160
+ .action(async (id: string, options: { yes?: boolean } & OutputOptions) => {
161
+ try {
162
+ const escrowId = BigInt(id);
163
+
164
+ // Get escrow details
165
+ const escrow = await getEscrow(escrowId);
166
+
167
+ // Verify sender
168
+ const address = getWalletAddress() as `0x${string}`;
169
+ if (escrow.sender.toLowerCase() !== address.toLowerCase()) {
170
+ error('You are not the sender of this escrow');
171
+ process.exit(1);
172
+ }
173
+
174
+ // Check status
175
+ if (escrow.status !== 1) { // 1 = active
176
+ error(`Escrow is not active (status: ${formatStatus(escrow.status)})`);
177
+ process.exit(1);
178
+ }
179
+
180
+ // Confirm
181
+ if (!options.yes) {
182
+ console.log();
183
+ console.log('Escrow details:');
184
+ console.log(' ID: ', id);
185
+ console.log(' To: ', escrow.recipient);
186
+ console.log(' Amount: ', formatUSDC(escrow.amount), 'USDC');
187
+ console.log();
188
+
189
+ const confirmed = await confirm('Release this escrow?');
190
+ if (!confirmed) {
191
+ info('Cancelled');
192
+ process.exit(0);
193
+ }
194
+ }
195
+
196
+ const txHash = await withSpinner(
197
+ 'Releasing escrow...',
198
+ async () => {
199
+ return await releaseEscrow(escrowId);
200
+ }
201
+ );
202
+
203
+ if (outputJSON({
204
+ txHash,
205
+ escrowId: id,
206
+ released: formatUSDC(escrow.amount),
207
+ }, options)) {
208
+ return;
209
+ }
210
+
211
+ success('Escrow released successfully!');
212
+ info(`Transaction: ${txHash}`);
213
+ info(`Released: ${formatUSDC(escrow.amount)} USDC`);
214
+ info(`Recipient: ${escrow.recipient}`);
215
+ } catch (err) {
216
+ error(`Failed to release escrow: ${err}`);
217
+ process.exit(1);
218
+ }
219
+ });
220
+
221
+ return cmd;
222
+ }
@@ -0,0 +1,56 @@
1
+ import { Command } from 'commander';
2
+ import { error, info, warning } from '../lib/display';
3
+
4
+ /**
5
+ * Mandate commands
6
+ * Note: Full mandate implementation requires additional contract functions
7
+ * This is a placeholder for future implementation
8
+ */
9
+ export function createMandateCommand(): Command {
10
+ const cmd = new Command('mandate')
11
+ .description('Manage payment mandates (coming soon)');
12
+
13
+ cmd
14
+ .command('create')
15
+ .description('Create a new mandate')
16
+ .option('--agent <address>', 'Agent address')
17
+ .option('--limit <amount>', 'Spending limit in USDC')
18
+ .option('--duration <days>', 'Duration in days')
19
+ .action(async () => {
20
+ warning('Mandate creation is not yet implemented');
21
+ info('This feature will be available in a future update');
22
+ console.log();
23
+ console.log('Mandates allow you to delegate spending permissions to agents');
24
+ console.log('with configurable limits and time restrictions.');
25
+ console.log();
26
+ });
27
+
28
+ cmd
29
+ .command('list')
30
+ .description('List your mandates')
31
+ .action(async () => {
32
+ warning('Mandate listing is not yet implemented');
33
+ info('This feature will be available in a future update');
34
+ });
35
+
36
+ cmd
37
+ .command('revoke')
38
+ .description('Revoke a mandate')
39
+ .argument('<id>', 'Mandate ID')
40
+ .action(async () => {
41
+ warning('Mandate revocation is not yet implemented');
42
+ info('This feature will be available in a future update');
43
+ });
44
+
45
+ cmd
46
+ .command('adjust')
47
+ .description('Adjust mandate limits')
48
+ .argument('<id>', 'Mandate ID')
49
+ .option('--limit <amount>', 'New spending limit')
50
+ .action(async () => {
51
+ warning('Mandate adjustment is not yet implemented');
52
+ info('This feature will be available in a future update');
53
+ });
54
+
55
+ return cmd;
56
+ }
@@ -0,0 +1,96 @@
1
+ import { Command } from 'commander';
2
+ import { createEscrow } from '../lib/contracts';
3
+ import { success, error, info, withSpinner, outputJSON, formatAddress, confirm } from '../lib/display';
4
+ import type { OutputOptions } from '../lib/types';
5
+
6
+ /**
7
+ * Simple pay command (wrapper around escrow create)
8
+ */
9
+ export function createPayCommand(): Command {
10
+ const cmd = new Command('pay')
11
+ .description('Execute payment (creates escrow)')
12
+ .requiredOption('--to <address>', 'Recipient address')
13
+ .requiredOption('--amount <amount>', 'Amount in USDC')
14
+ .option('--description <desc>', 'Payment description', 'Payment via PayLobster CLI')
15
+ .option('--mandate <id>', 'Mandate ID (not yet implemented)')
16
+ .option('--yes', 'Skip confirmation')
17
+ .option('--json', 'Output as JSON')
18
+ .action(async (options: {
19
+ to: string;
20
+ amount: string;
21
+ description: string;
22
+ mandate?: string;
23
+ yes?: boolean;
24
+ } & OutputOptions) => {
25
+ try {
26
+ // Validate address format
27
+ if (!options.to.startsWith('0x') || options.to.length !== 42) {
28
+ error('Invalid recipient address format');
29
+ process.exit(1);
30
+ }
31
+
32
+ // Validate amount
33
+ const amount = parseFloat(options.amount);
34
+ if (isNaN(amount) || amount <= 0) {
35
+ error('Invalid amount. Must be a positive number');
36
+ process.exit(1);
37
+ }
38
+
39
+ if (options.mandate) {
40
+ error('Mandate payments are not yet implemented');
41
+ info('Use plob escrow create instead');
42
+ process.exit(1);
43
+ }
44
+
45
+ // Confirm payment
46
+ if (!options.yes) {
47
+ console.log();
48
+ console.log('Payment details:');
49
+ console.log(' To: ', options.to);
50
+ console.log(' Amount: ', options.amount, 'USDC');
51
+ console.log(' Description: ', options.description);
52
+ console.log();
53
+
54
+ const confirmed = await confirm('Send this payment?');
55
+ if (!confirmed) {
56
+ info('Cancelled');
57
+ process.exit(0);
58
+ }
59
+ }
60
+
61
+ info(`Sending ${options.amount} USDC to ${formatAddress(options.to)}`);
62
+
63
+ const txHash = await withSpinner(
64
+ 'Processing payment...',
65
+ async () => {
66
+ return await createEscrow(
67
+ options.to as `0x${string}`,
68
+ options.amount,
69
+ options.description
70
+ );
71
+ }
72
+ );
73
+
74
+ if (outputJSON({
75
+ txHash: txHash.toString(),
76
+ to: options.to,
77
+ amount: options.amount,
78
+ description: options.description,
79
+ }, options)) {
80
+ return;
81
+ }
82
+
83
+ success('Payment sent successfully!');
84
+ info(`Transaction: ${txHash.toString()}`);
85
+ info(`Recipient: ${options.to}`);
86
+ info(`Amount: ${options.amount} USDC`);
87
+ console.log();
88
+ info('Note: Payment is held in escrow. Use `plob escrow release <id>` to release funds.');
89
+ } catch (err) {
90
+ error(`Failed to send payment: ${err}`);
91
+ process.exit(1);
92
+ }
93
+ });
94
+
95
+ return cmd;
96
+ }
@@ -0,0 +1,57 @@
1
+ import { Command } from 'commander';
2
+ import { registerAgent, getAgentInfo } from '../lib/contracts';
3
+ import { getWalletAddress } from '../lib/wallet';
4
+ import { success, error, info, withSpinner, outputJSON } from '../lib/display';
5
+ import type { OutputOptions } from '../lib/types';
6
+
7
+ export function createRegisterCommand(): Command {
8
+ const cmd = new Command('register')
9
+ .description('Register agent identity on-chain')
10
+ .requiredOption('--name <name>', 'Agent name')
11
+ .requiredOption('--capabilities <capabilities>', 'Comma-separated capabilities (e.g., "code-review,bug-fix")')
12
+ .option('--json', 'Output as JSON')
13
+ .action(async (options: { name: string; capabilities: string } & OutputOptions) => {
14
+ try {
15
+ // Check if already registered
16
+ const address = getWalletAddress() as `0x${string}`;
17
+ const agentInfo = await getAgentInfo(address);
18
+
19
+ if (agentInfo.registered) {
20
+ error('Agent is already registered');
21
+ info(`Current name: ${agentInfo.name}`);
22
+ info(`Token ID: ${agentInfo.tokenId.toString()}`);
23
+ process.exit(1);
24
+ }
25
+
26
+ // Register
27
+ const txHash = await withSpinner(
28
+ 'Registering agent on-chain...',
29
+ async () => {
30
+ return await registerAgent(options.name, options.capabilities);
31
+ }
32
+ );
33
+
34
+ // Get updated info
35
+ const updatedInfo = await getAgentInfo(address);
36
+
37
+ if (outputJSON({
38
+ txHash: txHash.toString(),
39
+ agentId: updatedInfo.tokenId.toString(),
40
+ name: updatedInfo.name,
41
+ address,
42
+ }, options)) {
43
+ return;
44
+ }
45
+
46
+ success('Agent registered successfully!');
47
+ info(`Name: ${updatedInfo.name}`);
48
+ info(`Agent ID: ${updatedInfo.tokenId.toString()}`);
49
+ info(`Transaction: ${txHash.toString()}`);
50
+ } catch (err) {
51
+ error(`Failed to register agent: ${err}`);
52
+ process.exit(1);
53
+ }
54
+ });
55
+
56
+ return cmd;
57
+ }
@@ -0,0 +1,84 @@
1
+ import { Command } from 'commander';
2
+ import { getReputation, getAgentInfo } from '../lib/contracts';
3
+ import { error, outputJSON, printReputation, header } from '../lib/display';
4
+ import type { OutputOptions } from '../lib/types';
5
+
6
+ export function createReputationCommand(): Command {
7
+ const cmd = new Command('reputation')
8
+ .description('Check reputation score')
9
+ .argument('[address]', 'Address to check (default: your wallet)')
10
+ .option('--json', 'Output as JSON')
11
+ .action(async (addressArg: string | undefined, options: OutputOptions) => {
12
+ try {
13
+ let address: `0x${string}`;
14
+
15
+ if (addressArg) {
16
+ // Validate address format
17
+ if (!addressArg.startsWith('0x') || addressArg.length !== 42) {
18
+ error('Invalid address format');
19
+ process.exit(1);
20
+ }
21
+ address = addressArg as `0x${string}`;
22
+ } else {
23
+ // Use wallet address
24
+ const { getWalletAddress } = await import('../lib/wallet');
25
+ address = getWalletAddress() as `0x${string}`;
26
+ }
27
+
28
+ // Fetch reputation and agent info
29
+ const [reputation, agentInfo] = await Promise.all([
30
+ getReputation(address),
31
+ getAgentInfo(address),
32
+ ]);
33
+
34
+ const reputationScore = Number(reputation.score);
35
+ const trustVector = Number(reputation.trustVector);
36
+
37
+ if (outputJSON({
38
+ address,
39
+ name: agentInfo.name,
40
+ registered: agentInfo.registered,
41
+ reputation: {
42
+ score: reputationScore,
43
+ trustVector,
44
+ },
45
+ }, options)) {
46
+ return;
47
+ }
48
+
49
+ // Pretty output
50
+ header('Reputation Report');
51
+ console.log();
52
+ console.log('Address: ', address);
53
+
54
+ if (agentInfo.registered) {
55
+ console.log('Name: ', agentInfo.name);
56
+ console.log('Agent ID: ', agentInfo.tokenId.toString());
57
+ } else {
58
+ console.log('Status: ', 'Not registered');
59
+ }
60
+
61
+ console.log();
62
+ console.log('Reputation: ', printReputation(reputationScore));
63
+ console.log('Trust: ', trustVector);
64
+ console.log();
65
+
66
+ // Add interpretation
67
+ if (reputationScore >= 80) {
68
+ console.log('✅ Excellent reputation - highly trusted');
69
+ } else if (reputationScore >= 60) {
70
+ console.log('⚠️ Good reputation - generally trusted');
71
+ } else if (reputationScore >= 40) {
72
+ console.log('⚠️ Fair reputation - proceed with caution');
73
+ } else {
74
+ console.log('❌ Low reputation - high risk');
75
+ }
76
+ console.log();
77
+ } catch (err) {
78
+ error(`Failed to fetch reputation: ${err}`);
79
+ process.exit(1);
80
+ }
81
+ });
82
+
83
+ return cmd;
84
+ }