clawskill 1.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.
Files changed (2) hide show
  1. package/bin/clawskill.js +410 -0
  2. package/package.json +19 -0
@@ -0,0 +1,410 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ClawSkill — Mine RTC tokens with your AI agent on real hardware.
4
+ *
5
+ * Modern machines get 1x multiplier. Vintage hardware gets bonus.
6
+ * VMs are detected and penalized — real iron only.
7
+ *
8
+ * Usage:
9
+ * npm install -g clawskill
10
+ * clawskill install --wallet my-agent
11
+ * clawskill start
12
+ */
13
+
14
+ const { execSync, spawn } = require('child_process');
15
+ const fs = require('fs');
16
+ const https = require('https');
17
+ const http = require('http');
18
+ const os = require('os');
19
+ const path = require('path');
20
+ const readline = require('readline');
21
+
22
+ const REPO_BASE = 'https://raw.githubusercontent.com/Scottcjn/Rustchain/main';
23
+ const INSTALL_DIR = path.join(os.homedir(), '.clawskill');
24
+ const VENV_DIR = path.join(INSTALL_DIR, 'venv');
25
+ const NODE_URL = 'https://50.28.86.131';
26
+
27
+ // ANSI colors
28
+ const C = '\x1b[36m', G = '\x1b[32m', R = '\x1b[31m', Y = '\x1b[33m';
29
+ const B = '\x1b[1m', D = '\x1b[2m', NC = '\x1b[0m';
30
+
31
+ const log = (m) => console.log(`${C}[clawskill]${NC} ${m}`);
32
+ const ok = (m) => console.log(`${G}[OK]${NC} ${m}`);
33
+ const warn = (m) => console.log(`${Y}[WARN]${NC} ${m}`);
34
+
35
+ function downloadFile(url, dest) {
36
+ return new Promise((resolve, reject) => {
37
+ const file = fs.createWriteStream(dest);
38
+ const mod = url.startsWith('https') ? https : http;
39
+ const opts = { rejectUnauthorized: false };
40
+ mod.get(url, opts, (res) => {
41
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
42
+ file.close();
43
+ fs.unlinkSync(dest);
44
+ return downloadFile(res.headers.location, dest).then(resolve).catch(reject);
45
+ }
46
+ res.pipe(file);
47
+ file.on('finish', () => {
48
+ file.close();
49
+ const size = fs.statSync(dest).size;
50
+ if (size < 100) return reject(new Error(`File too small (${size} bytes)`));
51
+ resolve(size);
52
+ });
53
+ }).on('error', (e) => { file.close(); reject(e); });
54
+ });
55
+ }
56
+
57
+ function ask(prompt) {
58
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
59
+ return new Promise((resolve) => {
60
+ rl.question(prompt, (ans) => { rl.close(); resolve(ans.trim()); });
61
+ });
62
+ }
63
+
64
+ function detectVM() {
65
+ const hints = [];
66
+ if (os.platform() === 'linux') {
67
+ const dmiPaths = ['/sys/class/dmi/id/sys_vendor', '/sys/class/dmi/id/product_name'];
68
+ const vmVendors = ['qemu', 'vmware', 'virtualbox', 'xen', 'kvm', 'microsoft', 'parallels'];
69
+ for (const p of dmiPaths) {
70
+ try {
71
+ const val = fs.readFileSync(p, 'utf8').trim().toLowerCase();
72
+ if (vmVendors.some(v => val.includes(v))) hints.push(`${p}: ${val}`);
73
+ } catch (e) {}
74
+ }
75
+ try {
76
+ const cpu = fs.readFileSync('/proc/cpuinfo', 'utf8').toLowerCase();
77
+ if (cpu.includes('hypervisor')) hints.push('cpuinfo: hypervisor flag');
78
+ } catch (e) {}
79
+ }
80
+ return hints;
81
+ }
82
+
83
+ async function cmdInstall(walletArg) {
84
+ console.log(`
85
+ ${C}${B}
86
+ ██████╗██╗ █████╗ ██╗ ██╗███████╗██╗ ██╗██╗██╗ ██╗
87
+ ██╔════╝██║ ██╔══██╗██║ ██║██╔════╝██║ ██╔╝██║██║ ██║
88
+ ██║ ██║ ███████║██║ █╗ ██║███████╗█████╔╝ ██║██║ ██║
89
+ ██║ ██║ ██╔══██║██║███╗██║╚════██║██╔═██╗ ██║██║ ██║
90
+ ╚██████╗███████╗██║ ██║╚███╔███╔╝███████║██║ ██╗██║███████╗███████╗
91
+ ╚═════╝╚══════╝╚═╝ ╚═╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝╚═╝╚══════╝╚══════╝
92
+ ${NC}
93
+ ${D} Mine RTC tokens with your AI agent on real hardware${NC}
94
+ ${D} Modern x86/ARM = 1x | Vintage PowerPC = up to 2.5x | VM = ~0x${NC}
95
+ `);
96
+
97
+ const plat = os.platform();
98
+ const arch = os.arch();
99
+ log(`Platform: ${plat} | Arch: ${arch}`);
100
+
101
+ if (plat !== 'linux' && plat !== 'darwin') {
102
+ console.error(`${R}[ERROR]${NC} Unsupported platform: ${plat}. Use Linux or macOS.`);
103
+ process.exit(1);
104
+ }
105
+
106
+ // VM check
107
+ const vmHints = detectVM();
108
+ if (vmHints.length > 0) {
109
+ console.log(`
110
+ ${R}${B} ╔══════════════════════════════════════════════════════════╗
111
+ ║ ⚠ VM DETECTED — READ THIS ⚠ ║
112
+ ╠══════════════════════════════════════════════════════════╣
113
+ ║ This machine appears to be a virtual machine. ║
114
+ ║ RustChain will detect VMs and assign near-zero weight. ║
115
+ ║ Your miner will attest but earn effectively nothing. ║
116
+ ║ To earn RTC, run on bare-metal hardware. ║
117
+ ╚══════════════════════════════════════════════════════════╝${NC}`);
118
+ for (const h of vmHints.slice(0, 4)) console.log(` ${R} • ${h}${NC}`);
119
+ console.log();
120
+ }
121
+
122
+ // Wallet
123
+ let wallet = walletArg;
124
+ if (!wallet) {
125
+ wallet = await ask(`${C}[clawskill]${NC} Enter agent wallet name (e.g. my-claw-agent): `);
126
+ }
127
+ if (!wallet) {
128
+ const host = os.hostname().split('.')[0] || 'agent';
129
+ wallet = `claw-${host}-${Date.now() % 100000}`;
130
+ warn(`No wallet provided. Auto-generated: ${wallet}`);
131
+ }
132
+
133
+ // Create install dir
134
+ log(`Installing to ${INSTALL_DIR}`);
135
+ fs.mkdirSync(INSTALL_DIR, { recursive: true });
136
+ fs.writeFileSync(path.join(INSTALL_DIR, '.wallet'), wallet);
137
+
138
+ // Check for python3
139
+ let pythonBin = 'python3';
140
+ try { execSync('python3 --version', { stdio: 'pipe' }); }
141
+ catch (e) {
142
+ try { execSync('python --version', { stdio: 'pipe' }); pythonBin = 'python'; }
143
+ catch (e2) {
144
+ console.error(`${R}[ERROR]${NC} Python 3 not found. Install Python 3.8+ first.`);
145
+ process.exit(1);
146
+ }
147
+ }
148
+
149
+ // Create venv
150
+ if (!fs.existsSync(VENV_DIR)) {
151
+ log('Creating Python environment...');
152
+ execSync(`${pythonBin} -m venv "${VENV_DIR}"`, { stdio: 'inherit' });
153
+ }
154
+
155
+ // Install deps
156
+ log('Installing dependencies...');
157
+ const pip = path.join(VENV_DIR, 'bin', 'pip');
158
+ execSync(`"${pip}" install --upgrade pip -q`, { stdio: 'pipe' });
159
+ execSync(`"${pip}" install requests -q`, { stdio: 'pipe' });
160
+ ok('Dependencies ready');
161
+
162
+ // Download miner files
163
+ log('Downloading miner from RustChain repo...');
164
+ const downloads = [
165
+ [`${REPO_BASE}/miners/linux/fingerprint_checks.py`, 'fingerprint_checks.py'],
166
+ ];
167
+
168
+ if (plat === 'linux') {
169
+ downloads.push([`${REPO_BASE}/miners/linux/rustchain_linux_miner.py`, 'miner.py']);
170
+ } else if (plat === 'darwin') {
171
+ downloads.push([`${REPO_BASE}/miners/macos/rustchain_mac_miner_v2.4.py`, 'miner.py']);
172
+ }
173
+
174
+ for (const [url, filename] of downloads) {
175
+ const dest = path.join(INSTALL_DIR, filename);
176
+ const size = await downloadFile(url, dest);
177
+ log(` ${filename} (${(size / 1024).toFixed(1)} KB)`);
178
+ }
179
+ ok('Miner files downloaded');
180
+
181
+ // Setup service
182
+ if (plat === 'linux') {
183
+ setupSystemd(wallet);
184
+ } else if (plat === 'darwin') {
185
+ setupLaunchd(wallet);
186
+ }
187
+
188
+ // Network check
189
+ log('Checking RustChain network...');
190
+ try {
191
+ const data = await new Promise((resolve, reject) => {
192
+ https.get(`${NODE_URL}/api/miners`, { rejectUnauthorized: false }, (res) => {
193
+ let d = '';
194
+ res.on('data', c => d += c);
195
+ res.on('end', () => resolve(d));
196
+ }).on('error', reject);
197
+ });
198
+ const miners = JSON.parse(data);
199
+ log(`Active miners on network: ${miners.length}`);
200
+ } catch (e) {
201
+ warn('Could not reach network (node may be temporarily unavailable)');
202
+ }
203
+
204
+ console.log(`
205
+ ${G}${B}═══════════════════════════════════════════════════════════
206
+ ClawSkill installed! Your agent is ready to mine RTC.
207
+
208
+ Wallet: ${wallet}
209
+ Location: ${INSTALL_DIR}
210
+ Reward: 1x multiplier (modern hardware)
211
+
212
+ Commands:
213
+ clawskill start Start mining in background
214
+ clawskill stop Stop mining
215
+ clawskill status Check miner + network status
216
+ clawskill logs View miner output
217
+
218
+ How it works:
219
+ • Your agent proves real hardware via 6 fingerprint checks
220
+ • Attestation happens automatically every few minutes
221
+ • RTC tokens accumulate in your wallet each epoch (~10 min)
222
+ • Check balance: clawskill status
223
+
224
+ Multipliers:
225
+ Modern x86/ARM → 1.0x (you are here)
226
+ Apple Silicon → 1.2x
227
+ PowerPC G5 → 2.0x
228
+ PowerPC G4 → 2.5x
229
+ VM/Emulator → ~0x (detected & penalized)
230
+ ═══════════════════════════════════════════════════════════${NC}
231
+ `);
232
+ }
233
+
234
+ function setupSystemd(wallet) {
235
+ const svcDir = path.join(os.homedir(), '.config', 'systemd', 'user');
236
+ fs.mkdirSync(svcDir, { recursive: true });
237
+ const svcFile = path.join(svcDir, 'clawskill-miner.service');
238
+ const pythonBin = path.join(VENV_DIR, 'bin', 'python');
239
+ const minerPy = path.join(INSTALL_DIR, 'miner.py');
240
+
241
+ fs.writeFileSync(svcFile, `[Unit]
242
+ Description=ClawSkill RTC Miner — AI Agent Mining
243
+ After=network-online.target
244
+ Wants=network-online.target
245
+
246
+ [Service]
247
+ ExecStart=${pythonBin} ${minerPy} --wallet ${wallet}
248
+ Restart=always
249
+ RestartSec=30
250
+ WorkingDirectory=${INSTALL_DIR}
251
+ Environment=PYTHONUNBUFFERED=1
252
+
253
+ [Install]
254
+ WantedBy=default.target
255
+ `);
256
+
257
+ try {
258
+ execSync('systemctl --user daemon-reload', { stdio: 'pipe' });
259
+ execSync('systemctl --user enable clawskill-miner', { stdio: 'pipe' });
260
+ execSync('systemctl --user start clawskill-miner', { stdio: 'pipe' });
261
+ ok('Service installed and started');
262
+ } catch (e) {
263
+ warn('Systemd user services not available. Use: clawskill start');
264
+ }
265
+ }
266
+
267
+ function setupLaunchd(wallet) {
268
+ const plistDir = path.join(os.homedir(), 'Library', 'LaunchAgents');
269
+ fs.mkdirSync(plistDir, { recursive: true });
270
+ const plistFile = path.join(plistDir, 'com.clawskill.miner.plist');
271
+ const pythonBin = path.join(VENV_DIR, 'bin', 'python');
272
+ const minerPy = path.join(INSTALL_DIR, 'miner.py');
273
+
274
+ fs.writeFileSync(plistFile, `<?xml version="1.0" encoding="UTF-8"?>
275
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
276
+ "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
277
+ <plist version="1.0">
278
+ <dict>
279
+ <key>Label</key>
280
+ <string>com.clawskill.miner</string>
281
+ <key>ProgramArguments</key>
282
+ <array>
283
+ <string>${pythonBin}</string>
284
+ <string>${minerPy}</string>
285
+ <string>--wallet</string>
286
+ <string>${wallet}</string>
287
+ </array>
288
+ <key>WorkingDirectory</key>
289
+ <string>${INSTALL_DIR}</string>
290
+ <key>RunAtLoad</key>
291
+ <true/>
292
+ <key>KeepAlive</key>
293
+ <true/>
294
+ <key>StandardOutPath</key>
295
+ <string>${path.join(INSTALL_DIR, 'miner.log')}</string>
296
+ <key>StandardErrorPath</key>
297
+ <string>${path.join(INSTALL_DIR, 'miner.err')}</string>
298
+ </dict>
299
+ </plist>`);
300
+
301
+ try {
302
+ execSync(`launchctl unload "${plistFile}" 2>/dev/null`, { stdio: 'pipe' });
303
+ } catch (e) {}
304
+ try {
305
+ execSync(`launchctl load "${plistFile}"`, { stdio: 'pipe' });
306
+ ok('LaunchAgent installed and loaded');
307
+ } catch (e) {
308
+ warn('Could not load LaunchAgent. Use: clawskill start');
309
+ }
310
+ }
311
+
312
+ function cmdStart() {
313
+ if (os.platform() === 'linux') {
314
+ execSync('systemctl --user start clawskill-miner', { stdio: 'inherit' });
315
+ } else if (os.platform() === 'darwin') {
316
+ const pf = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.clawskill.miner.plist');
317
+ try { execSync(`launchctl load "${pf}"`, { stdio: 'inherit' }); } catch (e) {}
318
+ }
319
+ ok('Miner started');
320
+ }
321
+
322
+ function cmdStop() {
323
+ if (os.platform() === 'linux') {
324
+ try { execSync('systemctl --user stop clawskill-miner', { stdio: 'pipe' }); } catch (e) {}
325
+ } else if (os.platform() === 'darwin') {
326
+ const pf = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.clawskill.miner.plist');
327
+ try { execSync(`launchctl unload "${pf}"`, { stdio: 'pipe' }); } catch (e) {}
328
+ }
329
+ ok('Miner stopped');
330
+ }
331
+
332
+ function cmdStatus() {
333
+ if (os.platform() === 'linux') {
334
+ try { execSync('systemctl --user status clawskill-miner', { stdio: 'inherit' }); } catch (e) {}
335
+ } else if (os.platform() === 'darwin') {
336
+ try { execSync('launchctl list | grep clawskill', { stdio: 'inherit' }); } catch (e) {}
337
+ }
338
+ const wf = path.join(INSTALL_DIR, '.wallet');
339
+ if (fs.existsSync(wf)) log(`Wallet: ${fs.readFileSync(wf, 'utf8').trim()}`);
340
+
341
+ https.get(`${NODE_URL}/health`, { rejectUnauthorized: false }, (res) => {
342
+ let d = '';
343
+ res.on('data', c => d += c);
344
+ res.on('end', () => {
345
+ try {
346
+ const h = JSON.parse(d);
347
+ log(`Network: ${h.ok ? 'online' : 'offline'} (v${h.version || '?'})`);
348
+ } catch (e) { warn('Could not parse network status'); }
349
+ });
350
+ }).on('error', () => warn('Could not reach network'));
351
+ }
352
+
353
+ function cmdLogs() {
354
+ if (os.platform() === 'linux') {
355
+ spawn('journalctl', ['--user', '-u', 'clawskill-miner', '-f', '--no-pager', '-n', '50'], { stdio: 'inherit' });
356
+ } else {
357
+ const lf = path.join(INSTALL_DIR, 'miner.log');
358
+ if (fs.existsSync(lf)) spawn('tail', ['-f', lf], { stdio: 'inherit' });
359
+ else warn('No log file found');
360
+ }
361
+ }
362
+
363
+ function cmdUninstall() {
364
+ log('Stopping miner...');
365
+ cmdStop();
366
+ if (os.platform() === 'linux') {
367
+ try { execSync('systemctl --user disable clawskill-miner', { stdio: 'pipe' }); } catch (e) {}
368
+ const sf = path.join(os.homedir(), '.config', 'systemd', 'user', 'clawskill-miner.service');
369
+ try { fs.unlinkSync(sf); } catch (e) {}
370
+ } else if (os.platform() === 'darwin') {
371
+ const pf = path.join(os.homedir(), 'Library', 'LaunchAgents', 'com.clawskill.miner.plist');
372
+ try { fs.unlinkSync(pf); } catch (e) {}
373
+ }
374
+ try { fs.rmSync(INSTALL_DIR, { recursive: true, force: true }); } catch (e) {}
375
+ ok('ClawSkill miner uninstalled');
376
+ }
377
+
378
+ // Main
379
+ const args = process.argv.slice(2);
380
+ const cmd = args[0] || 'install';
381
+ const walletIdx = args.indexOf('--wallet');
382
+ const walletArg = walletIdx >= 0 ? args[walletIdx + 1] : null;
383
+
384
+ switch (cmd) {
385
+ case 'install': cmdInstall(walletArg); break;
386
+ case 'start': cmdStart(); break;
387
+ case 'stop': cmdStop(); break;
388
+ case 'status': cmdStatus(); break;
389
+ case 'logs': cmdLogs(); break;
390
+ case 'uninstall': cmdUninstall(); break;
391
+ case '--help': case '-h':
392
+ console.log(`
393
+ ClawSkill — Mine RTC tokens with your AI agent on real hardware
394
+
395
+ Commands:
396
+ clawskill install [--wallet NAME] Install miner and configure wallet
397
+ clawskill start Start mining in background
398
+ clawskill stop Stop mining
399
+ clawskill status Check miner + network status
400
+ clawskill logs View miner output
401
+ clawskill uninstall Remove everything
402
+
403
+ Modern hardware gets 1x multiplier. VMs are detected and penalized.
404
+ Vintage hardware (PowerPC G4/G5) gets up to 2.5x bonus.
405
+ `);
406
+ break;
407
+ default:
408
+ console.error(`Unknown command: ${cmd}. Use --help for usage.`);
409
+ process.exit(1);
410
+ }
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "clawskill",
3
+ "version": "1.0.1",
4
+ "description": "ClawSkill — Let your AI agent mine RTC tokens on any modern hardware. 1x multiplier, built-in wallet, VM-penalized.",
5
+ "bin": {
6
+ "clawskill": "./bin/clawskill.js"
7
+ },
8
+ "keywords": ["clawskill", "ai-agent", "miner", "rustchain", "rtc", "openclaw", "proof-of-antiquity", "blockchain"],
9
+ "author": "Elyan Labs <scott@elyanlabs.ai>",
10
+ "license": "MIT",
11
+ "homepage": "https://bottube.ai",
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/Scottcjn/Rustchain"
15
+ },
16
+ "engines": {
17
+ "node": ">=14"
18
+ }
19
+ }