@umimoney/clawdbot-setup 0.1.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 @@
1
+ #!/usr/bin/env node
package/dist/index.js ADDED
@@ -0,0 +1,431 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
18
+ // If the importer is in node compatibility mode or this is not an ESM
19
+ // file that has been converted to a CommonJS file using a Babel-
20
+ // compatible transform (i.e. "__esModule" has not been set), then set
21
+ // "default" to the CommonJS "module.exports" for node compatibility.
22
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
23
+ mod
24
+ ));
25
+
26
+ // src/index.ts
27
+ var fs = __toESM(require("fs"));
28
+ var path = __toESM(require("path"));
29
+ var os = __toESM(require("os"));
30
+ var https = __toESM(require("https"));
31
+ var import_child_process = require("child_process");
32
+ var import_prompts = __toESM(require("prompts"));
33
+ var import_chalk = __toESM(require("chalk"));
34
+ var API_BASE = "https://server.umi.app/api";
35
+ var RELAY_PLUGIN_PACKAGE = "@umimoney/clawdbot-relay-plugin";
36
+ var RELAY_PLUGIN_VERSION = "0.1.21";
37
+ async function validateApiKey(apiKey) {
38
+ return new Promise((resolve) => {
39
+ const url = new URL(`${API_BASE}/agent-external/info`);
40
+ const req = https.request(url, {
41
+ method: "GET",
42
+ headers: {
43
+ "Authorization": `Bearer ${apiKey}`,
44
+ "Content-Type": "application/json"
45
+ }
46
+ }, (res) => {
47
+ let data = "";
48
+ res.on("data", (chunk) => data += chunk);
49
+ res.on("end", () => {
50
+ try {
51
+ const json = JSON.parse(data);
52
+ if (json.error) {
53
+ resolve({ valid: false, error: json.error });
54
+ } else if (json.agent) {
55
+ resolve({ valid: true, agent: json.agent });
56
+ } else {
57
+ resolve({ valid: false, error: "Unexpected response format" });
58
+ }
59
+ } catch (e) {
60
+ resolve({ valid: false, error: "Failed to parse response" });
61
+ }
62
+ });
63
+ });
64
+ req.on("error", (e) => {
65
+ resolve({ valid: false, error: e.message });
66
+ });
67
+ req.end();
68
+ });
69
+ }
70
+ function findClawdbotConfig() {
71
+ const possiblePaths = [
72
+ path.join(os.homedir(), ".clawdbot", "clawdbot.json"),
73
+ path.join(os.homedir(), ".moltbot", "moltbot.json"),
74
+ path.join(os.homedir(), ".config", "clawdbot", "clawdbot.json"),
75
+ path.join(os.homedir(), ".config", "moltbot", "moltbot.json")
76
+ ];
77
+ for (const p of possiblePaths) {
78
+ if (fs.existsSync(p)) {
79
+ return p;
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+ function findPluginPath() {
85
+ const possiblePaths = [
86
+ "/opt/homebrew/lib/node_modules/clawdbot/node_modules/@umimoney/clawdbot-relay-plugin",
87
+ "/opt/homebrew/lib/node_modules/moltbot/node_modules/@umimoney/clawdbot-relay-plugin",
88
+ "/usr/local/lib/node_modules/clawdbot/node_modules/@umimoney/clawdbot-relay-plugin",
89
+ "/usr/local/lib/node_modules/moltbot/node_modules/@umimoney/clawdbot-relay-plugin",
90
+ path.join(os.homedir(), ".clawdbot", "node_modules", "@umimoney", "clawdbot-relay-plugin"),
91
+ path.join(os.homedir(), ".moltbot", "node_modules", "@umimoney", "clawdbot-relay-plugin")
92
+ ];
93
+ for (const p of possiblePaths) {
94
+ if (fs.existsSync(p)) {
95
+ return p;
96
+ }
97
+ }
98
+ return null;
99
+ }
100
+ function readConfig(configPath) {
101
+ try {
102
+ const content = fs.readFileSync(configPath, "utf-8");
103
+ const stripped = content.replace(/\/\/.*$/gm, "").replace(/\/\*[\s\S]*?\*\//g, "");
104
+ return JSON.parse(stripped);
105
+ } catch (e) {
106
+ return {};
107
+ }
108
+ }
109
+ function writeConfig(configPath, config) {
110
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), "utf-8");
111
+ }
112
+ function updateConfig(configPath, apiKey, pluginPath) {
113
+ const config = readConfig(configPath);
114
+ if (!config.channels) config.channels = {};
115
+ config.channels["umi-relay"] = {
116
+ enabled: true,
117
+ apiKey
118
+ };
119
+ if (!config.plugins) config.plugins = {};
120
+ if (!config.plugins.entries) config.plugins.entries = {};
121
+ config.plugins.entries["umi-relay"] = {
122
+ enabled: true,
123
+ config: {
124
+ apiKey
125
+ }
126
+ };
127
+ if (!config.env) config.env = {};
128
+ if (!config.env.vars) config.env.vars = {};
129
+ config.env.vars["UMI_API_KEY"] = apiKey;
130
+ if (pluginPath) {
131
+ if (!config.plugins.load) config.plugins.load = {};
132
+ if (!config.plugins.load.paths) config.plugins.load.paths = [];
133
+ if (!config.plugins.load.paths.includes(pluginPath)) {
134
+ config.plugins.load.paths.push(pluginPath);
135
+ }
136
+ }
137
+ writeConfig(configPath, config);
138
+ }
139
+ function findLaunchAgentPlist() {
140
+ const possiblePaths = [
141
+ path.join(os.homedir(), "Library", "LaunchAgents", "com.clawdbot.gateway.plist"),
142
+ path.join(os.homedir(), "Library", "LaunchAgents", "com.moltbot.gateway.plist")
143
+ ];
144
+ for (const p of possiblePaths) {
145
+ if (fs.existsSync(p)) {
146
+ return p;
147
+ }
148
+ }
149
+ return null;
150
+ }
151
+ function updateLaunchAgentPlist(plistPath, apiKey) {
152
+ try {
153
+ try {
154
+ (0, import_child_process.execSync)(`/usr/libexec/PlistBuddy -c 'Set :EnvironmentVariables:UMI_API_KEY ${apiKey}' "${plistPath}"`, { stdio: "pipe" });
155
+ } catch {
156
+ (0, import_child_process.execSync)(`/usr/libexec/PlistBuddy -c 'Add :EnvironmentVariables:UMI_API_KEY string ${apiKey}' "${plistPath}"`, { stdio: "pipe" });
157
+ }
158
+ return true;
159
+ } catch (e) {
160
+ return false;
161
+ }
162
+ }
163
+ function getServiceName() {
164
+ const possibleNames = ["com.clawdbot.gateway", "com.moltbot.gateway"];
165
+ for (const name of possibleNames) {
166
+ const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${name}.plist`);
167
+ if (fs.existsSync(plistPath)) {
168
+ return name;
169
+ }
170
+ }
171
+ return null;
172
+ }
173
+ function restartService() {
174
+ const platform2 = os.platform();
175
+ if (platform2 === "darwin") {
176
+ const serviceName = getServiceName();
177
+ if (!serviceName) {
178
+ console.log(import_chalk.default.yellow(" Could not find LaunchAgent service"));
179
+ return false;
180
+ }
181
+ const uid = process.getuid?.() || 501;
182
+ const plistPath = path.join(os.homedir(), "Library", "LaunchAgents", `${serviceName}.plist`);
183
+ try {
184
+ try {
185
+ (0, import_child_process.execSync)(`launchctl bootout gui/${uid}/${serviceName}`, { stdio: "pipe" });
186
+ } catch {
187
+ }
188
+ (0, import_child_process.execSync)("sleep 2");
189
+ (0, import_child_process.execSync)(`launchctl bootstrap gui/${uid} "${plistPath}"`, { stdio: "pipe" });
190
+ return true;
191
+ } catch (e) {
192
+ return false;
193
+ }
194
+ } else if (platform2 === "linux") {
195
+ try {
196
+ (0, import_child_process.execSync)("systemctl --user restart clawdbot-gateway || systemctl --user restart moltbot-gateway", { stdio: "pipe" });
197
+ return true;
198
+ } catch {
199
+ return false;
200
+ }
201
+ }
202
+ return false;
203
+ }
204
+ function updatePlugin() {
205
+ const clawdbotPaths = [
206
+ "/opt/homebrew/lib/node_modules/clawdbot",
207
+ "/opt/homebrew/lib/node_modules/moltbot",
208
+ "/usr/local/lib/node_modules/clawdbot",
209
+ "/usr/local/lib/node_modules/moltbot"
210
+ ];
211
+ for (const p of clawdbotPaths) {
212
+ if (fs.existsSync(p)) {
213
+ try {
214
+ (0, import_child_process.execSync)(`cd "${p}" && npm update ${RELAY_PLUGIN_PACKAGE}@${RELAY_PLUGIN_VERSION}`, { stdio: "pipe" });
215
+ return true;
216
+ } catch {
217
+ }
218
+ }
219
+ }
220
+ return false;
221
+ }
222
+ async function verifyConnection(agentName, timeout = 1e4) {
223
+ const logPaths = [
224
+ path.join(os.homedir(), ".clawdbot", "logs", "gateway.log"),
225
+ path.join(os.homedir(), ".moltbot", "logs", "gateway.log")
226
+ ];
227
+ const startTime = Date.now();
228
+ while (Date.now() - startTime < timeout) {
229
+ for (const logPath of logPaths) {
230
+ if (fs.existsSync(logPath)) {
231
+ try {
232
+ const content = fs.readFileSync(logPath, "utf-8");
233
+ const lines = content.split("\n").slice(-50);
234
+ for (const line of lines) {
235
+ if (line.includes(`Authenticated as ${agentName}`) || line.includes(`Connected as "${agentName}"`)) {
236
+ return true;
237
+ }
238
+ }
239
+ } catch {
240
+ }
241
+ }
242
+ }
243
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
244
+ }
245
+ return false;
246
+ }
247
+ async function main() {
248
+ const args = process.argv.slice(2);
249
+ const isReconfigure = args.includes("--reconfigure") || args.includes("-r");
250
+ const isValidateOnly = args.includes("--validate") || args.includes("-v");
251
+ const isHelp = args.includes("--help") || args.includes("-h");
252
+ if (isHelp) {
253
+ console.log(`
254
+ ${import_chalk.default.bold("UMI Clawdbot Setup")}
255
+
256
+ Usage: npx @umimoney/clawdbot-setup [options]
257
+
258
+ Options:
259
+ --reconfigure, -r Force reconfiguration even if already set up
260
+ --validate, -v Just validate the current API key without changes
261
+ --help, -h Show this help message
262
+
263
+ This tool:
264
+ 1. Validates your UMI API key
265
+ 2. Shows which agent the key belongs to
266
+ 3. Updates all required config locations
267
+ 4. Restarts the service
268
+ 5. Verifies the connection
269
+ `);
270
+ process.exit(0);
271
+ }
272
+ console.log();
273
+ console.log(import_chalk.default.bold.cyan(" UMI Clawdbot Setup"));
274
+ console.log();
275
+ const configPath = findClawdbotConfig();
276
+ if (!configPath) {
277
+ console.log(import_chalk.default.red(" Error: Clawdbot/Moltbot config not found."));
278
+ console.log(import_chalk.default.gray(" Make sure clawdbot or moltbot is installed first."));
279
+ console.log();
280
+ process.exit(1);
281
+ }
282
+ console.log(import_chalk.default.gray(` Found config: ${configPath}`));
283
+ const existingConfig = readConfig(configPath);
284
+ const existingKey = existingConfig?.channels?.["umi-relay"]?.apiKey || existingConfig?.env?.vars?.UMI_API_KEY;
285
+ if (existingKey && !isReconfigure && !isValidateOnly) {
286
+ console.log();
287
+ console.log(import_chalk.default.yellow(" UMI relay is already configured."));
288
+ console.log(import_chalk.default.gray(` Existing key: ${existingKey.substring(0, 12)}...`));
289
+ const { action } = await (0, import_prompts.default)({
290
+ type: "select",
291
+ name: "action",
292
+ message: "What would you like to do?",
293
+ choices: [
294
+ { title: "Validate current key", value: "validate" },
295
+ { title: "Reconfigure with new key", value: "reconfigure" },
296
+ { title: "Exit", value: "exit" }
297
+ ]
298
+ });
299
+ if (action === "exit" || !action) {
300
+ process.exit(0);
301
+ }
302
+ if (action === "validate") {
303
+ console.log();
304
+ console.log(import_chalk.default.gray(" Validating current key..."));
305
+ const result = await validateApiKey(existingKey);
306
+ if (result.valid && result.agent) {
307
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Key is valid`));
308
+ console.log(import_chalk.default.white(` Agent: ${import_chalk.default.bold(result.agent.name)}`));
309
+ console.log(import_chalk.default.gray(` ID: ${result.agent.id}`));
310
+ console.log(import_chalk.default.gray(` Chains: ${result.agent.chains.join(", ")}`));
311
+ console.log(import_chalk.default.gray(` Scopes: ${result.agent.scopes.join(", ")}`));
312
+ console.log(import_chalk.default.gray(` Whitelisted: ${result.agent.whitelisted ? "Yes" : "No"}`));
313
+ } else {
314
+ console.log(import_chalk.default.red(` ${import_chalk.default.bold("\u2717")} Key is invalid: ${result.error}`));
315
+ }
316
+ console.log();
317
+ process.exit(result.valid ? 0 : 1);
318
+ }
319
+ }
320
+ if (isValidateOnly && existingKey) {
321
+ console.log();
322
+ console.log(import_chalk.default.gray(" Validating current key..."));
323
+ const result = await validateApiKey(existingKey);
324
+ if (result.valid && result.agent) {
325
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Key is valid`));
326
+ console.log(import_chalk.default.white(` Agent: ${import_chalk.default.bold(result.agent.name)}`));
327
+ } else {
328
+ console.log(import_chalk.default.red(` ${import_chalk.default.bold("\u2717")} Key is invalid: ${result.error}`));
329
+ }
330
+ console.log();
331
+ process.exit(result.valid ? 0 : 1);
332
+ }
333
+ console.log();
334
+ const { apiKey } = await (0, import_prompts.default)({
335
+ type: "password",
336
+ name: "apiKey",
337
+ message: "Enter your UMI API key:",
338
+ validate: (value) => value.startsWith("umi_") ? true : 'API key must start with "umi_"'
339
+ });
340
+ if (!apiKey) {
341
+ console.log(import_chalk.default.red(" Cancelled."));
342
+ process.exit(1);
343
+ }
344
+ console.log();
345
+ console.log(import_chalk.default.gray(" Validating key..."));
346
+ const validation = await validateApiKey(apiKey);
347
+ if (!validation.valid) {
348
+ console.log(import_chalk.default.red(` ${import_chalk.default.bold("\u2717")} Invalid API key: ${validation.error}`));
349
+ console.log();
350
+ console.log(import_chalk.default.gray(" Tip: You can validate your key manually with:"));
351
+ console.log(import_chalk.default.gray(` curl -H "Authorization: Bearer <key>" ${API_BASE}/agent-external/info`));
352
+ console.log();
353
+ process.exit(1);
354
+ }
355
+ const agent = validation.agent;
356
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Key validated`));
357
+ console.log();
358
+ console.log(import_chalk.default.white(` This key is for agent: ${import_chalk.default.bold.cyan(agent.name)}`));
359
+ console.log(import_chalk.default.gray(` ID: ${agent.id}`));
360
+ console.log(import_chalk.default.gray(` Chains: ${agent.chains.join(", ")}`));
361
+ console.log(import_chalk.default.gray(` Scopes: ${agent.scopes.join(", ")}`));
362
+ console.log(import_chalk.default.gray(` Whitelisted: ${agent.whitelisted ? import_chalk.default.green("Yes") : import_chalk.default.yellow("No")}`));
363
+ console.log();
364
+ const { confirm } = await (0, import_prompts.default)({
365
+ type: "confirm",
366
+ name: "confirm",
367
+ message: "Continue with setup?",
368
+ initial: true
369
+ });
370
+ if (!confirm) {
371
+ console.log(import_chalk.default.red(" Cancelled."));
372
+ process.exit(1);
373
+ }
374
+ console.log();
375
+ const pluginPath = findPluginPath();
376
+ console.log(import_chalk.default.gray(" Updating config..."));
377
+ try {
378
+ updateConfig(configPath, apiKey, pluginPath);
379
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Updated ${configPath}`));
380
+ } catch (e) {
381
+ console.log(import_chalk.default.red(` ${import_chalk.default.bold("\u2717")} Failed to update config: ${e.message}`));
382
+ process.exit(1);
383
+ }
384
+ if (os.platform() === "darwin") {
385
+ const plistPath = findLaunchAgentPlist();
386
+ if (plistPath) {
387
+ console.log(import_chalk.default.gray(" Updating LaunchAgent..."));
388
+ if (updateLaunchAgentPlist(plistPath, apiKey)) {
389
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Updated ${plistPath}`));
390
+ } else {
391
+ console.log(import_chalk.default.yellow(` ${import_chalk.default.bold("!")} Could not update LaunchAgent plist`));
392
+ }
393
+ }
394
+ }
395
+ console.log(import_chalk.default.gray(" Updating relay plugin..."));
396
+ if (updatePlugin()) {
397
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Updated ${RELAY_PLUGIN_PACKAGE} to v${RELAY_PLUGIN_VERSION}`));
398
+ } else {
399
+ console.log(import_chalk.default.yellow(` ${import_chalk.default.bold("!")} Could not update plugin (may need manual update)`));
400
+ }
401
+ console.log();
402
+ console.log(import_chalk.default.gray(" Restarting service..."));
403
+ if (restartService()) {
404
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Service restarted`));
405
+ } else {
406
+ console.log(import_chalk.default.yellow(` ${import_chalk.default.bold("!")} Could not restart service automatically`));
407
+ console.log(import_chalk.default.gray(" You may need to restart manually"));
408
+ }
409
+ console.log();
410
+ console.log(import_chalk.default.gray(" Verifying connection (this may take a few seconds)..."));
411
+ const connected = await verifyConnection(agent.name, 15e3);
412
+ if (connected) {
413
+ console.log(import_chalk.default.green(` ${import_chalk.default.bold("\u2713")} Connected as "${agent.name}"`));
414
+ } else {
415
+ console.log(import_chalk.default.yellow(` ${import_chalk.default.bold("!")} Could not verify connection`));
416
+ console.log(import_chalk.default.gray(" Check logs at ~/.clawdbot/logs/gateway.log"));
417
+ }
418
+ console.log();
419
+ console.log(import_chalk.default.green.bold(" Setup complete!"));
420
+ console.log(import_chalk.default.gray(` Your agent "${agent.name}" should now be connected to umi.app`));
421
+ console.log();
422
+ if (!agent.whitelisted) {
423
+ console.log(import_chalk.default.yellow(" Note: Your agent is not whitelisted yet."));
424
+ console.log(import_chalk.default.gray(" Visit umi.app to whitelist it before executing transactions."));
425
+ console.log();
426
+ }
427
+ }
428
+ main().catch((e) => {
429
+ console.error(import_chalk.default.red("Error:"), e.message);
430
+ process.exit(1);
431
+ });
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@umimoney/clawdbot-setup",
3
+ "version": "0.1.0",
4
+ "description": "One-command setup for UMI relay with Clawdbot/Moltbot",
5
+ "bin": {
6
+ "clawdbot-setup": "./dist/index.js",
7
+ "umi-setup": "./dist/index.js"
8
+ },
9
+ "main": "dist/index.js",
10
+ "types": "dist/index.d.ts",
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsup src/index.ts --format cjs --dts --clean",
16
+ "prepublishOnly": "npm run build"
17
+ },
18
+ "keywords": [
19
+ "umi",
20
+ "clawdbot",
21
+ "moltbot",
22
+ "setup",
23
+ "relay",
24
+ "agent"
25
+ ],
26
+ "author": "UMI Labs",
27
+ "license": "MIT",
28
+ "dependencies": {
29
+ "chalk": "^4.1.2",
30
+ "prompts": "^2.4.2"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^20.0.0",
34
+ "@types/prompts": "^2.4.9",
35
+ "tsup": "^8.0.0",
36
+ "typescript": "^5.3.0"
37
+ }
38
+ }