clawcupid-connect 0.0.1
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/cli.js +136 -0
- package/package.json +29 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { execa } from 'execa';
|
|
3
|
+
import open from 'open';
|
|
4
|
+
import JSON5 from 'json5';
|
|
5
|
+
import fs from 'node:fs/promises';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import crypto from 'node:crypto';
|
|
9
|
+
function usage() {
|
|
10
|
+
console.log('Usage: clawcupid-connect <setup|status> [--code CODE] [--api URL]');
|
|
11
|
+
process.exit(1);
|
|
12
|
+
}
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
const cmd = args[0];
|
|
15
|
+
const getFlag = (name) => {
|
|
16
|
+
const idx = args.indexOf(name);
|
|
17
|
+
if (idx === -1)
|
|
18
|
+
return undefined;
|
|
19
|
+
return args[idx + 1];
|
|
20
|
+
};
|
|
21
|
+
const apiBase = getFlag('--api') ?? process.env.CLAWCUPID_API ?? 'https://api.clawcupid.ai';
|
|
22
|
+
function clawdbotConfigPath() {
|
|
23
|
+
// per docs: ~/.clawdbot/clawdbot.json (JSON5)
|
|
24
|
+
return path.join(os.homedir(), '.clawdbot', 'clawdbot.json');
|
|
25
|
+
}
|
|
26
|
+
async function ensureHooksEnabled() {
|
|
27
|
+
const cfgPath = clawdbotConfigPath();
|
|
28
|
+
let raw = '';
|
|
29
|
+
try {
|
|
30
|
+
raw = await fs.readFile(cfgPath, 'utf8');
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
raw = '{\n}\n';
|
|
34
|
+
await fs.mkdir(path.dirname(cfgPath), { recursive: true });
|
|
35
|
+
}
|
|
36
|
+
const cfg = JSON5.parse(raw);
|
|
37
|
+
cfg.hooks = cfg.hooks ?? {};
|
|
38
|
+
cfg.hooks.enabled = true;
|
|
39
|
+
cfg.hooks.path = cfg.hooks.path ?? '/hooks';
|
|
40
|
+
cfg.hooks.token = cfg.hooks.token ?? crypto.randomBytes(32).toString('base64url');
|
|
41
|
+
const nextRaw = JSON5.stringify(cfg, null, 2) + '\n';
|
|
42
|
+
await fs.writeFile(cfgPath, nextRaw, 'utf8');
|
|
43
|
+
return { hookToken: cfg.hooks.token };
|
|
44
|
+
}
|
|
45
|
+
async function detectCli() {
|
|
46
|
+
try {
|
|
47
|
+
await execa('openclaw', ['--version'], { stdio: 'ignore' });
|
|
48
|
+
return 'openclaw';
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return 'clawdbot';
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function restartGateway() {
|
|
55
|
+
const cli = await detectCli();
|
|
56
|
+
try {
|
|
57
|
+
await execa(cli, ['gateway', 'restart'], { stdio: 'inherit' });
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// fallback: at least try status so user sees an error
|
|
61
|
+
await execa(cli, ['gateway', 'status'], { stdio: 'inherit' });
|
|
62
|
+
throw new Error(`Failed to restart ${cli} gateway`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
async function run() {
|
|
66
|
+
if (!cmd)
|
|
67
|
+
usage();
|
|
68
|
+
if (cmd === 'status') {
|
|
69
|
+
console.log('api:', apiBase);
|
|
70
|
+
console.log('clawdbot config:', clawdbotConfigPath());
|
|
71
|
+
try {
|
|
72
|
+
const { stdout } = await execa('tailscale', ['status', '--json']);
|
|
73
|
+
console.log('tailscale: ok');
|
|
74
|
+
console.log(stdout.slice(0, 200) + (stdout.length > 200 ? '...' : ''));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
console.log('tailscale: not available');
|
|
78
|
+
}
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (cmd === 'setup') {
|
|
82
|
+
const code = getFlag('--code');
|
|
83
|
+
if (!code) {
|
|
84
|
+
console.error('Missing --code');
|
|
85
|
+
process.exit(2);
|
|
86
|
+
}
|
|
87
|
+
// 1) Check tailscale CLI
|
|
88
|
+
try {
|
|
89
|
+
await execa('tailscale', ['status'], { stdio: 'ignore' });
|
|
90
|
+
}
|
|
91
|
+
catch {
|
|
92
|
+
console.log('Tailscale not found. Opening install page...');
|
|
93
|
+
await open('https://tailscale.com/download');
|
|
94
|
+
console.log('Install Tailscale, login, then re-run setup.');
|
|
95
|
+
process.exit(3);
|
|
96
|
+
}
|
|
97
|
+
// 2) Get hostname
|
|
98
|
+
const { stdout } = await execa('tailscale', ['status', '--json']);
|
|
99
|
+
// TODO: parse JSON robustly. Temporary heuristic.
|
|
100
|
+
const hostname = /"Self":\s*\{[\s\S]*?"HostName":\s*"([^"]+)"/.exec(stdout)?.[1];
|
|
101
|
+
if (!hostname) {
|
|
102
|
+
console.error('Could not detect tailscale hostname. Are you logged in?');
|
|
103
|
+
console.log('Try: tailscale up');
|
|
104
|
+
process.exit(4);
|
|
105
|
+
}
|
|
106
|
+
// 3) Enable gateway hooks + (re)start gateway
|
|
107
|
+
const gatewayPort = 18789;
|
|
108
|
+
const { hookToken } = await ensureHooksEnabled();
|
|
109
|
+
await restartGateway();
|
|
110
|
+
// 4) Register to server
|
|
111
|
+
const res = await fetch(`${apiBase}/api/connect/register`, {
|
|
112
|
+
method: 'POST',
|
|
113
|
+
headers: { 'content-type': 'application/json' },
|
|
114
|
+
body: JSON.stringify({
|
|
115
|
+
code,
|
|
116
|
+
tailscaleHostname: hostname,
|
|
117
|
+
gatewayPort,
|
|
118
|
+
hookToken,
|
|
119
|
+
channel: 'telegram',
|
|
120
|
+
}),
|
|
121
|
+
});
|
|
122
|
+
if (!res.ok) {
|
|
123
|
+
console.error('Register failed:', res.status, await res.text());
|
|
124
|
+
process.exit(5);
|
|
125
|
+
}
|
|
126
|
+
console.log('Registered. Next step in Telegram:');
|
|
127
|
+
console.log(` clawcupid link ${code}`);
|
|
128
|
+
console.log('(This will bind your current chatId to your account.)');
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
usage();
|
|
132
|
+
}
|
|
133
|
+
run().catch((err) => {
|
|
134
|
+
console.error(err);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clawcupid-connect",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"clawcupid-connect": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/**"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"dev": "tsx src/cli.ts",
|
|
14
|
+
"build": "tsc -p tsconfig.json",
|
|
15
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
16
|
+
"lint": "echo 'no lint yet'",
|
|
17
|
+
"test": "echo 'no tests yet'"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"execa": "^9.6.0",
|
|
21
|
+
"json5": "^2.2.3",
|
|
22
|
+
"open": "^10.2.0",
|
|
23
|
+
"zod": "^4.1.5"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsx": "^4.20.5",
|
|
27
|
+
"typescript": "^5.9.2"
|
|
28
|
+
}
|
|
29
|
+
}
|