clawmoney 0.2.0 → 0.4.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.
- package/dist/commands/serve.d.ts +5 -0
- package/dist/commands/serve.js +38 -0
- package/dist/commands/tweet.d.ts +3 -3
- package/dist/commands/tweet.js +26 -45
- package/dist/index.js +16 -0
- package/dist/utils/bridge.d.ts +37 -0
- package/dist/utils/bridge.js +259 -0
- package/package.json +8 -7
|
@@ -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
|
+
}
|
package/dist/commands/tweet.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
interface TweetOptions {
|
|
2
2
|
media?: string;
|
|
3
|
+
draft?: boolean;
|
|
3
4
|
}
|
|
4
5
|
/**
|
|
5
|
-
* Post a tweet via
|
|
6
|
-
*
|
|
7
|
-
* since it requires the BNBot Chrome Extension to be running.
|
|
6
|
+
* Post a tweet via BNBot Chrome Extension through the Bridge server.
|
|
7
|
+
* Requires `clawmoney serve` to be running.
|
|
8
8
|
*/
|
|
9
9
|
export declare function tweetCommand(text: string, options: TweetOptions): Promise<void>;
|
|
10
10
|
export {};
|
package/dist/commands/tweet.js
CHANGED
|
@@ -1,69 +1,50 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import ora from 'ora';
|
|
3
|
-
import {
|
|
3
|
+
import { sendAction } from '../utils/bridge.js';
|
|
4
4
|
/**
|
|
5
|
-
* Post a tweet via
|
|
6
|
-
*
|
|
7
|
-
* since it requires the BNBot Chrome Extension to be running.
|
|
5
|
+
* Post a tweet via BNBot Chrome Extension through the Bridge server.
|
|
6
|
+
* Requires `clawmoney serve` to be running.
|
|
8
7
|
*/
|
|
9
8
|
export async function tweetCommand(text, options) {
|
|
9
|
+
const isDraft = options.draft || false;
|
|
10
10
|
console.log('');
|
|
11
|
-
console.log(chalk.dim(` Posting tweet: "${text.slice(0, 80)}${text.length > 80 ? '...' : ''}"`));
|
|
11
|
+
console.log(chalk.dim(` ${isDraft ? 'Drafting' : 'Posting'} tweet: "${text.slice(0, 80)}${text.length > 80 ? '...' : ''}"`));
|
|
12
12
|
if (options.media) {
|
|
13
13
|
console.log(chalk.dim(` Media: ${options.media}`));
|
|
14
14
|
}
|
|
15
15
|
console.log('');
|
|
16
|
-
const spinner = ora('
|
|
16
|
+
const spinner = ora(isDraft ? 'Filling tweet draft...' : 'Posting tweet...').start();
|
|
17
17
|
try {
|
|
18
|
-
const
|
|
18
|
+
const params = {
|
|
19
|
+
text,
|
|
20
|
+
draftOnly: isDraft,
|
|
21
|
+
};
|
|
19
22
|
if (options.media) {
|
|
20
|
-
|
|
23
|
+
params.media = [{ type: 'image', url: options.media }];
|
|
21
24
|
}
|
|
22
|
-
const result = await
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
});
|
|
27
|
-
let stdout = '';
|
|
28
|
-
let stderr = '';
|
|
29
|
-
child.stdout.on('data', (chunk) => {
|
|
30
|
-
stdout += chunk.toString();
|
|
31
|
-
});
|
|
32
|
-
child.stderr.on('data', (chunk) => {
|
|
33
|
-
stderr += chunk.toString();
|
|
34
|
-
});
|
|
35
|
-
child.on('close', (code) => {
|
|
36
|
-
if (code !== 0) {
|
|
37
|
-
reject(new Error(stderr.trim() || `bnbot-cli exited with code ${code}`));
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
resolve(stdout.trim());
|
|
41
|
-
});
|
|
42
|
-
child.on('error', (err) => {
|
|
43
|
-
reject(new Error(`Failed to spawn bnbot-cli: ${err.message}`));
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
spinner.succeed('Tweet posted');
|
|
47
|
-
// Try to parse and display tweet URL
|
|
48
|
-
try {
|
|
49
|
-
const data = JSON.parse(result);
|
|
50
|
-
if (data.url || data.tweet_url) {
|
|
51
|
-
console.log(` ${chalk.dim('URL:')} ${chalk.cyan(data.url || data.tweet_url)}`);
|
|
52
|
-
}
|
|
25
|
+
const result = await sendAction('post_tweet', params);
|
|
26
|
+
if (!result.success) {
|
|
27
|
+
spinner.fail(result.error || 'Failed');
|
|
28
|
+
return;
|
|
53
29
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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)}`);
|
|
57
38
|
}
|
|
58
39
|
}
|
|
59
40
|
}
|
|
60
41
|
catch (err) {
|
|
61
|
-
spinner.fail('Failed
|
|
42
|
+
spinner.fail('Failed');
|
|
62
43
|
console.error(chalk.red(err.message));
|
|
63
44
|
console.log('');
|
|
64
45
|
console.log(chalk.dim(' Make sure:'));
|
|
65
|
-
console.log(chalk.dim(' 1.
|
|
66
|
-
console.log(chalk.dim(' 2.
|
|
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'));
|
|
67
48
|
}
|
|
68
49
|
console.log('');
|
|
69
50
|
}
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ import { browseCommand } from './commands/browse.js';
|
|
|
5
5
|
import { hireSubmitCommand, hireVerifyCommand } from './commands/hire.js';
|
|
6
6
|
import { walletStatusCommand, walletBalanceCommand, walletAddressCommand, walletSendCommand, } from './commands/wallet.js';
|
|
7
7
|
import { tweetCommand } from './commands/tweet.js';
|
|
8
|
+
import { serveCommand } from './commands/serve.js';
|
|
8
9
|
const program = new Command();
|
|
9
10
|
program
|
|
10
11
|
.name('clawmoney')
|
|
@@ -118,11 +119,26 @@ wallet
|
|
|
118
119
|
process.exit(1);
|
|
119
120
|
}
|
|
120
121
|
});
|
|
122
|
+
// serve
|
|
123
|
+
program
|
|
124
|
+
.command('serve')
|
|
125
|
+
.description('Start the bridge server for Chrome Extension communication')
|
|
126
|
+
.option('-p, --port <port>', 'WebSocket port', '18900')
|
|
127
|
+
.action(async (options) => {
|
|
128
|
+
try {
|
|
129
|
+
await serveCommand(options);
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
console.error(err.message);
|
|
133
|
+
process.exit(1);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
121
136
|
// tweet
|
|
122
137
|
program
|
|
123
138
|
.command('tweet <text>')
|
|
124
139
|
.description('Post a tweet via BNBot Chrome Extension')
|
|
125
140
|
.option('-m, --media <path>', 'Path to media file')
|
|
141
|
+
.option('-d, --draft', 'Draft mode: fill tweet composer without posting')
|
|
126
142
|
.action(async (text, options) => {
|
|
127
143
|
try {
|
|
128
144
|
await tweetCommand(text, options);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge — WebSocket server that sits between CLI commands and the Chrome Extension.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* clawmoney serve → starts WS server (port 18900)
|
|
6
|
+
* Chrome Extension → connects as client (localRelayManager)
|
|
7
|
+
* clawmoney tweet → connects as client, sends action, gets result via server
|
|
8
|
+
*
|
|
9
|
+
* The server keeps a persistent connection to the extension.
|
|
10
|
+
* CLI commands connect briefly, send an action, and disconnect after getting a result.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* The Bridge server — start with `clawmoney serve`
|
|
14
|
+
*/
|
|
15
|
+
export declare class BridgeServer {
|
|
16
|
+
private wss;
|
|
17
|
+
private extensionClient;
|
|
18
|
+
private pendingRequests;
|
|
19
|
+
private extensionVersion;
|
|
20
|
+
private port;
|
|
21
|
+
constructor(port?: number);
|
|
22
|
+
start(): Promise<void>;
|
|
23
|
+
private handleMessage;
|
|
24
|
+
stop(): void;
|
|
25
|
+
isExtensionConnected(): boolean;
|
|
26
|
+
getExtensionVersion(): string | null;
|
|
27
|
+
getPort(): number;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Send an action to the Chrome Extension.
|
|
31
|
+
* Auto-starts bridge server if none is running, then waits for extension to connect.
|
|
32
|
+
*/
|
|
33
|
+
export declare function sendAction(actionType: string, params: Record<string, unknown>, port?: number): Promise<{
|
|
34
|
+
success: boolean;
|
|
35
|
+
data?: unknown;
|
|
36
|
+
error?: string;
|
|
37
|
+
}>;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bridge — WebSocket server that sits between CLI commands and the Chrome Extension.
|
|
3
|
+
*
|
|
4
|
+
* Architecture:
|
|
5
|
+
* clawmoney serve → starts WS server (port 18900)
|
|
6
|
+
* Chrome Extension → connects as client (localRelayManager)
|
|
7
|
+
* clawmoney tweet → connects as client, sends action, gets result via server
|
|
8
|
+
*
|
|
9
|
+
* The server keeps a persistent connection to the extension.
|
|
10
|
+
* CLI commands connect briefly, send an action, and disconnect after getting a result.
|
|
11
|
+
*/
|
|
12
|
+
import { WebSocketServer, WebSocket } from 'ws';
|
|
13
|
+
import { randomUUID } from 'node:crypto';
|
|
14
|
+
const DEFAULT_PORT = 18900;
|
|
15
|
+
const ACTION_TIMEOUT = 60000;
|
|
16
|
+
/**
|
|
17
|
+
* The Bridge server — start with `clawmoney serve`
|
|
18
|
+
*/
|
|
19
|
+
export class BridgeServer {
|
|
20
|
+
wss = null;
|
|
21
|
+
extensionClient = null;
|
|
22
|
+
pendingRequests = new Map();
|
|
23
|
+
extensionVersion = null;
|
|
24
|
+
port;
|
|
25
|
+
constructor(port) {
|
|
26
|
+
this.port = port || DEFAULT_PORT;
|
|
27
|
+
}
|
|
28
|
+
start() {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
this.wss = new WebSocketServer({ port: this.port, host: '127.0.0.1' });
|
|
31
|
+
this.wss.on('listening', () => {
|
|
32
|
+
resolve();
|
|
33
|
+
});
|
|
34
|
+
this.wss.on('error', (error) => {
|
|
35
|
+
if (error.code === 'EADDRINUSE') {
|
|
36
|
+
reject(new Error(`Port ${this.port} already in use. Another serve instance may be running.`));
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
reject(error);
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
this.wss.on('connection', (ws) => {
|
|
43
|
+
// Determine if this is the extension or a CLI client
|
|
44
|
+
// Extension sends a 'status' message on connect
|
|
45
|
+
// CLI clients send an 'action' message
|
|
46
|
+
ws.on('message', (data) => {
|
|
47
|
+
try {
|
|
48
|
+
const message = JSON.parse(data.toString());
|
|
49
|
+
this.handleMessage(ws, message);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
// ignore
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
ws.on('close', () => {
|
|
56
|
+
if (this.extensionClient === ws) {
|
|
57
|
+
this.extensionClient = null;
|
|
58
|
+
this.extensionVersion = null;
|
|
59
|
+
// Reject all pending requests
|
|
60
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
61
|
+
clearTimeout(pending.timer);
|
|
62
|
+
pending.reject(new Error('Extension disconnected'));
|
|
63
|
+
this.pendingRequests.delete(id);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
handleMessage(ws, message) {
|
|
71
|
+
switch (message.type) {
|
|
72
|
+
case 'status':
|
|
73
|
+
// Extension connected
|
|
74
|
+
if (this.extensionClient && this.extensionClient !== ws && this.extensionClient.readyState === WebSocket.OPEN) {
|
|
75
|
+
this.extensionClient.close(1000, 'Replaced by new connection');
|
|
76
|
+
}
|
|
77
|
+
this.extensionClient = ws;
|
|
78
|
+
this.extensionVersion = message.version;
|
|
79
|
+
break;
|
|
80
|
+
case 'action':
|
|
81
|
+
// CLI client sending an action — forward to extension
|
|
82
|
+
if (!this.extensionClient || this.extensionClient.readyState !== WebSocket.OPEN) {
|
|
83
|
+
ws.send(JSON.stringify({
|
|
84
|
+
type: 'action_result',
|
|
85
|
+
requestId: message.requestId,
|
|
86
|
+
success: false,
|
|
87
|
+
error: 'Extension not connected. Make sure BNBot Chrome Extension is running on a Twitter tab.',
|
|
88
|
+
}));
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
// Store pending request keyed to the CLI client WebSocket
|
|
92
|
+
const requestId = message.requestId;
|
|
93
|
+
const timer = setTimeout(() => {
|
|
94
|
+
this.pendingRequests.delete(requestId);
|
|
95
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
96
|
+
ws.send(JSON.stringify({
|
|
97
|
+
type: 'action_result',
|
|
98
|
+
requestId,
|
|
99
|
+
success: false,
|
|
100
|
+
error: `Action '${message.actionType}' timed out`,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
}, ACTION_TIMEOUT);
|
|
104
|
+
this.pendingRequests.set(requestId, {
|
|
105
|
+
resolve: (result) => {
|
|
106
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
107
|
+
ws.send(JSON.stringify(result));
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
reject: (error) => {
|
|
111
|
+
if (ws.readyState === WebSocket.OPEN) {
|
|
112
|
+
ws.send(JSON.stringify({
|
|
113
|
+
type: 'action_result',
|
|
114
|
+
requestId,
|
|
115
|
+
success: false,
|
|
116
|
+
error: error.message,
|
|
117
|
+
}));
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
timer,
|
|
121
|
+
});
|
|
122
|
+
// Forward to extension
|
|
123
|
+
this.extensionClient.send(JSON.stringify(message));
|
|
124
|
+
break;
|
|
125
|
+
case 'action_result':
|
|
126
|
+
// Extension sending back a result — forward to CLI client
|
|
127
|
+
const pending = this.pendingRequests.get(message.requestId);
|
|
128
|
+
if (pending) {
|
|
129
|
+
clearTimeout(pending.timer);
|
|
130
|
+
this.pendingRequests.delete(message.requestId);
|
|
131
|
+
pending.resolve(message);
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
case 'heartbeat':
|
|
135
|
+
// Respond to heartbeat from extension
|
|
136
|
+
break;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
stop() {
|
|
140
|
+
if (this.extensionClient) {
|
|
141
|
+
this.extensionClient.close(1000, 'Server shutting down');
|
|
142
|
+
this.extensionClient = null;
|
|
143
|
+
}
|
|
144
|
+
if (this.wss) {
|
|
145
|
+
this.wss.close();
|
|
146
|
+
this.wss = null;
|
|
147
|
+
}
|
|
148
|
+
for (const [id, pending] of this.pendingRequests) {
|
|
149
|
+
clearTimeout(pending.timer);
|
|
150
|
+
pending.reject(new Error('Server shutting down'));
|
|
151
|
+
}
|
|
152
|
+
this.pendingRequests.clear();
|
|
153
|
+
}
|
|
154
|
+
isExtensionConnected() {
|
|
155
|
+
return this.extensionClient !== null && this.extensionClient.readyState === WebSocket.OPEN;
|
|
156
|
+
}
|
|
157
|
+
getExtensionVersion() {
|
|
158
|
+
return this.extensionVersion;
|
|
159
|
+
}
|
|
160
|
+
getPort() {
|
|
161
|
+
return this.port;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// Singleton bridge server — auto-started on first sendAction call
|
|
165
|
+
let _server = null;
|
|
166
|
+
/**
|
|
167
|
+
* Ensure a bridge server is running. Starts one if needed.
|
|
168
|
+
*/
|
|
169
|
+
async function ensureBridge(port) {
|
|
170
|
+
if (_server)
|
|
171
|
+
return _server;
|
|
172
|
+
// Try connecting to an existing server first
|
|
173
|
+
const existing = await new Promise((resolve) => {
|
|
174
|
+
const ws = new WebSocket(`ws://127.0.0.1:${port}`);
|
|
175
|
+
const t = setTimeout(() => { ws.close(); resolve(false); }, 1000);
|
|
176
|
+
ws.on('open', () => { clearTimeout(t); ws.close(); resolve(true); });
|
|
177
|
+
ws.on('error', () => { clearTimeout(t); resolve(false); });
|
|
178
|
+
});
|
|
179
|
+
if (existing) {
|
|
180
|
+
// Another bridge (or `clawmoney serve`) is already running — use it as client
|
|
181
|
+
return null; // signal to use client mode
|
|
182
|
+
}
|
|
183
|
+
// Start our own bridge in-process
|
|
184
|
+
const server = new BridgeServer(port);
|
|
185
|
+
await server.start();
|
|
186
|
+
_server = server;
|
|
187
|
+
return server;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Send an action to the Chrome Extension.
|
|
191
|
+
* Auto-starts bridge server if none is running, then waits for extension to connect.
|
|
192
|
+
*/
|
|
193
|
+
export async function sendAction(actionType, params, port) {
|
|
194
|
+
const wsPort = port || DEFAULT_PORT;
|
|
195
|
+
// Ensure bridge is running
|
|
196
|
+
const server = await ensureBridge(wsPort).catch(() => null);
|
|
197
|
+
// If we own the server, wait for extension to connect (up to 30s)
|
|
198
|
+
if (server && _server === server) {
|
|
199
|
+
const waitStart = Date.now();
|
|
200
|
+
while (!server.isExtensionConnected() && Date.now() - waitStart < 30000) {
|
|
201
|
+
await new Promise(r => setTimeout(r, 500));
|
|
202
|
+
}
|
|
203
|
+
if (!server.isExtensionConnected()) {
|
|
204
|
+
return {
|
|
205
|
+
success: false,
|
|
206
|
+
error: 'Chrome Extension not connected. Make sure BNBot extension is running on a Twitter tab with OpenClaw integration enabled.',
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Send action via WebSocket client
|
|
211
|
+
return new Promise((resolve, reject) => {
|
|
212
|
+
const ws = new WebSocket(`ws://127.0.0.1:${wsPort}`);
|
|
213
|
+
const requestId = randomUUID();
|
|
214
|
+
let settled = false;
|
|
215
|
+
const timer = setTimeout(() => {
|
|
216
|
+
if (!settled) {
|
|
217
|
+
settled = true;
|
|
218
|
+
ws.close();
|
|
219
|
+
reject(new Error(`Action '${actionType}' timed out after ${ACTION_TIMEOUT / 1000}s`));
|
|
220
|
+
}
|
|
221
|
+
}, ACTION_TIMEOUT);
|
|
222
|
+
ws.on('open', () => {
|
|
223
|
+
ws.send(JSON.stringify({
|
|
224
|
+
type: 'action',
|
|
225
|
+
requestId,
|
|
226
|
+
actionType,
|
|
227
|
+
actionPayload: params,
|
|
228
|
+
}));
|
|
229
|
+
});
|
|
230
|
+
ws.on('message', (data) => {
|
|
231
|
+
try {
|
|
232
|
+
const msg = JSON.parse(data.toString());
|
|
233
|
+
if (msg.type === 'action_result' && msg.requestId === requestId) {
|
|
234
|
+
settled = true;
|
|
235
|
+
clearTimeout(timer);
|
|
236
|
+
ws.close();
|
|
237
|
+
resolve({ success: msg.success, data: msg.data, error: msg.error });
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
// ignore
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
ws.on('error', () => {
|
|
245
|
+
if (!settled) {
|
|
246
|
+
settled = true;
|
|
247
|
+
clearTimeout(timer);
|
|
248
|
+
reject(new Error('Cannot connect to bridge. Make sure BNBot Chrome Extension is running.'));
|
|
249
|
+
}
|
|
250
|
+
});
|
|
251
|
+
ws.on('close', () => {
|
|
252
|
+
if (!settled) {
|
|
253
|
+
settled = true;
|
|
254
|
+
clearTimeout(timer);
|
|
255
|
+
reject(new Error('Connection closed before response'));
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
});
|
|
259
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clawmoney",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "ClawMoney CLI -- Earn crypto with your AI agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -16,16 +16,17 @@
|
|
|
16
16
|
"prepublishOnly": "npm run build"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
+
"@types/ws": "^8.18.1",
|
|
19
20
|
"awal": "^2.2.0",
|
|
20
|
-
"bnbot-cli": "^1.3.0",
|
|
21
|
-
"commander": "^12.0.0",
|
|
22
|
-
"yaml": "^2.4.0",
|
|
23
21
|
"chalk": "^5.3.0",
|
|
24
|
-
"
|
|
22
|
+
"commander": "^12.0.0",
|
|
23
|
+
"ora": "^8.0.0",
|
|
24
|
+
"ws": "^8.20.0",
|
|
25
|
+
"yaml": "^2.4.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
27
|
-
"
|
|
28
|
-
"
|
|
28
|
+
"@types/node": "^20.0.0",
|
|
29
|
+
"typescript": "^5.4.0"
|
|
29
30
|
},
|
|
30
31
|
"engines": {
|
|
31
32
|
"node": ">=18"
|