@clawlabz/clawnetwork 0.1.16 → 0.1.18
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/index.ts +73 -47
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -2
package/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ declare function setInterval(fn: () => void, ms: number): unknown
|
|
|
7
7
|
declare function clearInterval(id: unknown): void
|
|
8
8
|
declare function fetch(url: string, init?: Record<string, unknown>): Promise<{ status: number; ok: boolean; text: () => Promise<string>; json: () => Promise<unknown> }>
|
|
9
9
|
|
|
10
|
-
const VERSION = '0.1.
|
|
10
|
+
const VERSION = '0.1.18'
|
|
11
11
|
const PLUGIN_ID = 'clawnetwork'
|
|
12
12
|
const GITHUB_REPO = 'clawlabz/claw-network'
|
|
13
13
|
const DEFAULT_RPC_PORT = 9710
|
|
@@ -123,16 +123,23 @@ const path = require('path')
|
|
|
123
123
|
const fs = require('fs')
|
|
124
124
|
const { execFileSync, spawn: nodeSpawn, fork } = require('child_process')
|
|
125
125
|
|
|
126
|
+
function getBaseDir(): string {
|
|
127
|
+
// OPENCLAW_DIR env var takes precedence (supports named profiles like ~/.openclaw-myprofile)
|
|
128
|
+
const envDir = process.env.OPENCLAW_DIR
|
|
129
|
+
if (envDir) return envDir
|
|
130
|
+
return path.join(os.homedir(), '.openclaw')
|
|
131
|
+
}
|
|
132
|
+
|
|
126
133
|
function homePath(...segments: string[]): string {
|
|
127
134
|
return path.join(os.homedir(), ...segments)
|
|
128
135
|
}
|
|
129
136
|
|
|
130
|
-
const WORKSPACE_DIR =
|
|
131
|
-
const BIN_DIR =
|
|
137
|
+
const WORKSPACE_DIR = path.join(getBaseDir(), 'workspace', 'clawnetwork')
|
|
138
|
+
const BIN_DIR = path.join(getBaseDir(), 'bin')
|
|
132
139
|
const DATA_DIR = homePath('.clawnetwork')
|
|
133
140
|
const WALLET_PATH = path.join(WORKSPACE_DIR, 'wallet.json')
|
|
134
141
|
const LOG_PATH = path.join(WORKSPACE_DIR, 'node.log')
|
|
135
|
-
const UI_PORT_FILE =
|
|
142
|
+
const UI_PORT_FILE = path.join(getBaseDir(), 'clawnetwork-ui-port')
|
|
136
143
|
|
|
137
144
|
function ensureDir(dir: string): void {
|
|
138
145
|
fs.mkdirSync(dir, { recursive: true })
|
|
@@ -475,7 +482,7 @@ let nodeStartedAt: number | null = null
|
|
|
475
482
|
let lastHealth: { blockHeight: number | null; peerCount: number | null; syncing: boolean } = { blockHeight: null, peerCount: null, syncing: false }
|
|
476
483
|
let cachedBinaryVersion: string | null = null
|
|
477
484
|
|
|
478
|
-
function isNodeRunning(): { running: boolean; pid: number | null } {
|
|
485
|
+
function isNodeRunning(rpcPort: number = DEFAULT_RPC_PORT): { running: boolean; pid: number | null } {
|
|
479
486
|
// Check in-memory process first
|
|
480
487
|
if (nodeProcess && !nodeProcess.killed) return { running: true, pid: nodeProcess.pid }
|
|
481
488
|
// Check PID file (for detached processes from previous CLI invocations)
|
|
@@ -483,17 +490,24 @@ function isNodeRunning(): { running: boolean; pid: number | null } {
|
|
|
483
490
|
try {
|
|
484
491
|
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10)
|
|
485
492
|
if (pid > 0) {
|
|
486
|
-
try { execFileSync('kill', ['-0', String(pid)], { timeout: 2000 }); return { running: true, pid } } catch {
|
|
493
|
+
try { execFileSync('kill', ['-0', String(pid)], { timeout: 2000 }); return { running: true, pid } } catch {
|
|
494
|
+
// PID file exists but process is dead — clean up stale PID file
|
|
495
|
+
try { fs.unlinkSync(pidFile) } catch { /* ok */ }
|
|
496
|
+
}
|
|
487
497
|
}
|
|
488
498
|
} catch { /* no file */ }
|
|
489
499
|
// Last resort: check if RPC port is responding (covers orphaned processes)
|
|
490
500
|
try {
|
|
491
|
-
execFileSync('curl', ['-sf', '--max-time', '1',
|
|
501
|
+
execFileSync('curl', ['-sf', '--max-time', '1', `http://localhost:${rpcPort}/health`], { timeout: 3000, encoding: 'utf8' })
|
|
492
502
|
// Port is responding — find PID by port
|
|
493
503
|
try {
|
|
494
|
-
const lsof = execFileSync('lsof', ['-ti',
|
|
504
|
+
const lsof = execFileSync('lsof', ['-ti', `:${rpcPort}`], { timeout: 3000, encoding: 'utf8' }).trim()
|
|
495
505
|
const pid = parseInt(lsof.split('\n')[0], 10)
|
|
496
|
-
if (pid > 0)
|
|
506
|
+
if (pid > 0) {
|
|
507
|
+
// Write recovered PID to file for future management
|
|
508
|
+
try { fs.writeFileSync(pidFile, String(pid)) } catch { /* ok */ }
|
|
509
|
+
return { running: true, pid }
|
|
510
|
+
}
|
|
497
511
|
} catch { /* ok */ }
|
|
498
512
|
return { running: true, pid: null }
|
|
499
513
|
} catch { /* not responding */ }
|
|
@@ -502,7 +516,7 @@ function isNodeRunning(): { running: boolean; pid: number | null } {
|
|
|
502
516
|
|
|
503
517
|
function buildStatus(cfg: PluginConfig): NodeStatus {
|
|
504
518
|
const wallet = loadWallet()
|
|
505
|
-
const nodeState = isNodeRunning()
|
|
519
|
+
const nodeState = isNodeRunning(cfg.rpcPort)
|
|
506
520
|
const uptime = nodeStartedAt ? Math.floor((Date.now() - nodeStartedAt) / 1000) : null
|
|
507
521
|
return {
|
|
508
522
|
running: nodeState.running,
|
|
@@ -557,7 +571,7 @@ function startNodeProcess(binaryPath: string, cfg: PluginConfig, api: OpenClawAp
|
|
|
557
571
|
api.logger?.warn?.('[clawnetwork] node already running (in-memory)')
|
|
558
572
|
return
|
|
559
573
|
}
|
|
560
|
-
const existingState = isNodeRunning()
|
|
574
|
+
const existingState = isNodeRunning(cfg.rpcPort)
|
|
561
575
|
if (existingState.running) {
|
|
562
576
|
api.logger?.info?.(`[clawnetwork] node already running (pid=${existingState.pid}), skipping start`)
|
|
563
577
|
return
|
|
@@ -678,8 +692,10 @@ function stopNode(api: OpenClawApi): void {
|
|
|
678
692
|
const stopFile = path.join(WORKSPACE_DIR, 'stop.signal')
|
|
679
693
|
try { fs.writeFileSync(stopFile, String(Date.now())) } catch { /* ok */ }
|
|
680
694
|
|
|
681
|
-
//
|
|
682
|
-
|
|
695
|
+
// Fallback: only use pkill if we had no PID to target (avoids killing other profiles' nodes)
|
|
696
|
+
if (!pid) {
|
|
697
|
+
try { execFileSync('pkill', ['-f', 'claw-node start'], { timeout: 3000 }) } catch { /* ok */ }
|
|
698
|
+
}
|
|
683
699
|
|
|
684
700
|
nodeProcess = null
|
|
685
701
|
nodeStartedAt = null
|
|
@@ -1291,7 +1307,7 @@ function buildUiHtml(cfg: PluginConfig): string {
|
|
|
1291
1307
|
document.getElementById('lastUpdate').textContent = 'Updated: ' + new Date().toLocaleTimeString();
|
|
1292
1308
|
} catch (e) {
|
|
1293
1309
|
console.error(e);
|
|
1294
|
-
renderStatus({ running: false, blockHeight: null, peerCount: null, walletAddress: '', network: 'mainnet', syncMode: 'light', rpcUrl: 'http://localhost:19877', pluginVersion: '
|
|
1310
|
+
renderStatus({ running: false, blockHeight: null, peerCount: null, walletAddress: '', network: 'mainnet', syncMode: 'light', rpcUrl: 'http://localhost:19877', pluginVersion: '${VERSION}', restartCount: 0, dataDir: '', balance: '', syncing: false, uptimeFormatted: '—', pid: null });
|
|
1295
1311
|
}
|
|
1296
1312
|
}
|
|
1297
1313
|
|
|
@@ -1450,10 +1466,22 @@ const fs = require('fs');
|
|
|
1450
1466
|
const os = require('os');
|
|
1451
1467
|
const path = require('path');
|
|
1452
1468
|
|
|
1469
|
+
// OPENCLAW_BASE_DIR and PLUGIN_VERSION are injected as const by startUiServer() prepend.
|
|
1470
|
+
// Use global lookup to avoid const/var redeclaration conflict.
|
|
1471
|
+
const _BASE = (typeof OPENCLAW_BASE_DIR !== 'undefined') ? OPENCLAW_BASE_DIR : path.join(os.homedir(), '.openclaw');
|
|
1472
|
+
const _PVER = (typeof PLUGIN_VERSION !== 'undefined') ? PLUGIN_VERSION : 'unknown';
|
|
1473
|
+
const OC_WORKSPACE = path.join(_BASE, 'workspace', 'clawnetwork');
|
|
1474
|
+
const OC_BIN_DIR = path.join(_BASE, 'bin');
|
|
1475
|
+
const OC_WALLET_PATH = path.join(OC_WORKSPACE, 'wallet.json');
|
|
1476
|
+
const OC_PID_FILE = path.join(OC_WORKSPACE, 'node.pid');
|
|
1477
|
+
const OC_CONFIG_PATH = path.join(OC_WORKSPACE, 'config.json');
|
|
1478
|
+
const OC_STOP_SIGNAL = path.join(OC_WORKSPACE, 'stop.signal');
|
|
1479
|
+
const OC_LOG_PATH_DEFAULT = path.join(OC_WORKSPACE, 'node.log');
|
|
1480
|
+
|
|
1453
1481
|
const PORT = parseInt(process.argv[2] || '19877', 10);
|
|
1454
1482
|
const RPC_PORT = parseInt(process.argv[3] || '9710', 10);
|
|
1455
|
-
const LOG_PATH = process.argv[4] ||
|
|
1456
|
-
const PORT_FILE = path.join(
|
|
1483
|
+
const LOG_PATH = process.argv[4] || OC_LOG_PATH_DEFAULT;
|
|
1484
|
+
const PORT_FILE = path.join(_BASE, 'clawnetwork-ui-port');
|
|
1457
1485
|
const MAX_RETRIES = 10;
|
|
1458
1486
|
|
|
1459
1487
|
async function fetchJson(url) {
|
|
@@ -1492,12 +1520,10 @@ function readBody(req) {
|
|
|
1492
1520
|
}
|
|
1493
1521
|
|
|
1494
1522
|
function findNodeBinary() {
|
|
1495
|
-
const binDir = path.join(os.homedir(), '.openclaw/bin');
|
|
1496
|
-
const dataDir = path.join(os.homedir(), '.clawnetwork');
|
|
1497
1523
|
const binName = process.platform === 'win32' ? 'claw-node.exe' : 'claw-node';
|
|
1498
|
-
let binary = path.join(
|
|
1524
|
+
let binary = path.join(OC_BIN_DIR, binName);
|
|
1499
1525
|
if (fs.existsSync(binary)) return binary;
|
|
1500
|
-
binary = path.join(
|
|
1526
|
+
binary = path.join(os.homedir(), '.clawnetwork', 'bin', 'claw-node');
|
|
1501
1527
|
if (fs.existsSync(binary)) return binary;
|
|
1502
1528
|
return null;
|
|
1503
1529
|
}
|
|
@@ -1540,7 +1566,7 @@ async function handle(req, res) {
|
|
|
1540
1566
|
}
|
|
1541
1567
|
} catch {}
|
|
1542
1568
|
try {
|
|
1543
|
-
const walletPath =
|
|
1569
|
+
const walletPath = OC_WALLET_PATH;
|
|
1544
1570
|
const w = JSON.parse(fs.readFileSync(walletPath, 'utf8'));
|
|
1545
1571
|
walletAddress = w.address || '';
|
|
1546
1572
|
if (w.address) {
|
|
@@ -1557,15 +1583,15 @@ async function handle(req, res) {
|
|
|
1557
1583
|
rpcUrl: 'http://localhost:' + RPC_PORT,
|
|
1558
1584
|
walletAddress,
|
|
1559
1585
|
binaryVersion: h.version,
|
|
1560
|
-
pluginVersion:
|
|
1586
|
+
pluginVersion: _PVER,
|
|
1561
1587
|
uptime: h.uptime_secs,
|
|
1562
1588
|
uptimeFormatted: h.uptime_secs < 60 ? h.uptime_secs + 's' : h.uptime_secs < 3600 ? Math.floor(h.uptime_secs/60) + 'm' : Math.floor(h.uptime_secs/3600) + 'h ' + Math.floor((h.uptime_secs%3600)/60) + 'm',
|
|
1563
1589
|
restartCount: 0, dataDir: path.join(os.homedir(), '.clawnetwork'), balance, agentName, syncing: h.status === 'degraded', peerless: h.peer_count === 0, lastBlockAgeSecs: h.last_block_age_secs,
|
|
1564
1590
|
upgradeLevel, latestVersion, releaseUrl, changelog, announcement,
|
|
1565
1591
|
});
|
|
1566
1592
|
} catch {
|
|
1567
|
-
const walletAddr = (() => { try { return JSON.parse(fs.readFileSync(
|
|
1568
|
-
json(200, { running: false, blockHeight: null, peerCount: null, walletAddress: walletAddr, network: 'mainnet', syncMode: 'light', rpcUrl: 'http://localhost:' + RPC_PORT, pluginVersion:
|
|
1593
|
+
const walletAddr = (() => { try { return JSON.parse(fs.readFileSync(OC_WALLET_PATH, 'utf8')).address; } catch { return ''; } })();
|
|
1594
|
+
json(200, { running: false, blockHeight: null, peerCount: null, walletAddress: walletAddr, network: 'mainnet', syncMode: 'light', rpcUrl: 'http://localhost:' + RPC_PORT, pluginVersion: _PVER, restartCount: 0, dataDir: path.join(os.homedir(), '.clawnetwork'), balance: '', agentName: '', syncing: false, uptimeFormatted: '—', pid: null, upgradeLevel: 'unknown', latestVersion: '', releaseUrl: '', changelog: '', announcement: null });
|
|
1569
1595
|
}
|
|
1570
1596
|
return;
|
|
1571
1597
|
}
|
|
@@ -1585,7 +1611,7 @@ async function handle(req, res) {
|
|
|
1585
1611
|
return;
|
|
1586
1612
|
}
|
|
1587
1613
|
try {
|
|
1588
|
-
const walletPath =
|
|
1614
|
+
const walletPath = OC_WALLET_PATH;
|
|
1589
1615
|
const w = JSON.parse(fs.readFileSync(walletPath, 'utf8'));
|
|
1590
1616
|
json(200, { address: w.address, secretKey: w.secret_key || w.secretKey || w.private_key || '' });
|
|
1591
1617
|
} catch (e) { json(400, { error: 'No wallet found' }); }
|
|
@@ -1594,7 +1620,7 @@ async function handle(req, res) {
|
|
|
1594
1620
|
// ── Business API endpoints (mirrors Gateway methods) ──
|
|
1595
1621
|
if (p === '/api/wallet/balance') {
|
|
1596
1622
|
try {
|
|
1597
|
-
const walletPath =
|
|
1623
|
+
const walletPath = OC_WALLET_PATH;
|
|
1598
1624
|
const w = JSON.parse(fs.readFileSync(walletPath, 'utf8'));
|
|
1599
1625
|
const address = new URL(req.url, 'http://localhost').searchParams.get('address') || w.address;
|
|
1600
1626
|
const b = await rpcCall('claw_getBalance', [address]);
|
|
@@ -1669,7 +1695,7 @@ async function handle(req, res) {
|
|
|
1669
1695
|
}
|
|
1670
1696
|
if (p === '/api/node/config') {
|
|
1671
1697
|
try {
|
|
1672
|
-
const cfgPath =
|
|
1698
|
+
const cfgPath = OC_CONFIG_PATH;
|
|
1673
1699
|
const cfg = fs.existsSync(cfgPath) ? JSON.parse(fs.readFileSync(cfgPath, 'utf8')) : {};
|
|
1674
1700
|
json(200, { ...cfg, rpcPort: RPC_PORT, uiPort: PORT });
|
|
1675
1701
|
} catch (e) { json(200, { rpcPort: RPC_PORT, uiPort: PORT }); }
|
|
@@ -1679,7 +1705,7 @@ async function handle(req, res) {
|
|
|
1679
1705
|
const a = p.split('/').pop();
|
|
1680
1706
|
if (a === 'faucet') {
|
|
1681
1707
|
try {
|
|
1682
|
-
const w = JSON.parse(fs.readFileSync(
|
|
1708
|
+
const w = JSON.parse(fs.readFileSync(OC_WALLET_PATH, 'utf8'));
|
|
1683
1709
|
const r = await rpcCall('claw_faucet', [w.address]);
|
|
1684
1710
|
json(200, { message: 'Faucet success', ...r });
|
|
1685
1711
|
} catch (e) { json(400, { error: e.message }); }
|
|
@@ -1688,7 +1714,7 @@ async function handle(req, res) {
|
|
|
1688
1714
|
if (a === 'start') {
|
|
1689
1715
|
try {
|
|
1690
1716
|
// Check if already running — try RPC health first (covers stale PID file)
|
|
1691
|
-
const pidFile =
|
|
1717
|
+
const pidFile = OC_PID_FILE;
|
|
1692
1718
|
try {
|
|
1693
1719
|
const h = await fetchJson('http://localhost:' + RPC_PORT + '/health');
|
|
1694
1720
|
if (h && (h.status === 'ok' || h.status === 'degraded')) {
|
|
@@ -1707,14 +1733,14 @@ async function handle(req, res) {
|
|
|
1707
1733
|
if (pid > 0) { try { process.kill(pid, 0); json(200, { message: 'Node already running', pid }); return; } catch {} }
|
|
1708
1734
|
} catch {}
|
|
1709
1735
|
// Find binary
|
|
1710
|
-
const binDir =
|
|
1736
|
+
const binDir = OC_BIN_DIR;
|
|
1711
1737
|
const dataDir = path.join(os.homedir(), '.clawnetwork');
|
|
1712
1738
|
const binName = process.platform === 'win32' ? 'claw-node.exe' : 'claw-node';
|
|
1713
1739
|
let binary = path.join(binDir, binName);
|
|
1714
1740
|
if (!fs.existsSync(binary)) { binary = path.join(dataDir, 'bin', 'claw-node'); }
|
|
1715
1741
|
if (!fs.existsSync(binary)) { json(400, { error: 'claw-node binary not found. Run: openclaw clawnetwork:download' }); return; }
|
|
1716
1742
|
// Read config for network/ports
|
|
1717
|
-
const cfgPath =
|
|
1743
|
+
const cfgPath = OC_CONFIG_PATH;
|
|
1718
1744
|
let network = 'mainnet', p2pPort = 9711, syncMode = 'light', extraPeers = [];
|
|
1719
1745
|
try {
|
|
1720
1746
|
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
@@ -1728,7 +1754,7 @@ async function handle(req, res) {
|
|
|
1728
1754
|
const args = ['start', '--network', network, '--rpc-port', String(RPC_PORT), '--p2p-port', String(p2pPort), '--sync-mode', syncMode, '--allow-genesis'];
|
|
1729
1755
|
for (const peer of peers) { args.push('--bootstrap', peer); }
|
|
1730
1756
|
// Spawn detached
|
|
1731
|
-
const logPath =
|
|
1757
|
+
const logPath = OC_LOG_PATH_DEFAULT;
|
|
1732
1758
|
const logFd = fs.openSync(logPath, 'a');
|
|
1733
1759
|
const { spawn: nodeSpawn } = require('child_process');
|
|
1734
1760
|
const child = nodeSpawn(binary, args, {
|
|
@@ -1740,7 +1766,7 @@ async function handle(req, res) {
|
|
|
1740
1766
|
fs.closeSync(logFd);
|
|
1741
1767
|
fs.writeFileSync(pidFile, String(child.pid));
|
|
1742
1768
|
// Remove stop signal if exists
|
|
1743
|
-
const stopFile =
|
|
1769
|
+
const stopFile = OC_STOP_SIGNAL;
|
|
1744
1770
|
try { fs.unlinkSync(stopFile); } catch {}
|
|
1745
1771
|
json(200, { message: 'Node started', pid: child.pid });
|
|
1746
1772
|
} catch (e) { json(500, { error: e.message }); }
|
|
@@ -1748,14 +1774,14 @@ async function handle(req, res) {
|
|
|
1748
1774
|
}
|
|
1749
1775
|
if (a === 'stop') {
|
|
1750
1776
|
try {
|
|
1751
|
-
const pidFile =
|
|
1777
|
+
const pidFile = OC_PID_FILE;
|
|
1752
1778
|
let pid = null;
|
|
1753
1779
|
try { pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10); } catch {}
|
|
1754
1780
|
if (pid && pid > 0) {
|
|
1755
1781
|
try { process.kill(pid, 'SIGTERM'); } catch {}
|
|
1756
1782
|
}
|
|
1757
1783
|
// Write stop signal for restart loop
|
|
1758
|
-
const stopFile =
|
|
1784
|
+
const stopFile = OC_STOP_SIGNAL;
|
|
1759
1785
|
try { fs.writeFileSync(stopFile, String(Date.now())); } catch {}
|
|
1760
1786
|
// Also kill by name (covers orphans)
|
|
1761
1787
|
try { require('child_process').execFileSync('pkill', ['-f', 'claw-node start'], { timeout: 3000 }); } catch {}
|
|
@@ -1772,12 +1798,12 @@ async function handle(req, res) {
|
|
|
1772
1798
|
if (a === 'restart') {
|
|
1773
1799
|
// Stop, wait, start — all server-side
|
|
1774
1800
|
try {
|
|
1775
|
-
const pidFile =
|
|
1801
|
+
const pidFile = OC_PID_FILE;
|
|
1776
1802
|
try {
|
|
1777
1803
|
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10);
|
|
1778
1804
|
if (pid > 0) try { process.kill(pid, 'SIGTERM'); } catch {}
|
|
1779
1805
|
} catch {}
|
|
1780
|
-
const stopFile =
|
|
1806
|
+
const stopFile = OC_STOP_SIGNAL;
|
|
1781
1807
|
try { fs.writeFileSync(stopFile, String(Date.now())); } catch {}
|
|
1782
1808
|
try { require('child_process').execFileSync('pkill', ['-f', 'claw-node start'], { timeout: 3000 }); } catch {}
|
|
1783
1809
|
try { fs.unlinkSync(pidFile); } catch {}
|
|
@@ -1788,12 +1814,12 @@ async function handle(req, res) {
|
|
|
1788
1814
|
}
|
|
1789
1815
|
try { fs.unlinkSync(stopFile); } catch {}
|
|
1790
1816
|
// Now start (reuse start logic inline)
|
|
1791
|
-
const binDir =
|
|
1817
|
+
const binDir = OC_BIN_DIR;
|
|
1792
1818
|
const binName = process.platform === 'win32' ? 'claw-node.exe' : 'claw-node';
|
|
1793
1819
|
let binary = path.join(binDir, binName);
|
|
1794
1820
|
if (!fs.existsSync(binary)) { binary = path.join(os.homedir(), '.clawnetwork/bin/claw-node'); }
|
|
1795
1821
|
if (!fs.existsSync(binary)) { json(400, { error: 'claw-node binary not found' }); return; }
|
|
1796
|
-
const cfgPath =
|
|
1822
|
+
const cfgPath = OC_CONFIG_PATH;
|
|
1797
1823
|
let network = 'mainnet', p2pPort = 9711, syncMode = 'light', extraPeers = [];
|
|
1798
1824
|
try {
|
|
1799
1825
|
const cfg = JSON.parse(fs.readFileSync(cfgPath, 'utf8'));
|
|
@@ -1806,7 +1832,7 @@ async function handle(req, res) {
|
|
|
1806
1832
|
const peers = [...(bootstrapPeers[network] || []), ...extraPeers];
|
|
1807
1833
|
const args = ['start', '--network', network, '--rpc-port', String(RPC_PORT), '--p2p-port', String(p2pPort), '--sync-mode', syncMode, '--allow-genesis'];
|
|
1808
1834
|
for (const peer of peers) { args.push('--bootstrap', peer); }
|
|
1809
|
-
const logPath =
|
|
1835
|
+
const logPath = OC_LOG_PATH_DEFAULT;
|
|
1810
1836
|
const logFd = fs.openSync(logPath, 'a');
|
|
1811
1837
|
const { spawn: nodeSpawn } = require('child_process');
|
|
1812
1838
|
const child = nodeSpawn(binary, args, {
|
|
@@ -1824,7 +1850,7 @@ async function handle(req, res) {
|
|
|
1824
1850
|
if (a === 'upgrade') {
|
|
1825
1851
|
try {
|
|
1826
1852
|
// 1. Stop running node
|
|
1827
|
-
const pidFile =
|
|
1853
|
+
const pidFile = OC_PID_FILE;
|
|
1828
1854
|
try {
|
|
1829
1855
|
const pid = parseInt(fs.readFileSync(pidFile, 'utf8').trim(), 10);
|
|
1830
1856
|
if (pid > 0) try { process.kill(pid, 'SIGTERM'); } catch {}
|
|
@@ -1832,7 +1858,7 @@ async function handle(req, res) {
|
|
|
1832
1858
|
try { require('child_process').execFileSync('pkill', ['-f', 'claw-node start'], { timeout: 5000 }); } catch {}
|
|
1833
1859
|
|
|
1834
1860
|
// 2. Download latest binary
|
|
1835
|
-
const binDir =
|
|
1861
|
+
const binDir = OC_BIN_DIR;
|
|
1836
1862
|
const binName = process.platform === 'win32' ? 'claw-node.exe' : 'claw-node';
|
|
1837
1863
|
const target = process.platform === 'darwin'
|
|
1838
1864
|
? (process.arch === 'arm64' ? 'macos-aarch64' : 'macos-x86_64')
|
|
@@ -1914,8 +1940,8 @@ function startUiServer(cfg: PluginConfig, api: OpenClawApi): string | null {
|
|
|
1914
1940
|
const htmlPath = path.join(WORKSPACE_DIR, 'ui-dashboard.html')
|
|
1915
1941
|
fs.writeFileSync(htmlPath, buildUiHtml(cfg))
|
|
1916
1942
|
|
|
1917
|
-
// Inject HTML path into script (read from file, no template escaping issues)
|
|
1918
|
-
const fullScript = `const HTML_PATH = ${JSON.stringify(htmlPath)};\nconst HTML = require('fs').readFileSync(HTML_PATH, 'utf8');\n${UI_SERVER_SCRIPT}`
|
|
1943
|
+
// Inject base dir, version, and HTML path into script (read from file, no template escaping issues)
|
|
1944
|
+
const fullScript = `const OPENCLAW_BASE_DIR = ${JSON.stringify(getBaseDir())};\nconst PLUGIN_VERSION = ${JSON.stringify(VERSION)};\nconst HTML_PATH = ${JSON.stringify(htmlPath)};\nconst HTML = require('fs').readFileSync(HTML_PATH, 'utf8');\n${UI_SERVER_SCRIPT}`
|
|
1919
1945
|
fs.writeFileSync(scriptPath, fullScript)
|
|
1920
1946
|
|
|
1921
1947
|
try {
|
|
@@ -2129,7 +2155,7 @@ export default function register(api: OpenClawApi) {
|
|
|
2129
2155
|
|
|
2130
2156
|
const handleStart = async () => {
|
|
2131
2157
|
// Check if already running (in-memory or detached via PID file)
|
|
2132
|
-
const state = isNodeRunning()
|
|
2158
|
+
const state = isNodeRunning(cfg.rpcPort)
|
|
2133
2159
|
if (state.running) {
|
|
2134
2160
|
out({ message: 'Node already running', pid: state.pid })
|
|
2135
2161
|
return
|
|
@@ -2392,7 +2418,7 @@ export default function register(api: OpenClawApi) {
|
|
|
2392
2418
|
;(async () => {
|
|
2393
2419
|
try {
|
|
2394
2420
|
// Check if already running (e.g. from a previous detached start)
|
|
2395
|
-
const state = isNodeRunning()
|
|
2421
|
+
const state = isNodeRunning(cfg.rpcPort)
|
|
2396
2422
|
if (state.running) {
|
|
2397
2423
|
api.logger?.info?.(`[clawnetwork] node already running (pid=${state.pid})`)
|
|
2398
2424
|
|
|
@@ -2414,7 +2440,7 @@ export default function register(api: OpenClawApi) {
|
|
|
2414
2440
|
|
|
2415
2441
|
if (latestVersion && isVersionOlder(runningVersion, latestVersion)) {
|
|
2416
2442
|
api.logger?.info?.(`[clawnetwork] node ${runningVersion} → ${latestVersion} available, upgrading...`)
|
|
2417
|
-
|
|
2443
|
+
stopNode(api)
|
|
2418
2444
|
await sleep(3_000)
|
|
2419
2445
|
try {
|
|
2420
2446
|
const newBinary = await downloadBinary(api)
|
package/openclaw.plugin.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clawlabz/clawnetwork",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Run a ClawNetwork blockchain node inside OpenClaw. Every agent is a blockchain node.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -56,6 +56,6 @@
|
|
|
56
56
|
"scripts": {
|
|
57
57
|
"build": "echo 'no build step'",
|
|
58
58
|
"lint": "node -e \"process.exit(0)\"",
|
|
59
|
-
"test": "node
|
|
59
|
+
"test": "node --test tests/unit.test.mjs"
|
|
60
60
|
}
|
|
61
61
|
}
|