clawmoney 0.1.0 → 0.3.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.
@@ -0,0 +1,7 @@
1
+ interface BrowseOptions {
2
+ type?: string;
3
+ status?: string;
4
+ limit?: string;
5
+ }
6
+ export declare function browseCommand(options: BrowseOptions): Promise<void>;
7
+ export {};
@@ -0,0 +1,102 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { apiGet } from '../utils/api.js';
4
+ import { loadConfig } from '../utils/config.js';
5
+ function formatUsd(amount, decimals = 6) {
6
+ if (amount === undefined || amount === null)
7
+ return '-';
8
+ const num = typeof amount === 'string' ? parseFloat(amount) : amount;
9
+ if (isNaN(num))
10
+ return '-';
11
+ const usd = num / Math.pow(10, decimals);
12
+ return `$${usd.toFixed(2)}`;
13
+ }
14
+ function truncate(str, maxLen) {
15
+ if (!str)
16
+ return '-';
17
+ return str.length > maxLen ? str.slice(0, maxLen - 1) + '...' : str;
18
+ }
19
+ function printBoostTable(tasks) {
20
+ if (tasks.length === 0) {
21
+ console.log(chalk.dim(' No boost tasks found.'));
22
+ return;
23
+ }
24
+ // Header
25
+ console.log(chalk.bold(` ${'ID'.padEnd(8)} ${'Title'.padEnd(30)} ${'Reward'.padEnd(10)} ${'Budget'.padEnd(10)} ${'Joined'.padEnd(8)} ${'Status'.padEnd(10)}`));
26
+ console.log(chalk.dim(' ' + '-'.repeat(80)));
27
+ for (const task of tasks) {
28
+ const id = String(task.id).slice(0, 7);
29
+ const title = truncate(task.title || task.tweet_url, 28);
30
+ const reward = formatUsd(task.reward_per_user);
31
+ const budget = formatUsd(task.total_budget);
32
+ const joined = String(task.participants_count ?? '-');
33
+ const status = task.status || '-';
34
+ console.log(` ${chalk.cyan(id.padEnd(8))} ${title.padEnd(30)} ${chalk.green(reward.padEnd(10))} ${budget.padEnd(10)} ${joined.padEnd(8)} ${status.padEnd(10)}`);
35
+ }
36
+ }
37
+ function printHireTable(tasks) {
38
+ if (tasks.length === 0) {
39
+ console.log(chalk.dim(' No hire tasks found.'));
40
+ return;
41
+ }
42
+ // Header
43
+ console.log(chalk.bold(` ${'ID'.padEnd(8)} ${'Title'.padEnd(30)} ${'Budget'.padEnd(10)} ${'Subs'.padEnd(6)} ${'Platform'.padEnd(10)} ${'Ends'.padEnd(12)}`));
44
+ console.log(chalk.dim(' ' + '-'.repeat(78)));
45
+ for (const task of tasks) {
46
+ const id = String(task.id).slice(0, 7);
47
+ const title = truncate(task.title, 28);
48
+ const budget = formatUsd(task.total_budget);
49
+ const subs = String(task.submission_count ?? '-');
50
+ const platform = task.platform || 'twitter';
51
+ const ends = task.end_time ? new Date(task.end_time).toLocaleDateString() : '-';
52
+ console.log(` ${chalk.cyan(id.padEnd(8))} ${title.padEnd(30)} ${chalk.green(budget.padEnd(10))} ${subs.padEnd(6)} ${platform.padEnd(10)} ${ends.padEnd(12)}`);
53
+ }
54
+ }
55
+ export async function browseCommand(options) {
56
+ const config = loadConfig();
57
+ const apiKey = config?.api_key;
58
+ const taskType = options.type || 'boost';
59
+ const status = options.status || 'active';
60
+ const limit = parseInt(options.limit || '10', 10);
61
+ console.log('');
62
+ if (taskType === 'hire' || taskType === 'all') {
63
+ const hireSpinner = ora('Fetching hire tasks...').start();
64
+ try {
65
+ const resp = await apiGet(`/api/v1/hire/?status=${status}&sort_by=total_budget&sort_order=desc&limit=${limit}`, apiKey);
66
+ if (!resp.ok) {
67
+ hireSpinner.fail(`Failed to fetch hire tasks (${resp.status})`);
68
+ }
69
+ else {
70
+ const body = resp.data;
71
+ const tasks = (body.data || (Array.isArray(body) ? body : []));
72
+ hireSpinner.succeed(`Hire Tasks (${tasks.length})`);
73
+ printHireTable(tasks);
74
+ }
75
+ }
76
+ catch (err) {
77
+ hireSpinner.fail('Failed to fetch hire tasks');
78
+ console.error(chalk.red(err.message));
79
+ }
80
+ console.log('');
81
+ }
82
+ if (taskType === 'boost' || taskType === 'all') {
83
+ const boostSpinner = ora('Fetching boost tasks...').start();
84
+ try {
85
+ const resp = await apiGet(`/api/v1/tasks/?status=${status}&sort=reward&limit=${limit}`, apiKey);
86
+ if (!resp.ok) {
87
+ boostSpinner.fail(`Failed to fetch boost tasks (${resp.status})`);
88
+ }
89
+ else {
90
+ const body = resp.data;
91
+ const tasks = (body.data || (Array.isArray(body) ? body : []));
92
+ boostSpinner.succeed(`Boost Tasks (${tasks.length})`);
93
+ printBoostTable(tasks);
94
+ }
95
+ }
96
+ catch (err) {
97
+ boostSpinner.fail('Failed to fetch boost tasks');
98
+ console.error(chalk.red(err.message));
99
+ }
100
+ console.log('');
101
+ }
102
+ }
@@ -0,0 +1,10 @@
1
+ interface SubmitOptions {
2
+ url: string;
3
+ text?: string;
4
+ }
5
+ interface VerifyOptions {
6
+ witness?: boolean;
7
+ }
8
+ export declare function hireSubmitCommand(taskId: string, options: SubmitOptions): Promise<void>;
9
+ export declare function hireVerifyCommand(taskId: string, options: VerifyOptions): Promise<void>;
10
+ export {};
@@ -0,0 +1,109 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { apiPost } from '../utils/api.js';
4
+ import { awalExec } from '../utils/awal.js';
5
+ import { requireConfig } from '../utils/config.js';
6
+ import { prompt, confirm } from '../utils/prompt.js';
7
+ export async function hireSubmitCommand(taskId, options) {
8
+ const config = requireConfig();
9
+ console.log('');
10
+ const spinner = ora(`Submitting proof for task ${taskId}...`).start();
11
+ try {
12
+ const body = {
13
+ proof_url: options.url,
14
+ };
15
+ if (options.text) {
16
+ body.content = options.text;
17
+ }
18
+ const resp = await apiPost(`/api/v1/hire/${taskId}/submit`, body, config.api_key);
19
+ if (!resp.ok) {
20
+ spinner.fail('Submission failed');
21
+ console.error(chalk.red(JSON.stringify(resp.data)));
22
+ return;
23
+ }
24
+ spinner.succeed('Proof submitted successfully');
25
+ if (resp.data.id) {
26
+ console.log(chalk.dim(` Submission ID: ${resp.data.id}`));
27
+ }
28
+ if (resp.data.message) {
29
+ console.log(chalk.dim(` ${resp.data.message}`));
30
+ }
31
+ }
32
+ catch (err) {
33
+ spinner.fail('Submission failed');
34
+ console.error(chalk.red(err.message));
35
+ }
36
+ console.log('');
37
+ }
38
+ export async function hireVerifyCommand(taskId, options) {
39
+ const config = requireConfig();
40
+ console.log('');
41
+ if (options.witness) {
42
+ // Witness verification via x402
43
+ const tweetUrl = await prompt(chalk.cyan('? ') + 'Enter the tweet URL to verify: ');
44
+ if (!tweetUrl) {
45
+ console.log(chalk.red('Tweet URL is required for witness verification.'));
46
+ return;
47
+ }
48
+ // Extract tweet ID from URL
49
+ const tweetIdMatch = tweetUrl.match(/status\/(\d+)/);
50
+ if (!tweetIdMatch) {
51
+ console.log(chalk.red('Could not extract tweet ID from URL.'));
52
+ return;
53
+ }
54
+ const tweetId = tweetIdMatch[1];
55
+ const witnessSpinner = ora('Paying for witness verification via x402...').start();
56
+ try {
57
+ const witnessResult = await awalExec([
58
+ 'x402',
59
+ 'pay',
60
+ `https://witness.bnbot.ai/x/${tweetId}`,
61
+ ]);
62
+ witnessSpinner.succeed('Witness verification paid');
63
+ console.log(chalk.dim(` Response: ${JSON.stringify(witnessResult.data)}`));
64
+ // Submit the witness proof
65
+ const submitSpinner = ora('Submitting witness proof...').start();
66
+ const resp = await apiPost(`/api/v1/hire/${taskId}/verify`, {
67
+ type: 'witness',
68
+ tweet_id: tweetId,
69
+ witness_data: witnessResult.data,
70
+ }, config.api_key);
71
+ if (!resp.ok) {
72
+ submitSpinner.fail('Witness verification submission failed');
73
+ console.error(chalk.red(JSON.stringify(resp.data)));
74
+ }
75
+ else {
76
+ submitSpinner.succeed('Witness verification submitted');
77
+ }
78
+ }
79
+ catch (err) {
80
+ witnessSpinner.fail('Witness verification failed');
81
+ console.error(chalk.red(err.message));
82
+ }
83
+ }
84
+ else {
85
+ // Manual verification
86
+ console.log(chalk.bold(` Manual verification for task ${taskId}`));
87
+ console.log('');
88
+ const approved = await confirm('Approve this submission?', false);
89
+ const spinner = ora('Submitting verification...').start();
90
+ try {
91
+ const resp = await apiPost(`/api/v1/hire/${taskId}/verify`, {
92
+ type: 'manual',
93
+ approved,
94
+ }, config.api_key);
95
+ if (!resp.ok) {
96
+ spinner.fail('Verification submission failed');
97
+ console.error(chalk.red(JSON.stringify(resp.data)));
98
+ }
99
+ else {
100
+ spinner.succeed(`Verification submitted: ${approved ? 'APPROVED' : 'REJECTED'}`);
101
+ }
102
+ }
103
+ catch (err) {
104
+ spinner.fail('Verification failed');
105
+ console.error(chalk.red(err.message));
106
+ }
107
+ }
108
+ console.log('');
109
+ }
@@ -0,0 +1,5 @@
1
+ interface ServeOptions {
2
+ port?: string;
3
+ }
4
+ export declare function serveCommand(options: ServeOptions): Promise<void>;
5
+ export {};
@@ -0,0 +1,38 @@
1
+ import chalk from 'chalk';
2
+ import { BridgeServer } from '../utils/bridge.js';
3
+ export async function serveCommand(options) {
4
+ const port = parseInt(options.port || '18900', 10);
5
+ const server = new BridgeServer(port);
6
+ try {
7
+ await server.start();
8
+ }
9
+ catch (err) {
10
+ console.error(chalk.red(err.message));
11
+ process.exit(1);
12
+ }
13
+ console.log('');
14
+ console.log(chalk.green(' ClawMoney Bridge Server running'));
15
+ console.log(chalk.dim(` WebSocket listening on ws://127.0.0.1:${port}`));
16
+ console.log('');
17
+ console.log(chalk.dim(' Waiting for BNBot Chrome Extension to connect...'));
18
+ console.log(chalk.dim(' Press Ctrl+C to stop'));
19
+ console.log('');
20
+ // Check extension connection periodically
21
+ const statusInterval = setInterval(() => {
22
+ if (server.isExtensionConnected()) {
23
+ const ver = server.getExtensionVersion();
24
+ console.log(chalk.green(` Extension connected${ver ? ` (v${ver})` : ''}`));
25
+ clearInterval(statusInterval);
26
+ }
27
+ }, 2000);
28
+ // Graceful shutdown
29
+ const shutdown = () => {
30
+ console.log('');
31
+ console.log(chalk.dim(' Shutting down...'));
32
+ clearInterval(statusInterval);
33
+ server.stop();
34
+ process.exit(0);
35
+ };
36
+ process.on('SIGINT', shutdown);
37
+ process.on('SIGTERM', shutdown);
38
+ }
@@ -0,0 +1 @@
1
+ export declare function setupCommand(): Promise<void>;
@@ -0,0 +1,208 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { awalExec } from '../utils/awal.js';
4
+ import { apiGet, apiPost } from '../utils/api.js';
5
+ import { loadConfig, saveConfig, getConfigPath } from '../utils/config.js';
6
+ import { prompt } from '../utils/prompt.js';
7
+ import { execSync } from 'node:child_process';
8
+ export async function setupCommand() {
9
+ console.log(chalk.bold('\n ClawMoney Agent Setup\n'));
10
+ // Step 1: Check and install dependencies
11
+ const depSpinner = ora('Checking dependencies...').start();
12
+ try {
13
+ // Check if awal is available
14
+ try {
15
+ execSync('npx awal --version', { stdio: 'pipe' });
16
+ depSpinner.succeed('awal is available');
17
+ }
18
+ catch {
19
+ depSpinner.text = 'Installing awal...';
20
+ try {
21
+ execSync('npm install -g awal', { stdio: 'pipe' });
22
+ depSpinner.succeed('awal installed');
23
+ }
24
+ catch {
25
+ depSpinner.warn('Could not install awal globally. Will use npx.');
26
+ }
27
+ }
28
+ }
29
+ catch (err) {
30
+ depSpinner.fail('Failed to check dependencies');
31
+ console.error(chalk.red(err.message));
32
+ return;
33
+ }
34
+ // Step 2: Check wallet status
35
+ const walletSpinner = ora('Checking wallet status...').start();
36
+ let walletAddress = '';
37
+ let needsLogin = false;
38
+ try {
39
+ const status = await awalExec(['status']);
40
+ const statusData = status.data;
41
+ if (statusData.authenticated || statusData.loggedIn || statusData.address) {
42
+ walletAddress = statusData.address || '';
43
+ walletSpinner.succeed(`Wallet connected${walletAddress ? `: ${walletAddress}` : ''}`);
44
+ }
45
+ else {
46
+ needsLogin = true;
47
+ walletSpinner.info('Wallet not authenticated');
48
+ }
49
+ }
50
+ catch {
51
+ needsLogin = true;
52
+ walletSpinner.info('Wallet not authenticated');
53
+ }
54
+ // Step 3: Ask for email
55
+ const email = await prompt(chalk.cyan('? ') + 'Enter your email: ');
56
+ if (!email || !email.includes('@')) {
57
+ console.log(chalk.red('Invalid email address.'));
58
+ return;
59
+ }
60
+ // Step 4: Login wallet if needed
61
+ if (needsLogin) {
62
+ const loginSpinner = ora('Logging in to wallet...').start();
63
+ try {
64
+ const loginResult = await awalExec(['auth', 'login', email]);
65
+ const loginData = loginResult.data;
66
+ const flowId = loginData.flowId || loginData.flow_id;
67
+ if (!flowId) {
68
+ loginSpinner.fail('Login failed: no flow ID returned');
69
+ console.log(chalk.dim('Response:'), loginResult.raw);
70
+ return;
71
+ }
72
+ loginSpinner.info('OTP sent to your email');
73
+ const otp = await prompt(chalk.cyan('? ') + 'Enter OTP from email: ');
74
+ if (!otp) {
75
+ console.log(chalk.red('OTP is required.'));
76
+ return;
77
+ }
78
+ const verifySpinner = ora('Verifying OTP...').start();
79
+ try {
80
+ const verifyResult = await awalExec(['auth', 'verify', String(flowId), otp]);
81
+ verifySpinner.succeed('Wallet authenticated');
82
+ // Get wallet address
83
+ const addrResult = await awalExec(['address']);
84
+ const addrData = addrResult.data;
85
+ walletAddress = addrData.address || '';
86
+ if (walletAddress) {
87
+ console.log(chalk.dim(` Wallet: ${walletAddress}`));
88
+ }
89
+ }
90
+ catch (err) {
91
+ verifySpinner.fail('OTP verification failed');
92
+ console.error(chalk.red(err.message));
93
+ return;
94
+ }
95
+ }
96
+ catch (err) {
97
+ loginSpinner.fail('Wallet login failed');
98
+ console.error(chalk.red(err.message));
99
+ return;
100
+ }
101
+ }
102
+ // If we still don't have address, try fetching it
103
+ if (!walletAddress) {
104
+ try {
105
+ const addrResult = await awalExec(['address']);
106
+ const addrData = addrResult.data;
107
+ walletAddress = addrData.address || '';
108
+ }
109
+ catch {
110
+ // continue without address
111
+ }
112
+ }
113
+ // Step 5: Check agent status
114
+ const agentSpinner = ora('Checking agent status...').start();
115
+ try {
116
+ const checkResp = await apiGet(`/api/v1/claw-agents/check-email?email=${encodeURIComponent(email)}`);
117
+ if (!checkResp.ok) {
118
+ agentSpinner.fail(`API error: ${checkResp.status}`);
119
+ return;
120
+ }
121
+ const checkData = checkResp.data;
122
+ if (!checkData.exists || checkData.status === 'UNCLAIMED') {
123
+ // Step 6: Register new agent
124
+ agentSpinner.text = 'Registering agent...';
125
+ const registerBody = { email };
126
+ if (walletAddress) {
127
+ registerBody.wallet_address = walletAddress;
128
+ }
129
+ const regResp = await apiPost('/api/v1/claw-agents/register', registerBody);
130
+ if (!regResp.ok) {
131
+ agentSpinner.fail('Registration failed');
132
+ console.error(chalk.red(JSON.stringify(regResp.data)));
133
+ return;
134
+ }
135
+ const regData = regResp.data;
136
+ agentSpinner.succeed(`Agent registered: ${regData.slug}`);
137
+ saveConfig({
138
+ api_key: regData.api_key,
139
+ agent_id: regData.agent_id,
140
+ agent_slug: regData.slug,
141
+ email,
142
+ wallet_address: walletAddress || undefined,
143
+ });
144
+ }
145
+ else if (checkData.status === 'ACTIVE') {
146
+ // Step 7: Login existing agent via OTP
147
+ agentSpinner.info(`Agent found: ${checkData.slug || checkData.agent_id}`);
148
+ const loginSpinner2 = ora('Sending login OTP...').start();
149
+ const loginResp = await apiPost('/api/v1/claw-agents/login', { email });
150
+ if (!loginResp.ok) {
151
+ loginSpinner2.fail('Agent login failed');
152
+ console.error(chalk.red(JSON.stringify(loginResp.data)));
153
+ return;
154
+ }
155
+ loginSpinner2.info('OTP sent to your email');
156
+ const agentOtp = await prompt(chalk.cyan('? ') + 'Enter agent login OTP: ');
157
+ const verifySpinner2 = ora('Verifying...').start();
158
+ const verifyResp = await apiPost('/api/v1/claw-agents/login/verify', {
159
+ email,
160
+ otp: agentOtp,
161
+ flow_id: loginResp.data.flow_id,
162
+ });
163
+ if (!verifyResp.ok) {
164
+ verifySpinner2.fail('Agent login verification failed');
165
+ console.error(chalk.red(JSON.stringify(verifyResp.data)));
166
+ return;
167
+ }
168
+ const loginData = verifyResp.data;
169
+ verifySpinner2.succeed('Agent authenticated');
170
+ saveConfig({
171
+ api_key: loginData.api_key,
172
+ agent_id: loginData.agent_id,
173
+ agent_slug: loginData.slug,
174
+ email,
175
+ wallet_address: walletAddress || undefined,
176
+ });
177
+ }
178
+ else {
179
+ agentSpinner.warn(`Agent status: ${checkData.status}`);
180
+ console.log(chalk.yellow('Please contact support if you need help.'));
181
+ return;
182
+ }
183
+ }
184
+ catch (err) {
185
+ agentSpinner.fail('Failed to check agent status');
186
+ console.error(chalk.red(err.message));
187
+ return;
188
+ }
189
+ // Step 8: Print summary
190
+ const config = loadConfig();
191
+ console.log('');
192
+ console.log(chalk.green.bold(' Setup complete!'));
193
+ console.log('');
194
+ if (config) {
195
+ console.log(chalk.dim(` Agent ID: ${config.agent_id}`));
196
+ console.log(chalk.dim(` Agent Slug: ${config.agent_slug}`));
197
+ if (walletAddress) {
198
+ console.log(chalk.dim(` Wallet: ${walletAddress}`));
199
+ }
200
+ console.log(chalk.dim(` Config: ${getConfigPath()}`));
201
+ }
202
+ console.log('');
203
+ console.log(` Next steps:`);
204
+ console.log(` ${chalk.cyan('clawmoney browse')} Browse available tasks`);
205
+ console.log(` ${chalk.cyan('clawmoney wallet balance')} Check your wallet balance`);
206
+ console.log(` ${chalk.cyan('clawmoney hire submit')} Submit a task proof`);
207
+ console.log('');
208
+ }
@@ -0,0 +1,10 @@
1
+ interface TweetOptions {
2
+ media?: string;
3
+ draft?: boolean;
4
+ }
5
+ /**
6
+ * Post a tweet via BNBot Chrome Extension through the Bridge server.
7
+ * Requires `clawmoney serve` to be running.
8
+ */
9
+ export declare function tweetCommand(text: string, options: TweetOptions): Promise<void>;
10
+ export {};
@@ -0,0 +1,50 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { sendAction } from '../utils/bridge.js';
4
+ /**
5
+ * Post a tweet via BNBot Chrome Extension through the Bridge server.
6
+ * Requires `clawmoney serve` to be running.
7
+ */
8
+ export async function tweetCommand(text, options) {
9
+ const isDraft = options.draft || false;
10
+ console.log('');
11
+ console.log(chalk.dim(` ${isDraft ? 'Drafting' : 'Posting'} tweet: "${text.slice(0, 80)}${text.length > 80 ? '...' : ''}"`));
12
+ if (options.media) {
13
+ console.log(chalk.dim(` Media: ${options.media}`));
14
+ }
15
+ console.log('');
16
+ const spinner = ora(isDraft ? 'Filling tweet draft...' : 'Posting tweet...').start();
17
+ try {
18
+ const params = {
19
+ text,
20
+ draftOnly: isDraft,
21
+ };
22
+ if (options.media) {
23
+ params.media = [{ type: 'image', url: options.media }];
24
+ }
25
+ const result = await sendAction('post_tweet', params);
26
+ if (!result.success) {
27
+ spinner.fail(result.error || 'Failed');
28
+ return;
29
+ }
30
+ if (isDraft) {
31
+ spinner.succeed('Tweet draft ready — review and post manually');
32
+ }
33
+ else {
34
+ spinner.succeed('Tweet posted');
35
+ const data = result.data;
36
+ if (data?.url || data?.tweet_url) {
37
+ console.log(` ${chalk.dim('URL:')} ${chalk.cyan(data.url || data.tweet_url)}`);
38
+ }
39
+ }
40
+ }
41
+ catch (err) {
42
+ spinner.fail('Failed');
43
+ console.error(chalk.red(err.message));
44
+ console.log('');
45
+ console.log(chalk.dim(' Make sure:'));
46
+ console.log(chalk.dim(' 1. clawmoney serve is running'));
47
+ console.log(chalk.dim(' 2. BNBot Chrome Extension is open on a Twitter tab'));
48
+ }
49
+ console.log('');
50
+ }
@@ -0,0 +1,4 @@
1
+ export declare function walletStatusCommand(): Promise<void>;
2
+ export declare function walletBalanceCommand(): Promise<void>;
3
+ export declare function walletAddressCommand(): Promise<void>;
4
+ export declare function walletSendCommand(amount: string, to: string): Promise<void>;
@@ -0,0 +1,84 @@
1
+ import chalk from 'chalk';
2
+ import ora from 'ora';
3
+ import { awalExec } from '../utils/awal.js';
4
+ export async function walletStatusCommand() {
5
+ const spinner = ora('Getting wallet status...').start();
6
+ try {
7
+ const result = await awalExec(['status']);
8
+ spinner.succeed('Wallet Status');
9
+ console.log('');
10
+ const data = result.data;
11
+ for (const [key, value] of Object.entries(data)) {
12
+ console.log(` ${chalk.dim(key + ':')} ${value}`);
13
+ }
14
+ console.log('');
15
+ }
16
+ catch (err) {
17
+ spinner.fail('Failed to get wallet status');
18
+ console.error(chalk.red(err.message));
19
+ }
20
+ }
21
+ export async function walletBalanceCommand() {
22
+ const spinner = ora('Getting wallet balance...').start();
23
+ try {
24
+ const result = await awalExec(['balance']);
25
+ spinner.succeed('Wallet Balance');
26
+ console.log('');
27
+ const data = result.data;
28
+ if (typeof data === 'object' && data !== null) {
29
+ for (const [key, value] of Object.entries(data)) {
30
+ console.log(` ${chalk.dim(key + ':')} ${chalk.green(String(value))}`);
31
+ }
32
+ }
33
+ else {
34
+ console.log(` ${result.raw}`);
35
+ }
36
+ console.log('');
37
+ }
38
+ catch (err) {
39
+ spinner.fail('Failed to get wallet balance');
40
+ console.error(chalk.red(err.message));
41
+ }
42
+ }
43
+ export async function walletAddressCommand() {
44
+ const spinner = ora('Getting wallet address...').start();
45
+ try {
46
+ const result = await awalExec(['address']);
47
+ spinner.succeed('Wallet Address');
48
+ console.log('');
49
+ const data = result.data;
50
+ const address = data.address || result.raw.trim();
51
+ console.log(` ${chalk.cyan(String(address))}`);
52
+ console.log('');
53
+ }
54
+ catch (err) {
55
+ spinner.fail('Failed to get wallet address');
56
+ console.error(chalk.red(err.message));
57
+ }
58
+ }
59
+ export async function walletSendCommand(amount, to) {
60
+ console.log('');
61
+ console.log(chalk.bold(' Send Transaction'));
62
+ console.log(chalk.dim(` Amount: ${amount}`));
63
+ console.log(chalk.dim(` To: ${to}`));
64
+ console.log('');
65
+ const spinner = ora('Sending...').start();
66
+ try {
67
+ const result = await awalExec(['send', amount, to]);
68
+ spinner.succeed('Transaction sent');
69
+ console.log('');
70
+ const data = result.data;
71
+ if (data.txHash || data.hash || data.transactionHash) {
72
+ const hash = data.txHash || data.hash || data.transactionHash;
73
+ console.log(` ${chalk.dim('TX Hash:')} ${chalk.cyan(String(hash))}`);
74
+ }
75
+ else {
76
+ console.log(` ${result.raw}`);
77
+ }
78
+ console.log('');
79
+ }
80
+ catch (err) {
81
+ spinner.fail('Send failed');
82
+ console.error(chalk.red(err.message));
83
+ }
84
+ }